gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

sha3_s390x.go (6988B)


      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 gc && !purego
      6 // +build gc,!purego
      7 
      8 package sha3
      9 
     10 // This file contains code for using the 'compute intermediate
     11 // message digest' (KIMD) and 'compute last message digest' (KLMD)
     12 // instructions to compute SHA-3 and SHAKE hashes on IBM Z.
     13 
     14 import (
     15 	"hash"
     16 
     17 	"golang.org/x/sys/cpu"
     18 )
     19 
     20 // codes represent 7-bit KIMD/KLMD function codes as defined in
     21 // the Principles of Operation.
     22 type code uint64
     23 
     24 const (
     25 	// function codes for KIMD/KLMD
     26 	sha3_224  code = 32
     27 	sha3_256       = 33
     28 	sha3_384       = 34
     29 	sha3_512       = 35
     30 	shake_128      = 36
     31 	shake_256      = 37
     32 	nopad          = 0x100
     33 )
     34 
     35 // kimd is a wrapper for the 'compute intermediate message digest' instruction.
     36 // src must be a multiple of the rate for the given function code.
     37 //
     38 //go:noescape
     39 func kimd(function code, chain *[200]byte, src []byte)
     40 
     41 // klmd is a wrapper for the 'compute last message digest' instruction.
     42 // src padding is handled by the instruction.
     43 //
     44 //go:noescape
     45 func klmd(function code, chain *[200]byte, dst, src []byte)
     46 
     47 type asmState struct {
     48 	a         [200]byte       // 1600 bit state
     49 	buf       []byte          // care must be taken to ensure cap(buf) is a multiple of rate
     50 	rate      int             // equivalent to block size
     51 	storage   [3072]byte      // underlying storage for buf
     52 	outputLen int             // output length if fixed, 0 if not
     53 	function  code            // KIMD/KLMD function code
     54 	state     spongeDirection // whether the sponge is absorbing or squeezing
     55 }
     56 
     57 func newAsmState(function code) *asmState {
     58 	var s asmState
     59 	s.function = function
     60 	switch function {
     61 	case sha3_224:
     62 		s.rate = 144
     63 		s.outputLen = 28
     64 	case sha3_256:
     65 		s.rate = 136
     66 		s.outputLen = 32
     67 	case sha3_384:
     68 		s.rate = 104
     69 		s.outputLen = 48
     70 	case sha3_512:
     71 		s.rate = 72
     72 		s.outputLen = 64
     73 	case shake_128:
     74 		s.rate = 168
     75 	case shake_256:
     76 		s.rate = 136
     77 	default:
     78 		panic("sha3: unrecognized function code")
     79 	}
     80 
     81 	// limit s.buf size to a multiple of s.rate
     82 	s.resetBuf()
     83 	return &s
     84 }
     85 
     86 func (s *asmState) clone() *asmState {
     87 	c := *s
     88 	c.buf = c.storage[:len(s.buf):cap(s.buf)]
     89 	return &c
     90 }
     91 
     92 // copyIntoBuf copies b into buf. It will panic if there is not enough space to
     93 // store all of b.
     94 func (s *asmState) copyIntoBuf(b []byte) {
     95 	bufLen := len(s.buf)
     96 	s.buf = s.buf[:len(s.buf)+len(b)]
     97 	copy(s.buf[bufLen:], b)
     98 }
     99 
    100 // resetBuf points buf at storage, sets the length to 0 and sets cap to be a
    101 // multiple of the rate.
    102 func (s *asmState) resetBuf() {
    103 	max := (cap(s.storage) / s.rate) * s.rate
    104 	s.buf = s.storage[:0:max]
    105 }
    106 
    107 // Write (via the embedded io.Writer interface) adds more data to the running hash.
    108 // It never returns an error.
    109 func (s *asmState) Write(b []byte) (int, error) {
    110 	if s.state != spongeAbsorbing {
    111 		panic("sha3: write to sponge after read")
    112 	}
    113 	length := len(b)
    114 	for len(b) > 0 {
    115 		if len(s.buf) == 0 && len(b) >= cap(s.buf) {
    116 			// Hash the data directly and push any remaining bytes
    117 			// into the buffer.
    118 			remainder := len(b) % s.rate
    119 			kimd(s.function, &s.a, b[:len(b)-remainder])
    120 			if remainder != 0 {
    121 				s.copyIntoBuf(b[len(b)-remainder:])
    122 			}
    123 			return length, nil
    124 		}
    125 
    126 		if len(s.buf) == cap(s.buf) {
    127 			// flush the buffer
    128 			kimd(s.function, &s.a, s.buf)
    129 			s.buf = s.buf[:0]
    130 		}
    131 
    132 		// copy as much as we can into the buffer
    133 		n := len(b)
    134 		if len(b) > cap(s.buf)-len(s.buf) {
    135 			n = cap(s.buf) - len(s.buf)
    136 		}
    137 		s.copyIntoBuf(b[:n])
    138 		b = b[n:]
    139 	}
    140 	return length, nil
    141 }
    142 
    143 // Read squeezes an arbitrary number of bytes from the sponge.
    144 func (s *asmState) Read(out []byte) (n int, err error) {
    145 	n = len(out)
    146 
    147 	// need to pad if we were absorbing
    148 	if s.state == spongeAbsorbing {
    149 		s.state = spongeSqueezing
    150 
    151 		// write hash directly into out if possible
    152 		if len(out)%s.rate == 0 {
    153 			klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
    154 			s.buf = s.buf[:0]
    155 			return
    156 		}
    157 
    158 		// write hash into buffer
    159 		max := cap(s.buf)
    160 		if max > len(out) {
    161 			max = (len(out)/s.rate)*s.rate + s.rate
    162 		}
    163 		klmd(s.function, &s.a, s.buf[:max], s.buf)
    164 		s.buf = s.buf[:max]
    165 	}
    166 
    167 	for len(out) > 0 {
    168 		// flush the buffer
    169 		if len(s.buf) != 0 {
    170 			c := copy(out, s.buf)
    171 			out = out[c:]
    172 			s.buf = s.buf[c:]
    173 			continue
    174 		}
    175 
    176 		// write hash directly into out if possible
    177 		if len(out)%s.rate == 0 {
    178 			klmd(s.function|nopad, &s.a, out, nil)
    179 			return
    180 		}
    181 
    182 		// write hash into buffer
    183 		s.resetBuf()
    184 		if cap(s.buf) > len(out) {
    185 			s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
    186 		}
    187 		klmd(s.function|nopad, &s.a, s.buf, nil)
    188 	}
    189 	return
    190 }
    191 
    192 // Sum appends the current hash to b and returns the resulting slice.
    193 // It does not change the underlying hash state.
    194 func (s *asmState) Sum(b []byte) []byte {
    195 	if s.outputLen == 0 {
    196 		panic("sha3: cannot call Sum on SHAKE functions")
    197 	}
    198 
    199 	// Copy the state to preserve the original.
    200 	a := s.a
    201 
    202 	// Hash the buffer. Note that we don't clear it because we
    203 	// aren't updating the state.
    204 	klmd(s.function, &a, nil, s.buf)
    205 	return append(b, a[:s.outputLen]...)
    206 }
    207 
    208 // Reset resets the Hash to its initial state.
    209 func (s *asmState) Reset() {
    210 	for i := range s.a {
    211 		s.a[i] = 0
    212 	}
    213 	s.resetBuf()
    214 	s.state = spongeAbsorbing
    215 }
    216 
    217 // Size returns the number of bytes Sum will return.
    218 func (s *asmState) Size() int {
    219 	return s.outputLen
    220 }
    221 
    222 // BlockSize returns the hash's underlying block size.
    223 // The Write method must be able to accept any amount
    224 // of data, but it may operate more efficiently if all writes
    225 // are a multiple of the block size.
    226 func (s *asmState) BlockSize() int {
    227 	return s.rate
    228 }
    229 
    230 // Clone returns a copy of the ShakeHash in its current state.
    231 func (s *asmState) Clone() ShakeHash {
    232 	return s.clone()
    233 }
    234 
    235 // new224Asm returns an assembly implementation of SHA3-224 if available,
    236 // otherwise it returns nil.
    237 func new224Asm() hash.Hash {
    238 	if cpu.S390X.HasSHA3 {
    239 		return newAsmState(sha3_224)
    240 	}
    241 	return nil
    242 }
    243 
    244 // new256Asm returns an assembly implementation of SHA3-256 if available,
    245 // otherwise it returns nil.
    246 func new256Asm() hash.Hash {
    247 	if cpu.S390X.HasSHA3 {
    248 		return newAsmState(sha3_256)
    249 	}
    250 	return nil
    251 }
    252 
    253 // new384Asm returns an assembly implementation of SHA3-384 if available,
    254 // otherwise it returns nil.
    255 func new384Asm() hash.Hash {
    256 	if cpu.S390X.HasSHA3 {
    257 		return newAsmState(sha3_384)
    258 	}
    259 	return nil
    260 }
    261 
    262 // new512Asm returns an assembly implementation of SHA3-512 if available,
    263 // otherwise it returns nil.
    264 func new512Asm() hash.Hash {
    265 	if cpu.S390X.HasSHA3 {
    266 		return newAsmState(sha3_512)
    267 	}
    268 	return nil
    269 }
    270 
    271 // newShake128Asm returns an assembly implementation of SHAKE-128 if available,
    272 // otherwise it returns nil.
    273 func newShake128Asm() ShakeHash {
    274 	if cpu.S390X.HasSHA3 {
    275 		return newAsmState(shake_128)
    276 	}
    277 	return nil
    278 }
    279 
    280 // newShake256Asm returns an assembly implementation of SHAKE-256 if available,
    281 // otherwise it returns nil.
    282 func newShake256Asm() ShakeHash {
    283 	if cpu.S390X.HasSHA3 {
    284 		return newAsmState(shake_256)
    285 	}
    286 	return nil
    287 }