Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Rewriting ECC #114

Merged
merged 36 commits into from
Dec 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e00c89f
adding toByteString and fromByteString to PRK.
kazu-yamamoto Nov 8, 2016
60bb2ca
[ECC] Improve the code base to allow multiples different implementations
vincenthz Oct 16, 2015
7c833ed
improve description
vincenthz Mar 21, 2016
f3255c2
fix imports on older versions
vincenthz Mar 23, 2016
c29fa82
add a note about scalarInverse
vincenthz Mar 24, 2016
9a0ec91
implementing ecdh fpr P256 and P521.
kazu-yamamoto Nov 15, 2016
dea0469
adding Curve_P384R1.
kazu-yamamoto Nov 16, 2016
aa33c00
adding Curve_X25519.
kazu-yamamoto Nov 16, 2016
a6f1773
Eq and Show for Point and Scalar.
kazu-yamamoto Nov 16, 2016
c0b0846
implmenting encodePoint and decodePoint for TLS.
kazu-yamamoto Nov 17, 2016
2b9dce2
Dropping Show from PRK.
kazu-yamamoto Nov 28, 2016
39ecb35
removing a trailing space / a warning.
kazu-yamamoto Nov 30, 2016
3a2eb3c
using ByteArray(Access) instead of ByteString.
kazu-yamamoto Nov 30, 2016
be6bf11
using ScrubbedBytes directly.
kazu-yamamoto Nov 30, 2016
f84aa5d
documentation & relaxing types.
kazu-yamamoto Nov 30, 2016
58151b9
making PRK an instance of ByteArrayAccess and removing fromPRK/toPRK.
kazu-yamamoto Nov 30, 2016
e9ea55a
relaxing types of encodePoint and decodePoint.
kazu-yamamoto Nov 30, 2016
a5fb2ee
don't export function that replace existing functionality and by-pass…
vincenthz Dec 1, 2016
d80a87d
add new EC errors
vincenthz Dec 1, 2016
a9e3917
fix Curve25519 generate secret key to work in the MonadRandom instead…
vincenthz Dec 1, 2016
55f385a
change point decoding to be able to fail explicitely instead of async…
vincenthz Dec 1, 2016
f37d0b7
remove arithmetic on Curve25519. it's mathematically not possible
vincenthz Dec 1, 2016
f1ebbff
fixup haddock markup
vincenthz Dec 1, 2016
07b6e80
Rewrite EC primitive and types to have the curve as type
vincenthz Dec 1, 2016
422c5fd
remove reference to the old api in the documentation
vincenthz Dec 2, 2016
11e42a2
add the binding to get the size by bytes
vincenthz Dec 2, 2016
955f010
add internal proxy type to create witnesses
vincenthz Dec 2, 2016
7e6d7cc
complete rewrite of the type class
vincenthz Dec 2, 2016
8b5a36f
fix ECIES to work with the rewrite
vincenthz Dec 2, 2016
922bed5
add some documentation to ECIES
vincenthz Dec 2, 2016
052417e
properly check for point validity before making a point
vincenthz Dec 2, 2016
5e52a7f
use binary serializer for P256 instead of going through the simple po…
vincenthz Dec 2, 2016
f627bf4
make a faster and more secure related to memory blits of pointDh for …
vincenthz Dec 2, 2016
a9b722b
Add missing compatibility modules
vincenthz Dec 2, 2016
6e1d18f
use the correct compat imports
vincenthz Dec 2, 2016
07bfa10
fix proxy
vincenthz Dec 2, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions Crypto/ECC.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
-- |
-- Module : Crypto.ECC
-- License : BSD-style
-- Maintainer : Vincent Hanquez <[email protected]>
-- Stability : experimental
-- Portability : unknown
--
-- Elliptic Curve Cryptography
--
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Crypto.ECC
( Curve_P256R1(..)
, Curve_P384R1(..)
, Curve_P521R1(..)
, Curve_X25519(..)
, EllipticCurve(..)
, EllipticCurveDH(..)
, EllipticCurveArith(..)
, KeyPair(..)
, SharedSecret(..)
) where

import qualified Crypto.PubKey.ECC.P256 as P256
import qualified Crypto.ECC.Simple.Types as Simple
import qualified Crypto.ECC.Simple.Prim as Simple
import Crypto.Random
import Crypto.Error
import Crypto.Internal.Proxy
import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Number.Serialize (i2ospOf_, os2ip)
import qualified Crypto.PubKey.Curve25519 as X25519
import Data.Function (on)
import Data.ByteArray (convert)

-- | An elliptic curve key pair composed of the private part (a scalar), and
-- the associated point.
data KeyPair curve = KeyPair
{ keypairGetPublic :: !(Point curve)
, keypairGetPrivate :: !(Scalar curve)
}

newtype SharedSecret = SharedSecret ScrubbedBytes
deriving (Eq, ByteArrayAccess)

class EllipticCurve curve where
-- | Point on an Elliptic Curve
type Point curve :: *

-- | Scalar in the Elliptic Curve domain
type Scalar curve :: *

-- | Generate a new random scalar on the curve.
-- The scalar will represent a number between 1 and the order of the curve non included
curveGenerateScalar :: MonadRandom randomly => proxy curve -> randomly (Scalar curve)

-- | Generate a new random keypair
curveGenerateKeyPair :: MonadRandom randomly => proxy curve -> randomly (KeyPair curve)

-- | Get the curve size in bits
curveSizeBits :: proxy curve -> Int

-- | Encode a elliptic curve point into binary form
encodePoint :: ByteArray bs => proxy curve -> Point curve -> bs

-- | Try to decode the binary form of an elliptic curve point
decodePoint :: ByteArray bs => proxy curve -> bs -> CryptoFailable (Point curve)

