@@ -105,6 +105,8 @@ var (
105
105
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
106
106
// SHA3 and SHAKE algorithm capabilities:
107
107
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
108
+ // cSHAKE algorithm capabilities:
109
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2
108
110
// HMAC algorithm capabilities:
109
111
// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
110
112
// PBKDF2 algorithm capabilities:
@@ -179,6 +181,11 @@ var (
179
181
"SHAKE-256/VOT" : cmdShakeAftVot (sha3 .NewShake256 ()),
180
182
"SHAKE-256/MCT" : cmdShakeMct (sha3 .NewShake256 ()),
181
183
184
+ "cSHAKE-128" : cmdCShakeAft (func (N , S []byte ) * sha3.SHAKE { return sha3 .NewCShake128 (N , S ) }),
185
+ "cSHAKE-128/MCT" : cmdCShakeMct (func (N , S []byte ) * sha3.SHAKE { return sha3 .NewCShake128 (N , S ) }),
186
+ "cSHAKE-256" : cmdCShakeAft (func (N , S []byte ) * sha3.SHAKE { return sha3 .NewCShake256 (N , S ) }),
187
+ "cSHAKE-256/MCT" : cmdCShakeMct (func (N , S []byte ) * sha3.SHAKE { return sha3 .NewCShake256 (N , S ) }),
188
+
182
189
"HMAC-SHA2-224" : cmdHmacAft (func () fips140.Hash { return sha256 .New224 () }),
183
190
"HMAC-SHA2-256" : cmdHmacAft (func () fips140.Hash { return sha256 .New () }),
184
191
"HMAC-SHA2-384" : cmdHmacAft (func () fips140.Hash { return sha512 .New384 () }),
@@ -609,6 +616,90 @@ func cmdShakeMct(h *sha3.SHAKE) command {
609
616
}
610
617
}
611
618
619
+ func cmdCShakeAft (hFn func (N , S []byte ) * sha3.SHAKE ) command {
620
+ return command {
621
+ requiredArgs : 4 , // Message, output length bytes, function name, customization
622
+ handler : func (args [][]byte ) ([][]byte , error ) {
623
+ msg := args [0 ]
624
+ outLenBytes := binary .LittleEndian .Uint32 (args [1 ])
625
+ functionName := args [2 ]
626
+ customization := args [3 ]
627
+
628
+ h := hFn (functionName , customization )
629
+ h .Write (msg )
630
+
631
+ out := make ([]byte , outLenBytes )
632
+ h .Read (out )
633
+
634
+ return [][]byte {out }, nil
635
+ },
636
+ }
637
+ }
638
+
639
+ func cmdCShakeMct (hFn func (N , S []byte ) * sha3.SHAKE ) command {
640
+ return command {
641
+ requiredArgs : 6 , // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization
642
+ handler : func (args [][]byte ) ([][]byte , error ) {
643
+ message := args [0 ]
644
+ minOutLenBytes := binary .LittleEndian .Uint32 (args [1 ])
645
+ maxOutLenBytes := binary .LittleEndian .Uint32 (args [2 ])
646
+ outputLenBytes := binary .LittleEndian .Uint32 (args [3 ])
647
+ incrementBytes := binary .LittleEndian .Uint32 (args [4 ])
648
+ customization := args [5 ]
649
+
650
+ if outputLenBytes < 2 {
651
+ return nil , fmt .Errorf ("invalid output length: %d" , outputLenBytes )
652
+ }
653
+
654
+ rangeBits := (maxOutLenBytes * 8 - minOutLenBytes * 8 ) + 1
655
+ if rangeBits == 0 {
656
+ return nil , fmt .Errorf ("invalid maxOutLenBytes and minOutLenBytes: %d, %d" , maxOutLenBytes , minOutLenBytes )
657
+ }
658
+
659
+ // cSHAKE Monte Carlo test inner loop:
660
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1
661
+ for i := 0 ; i < 1000 ; i ++ {
662
+ // InnerMsg = Left(Output[i-1] || ZeroBits(128), 128);
663
+ boundary := min (len (message ), 16 )
664
+ innerMsg := make ([]byte , 16 )
665
+ copy (innerMsg , message [:boundary ])
666
+
667
+ // Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization);
668
+ h := hFn (nil , customization ) // Note: function name fixed to "" for MCT.
669
+ h .Write (innerMsg )
670
+ digest := make ([]byte , outputLenBytes )
671
+ h .Read (digest )
672
+ message = digest
673
+
674
+ // Rightmost_Output_bits = Right(Output[i], 16);
675
+ rightmostOutput := digest [outputLenBytes - 2 :]
676
+ // IMPORTANT: the specification says:
677
+ // NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string
678
+ // should be interpretted as a little endian-encoded number.
679
+ // This is **a lie**! It has to be interpreted as a big-endian number.
680
+ rightmostOutputBE := binary .BigEndian .Uint16 (rightmostOutput )
681
+
682
+ // OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement);
683
+ incrementBits := incrementBytes * 8
684
+ outputLenBits := (minOutLenBytes * 8 ) + (((uint32 )(rightmostOutputBE )% rangeBits )/ incrementBits )* incrementBits
685
+ outputLenBytes = outputLenBits / 8
686
+
687
+ // Customization = BitsToString(InnerMsg || Rightmost_Output_bits);
688
+ msgWithBits := append (innerMsg , rightmostOutput ... )
689
+ customization = make ([]byte , len (msgWithBits ))
690
+ for i , b := range msgWithBits {
691
+ customization [i ] = (b % 26 ) + 65
692
+ }
693
+ }
694
+
695
+ encodedOutputLenBytes := make ([]byte , 4 )
696
+ binary .LittleEndian .PutUint32 (encodedOutputLenBytes , outputLenBytes )
697
+
698
+ return [][]byte {message , encodedOutputLenBytes , customization }, nil
699
+ },
700
+ }
701
+ }
702
+
612
703
func cmdHmacAft (h func () fips140.Hash ) command {
613
704
return command {
614
705
requiredArgs : 2 , // Message and key
@@ -1973,7 +2064,7 @@ func TestACVP(t *testing.T) {
1973
2064
bsslModule = "boringssl.googlesource.com/boringssl.git"
1974
2065
bsslVersion = "v0.0.0-20250207174145-0bb19f6126cb"
1975
2066
goAcvpModule = "github.com/cpu/go-acvp"
1976
- goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d "
2067
+ goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be "
1977
2068
)
1978
2069
1979
2070
// In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows"
0 commit comments