sha3_s390x.mx raw

   1  // Copyright 2017 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build !purego
   6  
   7  package sha3
   8  
   9  import (
  10  	"crypto/internal/fips140/subtle"
  11  	"crypto/internal/fips140deps/cpu"
  12  	"crypto/internal/impl"
  13  )
  14  
  15  // This file contains code for using the 'compute intermediate
  16  // message digest' (KIMD) and 'compute last message digest' (KLMD)
  17  // instructions to compute SHA-3 and SHAKE hashes on IBM Z. See
  18  // [z/Architecture Principles of Operation, Fourteen Edition].
  19  //
  20  // [z/Architecture Principles of Operation, Fourteen Edition]: https://www.ibm.com/docs/en/module_1678991624569/pdf/SA22-7832-13.pdf
  21  
  22  var useSHA3 = cpu.S390XHasSHA3
  23  
  24  func init() {
  25  	// CP Assist for Cryptographic Functions (CPACF)
  26  	impl.Register("sha3", "CPACF", &useSHA3)
  27  }
  28  
  29  func keccakF1600(a *[200]byte) {
  30  	keccakF1600Generic(a)
  31  }
  32  
  33  // codes represent 7-bit KIMD/KLMD function codes as defined in
  34  // the Principles of Operation.
  35  type code uint64
  36  
  37  const (
  38  	// Function codes for KIMD/KLMD, from Figure 7-207.
  39  	sha3_224  code = 32
  40  	sha3_256  code = 33
  41  	sha3_384  code = 34
  42  	sha3_512  code = 35
  43  	shake_128 code = 36
  44  	shake_256 code = 37
  45  	nopad          = 0x100
  46  )
  47  
  48  // kimd is a wrapper for the 'compute intermediate message digest' instruction.
  49  // src is absorbed into the sponge state a.
  50  // len(src) must be a multiple of the rate for the given function code.
  51  //
  52  //go:noescape
  53  func kimd(function code, a *[200]byte, src []byte)
  54  
  55  // klmd is a wrapper for the 'compute last message digest' instruction.
  56  // src is padded and absorbed into the sponge state a.
  57  //
  58  // If the function is a SHAKE XOF, the sponge is then optionally squeezed into
  59  // dst by first applying the permutation and then copying the output until dst
  60  // runs out. If len(dst) is a multiple of rate (including zero), the final
  61  // permutation is not applied. If the nopad bit of function is set and len(src)
  62  // is zero, only squeezing is performed.
  63  //
  64  //go:noescape
  65  func klmd(function code, a *[200]byte, dst, src []byte)
  66  
  67  func (d *Digest) write(p []byte) (n int, err error) {
  68  	if d.state != spongeAbsorbing {
  69  		panic("sha3: Write after Read")
  70  	}
  71  	if !useSHA3 {
  72  		return d.writeGeneric(p)
  73  	}
  74  
  75  	n = len(p)
  76  
  77  	// If there is buffered input in the state, keep XOR'ing.
  78  	if d.n > 0 {
  79  		x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
  80  		d.n += x
  81  		p = p[x:]
  82  	}
  83  
  84  	// If the sponge is full, apply the permutation.
  85  	if d.n == d.rate {
  86  		// Absorbing a "rate"ful of zeroes effectively XORs the state with
  87  		// zeroes (a no-op) and then runs the permutation. The actual function
  88  		// doesn't matter, they all run the same permutation.
  89  		kimd(shake_128, &d.a, []byte{:rateK256})
  90  		d.n = 0
  91  	}
  92  
  93  	// Absorb full blocks with KIMD.
  94  	if len(p) >= d.rate {
  95  		wholeBlocks := len(p) / d.rate * d.rate
  96  		kimd(d.function(), &d.a, p[:wholeBlocks])
  97  		p = p[wholeBlocks:]
  98  	}
  99  
 100  	// If there is any trailing input, XOR it into the state.
 101  	if len(p) > 0 {
 102  		d.n += subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
 103  	}
 104  
 105  	return
 106  }
 107  
 108  func (d *Digest) sum(b []byte) []byte {
 109  	if d.state != spongeAbsorbing {
 110  		panic("sha3: Sum after Read")
 111  	}
 112  	if !useSHA3 || d.dsbyte != dsbyteSHA3 && d.dsbyte != dsbyteShake {
 113  		return d.sumGeneric(b)
 114  	}
 115  
 116  	// Copy the state to preserve the original.
 117  	a := d.a
 118  
 119  	// We "absorb" a buffer of zeroes as long as the amount of input we already
 120  	// XOR'd into the sponge, to skip over it. The max cap is specified to avoid
 121  	// an allocation.
 122  	buf := []byte{:d.n:rateK256}
 123  	function := d.function()
 124  	switch function {
 125  	case sha3_224, sha3_256, sha3_384, sha3_512:
 126  		klmd(function, &a, nil, buf)
 127  		return append(b, a[:d.outputLen]...)
 128  	case shake_128, shake_256:
 129  		h := []byte{:d.outputLen:64}
 130  		klmd(function, &a, h, buf)
 131  		return append(b, h...)
 132  	default:
 133  		panic("sha3: unknown function")
 134  	}
 135  }
 136  
 137  func (d *Digest) read(out []byte) (n int, err error) {
 138  	if !useSHA3 || d.dsbyte != dsbyteShake {
 139  		return d.readGeneric(out)
 140  	}
 141  
 142  	n = len(out)
 143  
 144  	if d.state == spongeAbsorbing {
 145  		d.state = spongeSqueezing
 146  
 147  		// We "absorb" a buffer of zeroes as long as the amount of input we
 148  		// already XOR'd into the sponge, to skip over it. The max cap is
 149  		// specified to avoid an allocation.
 150  		buf := []byte{:d.n:rateK256}
 151  		klmd(d.function(), &d.a, out, buf)
 152  	} else {
 153  		// We have "buffered" output still to copy.
 154  		if d.n < d.rate {
 155  			x := copy(out, d.a[d.n:d.rate])
 156  			d.n += x
 157  			out = out[x:]
 158  		}
 159  		if len(out) == 0 {
 160  			return
 161  		}
 162  
 163  		klmd(d.function()|nopad, &d.a, out, nil)
 164  	}
 165  
 166  	if len(out)%d.rate == 0 {
 167  		// The final permutation was not performed,
 168  		// so there is no "buffered" output.
 169  		d.n = d.rate
 170  	} else {
 171  		d.n = len(out) % d.rate
 172  	}
 173  
 174  	return
 175  }
 176  
 177  func (d *Digest) function() code {
 178  	switch d.rate {
 179  	case rateK256:
 180  		return shake_128
 181  	case rateK448:
 182  		return sha3_224
 183  	case rateK512:
 184  		if d.dsbyte == dsbyteSHA3 {
 185  			return sha3_256
 186  		} else {
 187  			return shake_256
 188  		}
 189  	case rateK768:
 190  		return sha3_384
 191  	case rateK1024:
 192  		return sha3_512
 193  	default:
 194  		panic("invalid rate")
 195  	}
 196  }
 197