]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips140test: add EDDSA ACVP tests
authorDaniel McCarney <daniel@binaryparadox.net>
Thu, 14 Nov 2024 21:00:43 +0000 (16:00 -0500)
committerGopher Robot <gobot@golang.org>
Fri, 7 Feb 2025 16:53:31 +0000 (08:53 -0800)
This commit adds ACVP test coverage for EDDSA (Ed25519, and
HashEd25519/Ed25519ph) for the keyGen, keyVer, sigGen, and sigVer
capabilities.

Updates #69642

Change-Id: I5122d86180bd4d2f7d94570a6dc939808aa24fc4
Reviewed-on: https://go-review.googlesource.com/c/go/+/621135
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/crypto/internal/fips140test/acvp_capabilities.json
src/crypto/internal/fips140test/acvp_test.config.json
src/crypto/internal/fips140test/acvp_test.go

index 8a4a97758cce39dc99706797665dfe77d4b1f07b..368c7809deb980964e49f6d6e4a7988051274d79 100644 (file)
   {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-224","derFuncEnabled":false,"entropyInputLen":[192],"nonceLen":[96],"persoStringLen":[192],"additionalInputLen":[0],"returnedBitsLen":224}]},
   {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-256","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":256}]},
   {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-384","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":384}]},
-  {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]}
+  {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]},
+
+  {"algorithm":"EDDSA","mode":"keyGen","revision":"1.0","curve":["ED-25519"]},
+  {"algorithm":"EDDSA","mode":"keyVer","revision":"1.0","curve":["ED-25519"]},
+  {"algorithm":"EDDSA","mode":"sigGen","revision":"1.0","pure":true,"preHash":true,"contextLength":[{"min":0,"max":255,"increment":1}],"curve":["ED-25519"]},
+  {"algorithm":"EDDSA","mode":"sigVer","revision":"1.0","pure":true,"preHash":true,"curve":["ED-25519"]}
 ]
index dc4d714f19c6207aa2c2558a72b5e2419c517815..2afd457f46ce90ec1458807f6786a63b79646eca 100644 (file)
@@ -27,5 +27,7 @@
 
   {"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"},
 
-  {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"}
+  {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"},
+
+  {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}
 ]
\ No newline at end of file
index 8dedb9a79159b5cd0720348b6cdeb715296a3f26..b160f60d17ccccad508058bda329bd30d190233a 100644 (file)
@@ -24,6 +24,8 @@ import (
        "crypto/internal/cryptotest"
        "crypto/internal/fips140"
        "crypto/internal/fips140/ecdsa"
+       "crypto/internal/fips140/ed25519"
+       "crypto/internal/fips140/edwards25519"
        "crypto/internal/fips140/hmac"
        "crypto/internal/fips140/mlkem"
        "crypto/internal/fips140/pbkdf2"
@@ -81,6 +83,8 @@ var (
        //   https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3
        // HMAC DRBG algorithm capabilities:
        //   https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
+       // EDDSA algorithm capabilities:
+       //   https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7
        //go:embed acvp_capabilities.json
        capabilitiesJson []byte
 
@@ -142,6 +146,11 @@ var (
                "hmacDRBG/SHA3-256":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New256() }),
                "hmacDRBG/SHA3-384":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New384() }),
                "hmacDRBG/SHA3-512":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New512() }),
+
+               "EDDSA/keyGen": cmdEddsaKeyGenAft(),
+               "EDDSA/keyVer": cmdEddsaKeyVerAft(),
+               "EDDSA/sigGen": cmdEddsaSigGenAftBft(),
+               "EDDSA/sigVer": cmdEddsaSigVerAft(),
        }
 )
 
@@ -397,6 +406,126 @@ func cmdPbkdf() command {
        }
 }
 
+func cmdEddsaKeyGenAft() command {
+       return command{
+               requiredArgs: 1, // Curve name
+               handler: func(args [][]byte) ([][]byte, error) {
+                       if string(args[0]) != "ED-25519" {
+                               return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
+                       }
+
+                       sk, err := ed25519.GenerateKey()
+                       if err != nil {
+                               return nil, fmt.Errorf("generating EDDSA keypair: %w", err)
+                       }
+
+                       // EDDSA/keyGen/AFT responses are d & q, described[0] as:
+                       //   d  The encoded private key point
+                       //   q  The encoded public key point
+                       //
+                       // Contrary to the description of a "point", d is the private key
+                       // seed bytes per FIPS.186-5[1] A.2.3.
+                       //
+                       // [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-9.1
+                       // [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
+                       return [][]byte{sk.Seed(), sk.PublicKey()}, nil
+               },
+       }
+}
+
+func cmdEddsaKeyVerAft() command {
+       return command{
+               requiredArgs: 2, // Curve name, Q
+               handler: func(args [][]byte) ([][]byte, error) {
+                       if string(args[0]) != "ED-25519" {
+                               return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
+                       }
+
+                       // Verify the point is on the curve. The higher-level ed25519 API does
+                       // this at signature verification time so we have to use the lower-level
+                       // edwards25519 package to do it here in absence of a signature to verify.
+                       if _, err := new(edwards25519.Point).SetBytes(args[1]); err != nil {
+                               return [][]byte{{0}}, nil
+                       }
+
+                       return [][]byte{{1}}, nil
+               },
+       }
+}
+
+func cmdEddsaSigGenAftBft() command {
+       return command{
+               requiredArgs: 5, // Curve name, private key seed, message, prehash, context
+               handler: func(args [][]byte) ([][]byte, error) {
+                       if string(args[0]) != "ED-25519" {
+                               return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
+                       }
+
+                       sk, err := ed25519.NewPrivateKeyFromSeed(args[1])
+                       if err != nil {
+                               return nil, fmt.Errorf("error creating private key: %w", err)
+                       }
+                       msg := args[2]
+                       prehash := args[3]
+                       context := string(args[4])
+
+                       var sig []byte
+                       if prehash[0] == 1 {
+                               h := sha512.New()
+                               h.Write(msg)
+                               msg = h.Sum(nil)
+
+                               // With ed25519 the context is only specified for sigGen tests when using prehashing.
+                               // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
+                               sig, err = ed25519.SignPH(sk, msg, context)
+                               if err != nil {
+                                       return nil, fmt.Errorf("error signing message: %w", err)
+                               }
+                       } else {
+                               sig = ed25519.Sign(sk, msg)
+                       }
+
+                       return [][]byte{sig}, nil
+               },
+       }
+}
+
+func cmdEddsaSigVerAft() command {
+       return command{
+               requiredArgs: 5, // Curve name, message, public key, signature, prehash
+               handler: func(args [][]byte) ([][]byte, error) {
+                       if string(args[0]) != "ED-25519" {
+                               return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
+                       }
+
+                       msg := args[1]
+                       pk, err := ed25519.NewPublicKey(args[2])
+                       if err != nil {
+                               return nil, fmt.Errorf("invalid public key: %w", err)
+                       }
+                       sig := args[3]
+                       prehash := args[4]
+
+                       if prehash[0] == 1 {
+                               h := sha512.New()
+                               h.Write(msg)
+                               msg = h.Sum(nil)
+                               // Context is only specified for sigGen, not sigVer.
+                               // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
+                               err = ed25519.VerifyPH(pk, msg, sig, "")
+                       } else {
+                               err = ed25519.Verify(pk, msg, sig)
+                       }
+
+                       if err != nil {
+                               return [][]byte{{0}}, nil
+                       }
+
+                       return [][]byte{{1}}, nil
+               },
+       }
+}
+
 func lookupHash(name string) (func() fips140.Hash, error) {
        var h func() fips140.Hash