class EllipticCurve curve => EllipticCurveDH curve where
-- | Generate a Diffie hellman secret value.
--
-- This is generally just the .x coordinate of the resulting point, that
-- is not hashed.
--
-- use `pointSmul` to keep the result in Point format.
ecdh :: proxy curve -> Scalar curve -> Point curve -> SharedSecret

class EllipticCurve curve => EllipticCurveArith curve where
-- | Add points on a curve
pointAdd :: proxy curve -> Point curve -> Point curve -> Point curve

-- | Scalar Multiplication on a curve
pointSmul :: proxy curve -> Scalar curve -> Point curve -> Point curve

-- -- | Scalar Inverse
-- scalarInverse :: Scalar curve -> Scalar curve

-- | P256 Curve
--
-- also known as P256
data Curve_P256R1 = Curve_P256R1

instance EllipticCurve Curve_P256R1 where
type Point Curve_P256R1 = P256.Point
type Scalar Curve_P256R1 = P256.Scalar
curveSizeBits _ = 256
curveGenerateScalar _ = P256.scalarGenerate
curveGenerateKeyPair _ = toKeyPair <$> P256.scalarGenerate
where toKeyPair scalar = KeyPair (P256.toPoint scalar) scalar
encodePoint _ p = P256.pointToBinary p
decodePoint _ bs = P256.pointFromBinary bs

instance EllipticCurveArith Curve_P256R1 where
pointAdd _ a b = P256.pointAdd a b
pointSmul _ s p = P256.pointMul s p

instance EllipticCurveDH Curve_P256R1 where
ecdh _ s p = SharedSecret $ P256.pointDh s p

data Curve_P384R1 = Curve_P384R1

instance EllipticCurve Curve_P384R1 where
type Point Curve_P384R1 = Simple.Point Simple.SEC_p384r1
type Scalar Curve_P384R1 = Simple.Scalar Simple.SEC_p384r1
curveSizeBits _ = 384
curveGenerateScalar _ = Simple.scalarGenerate
curveGenerateKeyPair _ = toKeyPair <$> Simple.scalarGenerate
where toKeyPair scalar = KeyPair (Simple.pointBaseMul scalar) scalar
encodePoint _ point = encodeECPoint point
decodePoint _ bs = decodeECPoint bs

instance EllipticCurveArith Curve_P384R1 where
pointAdd _ a b = Simple.pointAdd a b
pointSmul _ s p = Simple.pointMul s p

instance EllipticCurveDH Curve_P384R1 where
ecdh _ s p = SharedSecret $ i2ospOf_ (curveSizeBytes prx) x
where
prx = Proxy :: Proxy Curve_P384R1
Simple.Point x _ = pointSmul prx s p

data Curve_P521R1 = Curve_P521R1

instance EllipticCurve Curve_P521R1 where
type Point Curve_P521R1 = Simple.Point Simple.SEC_p521r1
type Scalar Curve_P521R1 = Simple.Scalar Simple.SEC_p521r1
curveSizeBits _ = 521
curveGenerateScalar _ = Simple.scalarGenerate
curveGenerateKeyPair _ = toKeyPair <$> Simple.scalarGenerate
where toKeyPair scalar = KeyPair (Simple.pointBaseMul scalar) scalar
encodePoint _ point = encodeECPoint point
decodePoint _ bs = decodeECPoint bs

instance EllipticCurveArith Curve_P521R1 where
pointAdd _ a b = Simple.pointAdd a b
pointSmul _ s p = Simple.pointMul s p

instance EllipticCurveDH Curve_P521R1 where
ecdh _ s p = SharedSecret $ i2ospOf_ (curveSizeBytes prx) x
where
prx = Proxy :: Proxy Curve_P521R1
Simple.Point x _ = pointSmul prx s p

data Curve_X25519 = Curve_X25519

instance EllipticCurve Curve_X25519 where
type Point Curve_X25519 = X25519.PublicKey
type Scalar Curve_X25519 = X25519.SecretKey
curveSizeBits _ = 255
curveGenerateScalar _ = X25519.generateSecretKey
curveGenerateKeyPair _ = do
s <- X25519.generateSecretKey
return $ KeyPair (X25519.toPublic s) s
encodePoint _ p = B.convert p
decodePoint _ bs = X25519.publicKey bs

instance EllipticCurveDH Curve_X25519 where
ecdh _ s p = SharedSecret $ convert secret
where secret = X25519.dh p s

encodeECPoint :: forall curve bs . (Simple.Curve curve, ByteArray bs) => Simple.Point curve -> bs
encodeECPoint Simple.PointO = error "encodeECPoint: cannot serialize point at infinity"
encodeECPoint (Simple.Point x y) = B.concat [uncompressed,xb,yb]
where
size = Simple.curveSizeBytes (Proxy :: Proxy curve)
uncompressed, xb, yb :: bs
uncompressed = B.singleton 4
xb = i2ospOf_ size x
yb = i2ospOf_ size y

decodeECPoint :: (Simple.Curve curve, ByteArray bs) => bs -> CryptoFailable (Simple.Point curve)
decodeECPoint mxy = case B.uncons mxy of
Nothing -> CryptoFailed $ CryptoError_PointSizeInvalid
Just (m,xy)
-- uncompressed
| m == 4 ->
let siz = B.length xy `div` 2
(xb,yb) = B.splitAt siz xy
x = os2ip xb
y = os2ip yb
in Simple.pointFromIntegers (x,y)
| otherwise -> CryptoFailed $ CryptoError_PointFormatInvalid

curveSizeBytes :: EllipticCurve c => Proxy c -> Int
curveSizeBytes proxy = (curveSizeBits proxy + 7) `div` 8
Loading