crypton-x509 1.9.2 → 1.10.0
raw patch · 8 files changed
+843/−6 lines, 8 filesdep ~cryptondep ~crypton-asn1-encodingPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: crypton, crypton-asn1-encoding
API changes (from Hackage documentation)
+ Data.X509: MLDSAKeyBoth :: MLDSAKeyForm
+ Data.X509: MLDSAKeyExpanded :: MLDSAKeyForm
+ Data.X509: MLDSAKeySeed :: MLDSAKeyForm
+ Data.X509: PrivKeyMLDSA44 :: PrivKeyMLDSA MLDSA44 -> PrivKey
+ Data.X509: PrivKeyMLDSA65 :: PrivKeyMLDSA MLDSA65 -> PrivKey
+ Data.X509: PrivKeyMLDSA87 :: PrivKeyMLDSA MLDSA87 -> PrivKey
+ Data.X509: PubKeyALG_MLDSA44 :: PubKeyALG
+ Data.X509: PubKeyALG_MLDSA65 :: PubKeyALG
+ Data.X509: PubKeyALG_MLDSA87 :: PubKeyALG
+ Data.X509: PubKeyMLDSA44 :: VerificationKey MLDSA44 -> PubKey
+ Data.X509: PubKeyMLDSA65 :: VerificationKey MLDSA65 -> PubKey
+ Data.X509: PubKeyMLDSA87 :: VerificationKey MLDSA87 -> PubKey
+ Data.X509: data MLDSAKeyForm
+ Data.X509: data PrivKeyMLDSA p
+ Data.X509: privkeyMLDSAFromKey :: SigningKey p -> PrivKeyMLDSA p
+ Data.X509: privkeyMLDSAFromSeed :: (MLDSA p, ByteArrayAccess ba) => proxy p -> MLDSAKeyForm -> ba -> CryptoFailable (PrivKeyMLDSA p)
+ Data.X509: privkeyMLDSA_form :: PrivKeyMLDSA p -> MLDSAKeyForm
+ Data.X509: privkeyMLDSA_key :: PrivKeyMLDSA p -> SigningKey p
+ Data.X509: privkeyMLDSA_seed :: PrivKeyMLDSA p -> Maybe ScrubbedBytes
Files
- ChangeLog.md +7/−0
- Data/X509.hs +7/−0
- Data/X509/AlgorithmIdentifier.hs +22/−1
- Data/X509/PrivateKey.hs +209/−3
- Data/X509/PublicKey.hs +30/−0
- Tests/MLDSAKeys.hs +365/−0
- Tests/Tests.hs +198/−0
- crypton-x509.cabal +5/−2
ChangeLog.md view
@@ -1,5 +1,12 @@ # ChangeLog for crypton-x509 +## 1.10.0++* Support ML-DSA (RFC 9881)+ [#35](https://github.com/kazu-yamamoto/crypton-certificate/pull/35)+* An ML-DSA private key keeps the form it was written in+ [#35](https://github.com/kazu-yamamoto/crypton-certificate/pull/35)+ ## 1.9.2 * Stop printing EC private keys
Data/X509.hs view
@@ -18,6 +18,13 @@ SerializedPoint (..), PrivKey (..), PrivKeyEC (..),+ PrivKeyMLDSA,+ MLDSAKeyForm (..),+ privkeyMLDSAFromSeed,+ privkeyMLDSAFromKey,+ privkeyMLDSA_key,+ privkeyMLDSA_seed,+ privkeyMLDSA_form, pubkeyToAlg, privkeyToAlg, module Data.X509.AlgorithmIdentifier,
Data/X509/AlgorithmIdentifier.hs view
@@ -42,6 +42,12 @@ PubKeyALG_Ed25519 | -- | EdDSA 448 signature algorithm PubKeyALG_Ed448+ | -- | ML-DSA-44 signature algorithm (RFC 9881)+ PubKeyALG_MLDSA44+ | -- | ML-DSA-65 signature algorithm (RFC 9881)+ PubKeyALG_MLDSA65+ | -- | ML-DSA-87 signature algorithm (RFC 9881)+ PubKeyALG_MLDSA87 | -- | Diffie Hellman Public Key algorithm PubKeyALG_DH | -- | Unknown Public Key algorithm@@ -66,6 +72,9 @@ getObjectID PubKeyALG_X448 = [1, 3, 101, 111] getObjectID PubKeyALG_Ed25519 = [1, 3, 101, 112] getObjectID PubKeyALG_Ed448 = [1, 3, 101, 113]+ getObjectID PubKeyALG_MLDSA44 = [2, 16, 840, 1, 101, 3, 4, 3, 17]+ getObjectID PubKeyALG_MLDSA65 = [2, 16, 840, 1, 101, 3, 4, 3, 18]+ getObjectID PubKeyALG_MLDSA87 = [2, 16, 840, 1, 101, 3, 4, 3, 19] getObjectID PubKeyALG_DH = [1, 2, 840, 10046, 2, 1] getObjectID (PubKeyALG_Unknown oid) = oid @@ -92,6 +101,18 @@ , ([2, 16, 840, 1, 101, 3, 4, 3, 2], SignatureALG HashSHA256 PubKeyALG_DSA) , ([1, 3, 101, 112], SignatureALG_IntrinsicHash PubKeyALG_Ed25519) , ([1, 3, 101, 113], SignatureALG_IntrinsicHash PubKeyALG_Ed448)+ ,+ ( [2, 16, 840, 1, 101, 3, 4, 3, 17]+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA44+ )+ ,+ ( [2, 16, 840, 1, 101, 3, 4, 3, 18]+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA65+ )+ ,+ ( [2, 16, 840, 1, 101, 3, 4, 3, 19]+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA87+ ) ] oidSig :: OID -> SignatureALG@@ -115,7 +136,7 @@ fromASN1 (Start Sequence : OID oid : Null : End Sequence : xs) = case oidSig oid of SignatureALG_IntrinsicHash _ ->- Left "fromASN1: X509.SignatureALG: EdDSA requires absent parameter"+ Left "fromASN1: X509.SignatureALG: EdDSA and ML-DSA require absent parameter" signatureAlg -> Right (signatureAlg, xs) fromASN1 (Start Sequence : OID oid : End Sequence : xs) = Right (oidSig oid, xs)
Data/X509/PrivateKey.hs view
@@ -9,12 +9,20 @@ module Data.X509.PrivateKey ( PrivKey (..), PrivKeyEC (..),+ PrivKeyMLDSA,+ MLDSAKeyForm (..),+ privkeyMLDSAFromSeed,+ privkeyMLDSAFromKey,+ privkeyMLDSA_key,+ privkeyMLDSA_seed,+ privkeyMLDSA_form, privkeyToAlg, ) where import Data.Maybe (fromMaybe)+import Data.Proxy (Proxy (..)) -import Data.ByteArray (ByteArrayAccess, convert)+import Data.ByteArray (ByteArrayAccess, ScrubbedBytes, convert) import qualified Data.ByteString as B import Data.ASN1.BinaryEncoding@@ -27,7 +35,7 @@ import Data.X509.OID (curvesOIDTable, lookupByOID, lookupOID) import Data.X509.PublicKey (SerializedPoint (..)) -import Crypto.Debug (DebugShow (..))+import Crypto.Debug (DebugShow (..), debugShowBytes) import Crypto.Error (CryptoFailable (..)) import Crypto.Number.Serialize (i2osp, os2ip) import qualified Crypto.PubKey.Curve25519 as X25519@@ -36,6 +44,7 @@ import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448+import qualified Crypto.PubKey.MLDSA as MLDSA import qualified Crypto.PubKey.RSA as RSA -- | Elliptic Curve Private Key@@ -98,6 +107,112 @@ . priv . showChar '}' +-- | Which of the three forms of RFC 9881 Section 6 a private key was read+-- as, and is written back out as.+data MLDSAKeyForm+ = -- | The seed alone, @seed@, which Section 6 recommends.+ MLDSAKeySeed+ | -- | The expanded key alone, @expandedKey@.+ MLDSAKeyExpanded+ | -- | Both together, @both@.+ MLDSAKeyBoth+ deriving (Show, Eq)++-- | An ML-DSA private key.+--+-- RFC 9881 Section 6 writes one as the seed it was derived from, as the+-- expanded key, or as both, and which of the three it was is part of the+-- key here. A key read from a file is therefore written back out as the+-- same thing it came in as, rather than as whichever form this module+-- happens to prefer.+--+-- The expanded key is there whatever the form: a seed is expanded as it is+-- read, so 'privkeyMLDSA_key' always answers. The seed is not, since a+-- key written as @expandedKey@ does not carry one; 'privkeyMLDSA_seed' is+-- a 'Maybe' for that reason, and a key whose seed was never on the wire+-- cannot be given one back -- @crypton@'s+-- @Crypto.PubKey.MLDSA.generateKeyPairAndSeed@ is where a seed that is to+-- be kept has to be caught.+--+-- The constructors are not exported: a seed and an expanded key that do+-- not belong together would be a key that signs with one and claims the+-- other, so the only ways in are 'privkeyMLDSAFromSeed', which expands the+-- seed itself, and 'privkeyMLDSAFromKey', which has no seed to disagree+-- with.+--+-- Two keys are equal when they hold the same thing /in the same form/: the+-- same key as a seed and as an expanded key are two different files, and+-- the encoding round trip says so.+data PrivKeyMLDSA p+ = PrivKeyMLDSA_Seed ScrubbedBytes (MLDSA.SigningKey p)+ | PrivKeyMLDSA_Expanded (MLDSA.SigningKey p)+ | PrivKeyMLDSA_Both ScrubbedBytes (MLDSA.SigningKey p)+ deriving (Eq)++-- | What the two instances below share, so that a form added to+-- 'PrivKeyMLDSA' cannot reach one of them and not the other. The+-- arguments render the seed and the key.+showsPrivKeyMLDSA+ :: (ScrubbedBytes -> String)+ -> (MLDSA.SigningKey p -> String)+ -> PrivKeyMLDSA p+ -> String+showsPrivKeyMLDSA seed key k = case k of+ PrivKeyMLDSA_Seed s sk -> con "PrivKeyMLDSA_Seed" [seed s, key sk]+ PrivKeyMLDSA_Expanded sk -> con "PrivKeyMLDSA_Expanded" [key sk]+ PrivKeyMLDSA_Both s sk -> con "PrivKeyMLDSA_Both" [seed s, key sk]+ where+ con name as = unwords (name : map (\a -> "(" ++ a ++ ")") as)++-- | The form is shown; neither the seed nor the key is. Use+-- 'Crypto.Debug.debugShow' to see them.+instance Show (PrivKeyMLDSA p) where+ show = showsPrivKeyMLDSA (const "<secret>") show++instance DebugShow (PrivKeyMLDSA p) where+ debugShow = showsPrivKeyMLDSA (debugShowBytes "seed") debugShow++-- | Build a key from its seed, to be written back out in the given form.+--+-- The expanded key is derived here, so it cannot fail to be the one the+-- seed belongs to. Passing 'MLDSAKeyExpanded' throws the seed away, which+-- is the way to turn a seed into a key that will be written without one.+privkeyMLDSAFromSeed+ :: (MLDSA.MLDSA p, ByteArrayAccess ba)+ => proxy p -> MLDSAKeyForm -> ba -> CryptoFailable (PrivKeyMLDSA p)+privkeyMLDSAFromSeed p form bs = case MLDSA.keyPairFromSeed p bs of+ CryptoFailed e -> CryptoFailed e+ CryptoPassed (_, sk) ->+ CryptoPassed $ case form of+ MLDSAKeySeed -> PrivKeyMLDSA_Seed seed sk+ MLDSAKeyExpanded -> PrivKeyMLDSA_Expanded sk+ MLDSAKeyBoth -> PrivKeyMLDSA_Both seed sk+ where+ seed = convert bs :: ScrubbedBytes++-- | Build a key from the expanded key alone, which is what a key that was+-- generated without keeping its seed has to be.+privkeyMLDSAFromKey :: MLDSA.SigningKey p -> PrivKeyMLDSA p+privkeyMLDSAFromKey = PrivKeyMLDSA_Expanded++-- | The expanded key, whatever form the key is in.+privkeyMLDSA_key :: PrivKeyMLDSA p -> MLDSA.SigningKey p+privkeyMLDSA_key (PrivKeyMLDSA_Seed _ sk) = sk+privkeyMLDSA_key (PrivKeyMLDSA_Expanded sk) = sk+privkeyMLDSA_key (PrivKeyMLDSA_Both _ sk) = sk++-- | The seed, for a key that has one.+privkeyMLDSA_seed :: PrivKeyMLDSA p -> Maybe ScrubbedBytes+privkeyMLDSA_seed (PrivKeyMLDSA_Seed s _) = Just s+privkeyMLDSA_seed (PrivKeyMLDSA_Expanded _) = Nothing+privkeyMLDSA_seed (PrivKeyMLDSA_Both s _) = Just s++-- | The form the key will be written out in.+privkeyMLDSA_form :: PrivKeyMLDSA p -> MLDSAKeyForm+privkeyMLDSA_form (PrivKeyMLDSA_Seed _ _) = MLDSAKeySeed+privkeyMLDSA_form (PrivKeyMLDSA_Expanded _) = MLDSAKeyExpanded+privkeyMLDSA_form (PrivKeyMLDSA_Both _ _) = MLDSAKeyBoth+ -- | Private key types known and used in X.509 data PrivKey = -- | RSA private key@@ -114,6 +229,12 @@ PrivKeyEd25519 Ed25519.SecretKey | -- | Ed448 private key PrivKeyEd448 Ed448.SecretKey+ | -- | ML-DSA-44 private key+ PrivKeyMLDSA44 (PrivKeyMLDSA MLDSA.MLDSA44)+ | -- | ML-DSA-65 private key+ PrivKeyMLDSA65 (PrivKeyMLDSA MLDSA.MLDSA65)+ | -- | ML-DSA-87 private key+ PrivKeyMLDSA87 (PrivKeyMLDSA MLDSA.MLDSA87) deriving (Show, Eq) -- | Rendering a private key with the key material in it, for the times when@@ -128,6 +249,9 @@ PrivKeyX448 p -> con "PrivKeyX448" $ debugShow p PrivKeyEd25519 p -> con "PrivKeyEd25519" $ debugShow p PrivKeyEd448 p -> con "PrivKeyEd448" $ debugShow p+ PrivKeyMLDSA44 p -> con "PrivKeyMLDSA44" $ debugShow p+ PrivKeyMLDSA65 p -> con "PrivKeyMLDSA65" $ debugShow p+ PrivKeyMLDSA87 p -> con "PrivKeyMLDSA87" $ debugShow p where con name body = name ++ " (" ++ body ++ ")" @@ -300,7 +424,12 @@ CryptoFailed e -> err ("invalid secret key: " ++ show e) Right _ -> err "unexpected inner format" Left e -> err (show e)- Nothing -> Left ("newcurveFromASN1: unexpected OID " ++ show oid)+ Nothing -> case getMLDSA oid of+ Just (name, parse) ->+ case decodeASN1' BER bs of+ Right inner -> (\k -> (k, zs)) <$> parse inner+ Left e -> Left (name ++ ".SigningKey.fromASN1: " ++ show e)+ Nothing -> Left ("newcurveFromASN1: unexpected OID " ++ show oid) _ -> Left "newcurveFromASN1: unexpected end format" | otherwise = Left ("newcurveFromASN1: unexpected version: " ++ show v) where@@ -309,10 +438,56 @@ getP [1, 3, 101, 112] = Just ("Ed25519", fmap PrivKeyEd25519 . Ed25519.secretKey) getP [1, 3, 101, 113] = Just ("Ed448", fmap PrivKeyEd448 . Ed448.secretKey) getP _ = Nothing+ getMLDSA [2, 16, 840, 1, 101, 3, 4, 3, 17] =+ Just+ ( "ML-DSA-44"+ , mldsaFromASN1 (Proxy :: Proxy MLDSA.MLDSA44) PrivKeyMLDSA44 "ML-DSA-44"+ )+ getMLDSA [2, 16, 840, 1, 101, 3, 4, 3, 18] =+ Just+ ( "ML-DSA-65"+ , mldsaFromASN1 (Proxy :: Proxy MLDSA.MLDSA65) PrivKeyMLDSA65 "ML-DSA-65"+ )+ getMLDSA [2, 16, 840, 1, 101, 3, 4, 3, 19] =+ Just+ ( "ML-DSA-87"+ , mldsaFromASN1 (Proxy :: Proxy MLDSA.MLDSA87) PrivKeyMLDSA87 "ML-DSA-87"+ )+ getMLDSA _ = Nothing isValidVersion version = version >= 0 && version <= 1 newcurveFromASN1 _ = Left "newcurveFromASN1: unexpected format" +-- | The private key of RFC 9881 Section 6: a CHOICE of the seed, tagged+-- [0], the expanded key, or both. A seed is expanded into the key; with+-- both, the expanded key must be what the seed expands to. Which of the+-- three it was is kept, so that 'mldsaToASN1' writes back what was read.+mldsaFromASN1+ :: MLDSA.MLDSA p+ => proxy p+ -> (PrivKeyMLDSA p -> PrivKey)+ -> String+ -> [ASN1]+ -> Either String PrivKey+mldsaFromASN1 p con name inner = case inner of+ [Other Context 0 seed] -> con <$> fromSeed MLDSAKeySeed seed+ [OctetString expanded] -> con . privkeyMLDSAFromKey <$> fromExpanded expanded+ [Start Sequence, OctetString seed, OctetString expanded, End Sequence] -> do+ k <- fromSeed MLDSAKeyBoth seed+ sk <- fromExpanded expanded+ if privkeyMLDSA_key k == sk+ then Right (con k)+ else err "seed and expandedKey do not match"+ _ -> err "unexpected inner format"+ where+ err s = Left (name ++ ".SigningKey.fromASN1: " ++ s)+ fromSeed form seed = case privkeyMLDSAFromSeed p form seed of+ CryptoPassed k -> Right k+ CryptoFailed e -> err ("invalid seed: " ++ show e)+ fromExpanded expanded = case MLDSA.signingKey expanded of+ CryptoPassed sk -> Right sk+ CryptoFailed e -> err ("invalid expandedKey: " ++ show e)+ containerWithTag :: ASN1Tag -> [ASN1] -> ([ASN1], [ASN1]) containerWithTag etag (Start (Container _ atag) : xs) | etag == atag = getConstructedEnd 0 xs@@ -331,6 +506,9 @@ privkeyToASN1 (PrivKeyX448 k) = newcurveToASN1 [1, 3, 101, 111] k privkeyToASN1 (PrivKeyEd25519 k) = newcurveToASN1 [1, 3, 101, 112] k privkeyToASN1 (PrivKeyEd448 k) = newcurveToASN1 [1, 3, 101, 113] k+privkeyToASN1 (PrivKeyMLDSA44 k) = mldsaToASN1 (getObjectID PubKeyALG_MLDSA44) k+privkeyToASN1 (PrivKeyMLDSA65 k) = mldsaToASN1 (getObjectID PubKeyALG_MLDSA65) k+privkeyToASN1 (PrivKeyMLDSA87 k) = mldsaToASN1 (getObjectID PubKeyALG_MLDSA87) k rsaToASN1 :: RSA.PrivateKey -> ASN1S rsaToASN1 key =@@ -426,6 +604,31 @@ , End Sequence ] +-- | The inverse of 'mldsaFromASN1': the form the key is in is the form it+-- is written in, so reading a key and writing it again gives back the+-- bytes it came from.+mldsaToASN1 :: OID -> PrivKeyMLDSA p -> ASN1S+mldsaToASN1 oid k =+ (++)+ [ Start Sequence+ , IntVal 0+ , Start Sequence+ , OID oid+ , End Sequence+ , OctetString (encodeASN1' DER inner)+ , End Sequence+ ]+ where+ inner = case k of+ PrivKeyMLDSA_Seed s _ -> [Other Context 0 (convert s)]+ PrivKeyMLDSA_Expanded sk -> [OctetString (convert sk)]+ PrivKeyMLDSA_Both s sk ->+ [ Start Sequence+ , OctetString (convert s)+ , OctetString (convert sk)+ , End Sequence+ ]+ mapLeft :: (a0 -> a1) -> Either a0 b -> Either a1 b mapLeft f (Left x) = Left (f x) mapLeft _ (Right x) = Right x@@ -439,3 +642,6 @@ privkeyToAlg (PrivKeyX448 _) = PubKeyALG_X448 privkeyToAlg (PrivKeyEd25519 _) = PubKeyALG_Ed25519 privkeyToAlg (PrivKeyEd448 _) = PubKeyALG_Ed448+privkeyToAlg (PrivKeyMLDSA44 _) = PubKeyALG_MLDSA44+privkeyToAlg (PrivKeyMLDSA65 _) = PubKeyALG_MLDSA65+privkeyToAlg (PrivKeyMLDSA87 _) = PubKeyALG_MLDSA87
Data/X509/PublicKey.hs view
@@ -35,6 +35,7 @@ import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448+import qualified Crypto.PubKey.MLDSA as MLDSA import qualified Crypto.PubKey.RSA.Types as RSA import Data.Word @@ -82,6 +83,12 @@ PubKeyEd25519 Ed25519.PublicKey | -- | Ed448 public key PubKeyEd448 Ed448.PublicKey+ | -- | ML-DSA-44 public key+ PubKeyMLDSA44 (MLDSA.VerificationKey MLDSA.MLDSA44)+ | -- | ML-DSA-65 public key+ PubKeyMLDSA65 (MLDSA.VerificationKey MLDSA.MLDSA65)+ | -- | ML-DSA-87 public key+ PubKeyMLDSA87 (MLDSA.VerificationKey MLDSA.MLDSA87) | -- | unrecognized format PubKeyUnknown OID B.ByteString deriving (Show, Eq)@@ -182,6 +189,20 @@ case xs of End Sequence : BitString bits : End Sequence : xs2 -> decodeCF "Ed448" PubKeyEd448 bits xs2 Ed448.publicKey _ -> Left ("fromASN1: X509.PubKey: unknown Ed448 format: " ++ show xs)+ -- RFC 9881 Section 4: the parameters are absent and the BIT STRING+ -- is the raw public key.+ | pkalg == getObjectID PubKeyALG_MLDSA44 =+ case xs of+ End Sequence : BitString bits : End Sequence : xs2 -> decodeCF "ML-DSA-44" PubKeyMLDSA44 bits xs2 MLDSA.verificationKey+ _ -> Left ("fromASN1: X509.PubKey: unknown ML-DSA-44 format: " ++ show xs)+ | pkalg == getObjectID PubKeyALG_MLDSA65 =+ case xs of+ End Sequence : BitString bits : End Sequence : xs2 -> decodeCF "ML-DSA-65" PubKeyMLDSA65 bits xs2 MLDSA.verificationKey+ _ -> Left ("fromASN1: X509.PubKey: unknown ML-DSA-65 format: " ++ show xs)+ | pkalg == getObjectID PubKeyALG_MLDSA87 =+ case xs of+ End Sequence : BitString bits : End Sequence : xs2 -> decodeCF "ML-DSA-87" PubKeyMLDSA87 bits xs2 MLDSA.verificationKey+ _ -> Left ("fromASN1: X509.PubKey: unknown ML-DSA-87 format: " ++ show xs) | otherwise = Left $ "fromASN1: unknown public key OID: " ++ show pkalg where decodeASN1Err format bits xs2 f =@@ -221,6 +242,9 @@ pubkeyToAlg (PubKeyX448 _) = PubKeyALG_X448 pubkeyToAlg (PubKeyEd25519 _) = PubKeyALG_Ed25519 pubkeyToAlg (PubKeyEd448 _) = PubKeyALG_Ed448+pubkeyToAlg (PubKeyMLDSA44 _) = PubKeyALG_MLDSA44+pubkeyToAlg (PubKeyMLDSA65 _) = PubKeyALG_MLDSA65+pubkeyToAlg (PubKeyMLDSA87 _) = PubKeyALG_MLDSA87 pubkeyToAlg (PubKeyUnknown oid _) = PubKeyALG_Unknown oid encodePK :: PubKey -> [ASN1]@@ -258,6 +282,12 @@ encodeInner (PubKeyEd25519 pubkey) = asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0] encodeInner (PubKeyEd448 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyMLDSA44 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyMLDSA65 pubkey) =+ asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0]+ encodeInner (PubKeyMLDSA87 pubkey) = asn1Container Sequence [pkalg] ++ [BitString $ toBitArray (convert pubkey) 0] encodeInner (PubKeyDH _) = error "encodeInner: unimplemented public key DH" encodeInner (PubKeyUnknown _ l) =
+ Tests/MLDSAKeys.hs view
@@ -0,0 +1,365 @@+-- | ML-DSA private keys in PKCS#8, as OpenSSL 3.6.4 writes them.+--+-- Not generated here: the point of these is that another implementation+-- made them. A round trip through this library's own encoder and decoder+-- says only that the two halves agree; these say that what comes out is+-- what the rest of the world reads.+--+-- openssl genpkey -algorithm ML-DSA-44 | openssl pkey -outform DER+--+-- OpenSSL writes the @both@ form of RFC 9881 section 6: the seed and the+-- expanded key in a SEQUENCE.+module MLDSAKeys (+ opensslMLDSA44,+ opensslMLDSA65,+ opensslMLDSA87,+) where++import qualified Data.ByteString as BS++import Data.ByteArray.Encoding (Base (Base16), convertFromBase)++hex :: String -> BS.ByteString+hex s = case convertFromBase Base16 (BS.pack (map (fromIntegral . fromEnum) s)) of+ Left e -> error e+ Right b -> b++-- | 2626 bytes of DER.+opensslMLDSA44 :: BS.ByteString+opensslMLDSA44 = hex $ concat+ [ "30820a3e020100300b060960864801650304031104820a2a30820a260420151dff249cb3"+ , "4b87169de5d99e2b19666f2a9efbecab731295509007c22ddcc604820a003053ed09fbcf"+ , "1d28675cc66c20e7bb04cb7e077b11f285aec9ce9ae530526ab0299ad6d0887cff9a40ff"+ , "d31ea92f2b7ef42338fe02d3159b236d1252012e65a60936c589b63435a8f2f65b5b6f16"+ , "058f72851d5e63f064187083aafbec42927db7b13528591a2336c476736e0c0a0c6dacb7"+ , "6c70949268a84b9530bb2bb2689608a72c48982044c01014a721d224644b820914876cd9"+ , "40090386418440221ba26ccc42818816608230420ba684d9b40921236959182d084852d8"+ , "380c04367102254e82b21021c78c4b442e123071822621184720c8226298120adb207118"+ , "248ae40084e2b4315ac220e0404089900023119201c628123351db10848bc88808382c0c"+ , "498c81360441380cc32012180460c2c844d0384144102909448ad2382592442a1929721a"+ , "2388d1328d51a68c21460e1811510ca3459a9608d0c824a4c87003b9840a284462b84d08"+ , "99501c803020b890c1b0654a20012403441146665430868b48910a448d4ca80801994d9a"+ , "847161288664248999427009c825609441a4948042200401046c2202311ca184a0002dc4"+ , "c24c51088898a6699aa2298b106d44448e1129721b000a93b229da1249cc164022182d91"+ , "26442014004c4866002461c1b0059a140c02238a1b410e0a3806cb9251524840cc80290b"+ , "04224218686440828c964852445209906162a27181066a5ab48c20984d893805cbc84881"+ , "8090d4a2915006651326649aa608e2c8059128041a27729c228853b86541382e89b23001"+ , "828d1b820022115159a41024436498a0508a06648c020093c6411b060e932021d0004021"+ , "21801c364609292198c2659c3449d8126a0811452246218c864ca0260c9c023199880c22"+ , "2149e39809d2342501a570d4a83150c0601c929082a60d02c629d0400a44068404b9611a"+ , "866003396d0a186463c0680820204b260a114992a30049099089044752a3186610298d8a"+ , "446682320850b2904ac289d9122d44462212246193a62804a28854a80c00b74c51044403"+ , "801012458e50162cd3285002c4051c388ca04412903070a1c861cc349080c42c43324224"+ , "45269c96696288688c268299b26c4c823000b2809c24051ab889530685028401d3c0491a"+ , "80680003861b252c523669d3c62019042453222983866d9102826496910a4321da462493"+ , "404ad23689233031a1104a01328108396880288d608271440404d81865d2a0818c44095c"+ , "a08d43188401c971101205c8c0045b1085dc2050cac410a320319a35cb74122d502593d4"+ , "edf07f9236080bd29e26691f48721d4724b5a1b13a14aae5f8a1d1e0504419ac39dea10a"+ , "5ad354bba5a81c391739a3505d5e92d3b35ad7a74c64b0c46229a61be43cfb9e14aa97ab"+ , "99295cf2212be68590e7e53659f2cb6a5718a0859acd609fd94845ddee0927c75547d1d4"+ , "ab9864f60266df48f9afae8ee8275f98c8273f6be0249e6f0c069da46d215596cbc1c5d2"+ , "ce17c67287e7696e45a6d9fea29ef1a7206855d87841a929837277f7aa0ef8118e52659e"+ , "a033c42ef06cbc913fb02ceeea3a1bc9d5c09e89d8dc49d85044a01e8803fe3a540b02f3"+ , "ec78fcf2611c103a8f9b5bd9db91b9a69a12b96402cc6866b16fd22923ce78e8c75754a3"+ , "6c04aa80b21f0a90c28ee2e6e567be4a278427619965e289dde9643fe4b483fa70367efb"+ , "9d52a517a2b1798dab0a4e89198cc3fd30afcd85ee423523f06cb23c7959c0d120256561"+ , "88c4a818e7fec6e7195cf3a5ad016f93d8a62cd6b557cc6400ed2e81b43613f0da80934d"+ , "d9be78bfdacd6fe50819498a076806a326fb3825dfff67a8dbf2da4cd81b88965d8b170e"+ , "87e56a796c028e6511ca9a3db4eefadc1a0d57d75e1d75ebefeffe9ac4d0ec5a60cad8ae"+ , "27e6f39afda951b2de41e4042845584e753654a619f1c9df5c7996ddde570ff42522538a"+ , "5e323936f2b3bced1eadffc5bcef84d16b729a8a9442ac7c3844b66dbc75deb4904bc207"+ , "948f162bbfbea6f8b7788f90cd66b61120b8c29b317cead830d018d6990b9bcfa6c907bd"+ , "8ea63176fa89bf0c4af60f28b4604bff034a36f70be8ed8d004ef520f292cc8e9202c0fb"+ , "28df92c04296547f3ab012068fd24cce21307201ade6b7b7071937471be57ef02173e7c0"+ , "fddcc302c210f3ba2defd3631b174a590371e81dc4a0c8a7c79ce59840d4fb1b2620ac11"+ , "c831b43da3525db213adbe3b35295aef04bed771db85cee59ce7a8ede9bf1782ed0b074f"+ , "c3db5bcc5b6d101e250df37913d3b76babc9ff7852fe9f47427d04ee0c19ed869297428c"+ , "84e0549e6fdbf16733fa32097dfd97ff5165c9dd34e6db794de6d9680e995fef0c22a3cc"+ , "28cf4fdb3b080269d7f1aa65516042186ad420a75841d7c762f0e4754113aa518d185d6a"+ , "934704b285d78fec4d34246c338e062687cc0f1f9311e948428ee7885492fd0c08da6471"+ , "d3a2afd3e7388989ceb0e91f905d1e0f6e2f67c2be69dbb6df0f421ca8403f69946e88fe"+ , "b695b0b1b6cd93a25a8316527505dbad480a59bce5b68d261851311ad410efd9ccb10ee5"+ , "0f8448d1493242050e016912f80789c15ea5bbf382600203360deec68ac3ccdd861c54b2"+ , "8555a398ef400792e6410f37aa74a502ecee6130da2f8b2a97005f76386978c1300e4e50"+ , "49a722a0af7de32b010a73a6514a614dc80901fa868ab749ed109ee5d10a3807e2b3b4d8"+ , "a5bbaa4b6d3f88104798135ecf77ddb314f7bfdc0a1eb461bc3a1890dea5e62ce4a1cdb0"+ , "411b585178bb6fedd29a56b1cabdc93d09e008199a6558742bf8d66899ea6f10aab34bb2"+ , "f6b08dddbba4169f6f61a7c5368addb74b6c4b8dbc9882abddbdcc403b749f5edd4a3b70"+ , "561a44b34c3f85ef84c845751e983025e50d984eaf38a0d470d73436a537ce1f07666751"+ , "8fcd15547d98e79f27c6241da5fdba9946a3916e2037f76ce82535a17a1618a8894e63a5"+ , "1fb2258a2e5e7794ad9e839cc03c3a2113204b514ac55e4e9e330b2295c65504eb16714d"+ , "af385fa09b3dc92a2594c75fada27a17cc09f6d5581b08a03136d1ddc4cd2bfe1f7c384a"+ , "9b01f26698bc0e3914448a6ce6f50ee09f618b6ee4b29694919cf1c1304c35c9fc429964"+ , "31f1c5e1965383bdd9d6e85a1df1f6a73065a1cc4dc00ae7e69bff0683d844c5bfdcdc08"+ , "05dcd36ffbcdd7bb94fe4194c715197401c97771cccf078d591cea169b25cb60e7148678"+ , "e4efb857bb101a78abb396a73fb8556fba6b265f7dc4c793cf58048a005be22917e61bf8"+ , "edb95cf1005c3a9b6c797f49f25dc13c869399091bcaa0e699cb8258e4b2c843da6a1048"+ , "48e4471eb1e8f08c7482c7531b30174cb433cac5050399fa607bc6244400cf0744caee56"+ , "31ac9a5ecf67abf77c6bfd438fb76f3d18d859b7e209c88e1e5fdeb77bfe999547a207c9"+ , "05e8889fa622043f2b8da2e052e5a160bb006bf40f69761820435c59585d49101607b046"+ , "291f407f795e7d71f5a43eafc36b319a03162a155a40799a61225efe3990aefa4779283d"+ , "ae2b66daa98b28ce95d0a0afcab2e42301f46eec233439e80391941904881e716c4f2c79"+ , "23711d2927e181193a6de8d4329ad358817ddb2463148c3ab985c19808aed1909cce"+ ]++-- | 4098 bytes of DER.+opensslMLDSA65 :: BS.ByteString+opensslMLDSA65 = hex $ concat+ [ "30820ffe020100300b060960864801650304031204820fea30820fe6042062c8740c6f5b"+ , "e0c726ecb2e8c6f1b22faf29ee7a562de1a95a6ace4993812c8e04820fc01a31edba22f1"+ , "50ee1738e8bf87429343d274b5bd69e60feda1dae7b881afd0354992fd2ba1a609acf0b4"+ , "4a0413a86ac8dca104cc460d7cd80db0f38c76ad816f8c692ec5b5c821aa21ded5f1e7b1"+ , "7a8ad3534d2850d1d3f08562ab2b8b00a18f8e796ecc8f9f6d44d19099aa49410fb23e37"+ , "981740d02d957bdd8dd19aa9463e52208184643106838414406247510502717570630322"+ , "333340348846565153734381027643367848711037342000305418167076011152763614"+ , "360036114818757772181646230261447105735122373755001016732454770100313157"+ , "017817783853214666474073350114481534144318477611815667075522034524034561"+ , "405058475248684860680411802753833017174355888413426888852426871532668712"+ , "111433846561762118875606253783552072354337335766843377042210322266862033"+ , "318347136247651233866617100468638340638002367511352001360712375002063667"+ , "513007528247530118344227327731070538433300147277812580606457801432336627"+ , "354041166152518730060160020748471117175588272420573372562508520727654411"+ , "207507452018363433575624541814133431773421663310458463112367254078641742"+ , "601601041567835052631717551465400580807676334023431865516435865273080275"+ , "105305862184715168400303265533644671604143424001288640550704174028060502"+ , "655158646531448117777064104154583325006466524860733405334611440438553060"+ , "561536627177465858121558620423860053888746373827387753536775632241028626"+ , "833887013814141312321545831375434468161657485845108015474443283753833717"+ , "753678738561138255737381602451863450022408252128406317347455344310081565"+ , "526811015763376527042614842148148805104082500020533740381561618131672237"+ , "806557607168670118153081638474686850760447381012211060418005871108243667"+ , "672823514026365327021815127654068432345354144202635848086606318504201076"+ , "347262054208141460281457238134715587066020113468581226120277165763646706"+ , "335268040647817457330735125026055883341578536181455620235405883043100185"+ , "836410080502321606151075828705654646467866335740352251484250636375724436"+ , "700476701341487842804788605677123552714662132871600465871663678172122308"+ , "117801578082508863160152568880765846330011510607645371033231548620270651"+ , "217822156271604815603740340311422686316862400374766762631221508365438245"+ , "322565585663385524478706630016782647387350068870323363054176624783638712"+ , "504004872703415740422242376674302301424417033455127724488012872205680268"+ , "074052636611562483800502260316637482200001108624572715700743752306022188"+ , "440684881514010455750377217655046186824282620128031056600471876815022773"+ , "465323471601830471086315511081723030757186532733414771668757146585873778"+ , "643523825637838431777263531448504444788253215812408468467773328233352487"+ , "470808848157886003582420058711663641226827647106518037834311220647336226"+ , "172235777106242832861510073285581843682263331052140236102155032852815016"+ , "601700412573263188186253846627461715416718320841166781368781674771073677"+ , "453304358813321407060576436306848150507710618286640354123320525147476718"+ , "177333846174371781255824717212823625567200001848525323737344106125680584"+ , "181846483106031726074672420026727441500182257456024485874381257168246807"+ , "585557261283143712318526341803073887550140836151518677231230288877371567"+ , "642718063771662662581227147768585853432257306476775841358601510038120126"+ , "407387663325055740436215754707688310d0d58aa8cc178e2462327d7adbbc0a8bd863"+ , "62d4c35db9d95f18842c38d2f408451e1f4f971623d954df6e0fa9a4595de7984746f11c"+ , "8b09de3bd6d2cc60788f319552e0e0364b1d5a3cce106c495bf349bcdb51000dec34590b"+ , "f11bcc1dcda4f2bf50efe394d62f846822fa3a96126974be047e456c7bb0a1124b448332"+ , "fcbd5865a1ef81be8838075bc129eca0c7dedc9a2736da6391124d1da59014391b35c625"+ , "74c66b96235ec17ad7ff4f7974d20d10a2ad9d7613c91e7785ef955f8d289baed537046b"+ , "90a18fd35058f6efbdf996625824f0f2b6da5449a64ec8c17155a152c5736f5185be3bf2"+ , "ece2ebb06947a0f39a12bd704b097b04291ae4af4ebdbe087a6a17cb1520c869f62ab927"+ , "99a6d2d798ef01978f6d00eeee529b28992d54aa47a64c99feca55ffcd52eb7c84a7fc19"+ , "3899a23b8a639d5f682e0bbf16cb12f609506866565fec091ee97001335a4252065447ec"+ , "81e734d2f911d0ac496fe94b40b7beb5b52d6f5949f5ade53b3aaa8d9ee35e7c7b6a5f80"+ , "f010b69e1f1d781c0f7dd730106b2dc17c9f9cfb64003acfca0013968d98d865f5a1d253"+ , "fbf78d7fc30f7bde65212f4aabfc3e976178ed6f94d12b084b3aa2031e4aeeabc2fb691e"+ , "9dbe40c2d7a32a92d86dab00c39c8bbf94b93f20c68ff711250ce43ad169c228133b0958"+ , "97c62cbe2706dad8cf23f2ed1ddca4200d6ce9fcb7c48ae6dd080316cfbe87d36a3a9a80"+ , "04caa374b0f08e9e0faadf53cd0130c0116aefa222ab2d2a7c8c7d5ab3e17e8a7d0a98dc"+ , "818331657ffb452e65e110b63ba008a6c1250a1198e11855078c1c76c3777dbd3da08160"+ , "78977b9873b9537da023466a3ccd47520bc3254224b583932259bfcf6df1cf9cae1bbde9"+ , "814c4bc05da3385d18af20e91dacebc9827cfb5c342205e49dbd3110af4c5ad0c9b3c435"+ , "945e9152929bb094444101dfc95c9847bec5721b0a629b2f1ef646c6eba796d4409fa889"+ , "240e127e9b530070dc78e504160aa8a7e01483c48d54925ae36ee91f6c1647c0c292522b"+ , "931ecc6544c1e1ef933205cc4665d7c43a5e537df9de1ce34b9eb985ab9abe607228a748"+ , "0f96f7f2c233feb9d3039980cf8c9aec54f92ec8211a9a2d7ad42eaa9c0da5e7d032e63d"+ , "d1c85cbc732c90f07e1411086c95f401a68da033db92a1144c09ada62e6022443b0ee70b"+ , "8ca04c4fe663c304449fcf4236b9cac8461d5ae3e3ccc409afc5f0aa4d02abe980995545"+ , "1198f88d143488f62d5ec2f5301f706a19efebda7878a6e1afa7daafcac0d45fb8451ea5"+ , "6c681937f0ccec0c1b3a437e12bdcbcb62a17ad1d99f499b8b9c1bb35e85dfb88bdccd91"+ , "f71e1bfba790a5200c166aedc29b7fed78b1e4a0691229f2e8add8377e369005867b1e5d"+ , "c43050fe546c65751e79ad032323e039e1ac67acc081c1b157771edfad6e275f105460f3"+ , "7da53ac4ea4941490527233925b7f860eebeaf89ef096a4a00979c61e6dc8bbcee482ad6"+ , "822041e8625a69fd6616981240cc2a01ca33bd67a674e273994632a43f141b89a89a24e4"+ , "fa94780b9b3fab34669f6f6acd264b4a0cb8f0f3f7260a784c79efcb9107d6d784ac4a67"+ , "a86f50da3c7cec7783914727dd0d06343d84f9760dd8c3de98eb3b6240277985b14e5baf"+ , "3ce83fb02d7bdd97fbd7aae97a6fd159c0c910f7004de43605dcec069c9e9dd9678b7bc6"+ , "2614217df4ba635ed1636149ac6c207bdb149a551d5b73037cb238f677a113316a857cea"+ , "6763fe1386e59568dd82970e7f006c0b312e49c31047e2af7b52c9964f94fd207fe7773a"+ , "68978dec08cf2cd350b9d1728c663725499e4f98504d8620762d175ac7a061552a65b088"+ , "fcf048b64d94f3e63bb1fb5daae5b8e6b4475fed3a7440406affcbbe1ad9100b50ec1fce"+ , "b5863a77ec8be20c17afa9fec9827d0cf108f945317c9b6aa295fd59ad9127d7455dd18d"+ , "5cae5bf6f821020255e7687f445e205ae71ecdb2511264284f04b6d5f3d30e26a608cfb0"+ , "a60623e1a66d3686344ce160092bf808c95ea6a9bef196a903a4d1482c354945fe88820e"+ , "f13501c270c02864a63134051184449ed9201d49184ff824c5185f82c49bda8cb1a2b051"+ , "163016814fd1bb5fdb2d936bc4f5c21e5ee3e8584179e43be5cde2f2b47c457be9980559"+ , "5bc3e9d8e4c9ce8e748e8cfa9f4ecacd228ddd7690084d0d893ab014bc72e70dad8264f5"+ , "8eb498caa0e3025f43fc71c02dd32afed753b5d8a46dd9c8b3978e8e4163423cfb0dbfec"+ , "a06b3666ab5743afc0d540604755bf716a1de0c6d32c7e28eda63e69053b9e54a4569ce5"+ , "58ed1049f3058efec60877a53b9f56ca3a217a95a3bf918f5d1a58fe2a890ff8f72f1d32"+ , "df30470cc667e504149b04207c13a16428e3f47b6ea1c6f889bd2363be544f91a326724b"+ , "fde2dd3984475c86a8dd5c7b45b5f76e9162959300790167bca61666085216404e140f4d"+ , "0c2787a85c6d2dfc018ab44e0ea0dc00a89eba64bf71a4e57a2266a96d7a39baebcb682b"+ , "c0361ff336ab7d0b440f5f9d320dd5f705e9316c3be45a3ff96f5ea87dc5ce397f3ae7c5"+ , "38188b253ac6df51906637a6ff5c26066f541eea6d63bdd7821451e1c4769216f5e45511"+ , "d99b949610d222135a8d3dfea12f0d704cdd4012882340db36c1e2085ed065b49fc998c6"+ , "bd4955282cc8c450fe8f5dac5fa4b0dd882a378b399b3097b8afab0ab1d2fe2433fda7f5"+ , "542707b50e49744832b3693b44377b8fbc9362367841e85e1ef9d2789617b302f935fc58"+ , "53fc5a6783bd307c2097f612b173d0b3b24fdf2b332ab9827ada091b8cb4243b23490438"+ , "84abf44ab780599d682484a898c89612dfa6e6e128626b23e32fc1c3bbe717cec0141bc7"+ , "379a3ebf1eb072f70e4aabbdc0a7635760cd74eb850c42bc2b9298794963b833c48ca544"+ , "683e512c5a734e713e10274b0ce5adbe15fad996643fa6c075db2fdac2cb4438027c6b5d"+ , "7eb4f2980c1513d92267f90a6ed8e287f6bde9e745712d2ac6de843f56223bb2f5bd35bc"+ , "c9fd83a782d437e0d6094af64255de70cc2240c7bbc57cb4c5ebff8bf288df4b28822306"+ , "02a1cb7a984e5f6923f8c5db79cea441f8a28a559be3c74d5352f00f5ab5ea6c369f94bf"+ , "432b66e7982c078980edef59d757d133033253b1b55066dac7954d2ca53fc42744eeb541"+ , "bcd971a1ebf832e2925177024222c3eeaa9226efe93e229d1561ff7ed471fc71fb435028"+ , "458438e20d671d26bf3fd1052a255a63b249d855c98f44cf1a01f72acb3e1dde713facf3"+ , "8195d7950e0584f98c0145d5e60d275d299a8607af142d12cfc7f1c1e19b5ce917a3062e"+ , "18f15890ef19f923edcf18a6af4e4b1514fe064b10153793acbc23c3ece6fe2e1095e202"+ , "1d92d82cca5b24d517bf9cd848af9813909604dfd4128b349dde403458e55a34ec4b41c8"+ , "97ea9a909515774e0aa757cb863296bc1c017a693bf7e104aabe3458a08f7b897a5b128d"+ , "463b03d52acd6fccafe603aeef466e3d88887533b76a0a33d3cad5ca1ad7"+ ]++-- | 4962 bytes of DER.+opensslMLDSA87 :: BS.ByteString+opensslMLDSA87 = hex $ concat+ [ "3082135e020100300b06096086480165030403130482134a30821346042086aea35731b2"+ , "7bde938f1eac39d757b84e88fddde9f585703952cca3a8f29b53048213204624fcb8e48e"+ , "f22d91bf330fb8378a5d2d89a7c7800d90c8f289209faef4e924f685483fb0f845abe9bc"+ , "130b4e070ca994d1fb925d736ba629eee21d10e126c02eb255fffa131ba3145c485db180"+ , "69c4bf25d5379c789593e78594b4931e02b497f5d16cfcd44ddf8970fc2271115ced6968"+ , "6c8fe8bf8eda96d66aaf309f650f54c885c396490000620929060bc465123632c892450a"+ , "094e8c1446d1a09113345214c488c3c401db20400b1712dc3844610888a0308502c64461"+ , "98619b068919184ce1805089c26c544671e2482840260160480c904001cc94305b269041"+ , "a4214428308922264c266d81284d0c366c62c211cb8630d238514188095b3689921626e2"+ , "388d10308a9c0010632242caa87003a4719022481cc18861c6480b028192960c8b100152"+ , "406adb846c19054624296603b2600ca76511056658c270d080851c98040a25691925290b"+ , "c7010ba051941264d446818aa4500b022e014231cc14229a382a50144111097140426022"+ , "072183b2688c1624c0c865db84216314125c16214022440b124a24829110a20903184e11"+ , "958184a825d19081d802028c18285286499ba024d9c24d8228469ab000e2924409c4818c"+ , "406c50348c9cb848494464403409cc301120c24863980540144a828684db3232d1b83184"+ , "420161c0658900450b208d08c18400c26d11b56053a42843c8091410261b9311c402600b"+ , "91880c24264a462501818cd9028184286ad4288c6204412146845c126413c00420246940"+ , "10610bb020009508d8107241c40d0c280d932485c032414432718a08405ab445da246c21"+ , "2562cc80208332660b1408004652c30061a30231c19451133305c0a20409166cc4408c12"+ , "4788014701999681c8c46d0ca26c4b368ac19829dab48cd3b68c011284c1a27090086cc2"+ , "34640c174e63120aa22266d18061c4262908474e0bc548d3a26d82184494a8049a804d50"+ , "36052016325cc0450b288d4a86695a2000db084e9c22819b380061a8881c1084c4462660"+ , "c028922252a33872e22672c91042d300264b124ad8927119320e1916325404624c0400c3"+ , "844d648045c0800d030668a4988098887011474d232066db2404a48421832664a2085042"+ , "805101250a5ab405c2a2001b2346a44609a00404a0846594462264c26499a08d92120e80"+ , "107000b800a2184593086a53187204087093060ae1a0881010429826468086410b364804"+ , "b020030266d3a42cd93842129781da9480180785648840e1c22ccab60c6038800cc93089"+ , "188901c9650105825b4681a33861990290ca027159c0045c240009870c42302c8332425b"+ , "2845a4189103c83000142c0812491126520a224804c924c11688dac201113046da84684c"+ , "c40ca2086908b510c8b640d32462c2a888a02665d8a42c09450a1b1464d28620c8386259"+ , "c67110041221352823174900b350121841a3484ca0947054006dd43801e39600112542a1"+ , "a66500c8850aa280d99468424686a30028a4c62d24496508130d61280aa0222d4a068610"+ , "348a8b16118aa8241a14609008000a4365a14849182630d9b2201a19800b34245bc46003"+ , "148201315092420421c1811bc205cb06911a3000013370cc0205e1a888030100c1081201"+ , "c92121170413472c8cc0655b162423434689362c542666980205ca868584946d9c288aa0"+ , "1664dc2442e3402c61c205892080a1008601937011106608014dcc186c99868de4406a41"+ , "080209b9711a46311a2081e3c88924a04d1112100a3101d90630830432e28244d8488643"+ , "144e19116641169109248a13c6900b2841cc146cdab229099268d48405d31251e0008ed1"+ , "38601321519a4670d9464a18148218000e18170e200728cb384402356a89a08141246c0c"+ , "1886024881d3a289429220a0188614446560c870c01010dc300ec2a00c0a1231d8384d19"+ , "4670e1920090322910822de1c008d11804a1102da3028981b231231484a1026ca3842d14"+ , "c7080cb68c11050d6124241b190582102e2440221bb1914c948010969193c45142188e23"+ , "431153c4614c42641ca61093b260042344cc249160a664881260ccb4712015419a80114c"+ , "160550902020b05041a02c1417208400464c264119470513860ce09460e20608a012418c"+ , "4260249030c318255b224619b86980240260101223b4315828495144529312264a8444da"+ , "b408e4b28cc0c8104bb861e4c2093b72853beba635de72bc5dffee98638ac0059b01dfa7"+ , "74f4a518039a355770b5c4e4cc09dcf898d3be26f98fa8e5b00baf0608055b66e90fd213"+ , "87a1e2a59d648650b128672779707d37ffae34d9f861a20f797bef2f191688653e789fdb"+ , "4f8ca396678f1ddd97befb8073e30577ee1ae6c879ec67185fe2511a47497613c3697263"+ , "8ead3a46de50376a11a19166adec634986d8a4331a7fdeb98734b6c1f9850619afa0d513"+ , "3409e2ce3b96a63db20b0e32aeb8f61e9ee7668a40f0bc1929b5a1890e347c91716cc3e1"+ , "9e6ab093215634b293d333c21df77e1fb7df0dc5588dcaccc4de79282e60d10c9a04fa16"+ , "3bee28c2275f0eb8d0ee30f4ed06541f57bef39b0808d14ae28c3585b4e538e87aec5ea8"+ , "b6c1fc19160ec3b4ddfc4f018d408bb5e34a5c691aa2b261e2bec96c66854611ff11f94d"+ , "a992c0db558d2d9851a758ea551a6285c8384b6a5790ff07cf4beabb644048b73b8a63ca"+ , "fa50885da407307d676bdfc01840e1513e47aac4306430f5ca946f3f7fa140bb6726138a"+ , "b29fcb3fbf551c6e97c4d63234d0e8a972cc1cd375422f71d8d3b8dc2eaeed51645196e4"+ , "b8c15a469b77b40aabaa3f0b6b6832f4c415fee3f83b9e02e2649879092bc980cdf39f28"+ , "b67b161f0dc49958fd4d32c2484c3a2732ceed9f2073bbd4247027118ead972ae6a74a58"+ , "a25af79ef715bd285f37602fd1a83605c37c0a39f5bf1b618e571eb96aa65c9162521fb6"+ , "79ef1f45bae2e6647c8ae17a3b3e1050004fb92f9f6cf0f178d65d462e59ff839c139262"+ , "1245da9faabbebe93025bf6522679cc84915a5315639f5d1ead92632975be7f29db03b90"+ , "892de9001dcfa7b8fbb7e35cbb3393b76ba88514f60600b9a6a8d0564643ddca1d6f72ad"+ , "c15389debf65bbb72add4fbe2c440ec6f8479d5b1d721feb0f698de826f1bb64ec2fb85a"+ , "61a9db8c6713cbfdedffa4fce1f403511af4765afb56f88a1664fbe5a37a736d9929ade5"+ , "8b192bf96433950f32385d94a4ea501005057dec3511b30996299c61d354712068eea89c"+ , "2ed098b94c7c353b4546ed9fb0637537155cc9abdf345246e20c7e300e13dad32c8d9f2e"+ , "1aba7ae20c8b90ab84e863a835cbf1a00288f6642a3ac050c91eb0987674dfdca68241b6"+ , "e5caf55937d838b5daeeaca88161a48c3951438d33d34814c9f71b0f5f9d657dd0702101"+ , "b1a5a8f708d0b8a3f19a17baa0d63e695e29c6ce78a2b443e023610b81aca48a8fae237b"+ , "0f82b98e69d89943d560c9731e4b395e4e75714ac915b56cb39cfbe9cf5e1d7ab1531883"+ , "21fead83dafddc45b9fa81f0f088bca3fe32684e290d8461e9514797c238262b1dbe42f0"+ , "827a1336273264fcd7ee59147c7e01e896b03b960b96f67cc3ac63f6dc05df6824069e19"+ , "d9518878a7d8b3f1356c452c5d93ffb0f443ed9180b6a7489c119631388f95eca3ce5ab6"+ , "8ffb56ee5cc8b879ac65ba27cd9819ffaa042f23e9ea3d4a1d00b64e73e14645a682c499"+ , "661760b0571f17c94680c30aab8cf3151405cd852621a23354591d4f0aad3d3a481fd634"+ , "b8521c25c3893f1cb7d34524878273bfce2fd45d134e1a78ece266bcfcfc7b043f49c1c3"+ , "916b2ff2848e93921b2b961d93a60fee7b4b34006a1fc5aac978bfb462a27fed57bcdead"+ , "a5864c8ca3e7e45a6cb1ca1af96ff56fe822dccde098ead28ff581a6ec34119dc44b8449"+ , "08ce63260a2fbcd887cc8557fde512c8048f4481452011f13709bf1919961a7a94d99f3c"+ , "e9c8c8311a12a2f6aae242a80af2971fa541999e33e110945a6f46a1e44f551256c8eefa"+ , "fbded8e69f0796b47a14e10e3d5ce65e9b06ef01fe7fa337b8ffcdc9159995bb1f7940bf"+ , "f9b7f06185c904f8bdd629f00db2fc12e5c53cc8cadff9913d755920fa61d3616fbacb90"+ , "d035a637dd5eaa1497efacb87eb2bc7e9fecf449773e925f51635f2a07d6945a8f270ab9"+ , "b1ebdba6228c8c53dfd1446eaaf2cc5a8887f40d91a97d6d9b0e27846185128c762b3981"+ , "a09619c3201b2dd3eafbfdb9a1863a13bfe97116b32dc8784474a1f5395694a0553a72ae"+ , "038afe497755b627632bd90ce3b3b0a15c5249fad5422a93e6cabc26989d6d586e8f935f"+ , "ccf40115b3fcbcda1c0bcb4d1da8eb5d9df47c940b410cb03c10aac83d11a6fe3066f092"+ , "6b3133e214b978f96902f591a159f3668d1c233122da7c3da21ffa9e8cffc556aa63cc7e"+ , "d7202d228fa149acf595261cd3d6f457bdfdb116a1b139ada16e265d417cca161ea4bfae"+ , "c4f2b1e4d2a1a9557a56f4cb36aba114e4d6279e45028fb25f96bc86546a3d351fb99433"+ , "8e9d108d9a5138badd1eb647a74b231871d8b5a994fa56eeb2e09ac04fd89c8f56c157a5"+ , "f9942c75087887098a5c0e959cf72e11bd9008d8eb57ccc4f9513200da7dbb6b3615efe5"+ , "90e619e1ff90c8781e9bf19d2b7b4e04884827d0bd94b297f4a8638575102dd236eca161"+ , "d9771cebd1cc529d85186c84ec86b0376a3ad7745b58af6bacca35b10fed57a349d2fb22"+ , "7b114ca86716a98de8a2aac6b5f678ecd7127e6a09babb182d8fcaff2394d3f65e98a43b"+ , "4d2f58bd29864f0cb0fbae6b6f1b68077f40cfb553c42d873157215e90437f4a648b2c66"+ , "ae049290f717197fb3f00acb82d659281009a0cf9682faa66fdcd2ad7219fb883a236fe9"+ , "3b7768e8df11ca70d094a9faa2c3a87e0293ec1a2feefdda5ea68a53ddced5f12aaa3820"+ , "6fe739d4ef29555dcc720bddcb0e09a757aca320442add161faf36d306682fc89f3aba84"+ , "b07c0a644602bf236f3fbe558e084b90108e3f16171c5bfab6f2e3d2017ef7b476bb3a0d"+ , "ce25e8398ac291259000dc320418d313d5ecba47a1173dfc66aa40a322076ad79c494f48"+ , "b5b2777545fd37cbdf6a295b0bd55982385e38dd4411cc560acc819a4a7e344befe841a0"+ , "964e84e15a517127fba2325e67223b42a308ef43e0a503cf850663a3986abea5b3ed9235"+ , "231ce6988f83c24fb0156a881f5380fb7aefbd6e8fcbb0cd192a80342ec8b5b1748d38fd"+ , "d62d2275594ac48a7dc4c1069a3663f33e10ec711e5d92506cf1e45f3fe21ace45ed80d5"+ , "c3221141a7308b3ea68263665c54d0cee1d36a49bb35595d0720e78b9b8f4e7f94f99947"+ , "219f8d222e0bcc9198bda51b569d70dd26e278b8c3606694c8e06539b6fdd1bef69ea854"+ , "647041ec4035f77bf13748f90ac6ca018f50af5511fd60f43d40ff0314310be5cfcba12b"+ , "c1fe793e66a5954ef7a7a5e1d5699042e96a3f61d026b35b376dd3f494325bcc3dad2571"+ , "5e40d5b9417a2d9c77b247200901a4b489aad5ab83d89f74da9e88e443d557536fb6c452"+ , "af978e477a87f0bcc8cfc0535a6023d7f92826e5ee1f75e6c81bff20d277555e03d7991b"+ , "3b3924023c33b5f80693bbbc33803a7a26206c654b05f6a39974dfe49b579b44a5f6706b"+ , "4841098b9bcaa215865faf270ff186e1208c4614d1217978f07574d85d2a506ae7f77763"+ , "b9e7419d00c8cee5688f14dd154ec9e7e3975f2119d0e9e64b071a6b80e8cf2c1b233317"+ , "d3a64e8caf73cea3b47f2e1102871d40851230e8f09e908fe86495f69fae0a5301b5b289"+ , "8167960fba4c1de5657ede5c958f3adcec887c9f21dfb25ff58edc283a28fb7f2e84fc2a"+ , "1ca28a4602baf26a71d2eaa5b7c2d5f4573d3329f4ed754893700f6e2379b97bb119de85"+ , "f3bc0367f0a23d31c4b7fc01c93574ffad9ea310d40b747fa12cda69e8da8a57ab09a703"+ , "33e76c02abeb43f92c9b118bf234fb33b2dc82f909fbb07250db23dde3dbc14a799b5fbf"+ , "4d5d2c361c8c21871c958117c1bc76d283c80156ab418848b8c189fc93ece61472e34109"+ , "231c2d888f785510f9b9310c49664bb206a548c8b54fb29bf75fc642ab200c1f6fc07ead"+ , "999fa61bc18ad5daba0e299658dde9865b51e54ff4cfe6cf26b5165884053c0ca7c6ff0d"+ , "0774f623ec012f9ec999e2a9b4e24bc854fa89100e07399e24a22c99945e8f1c1de485e5"+ , "43ee1e4f5f095f91d877d1f456c633f5ab5003ffbcea595827d88263ed67c6dc5f5a1aa4"+ , "0b5150c8f6cb4e336cf7ec2a69937fb9d5e1d56e901d608dc6d29c23e27959813fd678fa"+ , "957806dd510c3f69f8aca976178fe08a3e073272337bd1046885320c811d1e2d6d41d170"+ , "0a4cf6773c2cd62d0d5199ed928277a54eca08a42e9037be611d6e7344570db3cb0d82a0"+ , "d166e1162ea3d1b2d32ad10d90f542b8fa2dd9667c7ba465b7b66cda42d34acf612f7049"+ , "d6c720bb613fcffa6c749275c4326dca1a3c95c98ef3ebd79c2625e9b437e52a737a9c05"+ , "c5402a7ebcb81c71b7f9dff761ff3637a353969ce041397afe201cb5d4e519773b4fb9ab"+ , "5389cd6c43f57f7ddd0ce00e9150d31594b4d4584ed4c4f41d0990ec224bb825ff14046f"+ , "6d854347067607eb6740d578694c4542798bcff502517265b8173b0cd8200ae502321695"+ , "9cc405d2bab2ecd22dfa6a967edb6e84377ee2558177148a28bb7d07c85466ea4ddea4e1"+ , "49c0900217737ef402ca9580325c48e73a1a9c2cd62a6dea57489f0cb8399cd3e4a600a8"+ , "210b80de90e38c6c58d9e67b22788939bf01881afa9d325853a1ec6b783d5ce3bab56ac8"+ , "c967b451ece8e2f611faa073ce978344662d001714b493e7bd23937f5ebba2b3bc873931"+ , "e2f8d27fd01071f0b7cd32980f3438423c86ce2bd56d45665029ee7f3097"+ ]
Tests/Tests.hs view
@@ -17,11 +17,18 @@ import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.Ed25519 as Ed25519 import qualified Crypto.PubKey.Ed448 as Ed448+import qualified Crypto.PubKey.MLDSA as MLDSA import qualified Crypto.PubKey.RSA as RSA+import Data.ASN1.BinaryEncoding (DER (..))+import Data.ASN1.Encoding (decodeASN1', encodeASN1') import Data.ASN1.Types+import Data.ByteArray (convert) import Data.List (isInfixOf, nub, sort)+import Data.Proxy (Proxy (..)) import Data.X509 +import MLDSAKeys+ import Data.Hourglass instance Arbitrary RSA.PublicKey where@@ -64,6 +71,9 @@ , PubKeyX448 <$> arbitrary , PubKeyEd25519 <$> arbitrary , PubKeyEd448 <$> arbitrary+ , PubKeyMLDSA44 . MLDSA.toPublic <$> arbitraryMLDSA (Proxy :: Proxy MLDSA.MLDSA44)+ , PubKeyMLDSA65 . MLDSA.toPublic <$> arbitraryMLDSA (Proxy :: Proxy MLDSA.MLDSA65)+ , PubKeyMLDSA87 . MLDSA.toPublic <$> arbitraryMLDSA (Proxy :: Proxy MLDSA.MLDSA87) ] instance Arbitrary RSA.PrivateKey where@@ -102,8 +112,21 @@ , PrivKeyX448 <$> arbitrary , PrivKeyEd25519 <$> arbitrary , PrivKeyEd448 <$> arbitrary+ , PrivKeyMLDSA44 <$> arbitraryPrivMLDSA (Proxy :: Proxy MLDSA.MLDSA44)+ , PrivKeyMLDSA65 <$> arbitraryPrivMLDSA (Proxy :: Proxy MLDSA.MLDSA65)+ , PrivKeyMLDSA87 <$> arbitraryPrivMLDSA (Proxy :: Proxy MLDSA.MLDSA87) ] +arbitraryMLDSA :: MLDSA.MLDSA p => proxy p -> Gen (MLDSA.SigningKey p)+arbitraryMLDSA p = snd . throwCryptoError . MLDSA.keyPairFromSeed p <$> arbitraryBS 32 32++-- | All three forms are generated, so that the marshalling round trip+-- covers each of them and not just whichever one this module would pick.+arbitraryPrivMLDSA :: MLDSA.MLDSA p => proxy p -> Gen (PrivKeyMLDSA p)+arbitraryPrivMLDSA p = do+ form <- elements [MLDSAKeySeed, MLDSAKeyExpanded, MLDSAKeyBoth]+ throwCryptoError . privkeyMLDSAFromSeed p form <$> arbitraryBS 32 32+ instance Arbitrary HashALG where arbitrary = elements@@ -134,6 +157,9 @@ , SignatureALG HashSHA512 PubKeyALG_EC , SignatureALG_IntrinsicHash PubKeyALG_Ed25519 , SignatureALG_IntrinsicHash PubKeyALG_Ed448+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA44+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA65+ , SignatureALG_IntrinsicHash PubKeyALG_MLDSA87 ] arbitraryBS r1 r2 = choose (r1, r2) >>= \l -> (B.pack <$> replicateM l arbitrary)@@ -269,6 +295,163 @@ && digits `isInfixOf` debugShow k && digits `isInfixOf` debugShow (PrivKeyEC k) +-- | RFC 9881 Section 6: an ML-DSA-44 private key in PKCS#8 is the seed,+-- tagged [0], the expanded key, or both. All three give one signing key,+-- and each is written back out as what it was read as.+newtype MLDSASeed = MLDSASeed B.ByteString deriving (Show)++instance Arbitrary MLDSASeed where+ arbitrary = MLDSASeed <$> arbitraryBS 32 32++mldsaPKCS8ASN1 :: [ASN1] -> [ASN1]+mldsaPKCS8ASN1 inner =+ [ Start Sequence+ , IntVal 0+ , Start Sequence+ , OID [2, 16, 840, 1, 101, 3, 4, 3, 17]+ , End Sequence+ , OctetString (encodeASN1' DER inner)+ , End Sequence+ ]++mldsaPKCS8 :: [ASN1] -> Either String (PrivKey, [ASN1])+mldsaPKCS8 = fromASN1 . mldsaPKCS8ASN1++mldsaExpanded :: B.ByteString -> B.ByteString+mldsaExpanded seed =+ convert $+ snd $+ throwCryptoError $+ MLDSA.keyPairFromSeed (Proxy :: Proxy MLDSA.MLDSA44) seed++-- | The three encodings of one seed, with the form each of them is.+mldsaForms :: B.ByteString -> [(MLDSAKeyForm, [ASN1])]+mldsaForms seed =+ [ (MLDSAKeySeed, [Other Context 0 seed])+ , (MLDSAKeyExpanded, [OctetString expanded])+ ,+ ( MLDSAKeyBoth+ , [Start Sequence, OctetString seed, OctetString expanded, End Sequence]+ )+ ]+ where+ expanded = mldsaExpanded seed++-- | Each form parses, and all three carry the one signing key the seed+-- expands to. The forms themselves stay apart: the parsed keys are three+-- different values, because they are three different files.+property_mldsa_forms :: MLDSASeed -> Bool+property_mldsa_forms (MLDSASeed seed) =+ map (fmap fst . mldsaPKCS8 . snd) (mldsaForms seed) == map (Right . expected) forms+ && length (nub (map expected forms)) == 3+ where+ forms = map fst (mldsaForms seed)+ expected form =+ PrivKeyMLDSA44 $+ throwCryptoError $+ privkeyMLDSAFromSeed (Proxy :: Proxy MLDSA.MLDSA44) form seed++-- | Reading a key and writing it again gives back the bytes it came from,+-- for each of the three forms. This is what keeping the form is for: a+-- key store that rewrites a file must not turn a seed into an expanded key+-- behind the owner's back.+property_mldsa_form_round_trip :: MLDSASeed -> Bool+property_mldsa_form_round_trip (MLDSASeed seed) = all ok (mldsaForms seed)+ where+ ok (form, inner) = case mldsaPKCS8 inner of+ Right (k, []) ->+ toASN1 k [] == mldsaPKCS8ASN1 inner+ && formOf k == Just form+ _ -> False+ formOf (PrivKeyMLDSA44 k) = Just (privkeyMLDSA_form k)+ formOf _ = Nothing++-- | The seed caught at generation, written out and read back.+--+-- This is the whole point of the two halves: @crypton@'s+-- 'MLDSA.generateKeyPairAndSeed' is the only way to keep the seed a key was+-- made from, and the seed form of RFC 9881 Section 6 is where it goes.+-- Nothing else here generates a key, so without this the two never meet.+--+-- The key the seed expands to is the one that was generated, the file reads+-- back as what was written, and the file is shorter than the expanded key+-- alone -- which is what writing the seed is for.+property_mldsa_generated_seed :: Property+property_mldsa_generated_seed = ioProperty $ do+ (_, sk, seed) <- MLDSA.generateKeyPairAndSeed p+ let k = throwCryptoError $ privkeyMLDSAFromSeed p MLDSAKeySeed seed+ privkey = PrivKeyMLDSA44 k+ encoded = toASN1 privkey []+ return $+ privkeyMLDSA_key k == sk+ && fromASN1 encoded == Right (privkey, [])+ && B.length (encodeASN1' DER encoded) < B.length (convert sk :: B.ByteString)+ where+ p = Proxy :: Proxy MLDSA.MLDSA44++-- | What another implementation writes, this one reads and writes back.+--+-- Everything else here encodes with this library and decodes with it again,+-- which says the two halves agree and nothing about the bytes. These keys+-- were made by OpenSSL 3.6.4, so they say what no round trip can: that a+-- PKCS#8 from the rest of the world parses, and that what goes back out is+-- byte for byte what came in.+--+-- OpenSSL writes the @both@ form, which is also the case that has something+-- to check -- the expanded key must be what the seed expands to, or the+-- parse is refused.+property_mldsa_openssl :: Bool+property_mldsa_openssl = all ok keys+ where+ keys =+ [ (opensslMLDSA44, "ML-DSA-44")+ , (opensslMLDSA65, "ML-DSA-65")+ , (opensslMLDSA87, "ML-DSA-87")+ ]+ ok (der, _) = case decodeASN1' DER der of+ Left _ -> False+ Right asn1 -> case fromASN1 asn1 :: Either String (PrivKey, [ASN1]) of+ Right (k, []) ->+ formOf k == Just MLDSAKeyBoth+ && encodeASN1' DER (toASN1 k []) == der+ _ -> False+ formOf (PrivKeyMLDSA44 k) = Just (privkeyMLDSA_form k)+ formOf (PrivKeyMLDSA65 k) = Just (privkeyMLDSA_form k)+ formOf (PrivKeyMLDSA87 k) = Just (privkeyMLDSA_form k)+ formOf _ = Nothing++-- | 'show' of an ML-DSA private key holds neither the seed nor the key,+-- and 'debugShow' holds both.+property_mldsa_show_redacts :: MLDSASeed -> Bool+property_mldsa_show_redacts (MLDSASeed seed) = all ok (map fst (mldsaForms seed))+ where+ hex = concatMap byte . B.unpack+ byte w = [digit (w `div` 16), digit (w `mod` 16)]+ digit n = "0123456789abcdef" !! fromIntegral n+ ok form =+ let k =+ throwCryptoError $+ privkeyMLDSAFromSeed (Proxy :: Proxy MLDSA.MLDSA44) form seed+ wrapped = PrivKeyMLDSA44 k+ shown = show k ++ show wrapped+ debugged = debugShow k ++ debugShow wrapped+ expanded = hex (mldsaExpanded seed)+ in not (hex seed `isInfixOf` shown)+ && not (expanded `isInfixOf` shown)+ && expanded `isInfixOf` debugged+ && (form == MLDSAKeyExpanded || hex seed `isInfixOf` debugged)++property_mldsa_mismatch :: MLDSASeed -> MLDSASeed -> Property+property_mldsa_mismatch (MLDSASeed seed1) (MLDSASeed seed2) =+ seed1 /= seed2 ==>+ either (const True) (const False) $+ mldsaPKCS8+ [ Start Sequence+ , OctetString seed1+ , OctetString (mldsaExpanded seed2)+ , End Sequence+ ]+ property_extension_id :: (Show e, Eq e, Extension e) => e -> Bool property_extension_id e = case extDecode (extEncode e) of Left err -> error err@@ -305,4 +488,19 @@ , testGroup "show" [testProperty "ec privkey is redacted" property_ec_show_redacts]+ , testGroup+ "ML-DSA private key"+ [ testProperty "seed, expandedKey and both" property_mldsa_forms+ , testProperty+ "each form is written back as itself"+ property_mldsa_form_round_trip+ , testProperty+ "a generated seed survives the round trip"+ property_mldsa_generated_seed+ , testProperty+ "a key OpenSSL wrote reads and writes back unchanged"+ (property_mldsa_openssl)+ , testProperty "both refused if they disagree" property_mldsa_mismatch+ , testProperty "is redacted" property_mldsa_show_redacts+ ] ]
crypton-x509.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: crypton-x509-version: 1.9.2+version: 1.10.0 license: BSD3 license-file: LICENSE copyright: Vincent Hanquez <vincent@snarc.org>@@ -44,7 +44,7 @@ base >=4.7 && <5, bytestring, containers,- crypton >=2.0 && <2.2,+ crypton >=2.1.8 && <2.3, crypton-asn1-encoding >=0.10.0 && <0.11, crypton-asn1-parse >=0.10.0 && <0.11, crypton-asn1-types >=0.4.1 && <0.5,@@ -56,6 +56,7 @@ test-suite test-x509 type: exitcode-stdio-1.0 main-is: Tests.hs+ other-modules: MLDSAKeys hs-source-dirs: Tests default-language: Haskell2010 ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures@@ -64,8 +65,10 @@ bytestring, crypton, crypton-x509,+ crypton-asn1-encoding, crypton-asn1-types, mtl,+ ram, tasty, tasty-quickcheck, time-hourglass