]> Cypherpunks repositories - gostls13.git/commit
crypto/sha3: reduce cSHAKE allocations
authorTom Thorogood <me+google@tomthorogood.co.uk>
Sun, 15 Dec 2024 01:38:43 +0000 (12:08 +1030)
committerGopher Robot <gobot@golang.org>
Tue, 25 Nov 2025 18:36:14 +0000 (10:36 -0800)
commitbd9222b525b44d91941fc4d179b467103817d463
tree0719daba2e8717d1ea73456ff9cc98bf98d67da8
parente3088d6eb8ff0d63edc3452cbed827cb67231182
crypto/sha3: reduce cSHAKE allocations

Consider a hypothetical SumCSHAKE256 function:

func SumCSHAKE256(N, S, data []byte, length int) []byte {
out := make([]byte, 64)
return sumCSHAKE256(out, N, S, data, length)
}

func sumCSHAKE256(out, N, S, data []byte, length int) []byte {
if len(out) < length {
out = make([]byte, length)
} else {
out = out[:length]
}
h := sha3.NewCSHAKE256(N, S)
h.Write(data)
h.Read(out)
return out
}

Currently this has 4 allocations:
- one for out (unless stack allocated),
- one for the SHAKE result of crypto/internal/fips140/sha3.newCShake,
- one for the initBlock allocation in crypto/internal/fips140/sha3.newCShake,
- one for the result of crypto/internal/fips140/sha3.bytepad.

We eliminate the SHAKE allocation by outlining the SHAKE allocation in
crypto/internal/fips140/sha3.NewCSHAKE128 and NewCSHAKE256. As
crypto/sha3.NewCSHAKE128 and NewCSHAKE256 immediately de-reference this
result, this allocation is eliminated.

We eliminate the bytepad allocation by instead writing the various
values directly with SHAKE.Write. Values passed to Write don't escape
and, with the exception of data (which is initBlock), all our Writes are
of fixed size allocations. We can't simply modify bytepad to return a
fixed size byte-slice as the length of data is not constant nor does it
have a reasonable upper bound.

We're stuck with the initBlock allocation because of the API (Reset and
the various marshallers), but we still net a substantial improvement.

benchstat output using the following benchmark:

        func BenchmarkSumCSHAKE256(b *testing.B) {
                N := []byte("N")
                S := []byte("S")
                data := []byte("testdata")

                b.SetBytes(64)

                for b.Loop() {
                        SumCSHAKE256(N, S, data, 64)
                }
        }

name             old time/op    new time/op    delta
SumCSHAKE256-12    1.09µs ±20%    0.79µs ± 1%  -27.41%  (p=0.000 n=10+9)

name             old speed      new speed      delta
SumCSHAKE256-12  59.8MB/s ±18%  81.0MB/s ± 1%  +35.33%  (p=0.000 n=10+9)

name             old alloc/op   new alloc/op   delta
SumCSHAKE256-12      536B ± 0%       88B ± 0%  -83.58%  (p=0.000 n=10+10)

name             old allocs/op  new allocs/op  delta
SumCSHAKE256-12      4.00 ± 0%      2.00 ± 0%  -50.00%  (p=0.000 n=10+10)

Updates #69982

Change-Id: If426ea8127c58f5ef062cf74712ec70fd26a7372
Reviewed-on: https://go-review.googlesource.com/c/go/+/636255
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
src/crypto/internal/fips140/sha3/shake.go