Skip to content

Commit f99a214

Browse files
cpugopherbot
authored andcommitted
crypto/internal/fips140test: add EDDSA ACVP tests
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent d9d87ed commit f99a214

File tree

3 files changed

+138
-2
lines changed

3 files changed

+138
-2
lines changed

src/crypto/internal/fips140test/acvp_capabilities.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,10 @@
3737
{"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}]},
3838
{"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}]},
3939
{"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}]},
40-
{"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}]}
40+
{"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}]},
41+
42+
{"algorithm":"EDDSA","mode":"keyGen","revision":"1.0","curve":["ED-25519"]},
43+
{"algorithm":"EDDSA","mode":"keyVer","revision":"1.0","curve":["ED-25519"]},
44+
{"algorithm":"EDDSA","mode":"sigGen","revision":"1.0","pure":true,"preHash":true,"contextLength":[{"min":0,"max":255,"increment":1}],"curve":["ED-25519"]},
45+
{"algorithm":"EDDSA","mode":"sigVer","revision":"1.0","pure":true,"preHash":true,"curve":["ED-25519"]}
4146
]

src/crypto/internal/fips140test/acvp_test.config.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,7 @@
2727

2828
{"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"},
2929

30-
{"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"}
30+
{"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"},
31+
32+
{"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}
3133
]

src/crypto/internal/fips140test/acvp_test.go

+129
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"crypto/internal/cryptotest"
2525
"crypto/internal/fips140"
2626
"crypto/internal/fips140/ecdsa"
27+
"crypto/internal/fips140/ed25519"
28+
"crypto/internal/fips140/edwards25519"
2729
"crypto/internal/fips140/hmac"
2830
"crypto/internal/fips140/mlkem"
2931
"crypto/internal/fips140/pbkdf2"
@@ -81,6 +83,8 @@ var (
8183
// https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3
8284
// HMAC DRBG algorithm capabilities:
8385
// https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
86+
// EDDSA algorithm capabilities:
87+
// https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7
8488
//go:embed acvp_capabilities.json
8589
capabilitiesJson []byte
8690

@@ -142,6 +146,11 @@ var (
142146
"hmacDRBG/SHA3-256": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New256() }),
143147
"hmacDRBG/SHA3-384": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New384() }),
144148
"hmacDRBG/SHA3-512": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New512() }),
149+
150+
"EDDSA/keyGen": cmdEddsaKeyGenAft(),
151+
"EDDSA/keyVer": cmdEddsaKeyVerAft(),
152+
"EDDSA/sigGen": cmdEddsaSigGenAftBft(),
153+
"EDDSA/sigVer": cmdEddsaSigVerAft(),
145154
}
146155
)
147156

@@ -397,6 +406,126 @@ func cmdPbkdf() command {
397406
}
398407
}
399408

409+
func cmdEddsaKeyGenAft() command {
410+
return command{
411+
requiredArgs: 1, // Curve name
412+
handler: func(args [][]byte) ([][]byte, error) {
413+
if string(args[0]) != "ED-25519" {
414+
return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
415+
}
416+
417+
sk, err := ed25519.GenerateKey()
418+
if err != nil {
419+
return nil, fmt.Errorf("generating EDDSA keypair: %w", err)
420+
}
421+
422+
// EDDSA/keyGen/AFT responses are d & q, described[0] as:
423+
// d The encoded private key point
424+
// q The encoded public key point
425+
//
426+
// Contrary to the description of a "point", d is the private key
427+
// seed bytes per FIPS.186-5[1] A.2.3.
428+
//
429+
// [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-9.1
430+
// [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
431+
return [][]byte{sk.Seed(), sk.PublicKey()}, nil
432+
},
433+
}
434+
}
435+
436+
func cmdEddsaKeyVerAft() command {
437+
return command{
438+
requiredArgs: 2, // Curve name, Q
439+
handler: func(args [][]byte) ([][]byte, error) {
440+
if string(args[0]) != "ED-25519" {
441+
return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
442+
}
443+
444+
// Verify the point is on the curve. The higher-level ed25519 API does
445+
// this at signature verification time so we have to use the lower-level
446+
// edwards25519 package to do it here in absence of a signature to verify.
447+
if _, err := new(edwards25519.Point).SetBytes(args[1]); err != nil {
448+
return [][]byte{{0}}, nil
449+
}
450+
451+
return [][]byte{{1}}, nil
452+
},
453+
}
454+
}
455+
456+
func cmdEddsaSigGenAftBft() command {
457+
return command{
458+
requiredArgs: 5, // Curve name, private key seed, message, prehash, context
459+
handler: func(args [][]byte) ([][]byte, error) {
460+
if string(args[0]) != "ED-25519" {
461+
return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
462+
}
463+
464+
sk, err := ed25519.NewPrivateKeyFromSeed(args[1])
465+
if err != nil {
466+
return nil, fmt.Errorf("error creating private key: %w", err)
467+
}
468+
msg := args[2]
469+
prehash := args[3]
470+
context := string(args[4])
471+
472+
var sig []byte
473+
if prehash[0] == 1 {
474+
h := sha512.New()
475+
h.Write(msg)
476+
msg = h.Sum(nil)
477+
478+
// With ed25519 the context is only specified for sigGen tests when using prehashing.
479+
// See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
480+
sig, err = ed25519.SignPH(sk, msg, context)
481+
if err != nil {
482+
return nil, fmt.Errorf("error signing message: %w", err)
483+
}
484+
} else {
485+
sig = ed25519.Sign(sk, msg)
486+
}
487+
488+
return [][]byte{sig}, nil
489+
},
490+
}
491+
}
492+
493+
func cmdEddsaSigVerAft() command {
494+
return command{
495+
requiredArgs: 5, // Curve name, message, public key, signature, prehash
496+
handler: func(args [][]byte) ([][]byte, error) {
497+
if string(args[0]) != "ED-25519" {
498+
return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
499+
}
500+
501+
msg := args[1]
502+
pk, err := ed25519.NewPublicKey(args[2])
503+
if err != nil {
504+
return nil, fmt.Errorf("invalid public key: %w", err)
505+
}
506+
sig := args[3]
507+
prehash := args[4]
508+
509+
if prehash[0] == 1 {
510+
h := sha512.New()
511+
h.Write(msg)
512+
msg = h.Sum(nil)
513+
// Context is only specified for sigGen, not sigVer.
514+
// See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
515+
err = ed25519.VerifyPH(pk, msg, sig, "")
516+
} else {
517+
err = ed25519.Verify(pk, msg, sig)
518+
}
519+
520+
if err != nil {
521+
return [][]byte{{0}}, nil
522+
}
523+
524+
return [][]byte{{1}}, nil
525+
},
526+
}
527+
}
528+
400529
func lookupHash(name string) (func() fips140.Hash, error) {
401530
var h func() fips140.Hash
402531

0 commit comments

Comments
 (0)