cryptonite 0.20 → 0.21
raw patch · 24 files changed
+1563/−42 lines, 24 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Crypto.Cipher.Salsa: data State
+ Crypto.Cipher.Salsa: State :: ScrubbedBytes -> State
+ Crypto.Cipher.Salsa: newtype State
+ Crypto.Cipher.XSalsa: combine :: ByteArray ba => State -> ba -> (ba, State)
+ Crypto.Cipher.XSalsa: data State
+ Crypto.Cipher.XSalsa: generate :: ByteArray ba => State -> Int -> (ba, State)
+ Crypto.Cipher.XSalsa: initialize :: (ByteArrayAccess key, ByteArrayAccess nonce) => Int -> key -> nonce -> State
+ Crypto.ECC: Curve_P256R1 :: Curve_P256R1
+ Crypto.ECC: Curve_P384R1 :: Curve_P384R1
+ Crypto.ECC: Curve_P521R1 :: Curve_P521R1
+ Crypto.ECC: Curve_X25519 :: Curve_X25519
+ Crypto.ECC: Curve_X448 :: Curve_X448
+ Crypto.ECC: KeyPair :: !(Point curve) -> !(Scalar curve) -> KeyPair curve
+ Crypto.ECC: SharedSecret :: ScrubbedBytes -> SharedSecret
+ Crypto.ECC: [keypairGetPrivate] :: KeyPair curve -> !(Scalar curve)
+ Crypto.ECC: [keypairGetPublic] :: KeyPair curve -> !(Point curve)
+ Crypto.ECC: class EllipticCurve curve where type Point curve :: * type Scalar curve :: * where {
+ Crypto.ECC: class EllipticCurve curve => EllipticCurveArith curve
+ Crypto.ECC: class EllipticCurve curve => EllipticCurveDH curve
+ Crypto.ECC: curveGenerateKeyPair :: (EllipticCurve curve, MonadRandom randomly) => proxy curve -> randomly (KeyPair curve)
+ Crypto.ECC: curveGenerateScalar :: (EllipticCurve curve, MonadRandom randomly) => proxy curve -> randomly (Scalar curve)
+ Crypto.ECC: curveSizeBits :: EllipticCurve curve => proxy curve -> Int
+ Crypto.ECC: data Curve_P256R1
+ Crypto.ECC: data Curve_P384R1
+ Crypto.ECC: data Curve_P521R1
+ Crypto.ECC: data Curve_X25519
+ Crypto.ECC: data Curve_X448
+ Crypto.ECC: data KeyPair curve
+ Crypto.ECC: decodePoint :: (EllipticCurve curve, ByteArray bs) => proxy curve -> bs -> CryptoFailable (Point curve)
+ Crypto.ECC: ecdh :: EllipticCurveDH curve => proxy curve -> Scalar curve -> Point curve -> SharedSecret
+ Crypto.ECC: encodePoint :: (EllipticCurve curve, ByteArray bs) => proxy curve -> Point curve -> bs
+ Crypto.ECC: instance Crypto.ECC.EllipticCurve Crypto.ECC.Curve_P256R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurve Crypto.ECC.Curve_P384R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurve Crypto.ECC.Curve_P521R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurve Crypto.ECC.Curve_X25519
+ Crypto.ECC: instance Crypto.ECC.EllipticCurve Crypto.ECC.Curve_X448
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveArith Crypto.ECC.Curve_P256R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveArith Crypto.ECC.Curve_P384R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveArith Crypto.ECC.Curve_P521R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveDH Crypto.ECC.Curve_P256R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveDH Crypto.ECC.Curve_P384R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveDH Crypto.ECC.Curve_P521R1
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveDH Crypto.ECC.Curve_X25519
+ Crypto.ECC: instance Crypto.ECC.EllipticCurveDH Crypto.ECC.Curve_X448
+ Crypto.ECC: instance Data.ByteArray.Types.ByteArrayAccess Crypto.ECC.SharedSecret
+ Crypto.ECC: instance GHC.Classes.Eq Crypto.ECC.SharedSecret
+ Crypto.ECC: newtype SharedSecret
+ Crypto.ECC: pointAdd :: EllipticCurveArith curve => proxy curve -> Point curve -> Point curve -> Point curve
+ Crypto.ECC: pointSmul :: EllipticCurveArith curve => proxy curve -> Scalar curve -> Point curve -> Point curve
+ Crypto.ECC: type family Scalar curve :: *;
+ Crypto.ECC: }
+ Crypto.Error: CryptoError_EcScalarOutOfBounds :: CryptoError
+ Crypto.Error: CryptoError_PointCoordinatesInvalid :: CryptoError
+ Crypto.Error: CryptoError_PointFormatInvalid :: CryptoError
+ Crypto.Error: CryptoError_PointFormatUnsupported :: CryptoError
+ Crypto.Error: CryptoError_PointSizeInvalid :: CryptoError
+ Crypto.KDF.HKDF: instance Data.ByteArray.Types.ByteArrayAccess (Crypto.KDF.HKDF.PRK a)
+ Crypto.PubKey.Curve25519: generateSecretKey :: MonadRandom m => m SecretKey
+ Crypto.PubKey.ECC.P256: instance GHC.Show.Show Crypto.PubKey.ECC.P256.Scalar
+ Crypto.PubKey.ECC.P256: pointDh :: ByteArray binary => Scalar -> Point -> binary
+ Crypto.PubKey.ECIES: deriveDecrypt :: EllipticCurveDH curve => proxy curve -> Point curve -> Scalar curve -> SharedSecret
+ Crypto.PubKey.ECIES: deriveEncrypt :: (MonadRandom randomly, EllipticCurveDH curve) => proxy curve -> Point curve -> randomly (Point curve, SharedSecret)
+ Crypto.PubKey.Ed448: generateSecretKey :: MonadRandom m => m SecretKey
- Crypto.KDF.HKDF: extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm) => ikm -> PRK a
+ Crypto.KDF.HKDF: extractSkip :: ByteArrayAccess ikm => ikm -> PRK a
Files
- Crypto/Cipher/AES.hs +15/−3
- Crypto/Cipher/Salsa.hs +1/−1
- Crypto/Cipher/XSalsa.hs +50/−0
- Crypto/ECC.hs +229/−0
- Crypto/ECC/Simple/Prim.hs +207/−0
- Crypto/ECC/Simple/Types.hs +615/−0
- Crypto/Error/Types.hs +6/−0
- Crypto/Internal/Proxy.hs +13/−0
- Crypto/KDF/HKDF.hs +9/−3
- Crypto/PubKey/Curve25519.hs +19/−1
- Crypto/PubKey/ECC/P256.hs +13/−1
- Crypto/PubKey/ECC/Types.hs +1/−1
- Crypto/PubKey/ECIES.hs +48/−0
- Crypto/PubKey/Ed448.hs +6/−0
- README.md +1/−4
- cbits/cryptonite_align.h +51/−0
- cbits/cryptonite_chacha.c +20/−22
- cbits/cryptonite_poly1305.c +1/−1
- cbits/cryptonite_sha3.c +14/−3
- cbits/cryptonite_xsalsa.c +80/−0
- cbits/cryptonite_xsalsa.h +37/−0
- cryptonite.cabal +17/−2
- tests/Tests.hs +2/−0
- tests/XSalsa.hs +108/−0
Crypto/Cipher/AES.hs view
@@ -18,6 +18,8 @@ import Crypto.Cipher.AES.Primitive import Crypto.Internal.Imports +import Data.ByteArray as BA+ -- | AES with 128 bit key newtype AES128 = AES128 AES deriving (NFData)@@ -33,17 +35,27 @@ instance Cipher AES128 where cipherName _ = "AES128" cipherKeySize _ = KeySizeFixed 16- cipherInit k = AES128 `fmap` initAES k+ cipherInit k = AES128 <$> (initAES =<< validateKeySize (undefined :: AES128) k) instance Cipher AES192 where cipherName _ = "AES192" cipherKeySize _ = KeySizeFixed 24- cipherInit k = AES192 `fmap` initAES k+ cipherInit k = AES192 <$> (initAES =<< validateKeySize (undefined :: AES192) k) instance Cipher AES256 where cipherName _ = "AES256" cipherKeySize _ = KeySizeFixed 32- cipherInit k = AES256 `fmap` initAES k+ cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k)++validateKeySize :: (ByteArrayAccess key, Cipher cipher) => cipher -> key -> CryptoFailable key+validateKeySize c k = if validKeyLength+ then CryptoPassed k+ else CryptoFailed CryptoError_KeySizeInvalid+ where keyLength = BA.length k+ validKeyLength = case cipherKeySize c of+ KeySizeRange low high -> keyLength >= low && keyLength <= high+ KeySizeEnum lengths -> keyLength `elem` lengths+ KeySizeFixed s -> keyLength == s #define INSTANCE_BLOCKCIPHER(CSTR) \ instance BlockCipher CSTR where \
Crypto/Cipher/Salsa.hs view
@@ -11,7 +11,7 @@ ( initialize , combine , generate- , State+ , State(..) ) where import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes)
+ Crypto/Cipher/XSalsa.hs view
@@ -0,0 +1,50 @@+-- |+-- Module : Crypto.Cipher.XSalsa+-- License : BSD-style+-- Maintainer : Brandon Hamilton <brandon.hamilton@gmail.com>+-- Stability : stable+-- Portability : good+--+-- Implementation of XSalsa20 algorithm+-- <https://cr.yp.to/snuffle/xsalsa-20081128.pdf>+-- Based on the Salsa20 algorithm with 256 bit key extended with 192 bit nonce++{-# LANGUAGE ForeignFunctionInterface #-}+module Crypto.Cipher.XSalsa+ ( initialize+ , combine+ , generate+ , State+ ) where++import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes)+import qualified Crypto.Internal.ByteArray as B+import Crypto.Internal.Compat+import Crypto.Internal.Imports+import Foreign.Ptr+import Foreign.Storable+import Foreign.C.Types+import Crypto.Cipher.Salsa hiding (initialize)++-- | Initialize a new XSalsa context with the number of rounds,+-- the key and the nonce associated.+initialize :: (ByteArrayAccess key, ByteArrayAccess nonce)+ => Int -- ^ number of rounds (8,12,20)+ -> key -- ^ the key (256 bits)+ -> nonce -- ^ the nonce (192 bits)+ -> State -- ^ the initial XSalsa state+initialize nbRounds key nonce+ | kLen /= 32 = error "XSalsa: key length should be 256 bits"+ | nonceLen /= 24 = error "XSalsa: nonce length should be 192 bits"+ | not (nbRounds `elem` [8,12,20]) = error "XSalsa: rounds should be 8, 12 or 20"+ | otherwise = unsafeDoIO $ do+ stPtr <- B.alloc 132 $ \stPtr ->+ B.withByteArray nonce $ \noncePtr ->+ B.withByteArray key $ \keyPtr ->+ ccryptonite_xsalsa_init stPtr (fromIntegral nbRounds) kLen keyPtr nonceLen noncePtr+ return $ State stPtr+ where kLen = B.length key+ nonceLen = B.length nonce++foreign import ccall "cryptonite_xsalsa_init"+ ccryptonite_xsalsa_init :: Ptr State -> Int -> Int -> Ptr Word8 -> Int -> Ptr Word8 -> IO ()
+ Crypto/ECC.hs view
@@ -0,0 +1,229 @@+-- |+-- Module : Crypto.ECC+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+-- Elliptic Curve Cryptography+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Crypto.ECC+ ( Curve_P256R1(..)+ , Curve_P384R1(..)+ , Curve_P521R1(..)+ , Curve_X25519(..)+ , Curve_X448(..)+ , 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 qualified Crypto.PubKey.Ed448 as X448+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 = mxy+ where+ mxy :: forall bs. ByteArray bs => bs+ mxy = B.concat [uncompressed, xy]+ where+ uncompressed, xy :: bs+ uncompressed = B.singleton 4+ xy = P256.pointToBinary p+ decodePoint _ mxy = case B.uncons mxy of+ Nothing -> CryptoFailed $ CryptoError_PointSizeInvalid+ Just (m,xy)+ -- uncompressed+ | m == 4 -> P256.pointFromBinary xy+ | otherwise -> CryptoFailed $ CryptoError_PointFormatInvalid++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++data Curve_X448 = Curve_X448++instance EllipticCurve Curve_X448 where+ type Point Curve_X448 = X448.PublicKey+ type Scalar Curve_X448 = X448.SecretKey+ curveSizeBits _ = 448+ curveGenerateScalar _ = X448.generateSecretKey+ curveGenerateKeyPair _ = do+ s <- X448.generateSecretKey+ return $ KeyPair (X448.toPublic s) s+ encodePoint _ p = B.convert p+ decodePoint _ bs = X448.publicKey bs++instance EllipticCurveDH Curve_X448 where+ ecdh _ s p = SharedSecret $ convert secret+ where secret = X448.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
+ Crypto/ECC/Simple/Prim.hs view
@@ -0,0 +1,207 @@+-- | Elliptic Curve Arithmetic.+--+-- /WARNING:/ These functions are vulnerable to timing attacks.+{-# LANGUAGE ScopedTypeVariables #-}+module Crypto.ECC.Simple.Prim+ ( scalarGenerate+ , scalarFromInteger+ , pointAdd+ , pointDouble+ , pointBaseMul+ , pointMul+ , pointAddTwoMuls+ , pointFromIntegers+ , isPointAtInfinity+ , isPointValid+ ) where++import Data.Maybe+import Crypto.Internal.Imports+import Crypto.Internal.Proxy+import Crypto.Number.ModArithmetic+import Crypto.Number.F2m+import Crypto.Number.Generate (generateBetween)+import Crypto.ECC.Simple.Types+import Crypto.Error+import Crypto.Random++-- | Generate a valid scalar for a specific Curve+scalarGenerate :: forall randomly curve . (MonadRandom randomly, Curve curve) => randomly (Scalar curve)+scalarGenerate =+ Scalar <$> generateBetween 1 (n - 1)+ where+ n = curveEccN $ curveParameters (Proxy :: Proxy curve)++scalarFromInteger :: forall curve . Curve curve => Integer -> CryptoFailable (Scalar curve)+scalarFromInteger n+ | n < 0 || n >= mx = CryptoFailed $ CryptoError_EcScalarOutOfBounds+ | otherwise = CryptoPassed $ Scalar n+ where+ mx = case curveType (Proxy :: Proxy curve) of+ CurveBinary (CurveBinaryParam b) -> b+ CurvePrime (CurvePrimeParam p) -> p++--TODO: Extract helper function for `fromMaybe PointO...`++-- | Elliptic Curve point negation:+-- @pointNegate p@ returns point @q@ such that @pointAdd p q == PointO@.+pointNegate :: Curve curve => Point curve -> Point curve+pointNegate PointO = PointO+pointNegate point@(Point x y) =+ case curveType point of+ CurvePrime {} -> Point x (-y)+ CurveBinary {} -> Point x (x `addF2m` y)++-- | Elliptic Curve point addition.+--+-- /WARNING:/ Vulnerable to timing attacks.+pointAdd :: Curve curve => Point curve -> Point curve -> Point curve+pointAdd PointO PointO = PointO+pointAdd PointO q = q+pointAdd p PointO = p+pointAdd p q+ | p == q = pointDouble p+ | p == pointNegate q = PointO+pointAdd point@(Point xp yp) (Point xq yq) =+ case ty of+ CurvePrime (CurvePrimeParam pr) -> fromMaybe PointO $ do+ s <- divmod (yp - yq) (xp - xq) pr+ let xr = (s ^ (2::Int) - xp - xq) `mod` pr+ yr = (s * (xp - xr) - yp) `mod` pr+ return $ Point xr yr+ CurveBinary (CurveBinaryParam fx) -> fromMaybe PointO $ do+ s <- divF2m fx (yp `addF2m` yq) (xp `addF2m` xq)+ let xr = mulF2m fx s s `addF2m` s `addF2m` xp `addF2m` xq `addF2m` a+ yr = mulF2m fx s (xp `addF2m` xr) `addF2m` xr `addF2m` yp+ return $ Point xr yr+ where+ ty = curveType point+ cc = curveParameters point+ a = curveEccA cc++-- | Elliptic Curve point doubling.+--+-- /WARNING:/ Vulnerable to timing attacks.+--+-- This perform the following calculation:+-- > lambda = (3 * xp ^ 2 + a) / 2 yp+-- > xr = lambda ^ 2 - 2 xp+-- > yr = lambda (xp - xr) - yp+--+-- With binary curve:+-- > xp == 0 => P = O+-- > otherwise =>+-- > s = xp + (yp / xp)+-- > xr = s ^ 2 + s + a+-- > yr = xp ^ 2 + (s+1) * xr+--+pointDouble :: Curve curve => Point curve -> Point curve+pointDouble PointO = PointO+pointDouble point@(Point xp yp) =+ case ty of+ CurvePrime (CurvePrimeParam pr) -> fromMaybe PointO $ do+ lambda <- divmod (3 * xp ^ (2::Int) + a) (2 * yp) pr+ let xr = (lambda ^ (2::Int) - 2 * xp) `mod` pr+ yr = (lambda * (xp - xr) - yp) `mod` pr+ return $ Point xr yr+ CurveBinary (CurveBinaryParam fx)+ | xp == 0 -> PointO+ | otherwise -> fromMaybe PointO $ do+ s <- return . addF2m xp =<< divF2m fx yp xp+ let xr = mulF2m fx s s `addF2m` s `addF2m` a+ yr = mulF2m fx xp xp `addF2m` mulF2m fx xr (s `addF2m` 1)+ return $ Point xr yr+ where+ ty = curveType point+ cc = curveParameters point+ a = curveEccA cc++-- | Elliptic curve point multiplication using the base+--+-- /WARNING:/ Vulnerable to timing attacks.+pointBaseMul :: Curve curve => Scalar curve -> Point curve+pointBaseMul n = pointMul n (curveEccG $ curveParameters (Proxy :: Proxy curve))++-- | Elliptic curve point multiplication (double and add algorithm).+--+-- /WARNING:/ Vulnerable to timing attacks.+pointMul :: Curve curve => Scalar curve -> Point curve -> Point curve+pointMul _ PointO = PointO+pointMul (Scalar n) p+ | n == 0 = PointO+ | n == 1 = p+ | odd n = pointAdd p (pointMul (Scalar (n - 1)) p)+ | otherwise = pointMul (Scalar (n `div` 2)) (pointDouble p)++-- | Elliptic curve double-scalar multiplication (uses Shamir's trick).+--+-- > pointAddTwoMuls n1 p1 n2 p2 == pointAdd (pointMul n1 p1)+-- > (pointMul n2 p2)+--+-- /WARNING:/ Vulnerable to timing attacks.+pointAddTwoMuls :: Curve curve => Scalar curve -> Point curve -> Scalar curve -> Point curve -> Point curve+pointAddTwoMuls _ PointO _ PointO = PointO+pointAddTwoMuls _ PointO n2 p2 = pointMul n2 p2+pointAddTwoMuls n1 p1 _ PointO = pointMul n1 p1+pointAddTwoMuls (Scalar n1) p1 (Scalar n2) p2 = go (n1, n2)+ where+ p0 = pointAdd p1 p2++ go (0, 0 ) = PointO+ go (k1, k2) =+ let q = pointDouble $ go (k1 `div` 2, k2 `div` 2)+ in case (odd k1, odd k2) of+ (True , True ) -> pointAdd p0 q+ (True , False ) -> pointAdd p1 q+ (False , True ) -> pointAdd p2 q+ (False , False ) -> q++-- | Check if a point is the point at infinity.+isPointAtInfinity :: Point curve -> Bool+isPointAtInfinity PointO = True+isPointAtInfinity _ = False++-- | Make a point on a curve from integer (x,y) coordinate+--+-- if the point is not valid related to the curve then an error is+-- returned instead of a point+pointFromIntegers :: forall curve . Curve curve => (Integer, Integer) -> CryptoFailable (Point curve)+pointFromIntegers (x,y)+ | isPointValid (Proxy :: Proxy curve) x y = CryptoPassed $ Point x y+ | otherwise = CryptoFailed $ CryptoError_PointCoordinatesInvalid++-- | check if a point is on specific curve+--+-- This perform three checks:+--+-- * x is not out of range+-- * y is not out of range+-- * the equation @y^2 = x^3 + a*x + b (mod p)@ holds+isPointValid :: Curve curve => proxy curve -> Integer -> Integer -> Bool+isPointValid proxy x y =+ case ty of+ CurvePrime (CurvePrimeParam p) ->+ let a = curveEccA cc+ b = curveEccB cc+ eqModP z1 z2 = (z1 `mod` p) == (z2 `mod` p)+ isValid e = e >= 0 && e < p+ in isValid x && isValid y && (y ^ (2 :: Int)) `eqModP` (x ^ (3 :: Int) + a * x + b)+ CurveBinary (CurveBinaryParam fx) ->+ let a = curveEccA cc+ b = curveEccB cc+ add = addF2m+ mul = mulF2m fx+ isValid e = modF2m fx e == e+ in and [ isValid x+ , isValid y+ , ((((x `add` a) `mul` x `add` y) `mul` x) `add` b `add` (squareF2m fx y)) == 0+ ]+ where+ ty = curveType proxy+ cc = curveParameters proxy++-- | div and mod+divmod :: Integer -> Integer -> Integer -> Maybe Integer+divmod y x m = do+ i <- inverse (x `mod` m) m+ return $ y * i `mod` m
+ Crypto/ECC/Simple/Types.hs view
@@ -0,0 +1,615 @@+{-# LANGUAGE DeriveDataTypeable #-}+-- |+-- Module : Crypto.ECC.Simple.Types+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : Experimental+-- Portability : Excellent+--+-- references:+-- <https://tools.ietf.org/html/rfc5915>+--+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+module Crypto.ECC.Simple.Types+ ( Curve(..)+ , Point(..)+ , Scalar(..)+ , CurveType(..)+ , CurveBinaryParam(..)+ , CurvePrimeParam(..)+ , curveSizeBits+ , curveSizeBytes+ , CurveParameters(..)+ -- * specific curves definition+ , SEC_p112r1(..)+ , SEC_p112r2(..)+ , SEC_p128r1(..)+ , SEC_p128r2(..)+ , SEC_p160k1(..)+ , SEC_p160r1(..)+ , SEC_p160r2(..)+ , SEC_p192k1(..)+ , SEC_p192r1(..) -- aka prime192v1+ , SEC_p224k1(..)+ , SEC_p224r1(..)+ , SEC_p256k1(..)+ , SEC_p256r1(..) -- aka prime256v1+ , SEC_p384r1(..)+ , SEC_p521r1(..)+ , SEC_t113r1(..)+ , SEC_t113r2(..)+ , SEC_t131r1(..)+ , SEC_t131r2(..)+ , SEC_t163k1(..)+ , SEC_t163r1(..)+ , SEC_t163r2(..)+ , SEC_t193r1(..)+ , SEC_t193r2(..)+ , SEC_t233k1(..) -- aka NIST K-233+ , SEC_t233r1(..)+ , SEC_t239k1(..)+ , SEC_t283k1(..)+ , SEC_t283r1(..)+ , SEC_t409k1(..)+ , SEC_t409r1(..)+ , SEC_t571k1(..)+ , SEC_t571r1(..)+ ) where++import Data.Data+import Crypto.Internal.Imports+import Crypto.Number.Basic (numBits)++class Curve curve where+ curveParameters :: proxy curve -> CurveParameters curve+ curveType :: proxy curve -> CurveType++-- | get the size of the curve in bits+curveSizeBits :: Curve curve => proxy curve -> Int+curveSizeBits proxy =+ case curveType proxy of+ CurvePrime (CurvePrimeParam p) -> numBits p+ CurveBinary (CurveBinaryParam c) -> numBits c - 1++-- | get the size of the curve in bytes+curveSizeBytes :: Curve curve => proxy curve -> Int+curveSizeBytes proxy = (curveSizeBits proxy + 7) `div` 8++-- | Define common parameters in a curve definition+-- of the form: y^2 = x^3 + ax + b.+data CurveParameters curve = CurveParameters+ { curveEccA :: Integer -- ^ curve parameter a+ , curveEccB :: Integer -- ^ curve parameter b+ , curveEccG :: Point curve -- ^ base point+ , curveEccN :: Integer -- ^ order of G+ , curveEccH :: Integer -- ^ cofactor+ } deriving (Show,Eq,Data,Typeable)++newtype CurveBinaryParam = CurveBinaryParam Integer+ deriving (Show,Read,Eq,Data,Typeable)++newtype CurvePrimeParam = CurvePrimeParam Integer+ deriving (Show,Read,Eq,Data,Typeable)++data CurveType =+ CurveBinary CurveBinaryParam+ | CurvePrime CurvePrimeParam+ deriving (Show,Read,Eq,Data,Typeable)++-- | ECC Private Number+newtype Scalar curve = Scalar Integer+ deriving (Show,Read,Eq,Data,Typeable)++-- | Define a point on a curve.+data Point curve =+ Point Integer Integer+ | PointO -- ^ Point at Infinity+ deriving (Show,Read,Eq,Data,Typeable)++instance NFData (Point curve) where+ rnf (Point x y) = x `seq` y `seq` ()+ rnf PointO = ()++data SEC_p112r1 = SEC_p112r1 deriving (Show,Read,Eq)+data SEC_p112r2 = SEC_p112r2 deriving (Show,Read,Eq)+data SEC_p128r1 = SEC_p128r1 deriving (Show,Read,Eq)+data SEC_p128r2 = SEC_p128r2 deriving (Show,Read,Eq)+data SEC_p160k1 = SEC_p160k1 deriving (Show,Read,Eq)+data SEC_p160r1 = SEC_p160r1 deriving (Show,Read,Eq)+data SEC_p160r2 = SEC_p160r2 deriving (Show,Read,Eq)+data SEC_p192k1 = SEC_p192k1 deriving (Show,Read,Eq)+data SEC_p192r1 = SEC_p192r1 deriving (Show,Read,Eq)+data SEC_p224k1 = SEC_p224k1 deriving (Show,Read,Eq)+data SEC_p224r1 = SEC_p224r1 deriving (Show,Read,Eq)+data SEC_p256k1 = SEC_p256k1 deriving (Show,Read,Eq)+data SEC_p256r1 = SEC_p256r1 deriving (Show,Read,Eq)+data SEC_p384r1 = SEC_p384r1 deriving (Show,Read,Eq)+data SEC_p521r1 = SEC_p521r1 deriving (Show,Read,Eq)+data SEC_t113r1 = SEC_t113r1 deriving (Show,Read,Eq)+data SEC_t113r2 = SEC_t113r2 deriving (Show,Read,Eq)+data SEC_t131r1 = SEC_t131r1 deriving (Show,Read,Eq)+data SEC_t131r2 = SEC_t131r2 deriving (Show,Read,Eq)+data SEC_t163k1 = SEC_t163k1 deriving (Show,Read,Eq)+data SEC_t163r1 = SEC_t163r1 deriving (Show,Read,Eq)+data SEC_t163r2 = SEC_t163r2 deriving (Show,Read,Eq)+data SEC_t193r1 = SEC_t193r1 deriving (Show,Read,Eq)+data SEC_t193r2 = SEC_t193r2 deriving (Show,Read,Eq)+data SEC_t233k1 = SEC_t233k1 deriving (Show,Read,Eq)+data SEC_t233r1 = SEC_t233r1 deriving (Show,Read,Eq)+data SEC_t239k1 = SEC_t239k1 deriving (Show,Read,Eq)+data SEC_t283k1 = SEC_t283k1 deriving (Show,Read,Eq)+data SEC_t283r1 = SEC_t283r1 deriving (Show,Read,Eq)+data SEC_t409k1 = SEC_t409k1 deriving (Show,Read,Eq)+data SEC_t409r1 = SEC_t409r1 deriving (Show,Read,Eq)+data SEC_t571k1 = SEC_t571k1 deriving (Show,Read,Eq)+data SEC_t571r1 = SEC_t571r1 deriving (Show,Read,Eq)++-- | Define names for known recommended curves.+instance Curve SEC_p112r1 where+ curveType _ = typeSEC_p112r1+ curveParameters _ = paramSEC_p112r1++instance Curve SEC_p112r2 where+ curveType _ = typeSEC_p112r2+ curveParameters _ = paramSEC_p112r2++instance Curve SEC_p128r1 where+ curveType _ = typeSEC_p128r1+ curveParameters _ = paramSEC_p128r1++instance Curve SEC_p128r2 where+ curveType _ = typeSEC_p128r2+ curveParameters _ = paramSEC_p128r2++instance Curve SEC_p160k1 where+ curveType _ = typeSEC_p160k1+ curveParameters _ = paramSEC_p160k1++instance Curve SEC_p160r1 where+ curveType _ = typeSEC_p160r1+ curveParameters _ = paramSEC_p160r1++instance Curve SEC_p160r2 where+ curveType _ = typeSEC_p160r2+ curveParameters _ = paramSEC_p160r2++instance Curve SEC_p192k1 where+ curveType _ = typeSEC_p192k1+ curveParameters _ = paramSEC_p192k1++instance Curve SEC_p192r1 where+ curveType _ = typeSEC_p192r1+ curveParameters _ = paramSEC_p192r1++instance Curve SEC_p224k1 where+ curveType _ = typeSEC_p224k1+ curveParameters _ = paramSEC_p224k1++instance Curve SEC_p224r1 where+ curveType _ = typeSEC_p224r1+ curveParameters _ = paramSEC_p224r1++instance Curve SEC_p256k1 where+ curveType _ = typeSEC_p256k1+ curveParameters _ = paramSEC_p256k1++instance Curve SEC_p256r1 where+ curveType _ = typeSEC_p256r1+ curveParameters _ = paramSEC_p256r1++instance Curve SEC_p384r1 where+ curveType _ = typeSEC_p384r1+ curveParameters _ = paramSEC_p384r1++instance Curve SEC_p521r1 where+ curveType _ = typeSEC_p521r1+ curveParameters _ = paramSEC_p521r1++instance Curve SEC_t113r1 where+ curveType _ = typeSEC_t113r1+ curveParameters _ = paramSEC_t113r1++instance Curve SEC_t113r2 where+ curveType _ = typeSEC_t113r2+ curveParameters _ = paramSEC_t113r2++instance Curve SEC_t131r1 where+ curveType _ = typeSEC_t131r1+ curveParameters _ = paramSEC_t131r1++instance Curve SEC_t131r2 where+ curveType _ = typeSEC_t131r2+ curveParameters _ = paramSEC_t131r2++instance Curve SEC_t163k1 where+ curveType _ = typeSEC_t163k1+ curveParameters _ = paramSEC_t163k1++instance Curve SEC_t163r1 where+ curveType _ = typeSEC_t163r1+ curveParameters _ = paramSEC_t163r1++instance Curve SEC_t163r2 where+ curveType _ = typeSEC_t163r2+ curveParameters _ = paramSEC_t163r2++instance Curve SEC_t193r1 where+ curveType _ = typeSEC_t193r1+ curveParameters _ = paramSEC_t193r1++instance Curve SEC_t193r2 where+ curveType _ = typeSEC_t193r2+ curveParameters _ = paramSEC_t193r2++instance Curve SEC_t233k1 where+ curveType _ = typeSEC_t233k1+ curveParameters _ = paramSEC_t233k1++instance Curve SEC_t233r1 where+ curveType _ = typeSEC_t233r1+ curveParameters _ = paramSEC_t233r1++instance Curve SEC_t239k1 where+ curveType _ = typeSEC_t239k1+ curveParameters _ = paramSEC_t239k1++instance Curve SEC_t283k1 where+ curveType _ = typeSEC_t283k1+ curveParameters _ = paramSEC_t283k1++instance Curve SEC_t283r1 where+ curveType _ = typeSEC_t283r1+ curveParameters _ = paramSEC_t283r1++instance Curve SEC_t409k1 where+ curveType _ = typeSEC_t409k1+ curveParameters _ = paramSEC_t409k1++instance Curve SEC_t409r1 where+ curveType _ = typeSEC_t409r1+ curveParameters _ = paramSEC_t409r1++instance Curve SEC_t571k1 where+ curveType _ = typeSEC_t571k1+ curveParameters _ = paramSEC_t571k1++instance Curve SEC_t571r1 where+ curveType _ = typeSEC_t571r1+ curveParameters _ = paramSEC_t571r1++{-+curvesOIDs :: [ (CurveName, [Integer]) ]+curvesOIDs =+ [ (SEC_p112r1, [1,3,132,0,6])+ , (SEC_p112r2, [1,3,132,0,7])+ , (SEC_p128r1, [1,3,132,0,28])+ , (SEC_p128r2, [1,3,132,0,29])+ , (SEC_p160k1, [1,3,132,0,9])+ , (SEC_p160r1, [1,3,132,0,8])+ , (SEC_p160r2, [1,3,132,0,30])+ , (SEC_p192k1, [1,3,132,0,31])+ , (SEC_p192r1, [1,2,840,10045,3,1,1])+ , (SEC_p224k1, [1,3,132,0,32])+ , (SEC_p224r1, [1,3,132,0,33])+ , (SEC_p256k1, [1,3,132,0,10])+ , (SEC_p256r1, [1,2,840,10045,3,1,7])+ , (SEC_p384r1, [1,3,132,0,34])+ , (SEC_p521r1, [1,3,132,0,35])+ , (SEC_t113r1, [1,3,132,0,4])+ , (SEC_t113r2, [1,3,132,0,5])+ , (SEC_t131r1, [1,3,132,0,22])+ , (SEC_t131r2, [1,3,132,0,23])+ , (SEC_t163k1, [1,3,132,0,1])+ , (SEC_t163r1, [1,3,132,0,2])+ , (SEC_t163r2, [1,3,132,0,15])+ , (SEC_t193r1, [1,3,132,0,24])+ , (SEC_t193r2, [1,3,132,0,25])+ , (SEC_t233k1, [1,3,132,0,26])+ , (SEC_t233r1, [1,3,132,0,27])+ , (SEC_t239k1, [1,3,132,0,3])+ , (SEC_t283k1, [1,3,132,0,16])+ , (SEC_t283r1, [1,3,132,0,17])+ , (SEC_t409k1, [1,3,132,0,36])+ , (SEC_t409r1, [1,3,132,0,37])+ , (SEC_t571k1, [1,3,132,0,38])+ , (SEC_t571r1, [1,3,132,0,39])+ ]+-}++typeSEC_p112r1 = CurvePrime $ CurvePrimeParam 0xdb7c2abf62e35e668076bead208b+paramSEC_p112r1 = CurveParameters+ { curveEccA = 0xdb7c2abf62e35e668076bead2088+ , curveEccB = 0x659ef8ba043916eede8911702b22+ , curveEccG = Point 0x09487239995a5ee76b55f9c2f098+ 0xa89ce5af8724c0a23e0e0ff77500+ , curveEccN = 0xdb7c2abf62e35e7628dfac6561c5+ , curveEccH = 1+ }+typeSEC_p112r2 = CurvePrime $ CurvePrimeParam 0xdb7c2abf62e35e668076bead208b+paramSEC_p112r2 = CurveParameters+ { curveEccA = 0x6127c24c05f38a0aaaf65c0ef02c+ , curveEccB = 0x51def1815db5ed74fcc34c85d709+ , curveEccG = Point 0x4ba30ab5e892b4e1649dd0928643+ 0xadcd46f5882e3747def36e956e97+ , curveEccN = 0x36df0aafd8b8d7597ca10520d04b+ , curveEccH = 4+ }+typeSEC_p128r1 = CurvePrime $ CurvePrimeParam 0xfffffffdffffffffffffffffffffffff+paramSEC_p128r1 = CurveParameters+ { curveEccA = 0xfffffffdfffffffffffffffffffffffc+ , curveEccB = 0xe87579c11079f43dd824993c2cee5ed3+ , curveEccG = Point 0x161ff7528b899b2d0c28607ca52c5b86+ 0xcf5ac8395bafeb13c02da292dded7a83+ , curveEccN = 0xfffffffe0000000075a30d1b9038a115+ , curveEccH = 1+ }+typeSEC_p128r2 = CurvePrime $ CurvePrimeParam 0xfffffffdffffffffffffffffffffffff+paramSEC_p128r2 = CurveParameters+ { curveEccA = 0xd6031998d1b3bbfebf59cc9bbff9aee1+ , curveEccB = 0x5eeefca380d02919dc2c6558bb6d8a5d+ , curveEccG = Point 0x7b6aa5d85e572983e6fb32a7cdebc140+ 0x27b6916a894d3aee7106fe805fc34b44+ , curveEccN = 0x3fffffff7fffffffbe0024720613b5a3+ , curveEccH = 4+ }+typeSEC_p160k1 = CurvePrime $ CurvePrimeParam 0x00fffffffffffffffffffffffffffffffeffffac73+paramSEC_p160k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000007+ , curveEccG = Point 0x003b4c382ce37aa192a4019e763036f4f5dd4d7ebb+ 0x00938cf935318fdced6bc28286531733c3f03c4fee+ , curveEccN = 0x0100000000000000000001b8fa16dfab9aca16b6b3+ , curveEccH = 1+ }+typeSEC_p160r1 = CurvePrime $ CurvePrimeParam 0x00ffffffffffffffffffffffffffffffff7fffffff+paramSEC_p160r1 = CurveParameters+ { curveEccA = 0x00ffffffffffffffffffffffffffffffff7ffffffc+ , curveEccB = 0x001c97befc54bd7a8b65acf89f81d4d4adc565fa45+ , curveEccG = Point 0x004a96b5688ef573284664698968c38bb913cbfc82+ 0x0023a628553168947d59dcc912042351377ac5fb32+ , curveEccN = 0x0100000000000000000001f4c8f927aed3ca752257+ , curveEccH = 1+ }+typeSEC_p160r2 = CurvePrime $ CurvePrimeParam 0x00fffffffffffffffffffffffffffffffeffffac73+paramSEC_p160r2 = CurveParameters+ { curveEccA = 0x00fffffffffffffffffffffffffffffffeffffac70+ , curveEccB = 0x00b4e134d3fb59eb8bab57274904664d5af50388ba+ , curveEccG = Point 0x0052dcb034293a117e1f4ff11b30f7199d3144ce6d+ 0x00feaffef2e331f296e071fa0df9982cfea7d43f2e+ , curveEccN = 0x0100000000000000000000351ee786a818f3a1a16b+ , curveEccH = 1+ }+typeSEC_p192k1 = CurvePrime $ CurvePrimeParam 0xfffffffffffffffffffffffffffffffffffffffeffffee37+paramSEC_p192k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000000000003+ , curveEccG = Point 0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d+ 0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d+ , curveEccN = 0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d+ , curveEccH = 1+ }+typeSEC_p192r1 = CurvePrime $ CurvePrimeParam 0xfffffffffffffffffffffffffffffffeffffffffffffffff+paramSEC_p192r1 = CurveParameters+ { curveEccA = 0xfffffffffffffffffffffffffffffffefffffffffffffffc+ , curveEccB = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1+ , curveEccG = Point 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012+ 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811+ , curveEccN = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831+ , curveEccH = 1+ }+typeSEC_p224k1 = CurvePrime $ CurvePrimeParam 0x00fffffffffffffffffffffffffffffffffffffffffffffffeffffe56d+paramSEC_p224k1 = CurveParameters+ { curveEccA = 0x0000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x0000000000000000000000000000000000000000000000000000000005+ , curveEccG = Point 0x00a1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c+ 0x007e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5+ , curveEccN = 0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7+ , curveEccH = 1+ }+typeSEC_p224r1 = CurvePrime $ CurvePrimeParam 0xffffffffffffffffffffffffffffffff000000000000000000000001+paramSEC_p224r1 = CurveParameters+ { curveEccA = 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe+ , curveEccB = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4+ , curveEccG = Point 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21+ 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34+ , curveEccN = 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d+ , curveEccH = 1+ }+typeSEC_p256k1 = CurvePrime $ CurvePrimeParam 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f+paramSEC_p256k1 = CurveParameters+ { curveEccA = 0x0000000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x0000000000000000000000000000000000000000000000000000000000000007+ , curveEccG = Point 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798+ 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8+ , curveEccN = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141+ , curveEccH = 1+ }+typeSEC_p256r1 = CurvePrime $ CurvePrimeParam 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff+paramSEC_p256r1 = CurveParameters+ { curveEccA = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc+ , curveEccB = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b+ , curveEccG = Point 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296+ 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5+ , curveEccN = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551+ , curveEccH = 1+ }+typeSEC_p384r1 = CurvePrime $ CurvePrimeParam 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff+paramSEC_p384r1 = CurveParameters+ { curveEccA = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc+ , curveEccB = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef+ , curveEccG = Point 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7+ 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f+ , curveEccN = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973+ , curveEccH = 1+ }+typeSEC_p521r1 = CurvePrime $ CurvePrimeParam 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff+paramSEC_p521r1 = CurveParameters+ { curveEccA = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc+ , curveEccB = 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00+ , curveEccG = Point 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66+ 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650+ , curveEccN = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409+ , curveEccH = 1+ }+typeSEC_t113r1 = CurveBinary $ CurveBinaryParam 0x020000000000000000000000000201+paramSEC_t113r1 = CurveParameters+ { curveEccA = 0x003088250ca6e7c7fe649ce85820f7+ , curveEccB = 0x00e8bee4d3e2260744188be0e9c723+ , curveEccG = Point 0x009d73616f35f4ab1407d73562c10f+ 0x00a52830277958ee84d1315ed31886+ , curveEccN = 0x0100000000000000d9ccec8a39e56f+ , curveEccH = 2+ }+typeSEC_t113r2 = CurveBinary $ CurveBinaryParam 0x020000000000000000000000000201+paramSEC_t113r2 = CurveParameters+ { curveEccA = 0x00689918dbec7e5a0dd6dfc0aa55c7+ , curveEccB = 0x0095e9a9ec9b297bd4bf36e059184f+ , curveEccG = Point 0x01a57a6a7b26ca5ef52fcdb8164797+ 0x00b3adc94ed1fe674c06e695baba1d+ , curveEccN = 0x010000000000000108789b2496af93+ , curveEccH = 2+ }+typeSEC_t131r1 = CurveBinary $ CurveBinaryParam 0x080000000000000000000000000000010d+paramSEC_t131r1 = CurveParameters+ { curveEccA = 0x07a11b09a76b562144418ff3ff8c2570b8+ , curveEccB = 0x0217c05610884b63b9c6c7291678f9d341+ , curveEccG = Point 0x0081baf91fdf9833c40f9c181343638399+ 0x078c6e7ea38c001f73c8134b1b4ef9e150+ , curveEccN = 0x0400000000000000023123953a9464b54d+ , curveEccH = 2+ }+typeSEC_t131r2 = CurveBinary $ CurveBinaryParam 0x080000000000000000000000000000010d+paramSEC_t131r2 = CurveParameters+ { curveEccA = 0x03e5a88919d7cafcbf415f07c2176573b2+ , curveEccB = 0x04b8266a46c55657ac734ce38f018f2192+ , curveEccG = Point 0x0356dcd8f2f95031ad652d23951bb366a8+ 0x0648f06d867940a5366d9e265de9eb240f+ , curveEccN = 0x0400000000000000016954a233049ba98f+ , curveEccH = 2+ }+typeSEC_t163k1 = CurveBinary $ CurveBinaryParam 0x0800000000000000000000000000000000000000c9+paramSEC_t163k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000001+ , curveEccB = 0x000000000000000000000000000000000000000001+ , curveEccG = Point 0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8+ 0x0289070fb05d38ff58321f2e800536d538ccdaa3d9+ , curveEccN = 0x04000000000000000000020108a2e0cc0d99f8a5ef+ , curveEccH = 2+ }+typeSEC_t163r1 = CurveBinary $ CurveBinaryParam 0x0800000000000000000000000000000000000000c9+paramSEC_t163r1 = CurveParameters+ { curveEccA = 0x07b6882caaefa84f9554ff8428bd88e246d2782ae2+ , curveEccB = 0x0713612dcddcb40aab946bda29ca91f73af958afd9+ , curveEccG = Point 0x0369979697ab43897789566789567f787a7876a654+ 0x00435edb42efafb2989d51fefce3c80988f41ff883+ , curveEccN = 0x03ffffffffffffffffffff48aab689c29ca710279b+ , curveEccH = 2+ }+typeSEC_t163r2 = CurveBinary $ CurveBinaryParam 0x0800000000000000000000000000000000000000c9+paramSEC_t163r2 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000001+ , curveEccB = 0x020a601907b8c953ca1481eb10512f78744a3205fd+ , curveEccG = Point 0x03f0eba16286a2d57ea0991168d4994637e8343e36+ 0x00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1+ , curveEccN = 0x040000000000000000000292fe77e70c12a4234c33+ , curveEccH = 2+ }+typeSEC_t193r1 = CurveBinary $ CurveBinaryParam 0x02000000000000000000000000000000000000000000008001+paramSEC_t193r1 = CurveParameters+ { curveEccA = 0x0017858feb7a98975169e171f77b4087de098ac8a911df7b01+ , curveEccB = 0x00fdfb49bfe6c3a89facadaa7a1e5bbc7cc1c2e5d831478814+ , curveEccG = Point 0x01f481bc5f0ff84a74ad6cdf6fdef4bf6179625372d8c0c5e1+ 0x0025e399f2903712ccf3ea9e3a1ad17fb0b3201b6af7ce1b05+ , curveEccN = 0x01000000000000000000000000c7f34a778f443acc920eba49+ , curveEccH = 2+ }+typeSEC_t193r2 = CurveBinary $ CurveBinaryParam 0x02000000000000000000000000000000000000000000008001+paramSEC_t193r2 = CurveParameters+ { curveEccA = 0x0163f35a5137c2ce3ea6ed8667190b0bc43ecd69977702709b+ , curveEccB = 0x00c9bb9e8927d4d64c377e2ab2856a5b16e3efb7f61d4316ae+ , curveEccG = Point 0x00d9b67d192e0367c803f39e1a7e82ca14a651350aae617e8f+ 0x01ce94335607c304ac29e7defbd9ca01f596f927224cdecf6c+ , curveEccN = 0x010000000000000000000000015aab561b005413ccd4ee99d5+ , curveEccH = 2+ }+typeSEC_t233k1 = CurveBinary $ CurveBinaryParam 0x020000000000000000000000000000000000000004000000000000000001+paramSEC_t233k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000000000000000000000001+ , curveEccG = Point 0x017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126+ 0x01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3+ , curveEccN = 0x008000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf+ , curveEccH = 4+ }+typeSEC_t233r1 = CurveBinary $ CurveBinaryParam 0x020000000000000000000000000000000000000004000000000000000001+paramSEC_t233r1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000001+ , curveEccB = 0x0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad+ , curveEccG = Point 0x00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b+ 0x01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052+ , curveEccN = 0x01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7+ , curveEccH = 2+ }+typeSEC_t239k1 = CurveBinary $ CurveBinaryParam 0x800000000000000000004000000000000000000000000000000000000001+paramSEC_t239k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000000000000000000000001+ , curveEccG = Point 0x29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc+ 0x76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca+ , curveEccN = 0x2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5+ , curveEccH = 4+ }+typeSEC_t283k1 = CurveBinary $ CurveBinaryParam 0x0800000000000000000000000000000000000000000000000000000000000000000010a1+paramSEC_t283k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccG = Point 0x0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836+ 0x01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259+ , curveEccN = 0x01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61+ , curveEccH = 4+ }+typeSEC_t283r1 = CurveBinary $ CurveBinaryParam 0x0800000000000000000000000000000000000000000000000000000000000000000010a1+paramSEC_t283r1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccB = 0x027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5+ , curveEccG = Point 0x05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053+ 0x03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4+ , curveEccN = 0x03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307+ , curveEccH = 2+ }+typeSEC_t409k1 = CurveBinary $ CurveBinaryParam 0x02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001+paramSEC_t409k1 = CurveParameters+ { curveEccA = 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccG = Point 0x0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746+ 0x01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b+ , curveEccN = 0x007ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf+ , curveEccH = 4+ }+typeSEC_t409r1 = CurveBinary $ CurveBinaryParam 0x02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001+paramSEC_t409r1 = CurveParameters+ { curveEccA = 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccB = 0x0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f+ , curveEccG = Point 0x015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7+ 0x0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706+ , curveEccN = 0x010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173+ , curveEccH = 2+ }+typeSEC_t571k1 = CurveBinary $ CurveBinaryParam 0x080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425+paramSEC_t571k1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+ , curveEccB = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccG = Point 0x026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972+ 0x0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3+ , curveEccN = 0x020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001+ , curveEccH = 4+ }+typeSEC_t571r1 = CurveBinary $ CurveBinaryParam 0x080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425+paramSEC_t571r1 = CurveParameters+ { curveEccA = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001+ , curveEccB = 0x02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a+ , curveEccG = Point 0x0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19+ 0x037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b+ , curveEccN = 0x03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47+ , curveEccH = 2+ }
Crypto/Error/Types.hs view
@@ -34,6 +34,12 @@ | CryptoError_SecretKeyStructureInvalid | CryptoError_PublicKeySizeInvalid | CryptoError_SharedSecretSizeInvalid+ -- elliptic cryptography error+ | CryptoError_EcScalarOutOfBounds+ | CryptoError_PointSizeInvalid+ | CryptoError_PointFormatInvalid+ | CryptoError_PointFormatUnsupported+ | CryptoError_PointCoordinatesInvalid -- Message authentification error | CryptoError_MacKeyInvalid | CryptoError_AuthenticationTagSizeInvalid
+ Crypto/Internal/Proxy.hs view
@@ -0,0 +1,13 @@+-- |+-- Module : Crypto.Internal.Proxy+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : Good+--+module Crypto.Internal.Proxy+ ( Proxy(..)+ ) where++-- | A type witness for 'a' as phantom type+data Proxy a = Proxy
Crypto/KDF/HKDF.hs view
@@ -18,15 +18,21 @@ ) where import Data.Word-import Crypto.Hash +import Crypto.Hash import Crypto.MAC.HMAC-import Crypto.Internal.ByteArray (ScrubbedBytes, Bytes, ByteArray, ByteArrayAccess)+import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import qualified Crypto.Internal.ByteArray as B -- | Pseudo Random Key data PRK a = PRK (HMAC a) | PRK_NoExpand ScrubbedBytes deriving (Eq) +instance ByteArrayAccess (PRK a) where+ length (PRK hm) = B.length hm+ length (PRK_NoExpand sb) = B.length sb+ withByteArray (PRK hm) = B.withByteArray hm+ withByteArray (PRK_NoExpand sb) = B.withByteArray sb+ -- | Extract a Pseudo Random Key using the parameter and the underlaying hash mechanism extract :: (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) => salt -- ^ Salt@@ -38,7 +44,7 @@ -- -- Only use when guaranteed to have a good quality and random data to use directly as key. -- This effectively skip a HMAC with key=salt and data=key.-extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm)+extractSkip :: ByteArrayAccess ikm => ikm -> PRK a extractSkip ikm = PRK_NoExpand $ B.convert ikm
Crypto/PubKey/Curve25519.hs view
@@ -9,6 +9,7 @@ -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-}+{-# LANGUAGE ScopedTypeVariables #-} module Crypto.PubKey.Curve25519 ( SecretKey , PublicKey@@ -20,17 +21,22 @@ -- * methods , dh , toPublic+ , generateSecretKey ) where +import Data.Bits import Data.Word import Foreign.Ptr+import Foreign.Storable import GHC.Ptr import Crypto.Error import Crypto.Internal.Compat import Crypto.Internal.Imports-import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)+import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes, Bytes, withByteArray) import qualified Crypto.Internal.ByteArray as B+import Crypto.Error (CryptoFailable(..))+import Crypto.Random -- | A Curve25519 Secret key newtype SecretKey = SecretKey ScrubbedBytes@@ -104,6 +110,18 @@ where basePoint = Ptr "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"# {-# NOINLINE toPublic #-}++-- | Generate a secret key.+generateSecretKey :: MonadRandom m => m SecretKey+generateSecretKey = tweakToSecretKey <$> getRandomBytes 32+ where+ tweakToSecretKey :: ScrubbedBytes -> SecretKey+ tweakToSecretKey bin = SecretKey $ B.copyAndFreeze bin $ \inp -> do+ modifyByte inp 0 (\e0 -> e0 .&. 0xf8)+ modifyByte inp 31 (\e31 -> (e31 .&. 0x7f) .|. 0x40)++ modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()+ modifyByte p n f = peekByteOff p n >>= pokeByteOff p n . f foreign import ccall "cryptonite_curve25519_donna" ccryptonite_curve25519 :: Ptr Word8 -- ^ public
Crypto/PubKey/ECC/P256.hs view
@@ -18,6 +18,7 @@ , pointBase , pointAdd , pointMul+ , pointDh , pointsMulVarTime , pointIsValid , toPoint@@ -56,7 +57,7 @@ -- | A P256 scalar newtype Scalar = Scalar ScrubbedBytes- deriving (Eq,ByteArrayAccess)+ deriving (Show,Eq,ByteArrayAccess) -- | A P256 point newtype Point = Point Bytes@@ -112,6 +113,14 @@ withScalar scalar $ \n -> withPoint p $ \px py -> withScalarZero $ \nzero -> ccryptonite_p256_points_mul_vartime nzero n px py dx dy +-- | Similar to 'pointMul', serializing the x coordinate as binary+pointDh :: ByteArray binary => Scalar -> Point -> binary+pointDh scalar p =+ B.unsafeCreate scalarSize $ \dst -> withTempPoint $ \dx dy -> do+ withScalar scalar $ \n -> withPoint p $ \px py -> withScalarZero $ \nzero ->+ ccryptonite_p256_points_mul_vartime nzero n px py dx dy+ ccryptonite_p256_to_bin (castPtr dx) dst+ -- | multiply the point @p with @n2 and add a lifted to curve value @n1 -- -- > n1 * G + n2 * p@@ -281,6 +290,9 @@ withNewScalarFreeze :: (Ptr P256Scalar -> IO ()) -> Scalar withNewScalarFreeze f = Scalar $ B.allocAndFreeze scalarSize f {-# NOINLINE withNewScalarFreeze #-}++withTempPoint :: (Ptr P256X -> Ptr P256Y -> IO a) -> IO a+withTempPoint f = allocTempScrubbed scalarSize (\p -> let px = castPtr p in f px (pxToPy px)) withTempScalar :: (Ptr P256Scalar -> IO a) -> IO a withTempScalar f = allocTempScrubbed scalarSize (f . castPtr)
Crypto/PubKey/ECC/Types.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-} -- |--- Module : Crypto.PubKey.ECC.types+-- Module : Crypto.PubKey.ECC.Types -- License : BSD-style -- Maintainer : Vincent Hanquez <vincent@snarc.org> -- Stability : Experimental
+ Crypto/PubKey/ECIES.hs view
@@ -0,0 +1,48 @@+-- |+-- Module : Crypto.PubKey.ECIES+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+-- IES with Elliptic curve <https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme>+--+-- This is a simple cryptographic system between 2 parties using Elliptic Curve.+--+-- The sending party create a shared secret using the receiver public key, and use the shared secret+-- to generate cryptographic material for an symmetric encryption scheme (preferably authenticated encryption).+--+-- The receiving party receive the temporary ephemeral public key which is combined to its secret key+-- to create the shared secret which just like on the sending is used to generate cryptographic material.+--+-- This module doesn't provide any symmetric data encryption capability or any mean to derive+-- cryptographic key material for a symmetric key from the shared secret.+-- this is left to the user for now.+--+module Crypto.PubKey.ECIES+ ( deriveEncrypt+ , deriveDecrypt+ ) where++import Crypto.ECC+import Crypto.Random+import Crypto.Internal.Proxy++-- | Generate random a new Shared secret and the associated point+-- to do a ECIES style encryption+deriveEncrypt :: (MonadRandom randomly, EllipticCurveDH curve)+ => proxy curve -- ^ representation of the curve+ -> Point curve -- ^ the public key of the receiver+ -> randomly (Point curve, SharedSecret)+deriveEncrypt proxy pub = do+ (KeyPair rPoint rScalar) <- curveGenerateKeyPair proxy+ return (rPoint, ecdh proxy rScalar pub)++-- | Derive the shared secret with the receiver key+-- and the R point of the scheme.+deriveDecrypt :: EllipticCurveDH curve+ => proxy curve -- ^ representation of the curve+ -> Point curve -- ^ The received R (supposedly, randomly generated on the encrypt side)+ -> Scalar curve -- ^ The secret key of the receiver+ -> SharedSecret+deriveDecrypt proxy point secret = ecdh proxy secret point
Crypto/PubKey/Ed448.hs view
@@ -20,6 +20,7 @@ -- * methods , dh , toPublic+ , generateSecretKey ) where import Data.Word@@ -27,6 +28,7 @@ import GHC.Ptr import Crypto.Error+import Crypto.Random import Crypto.Internal.Compat import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)@@ -91,6 +93,10 @@ where basePoint = Ptr "\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"# {-# NOINLINE toPublic #-}++-- | Generate a secret key.+generateSecretKey :: MonadRandom m => m SecretKey+generateSecretKey = SecretKey <$> getRandomBytes x448_bytes x448_bytes :: Int x448_bytes = 448 `quot` 8
README.md view
@@ -94,6 +94,7 @@ * [Salsa](http://cr.yp.to/snuffle.html) * [Salsa128-test-vectors](https://github.com/alexwebr/salsa20/blob/master/test_vectors.128) * [Salsa256-test-vectors](https://github.com/alexwebr/salsa20/blob/master/test_vectors.256)+* [XSalsa](https://cr.yp.to/snuffle/xsalsa-20081128.pdf) * [PBKDF2](http://tools.ietf.org/html/rfc2898) * [PBKDF2-test-vectors](http://www.ietf.org/rfc/rfc6070.txt) * [Scrypt](http://www.tarsnap.com/scrypt.html)@@ -101,7 +102,3 @@ * [Ed25519](http://ed25519.cr.yp.to/papers.html) * [AFIS](http://clemens.endorphin.org/cryptography) -TODO-------* add support for XSalsa
+ cbits/cryptonite_align.h view
@@ -0,0 +1,51 @@+#ifndef CRYPTONITE_ALIGN_H+#define CRYPTONITE_ALIGN_H++#include "cryptonite_bitfn.h"++#if (defined(__i386__))+# define UNALIGNED_ACCESS_OK+#elif defined(__x86_64__)+# define UNALIGNED_ACCESS_OK+#else+# define UNALIGNED_ACCESS_FAULT+#endif++/* n need to be power of 2.+ * IS_ALIGNED(p,8) */+#define IS_ALIGNED(p,alignment) (((uintptr_t) (p)) & ((alignment)-1))++#ifdef WITH_ASSERT_ALIGNMENT+#include <stdio.h>+#include <stdlib.h>+#include <inttypes.h>+# define ASSERT_ALIGNMENT(up, alignment) \+ do { if (IS_ALIGNED(up, alignment)) \+ { printf("ALIGNMENT-ASSERT-FAILURE: %s:%d: ptr=%p alignment=%d\n", __FILE__, __LINE__, (void *) up, (alignment)); \+ exit(99); \+ }; } while (0)+#else+# define ASSERT_ALIGNMENT(p, n) do {} while (0)+#endif++#ifdef UNALIGNED_ACCESS_OK+#define need_alignment(p,n) (0)+#else+#define need_alignment(p,n) IS_ALIGNED(p,n)+#endif++static inline uint32_t load_le32_aligned(const uint8_t *p)+{+ return le32_to_cpu(*((uint32_t *) p)); +}++#ifdef UNALIGNED_ACCESS_OK+#define load_le32(a) load_le32_aligned(a)+#else+static inline uint32_t load_le32(const uint8_t *p)+{+ return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);+}+#endif++#endif
cbits/cryptonite_chacha.c view
@@ -32,6 +32,7 @@ #include <string.h> #include "cryptonite_chacha.h" #include "cryptonite_bitfn.h"+#include "cryptonite_align.h" #include <stdio.h> #define QR(a,b,c,d) \@@ -46,11 +47,6 @@ static const uint8_t sigma[16] = "expand 32-byte k"; static const uint8_t tau[16] = "expand 16-byte k"; -static inline uint32_t load32(const uint8_t *p)-{- return le32_to_cpu(*((uint32_t *) p));-}- static void chacha_core(int rounds, block *out, const cryptonite_chacha_state *in) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;@@ -104,33 +100,35 @@ const uint8_t *constants = (keylen == 32) ? sigma : tau; int i; - st->d[0] = load32(constants + 0);- st->d[1] = load32(constants + 4);- st->d[2] = load32(constants + 8);- st->d[3] = load32(constants + 12);+ ASSERT_ALIGNMENT(constants, 4); - st->d[4] = load32(key + 0);- st->d[5] = load32(key + 4);- st->d[6] = load32(key + 8);- st->d[7] = load32(key + 12);+ st->d[0] = load_le32_aligned(constants + 0);+ st->d[1] = load_le32_aligned(constants + 4);+ st->d[2] = load_le32_aligned(constants + 8);+ st->d[3] = load_le32_aligned(constants + 12);++ st->d[4] = load_le32(key + 0);+ st->d[5] = load_le32(key + 4);+ st->d[6] = load_le32(key + 8);+ st->d[7] = load_le32(key + 12); /* we repeat the key on 128 bits */ if (keylen == 32) key += 16;- st->d[8] = load32(key + 0);- st->d[9] = load32(key + 4);- st->d[10] = load32(key + 8);- st->d[11] = load32(key + 12);+ st->d[8] = load_le32(key + 0);+ st->d[9] = load_le32(key + 4);+ st->d[10] = load_le32(key + 8);+ st->d[11] = load_le32(key + 12); st->d[12] = 0; switch (ivlen) { case 8: st->d[13] = 0;- st->d[14] = load32(iv + 0);- st->d[15] = load32(iv + 4);+ st->d[14] = load_le32(iv + 0);+ st->d[15] = load_le32(iv + 4); break; case 12:- st->d[13] = load32(iv + 0);- st->d[14] = load32(iv + 4);- st->d[15] = load32(iv + 8);+ st->d[13] = load_le32(iv + 0);+ st->d[14] = load_le32(iv + 4);+ st->d[15] = load_le32(iv + 8); default: return; }
cbits/cryptonite_poly1305.c view
@@ -132,7 +132,7 @@ /* fill the remaining bytes in the partial buffer */ if (length) { memcpy(ctx->buf + ctx->index, data, length);- ctx->index = length;+ ctx->index += length; } }
cbits/cryptonite_sha3.c view
@@ -25,6 +25,7 @@ #include <stdint.h> #include <string.h> #include "cryptonite_bitfn.h"+#include "cryptonite_align.h" #include "cryptonite_sha3.h" #define KECCAK_NB_ROUNDS 24@@ -124,9 +125,19 @@ ctx->bufindex = 0; } - /* process as much ctx->bufsz-block */- for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz)- sha3_do_chunk(ctx->state, (uint64_t *) data, ctx->bufsz / 8);+ if (need_alignment(data, 8)) {+ uint64_t tramp[200 - 2 * (224 / 8)];+ ASSERT_ALIGNMENT(tramp, 8);+ for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz) {+ memcpy(tramp, data, ctx->bufsz / 8);+ sha3_do_chunk(ctx->state, (uint64_t *) data, ctx->bufsz / 8);+ }+ } else {+ /* process as much ctx->bufsz-block */+ for (; len >= ctx->bufsz; len -= ctx->bufsz, data += ctx->bufsz)+ sha3_do_chunk(ctx->state, (uint64_t *) data, ctx->bufsz / 8);+ }+ /* append data into buf */ if (len) {
+ cbits/cryptonite_xsalsa.c view
@@ -0,0 +1,80 @@+/*+ * Copyright (c) 2016 Brandon Hamilton <brandon.hamilton@gmail.com>+ * + * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the author nor the names of his contributors+ * may be used to endorse or promote products derived from this software+ * without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */+#include <stdint.h>+#include <string.h>+#include "cryptonite_xsalsa.h"+#include "cryptonite_bitfn.h"++static inline uint32_t load32(const uint8_t *p)+{+ return le32_to_cpu(*((uint32_t *) p));+}++/* XSalsa20 algorithm as described in https://cr.yp.to/snuffle/xsalsa-20081128.pdf */+void cryptonite_xsalsa_init(cryptonite_salsa_context *ctx, uint8_t nb_rounds,+ uint32_t keylen, const uint8_t *key,+ uint32_t ivlen, const uint8_t *iv)+{+ memset(ctx, 0, sizeof(*ctx));+ ctx->nb_rounds = nb_rounds;++ /* Create initial 512-bit input block:+ (x0, x5, x10, x15) is the Salsa20 constant+ (x1, x2, x3, x4, x11, x12, x13, x14) is a 256-bit key+ (x6, x7, x8, x9) is the first 128 bits of a 192-bit nonce+ */+ cryptonite_salsa_init_core(&ctx->st, keylen, key, 8, iv);+ ctx->st.d[ 8] = load32(iv + 8);+ ctx->st.d[ 9] = load32(iv + 12);++ /* Compute (z0, z1, . . . , z15) = doubleround ^(r/2) (x0, x1, . . . , x15) */+ block hSalsa;+ memset(&hSalsa, 0, sizeof(block));+ cryptonite_salsa_core_xor(nb_rounds, &hSalsa, &ctx->st);+ + /* Build a new 512-bit input block (x′0, x′1, . . . , x′15):+ (x′0, x′5, x′10, x′15) is the Salsa20 constant+ (x′1,x′2,x′3,x′4,x′11,x′12,x′13,x′14) = (z0,z5,z10,z15,z6,z7,z8,z9)+ (x′6,x′7) is the last 64 bits of the 192-bit nonce+ (x′8, x′9) is a 64-bit block counter.+ */+ ctx->st.d[ 1] = hSalsa.d[ 0] - ctx->st.d[ 0];+ ctx->st.d[ 2] = hSalsa.d[ 5] - ctx->st.d[ 5];+ ctx->st.d[ 3] = hSalsa.d[10] - ctx->st.d[10];+ ctx->st.d[ 4] = hSalsa.d[15] - ctx->st.d[15];+ ctx->st.d[11] = hSalsa.d[ 6] - ctx->st.d[ 6];+ ctx->st.d[12] = hSalsa.d[ 7] - ctx->st.d[ 7];+ ctx->st.d[13] = hSalsa.d[ 8] - ctx->st.d[ 8];+ ctx->st.d[14] = hSalsa.d[ 9] - ctx->st.d[ 9];+ ctx->st.d[ 6] = load32(iv + 16);+ ctx->st.d[ 7] = load32(iv + 20);+ ctx->st.d[ 8] = 0;+ ctx->st.d[ 9] = 0;+}
+ cbits/cryptonite_xsalsa.h view
@@ -0,0 +1,37 @@+/*+ * Copyright (c) 2016 Brandon Hamilton <brandon.hamilton@gmail.com>+ *+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the author nor the names of his contributors+ * may be used to endorse or promote products derived from this software+ * without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */+#ifndef CRYPTONITE_XSALSA+#define CRYPTONITE_XSALSA++#include "cryptonite_salsa.h"++void cryptonite_xsalsa_init(cryptonite_salsa_context *ctx, uint8_t nb_rounds, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv);++#endif
cryptonite.cabal view
@@ -1,10 +1,10 @@ Name: cryptonite-Version: 0.20+Version: 0.21 Synopsis: Cryptography Primitives sink Description: A repository of cryptographic primitives. .- * Symmetric ciphers: AES, DES, 3DES, Blowfish, Camellia, RC4, Salsa, ChaCha.+ * Symmetric ciphers: AES, DES, 3DES, Blowfish, Camellia, RC4, Salsa, XSalsa, ChaCha. . * Hash: SHA1, SHA2, SHA3, MD2, MD4, MD5, Keccak, Skein, Ripemd, Tiger, Whirlpool, Blake2 .@@ -86,6 +86,11 @@ Default: False Manual: True +Flag check_alignment+ Description: extra check on alignment in C layers, which cause lowlevel assert errors. for debugging only.+ Default: False+ Manual: True+ Library Exposed-modules: Crypto.Cipher.AES Crypto.Cipher.Blowfish@@ -97,9 +102,11 @@ Crypto.Cipher.Salsa Crypto.Cipher.TripleDES Crypto.Cipher.Types+ Crypto.Cipher.XSalsa Crypto.ConstructHash.MiyaguchiPreneel Crypto.Data.AFIS Crypto.Data.Padding+ Crypto.ECC Crypto.Error Crypto.MAC.CMAC Crypto.MAC.Poly1305@@ -128,6 +135,7 @@ Crypto.PubKey.ECC.ECDSA Crypto.PubKey.ECC.P256 Crypto.PubKey.ECC.Types+ Crypto.PubKey.ECIES Crypto.PubKey.Ed25519 Crypto.PubKey.Ed448 Crypto.PubKey.RSA@@ -183,6 +191,9 @@ Crypto.Random.Probabilistic Crypto.PubKey.Internal Crypto.PubKey.ElGamal+ Crypto.ECC.Simple.Types+ Crypto.ECC.Simple.Prim+ Crypto.Internal.Proxy Crypto.Internal.ByteArray Crypto.Internal.Compat Crypto.Internal.CompatPrim@@ -201,6 +212,7 @@ cc-options: -fgnu89-inline C-sources: cbits/cryptonite_chacha.c , cbits/cryptonite_salsa.c+ , cbits/cryptonite_xsalsa.c , cbits/cryptonite_rc4.c , cbits/cryptonite_cpu.c , cbits/ed25519/ed25519.c@@ -290,6 +302,8 @@ if flag(support_deepseq) CPP-options: -DWITH_DEEPSEQ_SUPPORT Build-depends: deepseq+ if flag(check_alignment)+ cc-options: -DWITH_ASSERT_ALIGNMENT Test-Suite test-cryptonite type: exitcode-stdio-1.0@@ -335,6 +349,7 @@ Poly1305 Salsa Utils+ XSalsa Build-Depends: base >= 3 && < 5 , bytestring , memory
tests/Tests.hs view
@@ -9,6 +9,7 @@ import qualified Hash import qualified Poly1305 import qualified Salsa+import qualified XSalsa import qualified ChaCha import qualified ChaChaPoly1305 import qualified KAT_MiyaguchiPreneel@@ -67,6 +68,7 @@ , ChaCha.tests , ChaChaPoly1305.tests , Salsa.tests+ , XSalsa.tests ] , KAT_AFIS.tests ]
+ tests/XSalsa.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE OverloadedStrings #-}+module XSalsa (tests) where++import qualified Data.ByteString as B+import qualified Crypto.Cipher.XSalsa as XSalsa++import Imports++type Vector = (Int, B.ByteString, B.ByteString, B.ByteString, B.ByteString)++-- Test vectors generated by naclcrypto library (https://nacl.cr.yp.to)+vectors :: [Vector]+vectors =+ [ ( 20+ , "\xA6\xA7\x25\x1C\x1E\x72\x91\x6D\x11\xC2\xCB\x21\x4D\x3C\x25\x25\x39\x12\x1D\x8E\x23\x4E\x65\x2D\x65\x1F\xA4\xC8\xCF\xF8\x80\x30"+ , "\x9E\x64\x5A\x74\xE9\xE0\xA6\x0D\x82\x43\xAC\xD9\x17\x7A\xB5\x1A\x1B\xEB\x8D\x5A\x2F\x5D\x70\x0C"+ , "\x09\x3C\x5E\x55\x85\x57\x96\x25\x33\x7B\xD3\xAB\x61\x9D\x61\x57\x60\xD8\xC5\xB2\x24\xA8\x5B\x1D\x0E\xFE\x0E\xB8\xA7\xEE\x16\x3A\xBB\x03\x76\x52\x9F\xCC\x09\xBA\xB5\x06\xC6\x18\xE1\x3C\xE7\x77\xD8\x2C\x3A\xE9\xD1\xA6\xF9\x72\xD4\x16\x02\x87\xCB\xFE\x60\xBF\x21\x30\xFC\x0A\x6F\xF6\x04\x9D\x0A\x5C\x8A\x82\xF4\x29\x23\x1F\x00\x80\x82\xE8\x45\xD7\xE1\x89\xD3\x7F\x9E\xD2\xB4\x64\xE6\xB9\x19\xE6\x52\x3A\x8C\x12\x10\xBD\x52\xA0\x2A\x4C\x3F\xE4\x06\xD3\x08\x5F\x50\x68\xD1\x90\x9E\xEE\xCA\x63\x69\xAB\xC9\x81\xA4\x2E\x87\xFE\x66\x55\x83\xF0\xAB\x85\xAE\x71\xF6\xF8\x4F\x52\x8E\x6B\x39\x7A\xF8\x6F\x69\x17\xD9\x75\x4B\x73\x20\xDB\xDC\x2F\xEA\x81\x49\x6F\x27\x32\xF5\x32\xAC\x78\xC4\xE9\xC6\xCF\xB1\x8F\x8E\x9B\xDF\x74\x62\x2E\xB1\x26\x14\x14\x16\x77\x69\x71\xA8\x4F\x94\xD1\x56\xBE\xAF\x67\xAE\xCB\xF2\xAD\x41\x2E\x76\xE6\x6E\x8F\xAD\x76\x33\xF5\xB6\xD7\xF3\xD6\x4B\x5C\x6C\x69\xCE\x29\x00\x3C\x60\x24\x46\x5A\xE3\xB8\x9B\xE7\x8E\x91\x5D\x88\xB4\xB5\x62\x1D"+ , "\xB2\xAF\x68\x8E\x7D\x8F\xC4\xB5\x08\xC0\x5C\xC3\x9D\xD5\x83\xD6\x71\x43\x22\xC6\x4D\x7F\x3E\x63\x14\x7A\xED\xE2\xD9\x53\x49\x34\xB0\x4F\xF6\xF3\x37\xB0\x31\x81\x5C\xD0\x94\xBD\xBC\x6D\x7A\x92\x07\x7D\xCE\x70\x94\x12\x28\x68\x22\xEF\x07\x37\xEE\x47\xF6\xB7\xFF\xA2\x2F\x9D\x53\xF1\x1D\xD2\xB0\xA3\xBB\x9F\xC0\x1D\x9A\x88\xF9\xD5\x3C\x26\xE9\x36\x5C\x2C\x3C\x06\x3B\xC4\x84\x0B\xFC\x81\x2E\x4B\x80\x46\x3E\x69\xD1\x79\x53\x0B\x25\xC1\x58\xF5\x43\x19\x1C\xFF\x99\x31\x06\x51\x1A\xA0\x36\x04\x3B\xBC\x75\x86\x6A\xB7\xE3\x4A\xFC\x57\xE2\xCC\xE4\x93\x4A\x5F\xAA\xE6\xEA\xBE\x4F\x22\x17\x70\x18\x3D\xD0\x60\x46\x78\x27\xC2\x7A\x35\x41\x59\xA0\x81\x27\x5A\x29\x1F\x69\xD9\x46\xD6\xFE\x28\xED\x0B\x9C\xE0\x82\x06\xCF\x48\x49\x25\xA5\x1B\x94\x98\xDB\xDE\x17\x8D\xDD\x3A\xE9\x1A\x85\x81\xB9\x16\x82\xD8\x60\xF8\x40\x78\x2F\x6E\xEA\x49\xDB\xB9\xBD\x72\x15\x01\xD2\xC6\x71\x22\xDE\xA3\xB7\x28\x38\x48\xC5\xF1\x3E\x0C\x0D\xE8\x76\xBD\x22\x7A\x85\x6E\x4D\xE5\x93\xA3")+ , ( 20+ , "\x9E\x1D\xA2\x39\xD1\x55\xF5\x2A\xD3\x7F\x75\xC7\x36\x8A\x53\x66\x68\xB0\x51\x95\x29\x23\xAD\x44\xF5\x7E\x75\xAB\x58\x8E\x47\x5A"+ , "\xAF\x06\xF1\x78\x59\xDF\xFA\x79\x98\x91\xC4\x28\x8F\x66\x35\xB5\xC5\xA4\x5E\xEE\x90\x17\xFD\x72"+ , "\xFE\xAC\x9D\x54\xFC\x8C\x11\x5A\xE2\x47\xD9\xA7\xE9\x19\xDD\x76\xCF\xCB\xC7\x2D\x32\xCA\xE4\x94\x48\x60\x81\x7C\xBD\xFB\x8C\x04\xE6\xB1\xDF\x76\xA1\x65\x17\xCD\x33\xCC\xF1\xAC\xDA\x92\x06\x38\x9E\x9E\x31\x8F\x59\x66\xC0\x93\xCF\xB3\xEC\x2D\x9E\xE2\xDE\x85\x64\x37\xED\x58\x1F\x55\x2F\x26\xAC\x29\x07\x60\x9D\xF8\xC6\x13\xB9\xE3\x3D\x44\xBF\xC2\x1F\xF7\x91\x53\xE9\xEF\x81\xA9\xD6\x6C\xC3\x17\x85\x7F\x75\x2C\xC1\x75\xFD\x88\x91\xFE\xFE\xBB\x7D\x04\x1E\x65\x17\xC3\x16\x2D\x19\x7E\x21\x12\x83\x7D\x3B\xC4\x10\x43\x12\xAD\x35\xB7\x5E\xA6\x86\xE7\xC7\x0D\x4E\xC0\x47\x46\xB5\x2F\xF0\x9C\x42\x14\x51\x45\x9F\xB5\x9F"+ , "\x2C\x26\x1A\x2F\x4E\x61\xA6\x2E\x1B\x27\x68\x99\x16\xBF\x03\x45\x3F\xCB\xC9\x7B\xB2\xAF\x6F\x32\x93\x91\xEF\x06\x3B\x5A\x21\x9B\xF9\x84\xD0\x7D\x70\xF6\x02\xD8\x5F\x6D\xB6\x14\x74\xE9\xD9\xF5\xA2\xDE\xEC\xB4\xFC\xD9\x01\x84\xD1\x6F\x3B\x5B\x5E\x16\x8E\xE0\x3E\xA8\xC9\x3F\x39\x33\xA2\x2B\xC3\xD1\xA5\xAE\x8C\x2D\x8B\x02\x75\x7C\x87\xC0\x73\x40\x90\x52\xA2\xA8\xA4\x1E\x7F\x48\x7E\x04\x1F\x9A\x49\xA0\x99\x7B\x54\x0E\x18\x62\x1C\xAD\x3A\x24\xF0\xA5\x6D\x9B\x19\x22\x79\x29\x05\x7A\xB3\xBA\x95\x0F\x62\x74\xB1\x21\xF1\x93\xE3\x2E\x06\xE5\x38\x87\x81\xA1\xCB\x57\x31\x7C\x0B\xA6\x30\x5E\x91\x09\x61\xD0\x10\x02\xF0")+ , ( 20+ , "\xD5\xC7\xF6\x79\x7B\x7E\x7E\x9C\x1D\x7F\xD2\x61\x0B\x2A\xBF\x2B\xC5\xA7\x88\x5F\xB3\xFF\x78\x09\x2F\xB3\xAB\xE8\x98\x6D\x35\xE2"+ , "\x74\x4E\x17\x31\x2B\x27\x96\x9D\x82\x64\x44\x64\x0E\x9C\x4A\x37\x8A\xE3\x34\xF1\x85\x36\x9C\x95"+ , "\x77\x58\x29\x8C\x62\x8E\xB3\xA4\xB6\x96\x3C\x54\x45\xEF\x66\x97\x12\x22\xBE\x5D\x1A\x4A\xD8\x39\x71\x5D\x11\x88\x07\x17\x39\xB7\x7C\xC6\xE0\x5D\x54\x10\xF9\x63\xA6\x41\x67\x62\x97\x57"+ , "\x27\xB8\xCF\xE8\x14\x16\xA7\x63\x01\xFD\x1E\xEC\x6A\x4D\x99\x67\x50\x69\xB2\xDA\x27\x76\xC3\x60\xDB\x1B\xDF\xEA\x7C\x0A\xA6\x13\x91\x3E\x10\xF7\xA6\x0F\xEC\x04\xD1\x1E\x65\xF2\xD6\x4E")+ , ( 20+ , "\x73\x7D\x78\x11\xCE\x96\x47\x2E\xFE\xD1\x22\x58\xB7\x81\x22\xF1\x1D\xEA\xEC\x87\x59\xCC\xBD\x71\xEA\xC6\xBB\xEF\xA6\x27\x78\x5C"+ , "\x6F\xB2\xEE\x3D\xDA\x6D\xBD\x12\xF1\x27\x4F\x12\x67\x01\xEC\x75\xC3\x5C\x86\x60\x7A\xDB\x3E\xDD"+ , "\x50\x13\x25\xFB\x26\x45\x26\x48\x64\xDF\x11\xFA\xA1\x7B\xBD\x58\x31\x2B\x77\xCA\xD3\xD9\x4A\xC8\xFB\x85\x42\xF0\xEB\x65\x3A\xD7\x3D\x7F\xCE\x93\x2B\xB8\x74\xCB\x89\xAC\x39\xFC\x47\xF8\x26\x7C\xF0\xF0\xC2\x09\xF2\x04\xB2\xD8\x57\x8A\x3B\xDF\x46\x1C\xB6\xA2\x71\xA4\x68\xBE\xBA\xCC\xD9\x68\x50\x14\xCC\xBC\x9A\x73\x61\x8C\x6A\x5E\x77\x8A\x21\xCC\x84\x16\xC6\x0A\xD2\x4D\xDC\x41\x7A\x13\x0D\x53\xED\xA6\xDF\xBF\xE4\x7D\x09\x17\x0A\x7B\xE1\xA7\x08\xB7\xB5\xF3\xAD\x46\x43\x10\xBE\x36\xD9\xA2\xA9\x5D\xC3\x9E\x83\xD3\x86\x67\xE8\x42\xEB\x64\x11\xE8\xA2\x37\x12\x29\x7B\x16\x5F\x69\x0C\x2D\x7C\xA1\xB1\x34\x6E\x3C\x1F\xCC\xF5\xCA\xFD\x4F\x8B\xE0"+ , "\x67\x24\xC3\x72\xD2\xE9\x07\x4D\xA5\xE2\x7A\x6C\x54\xB2\xD7\x03\xDC\x1D\x4C\x9B\x1F\x8D\x90\xF0\x0C\x12\x2E\x69\x2A\xCE\x77\x00\xEA\xDC\xA9\x42\x54\x45\x07\xF1\x37\x5B\x65\x81\xD5\xA8\xFB\x39\x98\x1C\x1C\x0E\x6E\x1F\xF2\x14\x0B\x08\x2E\x9E\xC0\x16\xFC\xE1\x41\xD5\x19\x96\x47\xD4\x3B\x0B\x68\xBF\xD0\xFE\xA5\xE0\x0F\x46\x89\x62\xC7\x38\x4D\xD6\x12\x9A\xEA\x6A\x3F\xDF\xE7\x5A\xBB\x21\x0E\xD5\x60\x7C\xEF\x8F\xA0\xE1\x52\x83\x3D\x5A\xC3\x7D\x52\xE5\x57\xB9\x10\x98\xA3\x22\xE7\x6A\x45\xBB\xBC\xF4\x89\x9E\x79\x06\x18\xAA\x3F\x4C\x2E\x5E\x0F\xC3\xDE\x93\x26\x9A\x57\x7D\x77\xA5\x50\x2E\x8E\xA0\x2F\x71\x7B\x1D\xD2\xDF\x1E\xC6\x9D\x8B\x61\xCA")+ , ( 20+ , "\x76\x01\x58\xDA\x09\xF8\x9B\xBA\xB2\xC9\x9E\x69\x97\xF9\x52\x3A\x95\xFC\xEF\x10\x23\x9B\xCC\xA2\x57\x3B\x71\x05\xF6\x89\x8D\x34"+ , "\x43\x63\x6B\x2C\xC3\x46\xFC\x8B\x7C\x85\xA1\x9B\xF5\x07\xBD\xC3\xDA\xFE\x95\x3B\x88\xC6\x9D\xBA"+ , "\xD3\x0A\x6D\x42\xDF\xF4\x9F\x0E\xD0\x39\xA3\x06\xBA\xE9\xDE\xC8\xD9\xE8\x83\x66\xCC\x19\xE8\xC3\x64\x2F\xD5\x8F\xA0\x79\x4E\xBF\x80\x29\xD9\x49\x73\x03\x39\xB0\x82\x3A\x51\xF0\xF4\x9F\x0D\x2C\x71\xF1\x05\x1C\x1E\x0E\x2C\x86\x94\x1F\x17\x27\x89\xCD\xB1\xB0\x10\x74\x13\xE7\x0F\x98\x2F\xF9\x76\x18\x77\xBB\x52\x6E\xF1\xC3\xEB\x11\x06\xA9\x48\xD6\x0E\xF2\x1B\xD3\x5D\x32\xCF\xD6\x4F\x89\xB7\x9E\xD6\x3E\xCC\x5C\xCA\x56\x24\x6A\xF7\x36\x76\x6F\x28\x5D\x8E\x6B\x0D\xA9\xCB\x1C\xD2\x10\x20\x22\x3F\xFA\xCC\x5A\x32"+ , "\xC8\x15\xB6\xB7\x9B\x64\xF9\x36\x9A\xEC\x8D\xCE\x8C\x75\x3D\xF8\xA5\x0F\x2B\xC9\x7C\x70\xCE\x2F\x01\x4D\xB3\x3A\x65\xAC\x58\x16\xBA\xC9\xE3\x0A\xC0\x8B\xDD\xED\x30\x8C\x65\xCB\x87\xE2\x8E\x2E\x71\xB6\x77\xDC\x25\xC5\xA6\x49\x9C\x15\x53\x55\x5D\xAF\x1F\x55\x27\x0A\x56\x95\x9D\xFF\xA0\xC6\x6F\x24\xE0\xAF\x00\x95\x1E\xC4\xBB\x59\xCC\xC3\xA6\xC5\xF5\x2E\x09\x81\x64\x7E\x53\xE4\x39\x31\x3A\x52\xC4\x0F\xA7\x00\x4C\x85\x5B\x6E\x6E\xB2\x5B\x21\x2A\x13\x8E\x84\x3A\x9B\xA4\x6E\xDB\x2A\x03\x9E\xE8\x2A\x26\x3A\xBE")+ , ( 20+ , "\x27\xBA\x7E\x81\xE7\xED\xD4\xE7\x1B\xE5\x3C\x07\xCE\x8E\x63\x31\x38\xF2\x87\xE1\x55\xC7\xFA\x9E\x84\xC4\xAD\x80\x4B\x7F\xA1\xB9"+ , "\xEA\x05\xF4\xEB\xCD\x2F\xB6\xB0\x00\xDA\x06\x12\x86\x1B\xA5\x4F\xF5\xC1\x76\xFB\x60\x13\x91\xAA"+ , "\xE0\x9F\xF5\xD2\xCB\x05\x0D\x69\xB2\xD4\x24\x94\xBD\xE5\x82\x52\x38\xC7\x56\xD6\x99\x1D\x99\xD7\xA2\x0D\x1E\xF0\xB8\x3C\x37\x1C\x89\x87\x26\x90\xB2\xFC\x11\xD5\x36\x9F\x4F\xC4\x97\x1B\x6D\x3D\x6C\x07\x8A\xEF\x9B\x0F\x05\xC0\xE6\x1A\xB8\x9C\x02\x51\x68\x05\x4D\xEF\xEB\x03\xFE\xF6\x33\x85\x87\x00\xC5\x8B\x12\x62\xCE\x01\x13\x00\x01\x26\x73\xE8\x93\xE4\x49\x01\xDC\x18\xEE\xE3\x10\x56\x99\xC4\x4C\x80\x58\x97\xBD\xAF\x77\x6A\xF1\x83\x31\x62\xA2\x1A"+ , "\xA2\x3E\x7E\xF9\x3C\x5D\x06\x67\xC9\x6D\x9E\x40\x4D\xCB\xE6\xBE\x62\x02\x6F\xA9\x8F\x7A\x3F\xF9\xBA\x5D\x45\x86\x43\xA1\x6A\x1C\xEF\x72\x72\xDC\x60\x97\xA9\xB5\x2F\x35\x98\x35\x57\xC7\x7A\x11\xB3\x14\xB4\xF7\xD5\xDC\x2C\xCA\x15\xEE\x47\x61\x6F\x86\x18\x73\xCB\xFE\xD1\xD3\x23\x72\x17\x1A\x61\xE3\x8E\x44\x7F\x3C\xF3\x62\xB3\xAB\xBB\x2E\xD4\x17\x0D\x89\xDC\xB2\x81\x87\xB7\xBF\xD2\x06\xA3\xE0\x26\xF0\x84\xA7\xE0\xED\x63\xD3\x19\xDE\x6B\xC9\xAF\xC0")+ , ( 20+ , "\x67\x99\xD7\x6E\x5F\xFB\x5B\x49\x20\xBC\x27\x68\xBA\xFD\x3F\x8C\x16\x55\x4E\x65\xEF\xCF\x9A\x16\xF4\x68\x3A\x7A\x06\x92\x7C\x11"+ , "\x61\xAB\x95\x19\x21\xE5\x4F\xF0\x6D\x9B\x77\xF3\x13\xA4\xE4\x9D\xF7\xA0\x57\xD5\xFD\x62\x79\x89"+ , "\x47\x27\x66"+ , "\x8F\xD7\xDF")+ , ( 20+ , "\xF6\x82\x38\xC0\x83\x65\xBB\x29\x3D\x26\x98\x0A\x60\x64\x88\xD0\x9C\x2F\x10\x9E\xDA\xFA\x0B\xBA\xE9\x93\x7B\x5C\xC2\x19\xA4\x9C"+ , "\x51\x90\xB5\x1E\x9B\x70\x86\x24\x82\x0B\x5A\xBD\xF4\xE4\x0F\xAD\x1F\xB9\x50\xAD\x1A\xDC\x2D\x26"+ , "\x47\xEC\x6B\x1F\x73\xC4\xB7\xFF\x52\x74\xA0\xBF\xD7\xF4\x5F\x86\x48\x12\xC8\x5A\x12\xFB\xCB\x3C\x2C\xF8\xA3\xE9\x0C\xF6\x6C\xCF\x2E\xAC\xB5\x21\xE7\x48\x36\x3C\x77\xF5\x2E\xB4\x26\xAE\x57\xA0\xC6\xC7\x8F\x75\xAF\x71\x28\x45\x69\xE7\x9D\x1A\x92\xF9\x49\xA9\xD6\x9C\x4E\xFC\x0B\x69\x90\x2F\x1E\x36\xD7\x56\x27\x65\x54\x3E\x2D\x39\x42\xD9\xF6\xFF\x59\x48\xD8\xA3\x12\xCF\xF7\x2C\x1A\xFD\x9E\xA3\x08\x8A\xFF\x76\x40\xBF\xD2\x65\xF7\xA9\x94\x6E\x60\x6A\xBC\x77\xBC\xED\xAE\x6B\xDD\xC7\x5A\x0D\xBA\x0B\xD9\x17\xD7\x3E\x3B\xD1\x26\x8F\x72\x7E\x00\x96\x34\x5D\xA1\xED\x25\xCF\x55\x3E\xA7\xA9\x8F\xEA\x6B\x6F\x28\x57\x32\xDE\x37\x43\x15\x61\xEE\x1B\x30\x64\x88\x7F\xBC\xBD\x71\x93\x5E\x02"+ , "\x36\x16\x0E\x88\xD3\x50\x05\x29\xBA\x4E\xDB\xA1\x7B\xC2\x4D\x8C\xFA\xCA\x9A\x06\x80\xB3\xB1\xFC\x97\xCF\x03\xF3\x67\x5B\x7A\xC3\x01\xC8\x83\xA6\x8C\x07\x1B\xC5\x4A\xCD\xD3\xB6\x3A\xF4\xA2\xD7\x2F\x98\x5E\x51\xF9\xD6\x0A\x4C\x7F\xD4\x81\xAF\x10\xB2\xFC\x75\xE2\x52\xFD\xEE\x7E\xA6\xB6\x45\x31\x90\x61\x7D\xCC\x6E\x2F\xE1\xCD\x56\x58\x5F\xC2\xF0\xB0\xE9\x7C\x5C\x3F\x8A\xD7\xEB\x4F\x31\xBC\x48\x90\xC0\x38\x82\xAA\xC2\x4C\xC5\x3A\xCC\x19\x82\x29\x65\x26\x69\x0A\x22\x02\x71\xC2\xF6\xE3\x26\x75\x0D\x3F\xBD\xA5\xD5\xB6\x35\x12\xC8\x31\xF6\x78\x30\xF5\x9A\xC4\x9A\xAE\x33\x0B\x3E\x0E\x02\xC9\xEA\x00\x91\xD1\x98\x41\xF1\xB0\xE1\x3D\x69\xC9\xFB\xFE\x8A\x12\xD6\xF3\x0B\xB7\x34\xD9\xD2")+ , ( 20+ , "\x45\xB2\xBD\x0D\xE4\xED\x92\x93\xEC\x3E\x26\xC4\x84\x0F\xAA\xF6\x4B\x7D\x61\x9D\x51\xE9\xD7\xA2\xC7\xE3\x6C\x83\xD5\x84\xC3\xDF"+ , "\x54\x6C\x8C\x5D\x6B\xE8\xF9\x09\x52\xCA\xB3\xF3\x6D\x7C\x19\x57\xBA\xAA\x7A\x59\xAB\xE3\xD7\xE5"+ , "\x50\x07\xC8\xCD\x5B\x3C\x40\xE1\x7D\x7F\xE4\x23\xA8\x7A\xE0\xCE\xD8\x6B\xEC\x1C\x39\xDC\x07\xA2\x57\x72\xF3\xE9\x6D\xAB\xD5\x6C\xD3\xFD\x73\x19\xF6\xC9\x65\x49\x25\xF2\xD8\x70\x87\xA7\x00\xE1\xB1\x30\xDA\x79\x68\x95\xD1\xC9\xB9\xAC\xD6\x2B\x26\x61\x44\x06\x7D\x37\x3E\xD5\x1E\x78\x74\x98\xB0\x3C\x52\xFA\xAD\x16\xBB\x38\x26\xFA\x51\x1B\x0E\xD2\xA1\x9A\x86\x63\xF5\xBA\x2D\x6E\xA7\xC3\x8E\x72\x12\xE9\x69\x7D\x91\x48\x6C\x49\xD8\xA0\x00\xB9\xA1\x93\x5D\x6A\x7F\xF7\xEF\x23\xE7\x20\xA4\x58\x55\x48\x14\x40\x46\x3B\x4A\xC8\xC4\xF6\xE7\x06\x2A\xDC\x1F\x1E\x1E\x25\xD3\xD6\x5A\x31\x81\x2F\x58\xA7\x11\x60"+ , "\x8E\xAC\xFB\xA5\x68\x89\x8B\x10\xC0\x95\x7A\x7D\x44\x10\x06\x85\xE8\x76\x3A\x71\xA6\x9A\x8D\x16\xBC\x7B\x3F\x88\x08\x5B\xB9\xA2\xF0\x96\x42\xE4\xD0\x9A\x9F\x0A\xD0\x9D\x0A\xAD\x66\xB2\x26\x10\xC8\xBD\x02\xFF\x66\x79\xBB\x92\xC2\xC0\x26\xA2\x16\xBF\x42\x5C\x6B\xE3\x5F\xB8\xDA\xE7\xFF\x0C\x72\xB0\xEF\xD6\xA1\x80\x37\xC7\x0E\xED\x0C\xA9\x00\x62\xA4\x9A\x3C\x97\xFD\xC9\x0A\x8F\x9C\x2E\xA5\x36\xBF\xDC\x41\x91\x8A\x75\x82\xC9\x92\x7F\xAE\x47\xEF\xAA\x3D\xC8\x79\x67\xB7\x88\x7D\xEE\x1B\xF0\x71\x73\x4C\x76\x65\x90\x1D\x91\x05\xDA\xE2\xFD\xF6\x6B\x49\x18\xE5\x1D\x8F\x4A\x48\xC6\x0D\x19\xFB\xFB\xBC\xBA")+ , ( 20+ , "\xFE\x55\x9C\x9A\x28\x2B\xEB\x40\x81\x4D\x01\x6D\x6B\xFC\xB2\xC0\xC0\xD8\xBF\x07\x7B\x11\x10\xB8\x70\x3A\x3C\xE3\x9D\x70\xE0\xE1"+ , "\xB0\x76\x20\x0C\xC7\x01\x12\x59\x80\x5E\x18\xB3\x04\x09\x27\x54\x00\x27\x23\xEB\xEC\x5D\x62\x00"+ , "\x6D\xB6\x5B\x9E\xC8\xB1\x14\xA9\x44\x13\x7C\x82\x1F\xD6\x06\xBE\x75\x47\x8D\x92\x83\x66\xD5\x28\x40\x96\xCD\xEF\x78\x2F\xCF\xF7\xE8\xF5\x9C\xB8\xFF\xCD\xA9\x79\x75\x79\x02\xC5\xFF\xA6\xBC\x47\x7C\xEA\xA4\xCB\x5D\x5E\xA7\x6F\x94\xD9\x1E\x83\x3F\x82\x3A\x6B\xC7\x8F\x10\x55\xDF\xA6\xA9\x7B\xEA\x89\x65\xC1\xCD\xE6\x7A\x66\x8E\x00\x12\x57\x33\x4A\x58\x57\x27\xD9\xE0\xF7\xC1\xA0\x6E\x88\xD3\xD2\x5A\x4E\x6D\x90\x96\xC9\x68\xBF\x13\x8E\x11\x6A\x3E\xBE\xFF\xD4\xBB\x48\x08\xAD\xB1\xFD\x69\x81\x64\xBA\x0A\x35\xC7\x09\xA4\x7F\x16\xF1\xF4\x43\x5A\x23\x45\xA9\x19\x4A\x00\xB9\x5A\xBD\x51\x85\x1D\x50\x58\x09\xA6\x07\x7D\xA9\xBA\xCA\x58\x31\xAF\xFF\x31\x57\x8C\x48\x7E\xE6\x8F\x27\x67\x97\x4A\x98\xA7\xE8\x03\xAA\xC7\x88\xDA\x98\x31\x9C\x4E\xA8\xEA\xA3\xD3\x94\x85\x56\x51\xF4\x84\xCE\xF5\x43\xF5\x37\xE3\x51\x58\xEE\x29"+ , "\x4D\xCE\x9C\x8F\x97\xA0\x28\x05\x1B\x07\x27\xF3\x4E\x1B\x9E\xF2\x1F\x06\xF0\x76\x0F\x36\xE7\x17\x13\x20\x40\x27\x90\x20\x90\xBA\x2B\xB6\xB1\x34\x36\xEE\x77\x8D\x9F\x50\x53\x0E\xFB\xD7\xA3\x2B\x0D\x41\x44\x3F\x58\xCC\xAE\xE7\x81\xC7\xB7\x16\xD3\xA9\x6F\xDE\xC0\xE3\x76\x4E\xD7\x95\x9F\x34\xC3\x94\x12\x78\x59\x1E\xA0\x33\xB5\xCB\xAD\xC0\xF1\x91\x60\x32\xE9\xBE\xBB\xD1\xA8\x39\x5B\x83\xFB\x63\xB1\x45\x4B\xD7\x75\xBD\x20\xB3\xA2\xA9\x6F\x95\x12\x46\xAC\x14\xDA\xF6\x81\x66\xBA\x62\xF6\xCB\xFF\x8B\xD1\x21\xAC\x94\x98\xFF\x88\x52\xFD\x2B\xE9\x75\xDF\x52\xB5\xDA\xEF\x38\x29\xD1\x8E\xDA\x42\xE7\x15\x02\x2D\xCB\xF9\x30\xD0\xA7\x89\xEE\x6A\x14\x6C\x2C\x70\x88\xC3\x57\x73\xC6\x3C\x06\xB4\xAF\x45\x59\x85\x6A\xC1\x99\xCE\xD8\x68\x63\xE4\x29\x47\x07\x82\x53\x37\xC5\x85\x79\x70\xEB\x7F\xDD\xEB\x26\x37\x81\x30\x90\x11")+ , ( 20+ , "\x0A\xE1\x00\x12\xD7\xE5\x66\x14\xB0\x3D\xCC\x89\xB1\x4B\xAE\x92\x42\xFF\xE6\x30\xF3\xD7\xE3\x5C\xE8\xBB\xB9\x7B\xBC\x2C\x92\xC3"+ , "\xF9\x6B\x02\x5D\x6C\xF4\x6A\x8A\x12\xAC\x2A\xF1\xE2\xAE\xF1\xFB\x83\x59\x0A\xDA\xDA\xA5\xC5\xEA"+ , "\xEA\x0F\x35\x4E\x96\xF1\x2B\xC7\x2B\xBA\xA3\xD1\x2B\x4A\x8E\xD8\x79\xB0\x42\xF0\x68\x98\x78\xF4\x6B\x65\x1C\xC4\x11\x6D\x6F\x78\x40\x9B\x11\x43\x0B\x3A\xAA\x30\xB2\x07\x68\x91\xE8\xE1\xFA\x52\x8F\x2F\xD1\x69\xED\x93\xDC\x9F\x84\xE2\x44\x09\xEE\xC2\x10\x1D\xAF\x4D\x05\x7B\xE2\x49\x2D\x11\xDE\x64\x0C\xBD\x7B\x35\x5A\xD2\x9F\xB7\x04\x00\xFF\xFD\x7C\xD6\xD4\x25\xAB\xEE\xB7\x32\xA0\xEA\xA4\x33\x0A\xF4\xC6\x56\x25\x2C\x41\x73\xDE\xAB\x65\x3E\xB8\x5C\x58\x46\x2D\x7A\xB0\xF3\x5F\xD1\x2B\x61\x3D\x29\xD4\x73\xD3\x30\x31\x0D\xC3\x23\xD3\xC6\x63\x48\xBB\xDB\xB6\x8A\x32\x63\x24\x65\x7C\xAE\x7B\x77\xA9\xE3\x43\x58\xF2\xCE\xC5\x0C\x85\x60\x9E\x73\x05\x68\x56\x79\x6E\x3B\xE8\xD6\x2B\x6E\x2F\xE9\xF9\x53"+ , "\xE8\xAB\xD4\x89\x24\xB5\x4E\x5B\x80\x86\x6B\xE7\xD4\xEB\xE5\xCF\x42\x74\xCA\xFF\xF0\x8B\x39\xCB\x2D\x40\xA8\xF0\xB4\x72\x39\x8A\xED\xC7\x76\xE0\x79\x38\x12\xFB\xF1\xF6\x00\x78\x63\x5D\x2E\xD8\x6B\x15\xEF\xCD\xBA\x60\x41\x1E\xE2\x3B\x07\x23\x35\x92\xA4\x4E\xC3\x1B\x10\x13\xCE\x89\x64\x23\x66\x75\xF8\xF1\x83\xAE\xF8\x85\xE8\x64\xF2\xA7\x2E\xDF\x42\x15\xB5\x33\x8F\xA2\xB5\x46\x53\xDF\xA1\xA8\xC5\x5C\xE5\xD9\x5C\xC6\x05\xB9\xB3\x11\x52\x7F\x2E\x34\x63\xFF\xBE\xC7\x8A\x9D\x1D\x65\xDA\xBA\xD2\xF3\x38\x76\x9C\x9F\x43\xF1\x33\xA7\x91\xA1\x1C\x7E\xCA\x9A\xF0\xB7\x71\xA4\xAC\x32\x96\x3D\xC8\xF6\x31\xA2\xC1\x12\x17\xAC\x6E\x1B\x94\x30\xC1\xAA\xE1\xCE\xEB\xE2\x27\x03\xF4\x29\x99\x8A\x8F\xB8\xC6\x41")+ , ( 20+ , "\x08\x2C\x53\x9B\xC5\xB2\x0F\x97\xD7\x67\xCD\x3F\x22\x9E\xDA\x80\xB2\xAD\xC4\xFE\x49\xC8\x63\x29\xB5\xCD\x62\x50\xA9\x87\x74\x50"+ , "\x84\x55\x43\x50\x2E\x8B\x64\x91\x2D\x8F\x2C\x8D\x9F\xFF\xB3\xC6\x93\x65\x68\x65\x87\xC0\x8D\x0C"+ , "\xA9\x6B\xB7\xE9\x10\x28\x1A\x6D\xFA\xD7\xC8\xA9\xC3\x70\x67\x4F\x0C\xEE\xC1\xAD\x8D\x4F\x0D\xE3\x2F\x9A\xE4\xA2\x3E\xD3\x29\xE3\xD6\xBC\x70\x8F\x87\x66\x40\xA2\x29\x15\x3A\xC0\xE7\x28\x1A\x81\x88\xDD\x77\x69\x51\x38\xF0\x1C\xDA\x5F\x41\xD5\x21\x5F\xD5\xC6\xBD\xD4\x6D\x98\x2C\xB7\x3B\x1E\xFE\x29\x97\x97\x0A\x9F\xDB\xDB\x1E\x76\x8D\x7E\x5D\xB7\x12\x06\x8D\x8B\xA1\xAF\x60\x67\xB5\x75\x34\x95\xE2\x3E\x6E\x19\x63\xAF\x01\x2F\x9C\x7C\xE4\x50\xBF\x2D\xE6\x19\xD3\xD5\x95\x42\xFB\x55\xF3"+ , "\x83\x5D\xA7\x4F\xC6\xDE\x08\xCB\xDA\x27\x7A\x79\x66\xA0\x7C\x8D\xCD\x62\x7E\x7B\x17\xAD\xDE\x6D\x93\x0B\x65\x81\xE3\x12\x4B\x8B\xAA\xD0\x96\xF6\x93\x99\x1F\xED\xB1\x57\x29\x30\x60\x1F\xC7\x70\x95\x41\x83\x9B\x8E\x3F\xFD\x5F\x03\x3D\x20\x60\xD9\x99\xC6\xC6\xE3\x04\x82\x76\x61\x3E\x64\x80\x00\xAC\xB5\x21\x2C\xC6\x32\xA9\x16\xAF\xCE\x29\x0E\x20\xEB\xDF\x61\x2D\x08\xA6\xAA\x4C\x79\xA7\x4B\x07\x0D\x3F\x87\x2A\x86\x1F\x8D\xC6\xBB\x07\x61\x4D\xB5\x15\xD3\x63\x34\x9D\x3A\x8E\x33\x36\xA3")+ , ( 20+ , "\x3D\x02\xBF\xF3\x37\x5D\x40\x30\x27\x35\x6B\x94\xF5\x14\x20\x37\x37\xEE\x9A\x85\xD2\x05\x2D\xB3\xE4\xE5\xA2\x17\xC2\x59\xD1\x8A"+ , "\x74\x21\x6C\x95\x03\x18\x95\xF4\x8C\x1D\xBA\x65\x15\x55\xEB\xFA\x3C\xA3\x26\xA7\x55\x23\x70\x25"+ , "\x0D\x4B\x0F\x54\xFD\x09\xAE\x39\xBA\xA5\xFA\x4B\xAC\xCF\x2E\x66\x82\xE6\x1B\x25\x7E\x01\xF4\x2B\x8F"+ , "\x16\xC4\x00\x6C\x28\x36\x51\x90\x41\x1E\xB1\x59\x38\x14\xCF\x15\xE7\x4C\x22\x23\x8F\x21\x0A\xFC\x3D")+ , ( 20+ , "\xAD\x1A\x5C\x47\x68\x88\x74\xE6\x66\x3A\x0F\x3F\xA1\x6F\xA7\xEF\xB7\xEC\xAD\xC1\x75\xC4\x68\xE5\x43\x29\x14\xBD\xB4\x80\xFF\xC6"+ , "\xE4\x89\xEE\xD4\x40\xF1\xAA\xE1\xFA\xC8\xFB\x7A\x98\x25\x63\x54\x54\xF8\xF8\xF1\xF5\x2E\x2F\xCC"+ , "\xAA\x6C\x1E\x53\x58\x0F\x03\xA9\xAB\xB7\x3B\xFD\xAD\xED\xFE\xCA\xDA\x4C\x6B\x0E\xBE\x02\x0E\xF1\x0D\xB7\x45\xE5\x4B\xA8\x61\xCA\xF6\x5F\x0E\x40\xDF\xC5\x20\x20\x3B\xB5\x4D\x29\xE0\xA8\xF7\x8F\x16\xB3\xF1\xAA\x52\x5D\x6B\xFA\x33\xC5\x47\x26\xE5\x99\x88\xCF\xBE\xC7\x80\x56"+ , "\x02\xFE\x84\xCE\x81\xE1\x78\xE7\xAA\xBD\xD3\xBA\x92\x5A\x76\x6C\x3C\x24\x75\x6E\xEF\xAE\x33\x94\x2A\xF7\x5E\x8B\x46\x45\x56\xB5\x99\x7E\x61\x6F\x3F\x2D\xFC\x7F\xCE\x91\x84\x8A\xFD\x79\x91\x2D\x9F\xB5\x52\x01\xB5\x81\x3A\x5A\x07\x4D\x2C\x0D\x42\x92\xC1\xFD\x44\x18\x07\xC5")+ , ( 20+ , "\x05\x3A\x02\xBE\xDD\x63\x68\xC1\xFB\x8A\xFC\x7A\x1B\x19\x9F\x7F\x7E\xA2\x22\x0C\x9A\x4B\x64\x2A\x68\x50\x09\x1C\x9D\x20\xAB\x9C"+ , "\xC7\x13\xEE\xA5\xC2\x6D\xAD\x75\xAD\x3F\x52\x45\x1E\x00\x3A\x9C\xB0\xD6\x49\xF9\x17\xC8\x9D\xDE"+ , "\x8F\x0A\x8A\x16\x47\x60\x42\x65\x67\xE3\x88\x84\x02\x76\xDE\x3F\x95\xCB\x5E\x3F\xAD\xC6\xED\x3F\x3E\x4F\xE8\xBC\x16\x9D\x93\x88\x80\x4D\xCB\x94\xB6\x58\x7D\xBB\x66\xCB\x0B\xD5\xF8\x7B\x8E\x98\xB5\x2A\xF3\x7B\xA2\x90\x62\x9B\x85\x8E\x0E\x2A\xA7\x37\x80\x47\xA2\x66\x02"+ , "\x51\x67\x10\xE5\x98\x43\xE6\xFB\xD4\xF2\x5D\x0D\x8C\xA0\xEC\x0D\x47\xD3\x9D\x12\x5E\x9D\xAD\x98\x7E\x05\x18\xD4\x91\x07\x01\x4C\xB0\xAE\x40\x5E\x30\xC2\xEB\x37\x94\x75\x0B\xCA\x14\x2C\xE9\x5E\x29\x0C\xF9\x5A\xBE\x15\xE8\x22\x82\x3E\x2E\x7D\x3A\xB2\x1B\xC8\xFB\xD4\x45")+ , ( 20+ ,"\x5B\x14\xAB\x0F\xBE\xD4\xC5\x89\x52\x54\x8A\x6C\xB1\xE0\x00\x0C\xF4\x48\x14\x21\xF4\x12\x88\xEA\x0A\xA8\x4A\xDD\x9F\x7D\xEB\x96"+ , "\x54\xBF\x52\xB9\x11\x23\x1B\x95\x2B\xA1\xA6\xAF\x8E\x45\xB1\xC5\xA2\x9D\x97\xE2\xAB\xAD\x7C\x83"+ , "\x37\xFB\x44\xA6\x75\x97\x8B\x56\x0F\xF9\xA4\xA8\x70\x11\xD6\xF3\xAD\x2D\x37\xA2\xC3\x81\x5B\x45\xA3\xC0\xE6\xD1\xB1\xD8\xB1\x78\x4C\xD4\x68\x92\x7C\x2E\xE3\x9E\x1D\xCC\xD4\x76\x5E\x1C\x3D\x67\x6A\x33\x5B\xE1\xCC\xD6\x90\x0A\x45\xF5\xD4\x1A\x31\x76\x48\x31\x5D\x8A\x8C\x24\xAD\xC6\x4E\xB2\x85\xF6\xAE\xBA\x05\xB9\x02\x95\x86\x35\x3D\x30\x3F\x17\xA8\x07\x65\x8B\x9F\xF7\x90\x47\x4E\x17\x37\xBD\x5F\xDC\x60\x4A\xEF\xF8\xDF\xCA\xF1\x42\x7D\xCC\x3A\xAC\xBB\x02\x56\xBA\xDC\xD1\x83\xED\x75\xA2\xDC\x52\x45\x2F\x87\xD3\xC1\xED\x2A\xA5\x83\x47\x2B\x0A\xB9\x1C\xDA\x20\x61\x4E\x9B\x6F\xDB\xDA\x3B\x49\xB0\x98\xC9\x58\x23\xCC\x72\xD8\xE5\xB7\x17\xF2\x31\x4B\x03\x24\xE9\xCE"+ , "\xAE\x6D\xEB\x5D\x6C\xE4\x3D\x4B\x09\xD0\xE6\xB1\xC0\xE9\xF4\x61\x57\xBC\xD8\xAB\x50\xEA\xA3\x19\x7F\xF9\xFA\x2B\xF7\xAF\x64\x9E\xB5\x2C\x68\x54\x4F\xD3\xAD\xFE\x6B\x1E\xB3\x16\xF1\xF2\x35\x38\xD4\x70\xC3\x0D\xBF\xEC\x7E\x57\xB6\x0C\xBC\xD0\x96\xC7\x82\xE7\x73\x6B\x66\x91\x99\xC8\x25\x3E\x70\x21\x4C\xF2\xA0\x98\xFD\xA8\xEA\xC5\xDA\x79\xA9\x49\x6A\x3A\xAE\x75\x4D\x03\xB1\x7C\x6D\x70\xD1\x02\x7F\x42\xBF\x7F\x95\xCE\x3D\x1D\x9C\x33\x88\x54\xE1\x58\xFC\xC8\x03\xE4\xD6\x26\x2F\xB6\x39\x52\x1E\x47\x11\x6E\xF7\x8A\x7A\x43\x7C\xA9\x42\x7B\xA6\x45\xCD\x64\x68\x32\xFE\xAB\x82\x2A\x20\x82\x78\xE4\x5E\x93\xE1\x18\xD7\x80\xB9\x88\xD6\x53\x97\xED\xDF\xD7\xA8\x19\x52\x6E")+ , ( 20+ , "\xD7\x46\x36\xE3\x41\x3A\x88\xD8\x5F\x32\x2C\xA8\x0F\xB0\xBD\x65\x0B\xD0\xBF\x01\x34\xE2\x32\x91\x60\xB6\x96\x09\xCD\x58\xA4\xB0"+ , "\xEF\xB6\x06\xAA\x1D\x9D\x9F\x0F\x46\x5E\xAA\x7F\x81\x65\xF1\xAC\x09\xF5\xCB\x46\xFE\xCF\x2A\x57"+ , "\xF8\x54\x71\xB7\x5F\x6E\xC8\x1A\xBA\xC2\x79\x9E\xC0\x9E\x98\xE2\x80\xB2\xFF\xD6\x4C\xA2\x85\xE5\xA0\x10\x9C\xFB\x31\xFF\xAB\x2D\x61\x7B\x2C\x29\x52\xA2\xA8\xA7\x88\xFC\x0D\xA2\xAF\x7F\x53\x07\x58\xF7\x4F\x1A\xB5\x63\x91\xAB\x5F\xF2\xAD\xBC\xC5\xBE\x2D\x6C\x7F\x49\xFB\xE8\x11\x81\x04\xC6\xFF\x9A\x23\xC6\xDF\xE5\x2F\x57\x95\x4E\x6A\x69\xDC\xEE\x5D\xB0\x6F\x51\x4F\x4A\x0A\x57\x2A\x9A\x85\x25\xD9\x61\xDA\xE7\x22\x69\xB9\x87\x18\x9D\x46\x5D\xF6\x10\x71\x19\xC7\xFA\x79\x08\x53\xE0\x63\xCB\xA0\xFA\xB7\x80\x0C\xA9\x32\xE2\x58\x88\x0F\xD7\x4C\x33\xC7\x84\x67\x5B\xED\xAD\x0E\x7C\x09\xE9\xCC\x4D\x63\xDD\x5E\x97\x13\xD5\xD4\xA0\x19\x6E\x6B\x56\x22\x26\xAC\x31\xB4\xF5\x7C\x04\xF9\x0A\x18\x19\x73\x73\x7D\xDC\x7E\x80\xF3\x64\x11\x2A\x9F\xBB\x43\x5E\xBD\xBC\xAB\xF7\xD4\x90\xCE\x52"+ , "\xB2\xB7\x95\xFE\x6C\x1D\x4C\x83\xC1\x32\x7E\x01\x5A\x67\xD4\x46\x5F\xD8\xE3\x28\x13\x57\x5C\xBA\xB2\x63\xE2\x0E\xF0\x58\x64\xD2\xDC\x17\xE0\xE4\xEB\x81\x43\x6A\xDF\xE9\xF6\x38\xDC\xC1\xC8\xD7\x8F\x6B\x03\x06\xBA\xF9\x38\xE5\xD2\xAB\x0B\x3E\x05\xE7\x35\xCC\x6F\xFF\x2D\x6E\x02\xE3\xD6\x04\x84\xBE\xA7\xC7\xA8\xE1\x3E\x23\x19\x7F\xEA\x7B\x04\xD4\x7D\x48\xF4\xA4\xE5\x94\x41\x74\x53\x94\x92\x80\x0D\x3E\xF5\x1E\x2E\xE5\xE4\xC8\xA0\xBD\xF0\x50\xC2\xDD\x3D\xD7\x4F\xCE\x5E\x7E\x5C\x37\x36\x4F\x75\x47\xA1\x14\x80\xA3\x06\x3B\x9A\x0A\x15\x7B\x15\xB1\x0A\x5A\x95\x4D\xE2\x73\x1C\xED\x05\x5A\xA2\xE2\x76\x7F\x08\x91\xD4\x32\x9C\x42\x6F\x38\x08\xEE\x86\x7B\xED\x0D\xC7\x5B\x59\x22\xB7\xCF\xB8\x95\x70\x0F\xDA\x01\x61\x05\xA4\xC7\xB7\xF0\xBB\x90\xF0\x29\xF6\xBB\xCB\x04\xAC\x36\xAC\x16") + ]++tests = testGroup "XSalsa"+ [ testGroup "KAT" $+ map (\(i,f) -> testCase (show (i :: Int)) f) $ zip [1..] $ map (\(r, k, i, p, e) -> salsaRunSimple r k i p e) vectors+ ]+ where+ salsaRunSimple rounds key nonce plain expected =+ let salsa = XSalsa.initialize rounds key nonce+ in fst (XSalsa.combine salsa plain) @?= expected