123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- // 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.
- // +build !gccgo,!appengine
- package sha3
- // 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.
- import (
- "hash"
- "golang.org/x/sys/cpu"
- )
- // codes represent 7-bit KIMD/KLMD function codes as defined in
- // the Principles of Operation.
- type code uint64
- const (
- // function codes for KIMD/KLMD
- sha3_224 code = 32
- sha3_256 = 33
- sha3_384 = 34
- sha3_512 = 35
- shake_128 = 36
- shake_256 = 37
- nopad = 0x100
- )
- // kimd is a wrapper for the 'compute intermediate message digest' instruction.
- // src must be a multiple of the rate for the given function code.
- //go:noescape
- func kimd(function code, chain *[200]byte, src []byte)
- // klmd is a wrapper for the 'compute last message digest' instruction.
- // src padding is handled by the instruction.
- //go:noescape
- func klmd(function code, chain *[200]byte, dst, src []byte)
- type asmState struct {
- a [200]byte // 1600 bit state
- buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
- rate int // equivalent to block size
- storage [3072]byte // underlying storage for buf
- outputLen int // output length if fixed, 0 if not
- function code // KIMD/KLMD function code
- state spongeDirection // whether the sponge is absorbing or squeezing
- }
- func newAsmState(function code) *asmState {
- var s asmState
- s.function = function
- switch function {
- case sha3_224:
- s.rate = 144
- s.outputLen = 28
- case sha3_256:
- s.rate = 136
- s.outputLen = 32
- case sha3_384:
- s.rate = 104
- s.outputLen = 48
- case sha3_512:
- s.rate = 72
- s.outputLen = 64
- case shake_128:
- s.rate = 168
- case shake_256:
- s.rate = 136
- default:
- panic("sha3: unrecognized function code")
- }
- // limit s.buf size to a multiple of s.rate
- s.resetBuf()
- return &s
- }
- func (s *asmState) clone() *asmState {
- c := *s
- c.buf = c.storage[:len(s.buf):cap(s.buf)]
- return &c
- }
- // copyIntoBuf copies b into buf. It will panic if there is not enough space to
- // store all of b.
- func (s *asmState) copyIntoBuf(b []byte) {
- bufLen := len(s.buf)
- s.buf = s.buf[:len(s.buf)+len(b)]
- copy(s.buf[bufLen:], b)
- }
- // resetBuf points buf at storage, sets the length to 0 and sets cap to be a
- // multiple of the rate.
- func (s *asmState) resetBuf() {
- max := (cap(s.storage) / s.rate) * s.rate
- s.buf = s.storage[:0:max]
- }
- // Write (via the embedded io.Writer interface) adds more data to the running hash.
- // It never returns an error.
- func (s *asmState) Write(b []byte) (int, error) {
- if s.state != spongeAbsorbing {
- panic("sha3: write to sponge after read")
- }
- length := len(b)
- for len(b) > 0 {
- if len(s.buf) == 0 && len(b) >= cap(s.buf) {
- // Hash the data directly and push any remaining bytes
- // into the buffer.
- remainder := len(s.buf) % s.rate
- kimd(s.function, &s.a, b[:len(b)-remainder])
- if remainder != 0 {
- s.copyIntoBuf(b[len(b)-remainder:])
- }
- return length, nil
- }
- if len(s.buf) == cap(s.buf) {
- // flush the buffer
- kimd(s.function, &s.a, s.buf)
- s.buf = s.buf[:0]
- }
- // copy as much as we can into the buffer
- n := len(b)
- if len(b) > cap(s.buf)-len(s.buf) {
- n = cap(s.buf) - len(s.buf)
- }
- s.copyIntoBuf(b[:n])
- b = b[n:]
- }
- return length, nil
- }
- // Read squeezes an arbitrary number of bytes from the sponge.
- func (s *asmState) Read(out []byte) (n int, err error) {
- n = len(out)
- // need to pad if we were absorbing
- if s.state == spongeAbsorbing {
- s.state = spongeSqueezing
- // write hash directly into out if possible
- if len(out)%s.rate == 0 {
- klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
- s.buf = s.buf[:0]
- return
- }
- // write hash into buffer
- max := cap(s.buf)
- if max > len(out) {
- max = (len(out)/s.rate)*s.rate + s.rate
- }
- klmd(s.function, &s.a, s.buf[:max], s.buf)
- s.buf = s.buf[:max]
- }
- for len(out) > 0 {
- // flush the buffer
- if len(s.buf) != 0 {
- c := copy(out, s.buf)
- out = out[c:]
- s.buf = s.buf[c:]
- continue
- }
- // write hash directly into out if possible
- if len(out)%s.rate == 0 {
- klmd(s.function|nopad, &s.a, out, nil)
- return
- }
- // write hash into buffer
- s.resetBuf()
- if cap(s.buf) > len(out) {
- s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
- }
- klmd(s.function|nopad, &s.a, s.buf, nil)
- }
- return
- }
- // Sum appends the current hash to b and returns the resulting slice.
- // It does not change the underlying hash state.
- func (s *asmState) Sum(b []byte) []byte {
- if s.outputLen == 0 {
- panic("sha3: cannot call Sum on SHAKE functions")
- }
- // Copy the state to preserve the original.
- a := s.a
- // Hash the buffer. Note that we don't clear it because we
- // aren't updating the state.
- klmd(s.function, &a, nil, s.buf)
- return append(b, a[:s.outputLen]...)
- }
- // Reset resets the Hash to its initial state.
- func (s *asmState) Reset() {
- for i := range s.a {
- s.a[i] = 0
- }
- s.resetBuf()
- s.state = spongeAbsorbing
- }
- // Size returns the number of bytes Sum will return.
- func (s *asmState) Size() int {
- return s.outputLen
- }
- // BlockSize returns the hash's underlying block size.
- // The Write method must be able to accept any amount
- // of data, but it may operate more efficiently if all writes
- // are a multiple of the block size.
- func (s *asmState) BlockSize() int {
- return s.rate
- }
- // Clone returns a copy of the ShakeHash in its current state.
- func (s *asmState) Clone() ShakeHash {
- return s.clone()
- }
- // new224Asm returns an assembly implementation of SHA3-224 if available,
- // otherwise it returns nil.
- func new224Asm() hash.Hash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(sha3_224)
- }
- return nil
- }
- // new256Asm returns an assembly implementation of SHA3-256 if available,
- // otherwise it returns nil.
- func new256Asm() hash.Hash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(sha3_256)
- }
- return nil
- }
- // new384Asm returns an assembly implementation of SHA3-384 if available,
- // otherwise it returns nil.
- func new384Asm() hash.Hash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(sha3_384)
- }
- return nil
- }
- // new512Asm returns an assembly implementation of SHA3-512 if available,
- // otherwise it returns nil.
- func new512Asm() hash.Hash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(sha3_512)
- }
- return nil
- }
- // newShake128Asm returns an assembly implementation of SHAKE-128 if available,
- // otherwise it returns nil.
- func newShake128Asm() ShakeHash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(shake_128)
- }
- return nil
- }
- // newShake256Asm returns an assembly implementation of SHAKE-256 if available,
- // otherwise it returns nil.
- func newShake256Asm() ShakeHash {
- if cpu.S390X.HasSHA3 {
- return newAsmState(shake_256)
- }
- return nil
- }
|