// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build !purego package sha3 import ( "crypto/internal/fips140/subtle" "crypto/internal/fips140deps/cpu" "crypto/internal/impl" ) // This file contains code for using the 'compute intermediate // message digest' (KIMD) and 'compute last message digest' (KLMD) // instructions to compute SHA-3 and SHAKE hashes on IBM Z. See // [z/Architecture Principles of Operation, Fourteen Edition]. // // [z/Architecture Principles of Operation, Fourteen Edition]: https://www.ibm.com/docs/en/module_1678991624569/pdf/SA22-7832-13.pdf var useSHA3 = cpu.S390XHasSHA3 func init() { // CP Assist for Cryptographic Functions (CPACF) impl.Register("sha3", "CPACF", &useSHA3) } func keccakF1600(a *[200]byte) { keccakF1600Generic(a) } // codes represent 7-bit KIMD/KLMD function codes as defined in // the Principles of Operation. type code uint64 const ( // Function codes for KIMD/KLMD, from Figure 7-207. sha3_224 code = 32 sha3_256 code = 33 sha3_384 code = 34 sha3_512 code = 35 shake_128 code = 36 shake_256 code = 37 nopad = 0x100 ) // kimd is a wrapper for the 'compute intermediate message digest' instruction. // src is absorbed into the sponge state a. // len(src) must be a multiple of the rate for the given function code. // //go:noescape func kimd(function code, a *[200]byte, src []byte) // klmd is a wrapper for the 'compute last message digest' instruction. // src is padded and absorbed into the sponge state a. // // If the function is a SHAKE XOF, the sponge is then optionally squeezed into // dst by first applying the permutation and then copying the output until dst // runs out. If len(dst) is a multiple of rate (including zero), the final // permutation is not applied. If the nopad bit of function is set and len(src) // is zero, only squeezing is performed. // //go:noescape func klmd(function code, a *[200]byte, dst, src []byte) func (d *Digest) write(p []byte) (n int, err error) { if d.state != spongeAbsorbing { panic("sha3: Write after Read") } if !useSHA3 { return d.writeGeneric(p) } n = len(p) // If there is buffered input in the state, keep XOR'ing. if d.n > 0 { x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p) d.n += x p = p[x:] } // If the sponge is full, apply the permutation. if d.n == d.rate { // Absorbing a "rate"ful of zeroes effectively XORs the state with // zeroes (a no-op) and then runs the permutation. The actual function // doesn't matter, they all run the same permutation. kimd(shake_128, &d.a, make([]byte, rateK256)) d.n = 0 } // Absorb full blocks with KIMD. if len(p) >= d.rate { wholeBlocks := len(p) / d.rate * d.rate kimd(d.function(), &d.a, p[:wholeBlocks]) p = p[wholeBlocks:] } // If there is any trailing input, XOR it into the state. if len(p) > 0 { d.n += subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p) } return } func (d *Digest) sum(b []byte) []byte { if d.state != spongeAbsorbing { panic("sha3: Sum after Read") } if !useSHA3 || d.dsbyte != dsbyteSHA3 && d.dsbyte != dsbyteShake { return d.sumGeneric(b) } // Copy the state to preserve the original. a := d.a // We "absorb" a buffer of zeroes as long as the amount of input we already // XOR'd into the sponge, to skip over it. The max cap is specified to avoid // an allocation. buf := make([]byte, d.n, rateK256) function := d.function() switch function { case sha3_224, sha3_256, sha3_384, sha3_512: klmd(function, &a, nil, buf) return append(b, a[:d.outputLen]...) case shake_128, shake_256: h := make([]byte, d.outputLen, 64) klmd(function, &a, h, buf) return append(b, h...) default: panic("sha3: unknown function") } } func (d *Digest) read(out []byte) (n int, err error) { if !useSHA3 || d.dsbyte != dsbyteShake { return d.readGeneric(out) } n = len(out) if d.state == spongeAbsorbing { d.state = spongeSqueezing // We "absorb" a buffer of zeroes as long as the amount of input we // already XOR'd into the sponge, to skip over it. The max cap is // specified to avoid an allocation. buf := make([]byte, d.n, rateK256) klmd(d.function(), &d.a, out, buf) } else { // We have "buffered" output still to copy. if d.n < d.rate { x := copy(out, d.a[d.n:d.rate]) d.n += x out = out[x:] } if len(out) == 0 { return } klmd(d.function()|nopad, &d.a, out, nil) } if len(out)%d.rate == 0 { // The final permutation was not performed, // so there is no "buffered" output. d.n = d.rate } else { d.n = len(out) % d.rate } return } func (d *Digest) function() code { switch d.rate { case rateK256: return shake_128 case rateK448: return sha3_224 case rateK512: if d.dsbyte == dsbyteSHA3 { return sha3_256 } else { return shake_256 } case rateK768: return sha3_384 case rateK1024: return sha3_512 default: panic("invalid rate") } }