]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips140test: add cSHAKE ACVP tests
authorDaniel McCarney <daniel@binaryparadox.net>
Thu, 23 Jan 2025 19:34:46 +0000 (14:34 -0500)
committerGopher Robot <gobot@golang.org>
Tue, 11 Feb 2025 21:31:01 +0000 (13:31 -0800)
Adds ACVP test coverage for the SP 800-185 cSHAKE-128 and cSHAKE-256
algorithms based on the NIST spec:

  https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html

Updates #69642

Change-Id: I4a6ef9a99dfe520f3177e0e7c258326475690f5f
Reviewed-on: https://go-review.googlesource.com/c/go/+/648455
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@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 b7fa63f75ef103eee00bd385cc0586dd1a0414d6..b2007438ec1f4f3a8906d71538220b956d4756ae 100644 (file)
@@ -13,6 +13,8 @@
 
   {"algorithm":"SHAKE-128","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
   {"algorithm":"SHAKE-256","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
+  {"algorithm":"cSHAKE-128","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
+  {"algorithm":"cSHAKE-256","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
 
   {"algorithm":"HMAC-SHA2-224","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":224,"min":32}],"revision":"1.0"},
   {"algorithm":"HMAC-SHA2-256","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":256,"min":32}],"revision":"1.0"},
index 2f905e0870376ef7ef69f375d41ec67a4ff6db20..e14a28126715f3639464f7856d65d30c9e967349 100644 (file)
@@ -13,6 +13,8 @@
 
   {"Wrapper": "go", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"},
   {"Wrapper": "go", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"},
+  {"Wrapper": "go", "In": "vectors/cSHAKE-128.bz2", "Out": "expected/cSHAKE-128.bz2"},
+  {"Wrapper": "go", "In": "vectors/cSHAKE-256.bz2", "Out": "expected/cSHAKE-256.bz2"},
 
   {"Wrapper": "go", "In": "vectors/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"},
   {"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"},
index b1857c892c836d0f2ae62b6ee91441407c1bec74..f25f3d4f0f7cbe78b8a470dd3bce52bce10ec27b 100644 (file)
@@ -105,6 +105,8 @@ var (
        //   https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
        // SHA3 and SHAKE algorithm capabilities:
        //   https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
+       // cSHAKE algorithm capabilities:
+       //   https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2
        // HMAC algorithm capabilities:
        //   https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
        // PBKDF2 algorithm capabilities:
@@ -179,6 +181,11 @@ var (
                "SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()),
                "SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()),
 
+               "cSHAKE-128":     cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
+               "cSHAKE-128/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
+               "cSHAKE-256":     cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
+               "cSHAKE-256/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
+
                "HMAC-SHA2-224":     cmdHmacAft(func() fips140.Hash { return sha256.New224() }),
                "HMAC-SHA2-256":     cmdHmacAft(func() fips140.Hash { return sha256.New() }),
                "HMAC-SHA2-384":     cmdHmacAft(func() fips140.Hash { return sha512.New384() }),
@@ -609,6 +616,90 @@ func cmdShakeMct(h *sha3.SHAKE) command {
        }
 }
 
+func cmdCShakeAft(hFn func(N, S []byte) *sha3.SHAKE) command {
+       return command{
+               requiredArgs: 4, // Message, output length bytes, function name, customization
+               handler: func(args [][]byte) ([][]byte, error) {
+                       msg := args[0]
+                       outLenBytes := binary.LittleEndian.Uint32(args[1])
+                       functionName := args[2]
+                       customization := args[3]
+
+                       h := hFn(functionName, customization)
+                       h.Write(msg)
+
+                       out := make([]byte, outLenBytes)
+                       h.Read(out)
+
+                       return [][]byte{out}, nil
+               },
+       }
+}
+
+func cmdCShakeMct(hFn func(N, S []byte) *sha3.SHAKE) command {
+       return command{
+               requiredArgs: 6, // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization
+               handler: func(args [][]byte) ([][]byte, error) {
+                       message := args[0]
+                       minOutLenBytes := binary.LittleEndian.Uint32(args[1])
+                       maxOutLenBytes := binary.LittleEndian.Uint32(args[2])
+                       outputLenBytes := binary.LittleEndian.Uint32(args[3])
+                       incrementBytes := binary.LittleEndian.Uint32(args[4])
+                       customization := args[5]
+
+                       if outputLenBytes < 2 {
+                               return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
+                       }
+
+                       rangeBits := (maxOutLenBytes*8 - minOutLenBytes*8) + 1
+                       if rangeBits == 0 {
+                               return nil, fmt.Errorf("invalid maxOutLenBytes and minOutLenBytes: %d, %d", maxOutLenBytes, minOutLenBytes)
+                       }
+
+                       // cSHAKE Monte Carlo test inner loop:
+                       //   https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1
+                       for i := 0; i < 1000; i++ {
+                               // InnerMsg = Left(Output[i-1] || ZeroBits(128), 128);
+                               boundary := min(len(message), 16)
+                               innerMsg := make([]byte, 16)
+                               copy(innerMsg, message[:boundary])
+
+                               // Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization);
+                               h := hFn(nil, customization) // Note: function name fixed to "" for MCT.
+                               h.Write(innerMsg)
+                               digest := make([]byte, outputLenBytes)
+                               h.Read(digest)
+                               message = digest
+
+                               // Rightmost_Output_bits = Right(Output[i], 16);
+                               rightmostOutput := digest[outputLenBytes-2:]
+                               // IMPORTANT: the specification says:
+                               //   NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string
+                               //   should be interpretted as a little endian-encoded number.
+                               // This is **a lie**! It has to be interpreted as a big-endian number.
+                               rightmostOutputBE := binary.BigEndian.Uint16(rightmostOutput)
+
+                               // OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement);
+                               incrementBits := incrementBytes * 8
+                               outputLenBits := (minOutLenBytes * 8) + (((uint32)(rightmostOutputBE)%rangeBits)/incrementBits)*incrementBits
+                               outputLenBytes = outputLenBits / 8
+
+                               // Customization = BitsToString(InnerMsg || Rightmost_Output_bits);
+                               msgWithBits := append(innerMsg, rightmostOutput...)
+                               customization = make([]byte, len(msgWithBits))
+                               for i, b := range msgWithBits {
+                                       customization[i] = (b % 26) + 65
+                               }
+                       }
+
+                       encodedOutputLenBytes := make([]byte, 4)
+                       binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
+
+                       return [][]byte{message, encodedOutputLenBytes, customization}, nil
+               },
+       }
+}
+
 func cmdHmacAft(h func() fips140.Hash) command {
        return command{
                requiredArgs: 2, // Message and key
@@ -1973,7 +2064,7 @@ func TestACVP(t *testing.T) {
                bsslModule    = "boringssl.googlesource.com/boringssl.git"
                bsslVersion   = "v0.0.0-20250207174145-0bb19f6126cb"
                goAcvpModule  = "github.com/cpu/go-acvp"
-               goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d"
+               goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be"
        )
 
        // In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows"