gtsocial-umbx

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

shake.go (5421B)


      1 // Copyright 2014 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 package sha3
      6 
      7 // This file defines the ShakeHash interface, and provides
      8 // functions for creating SHAKE and cSHAKE instances, as well as utility
      9 // functions for hashing bytes to arbitrary-length output.
     10 //
     11 //
     12 // SHAKE implementation is based on FIPS PUB 202 [1]
     13 // cSHAKE implementations is based on NIST SP 800-185 [2]
     14 //
     15 // [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
     16 // [2] https://doi.org/10.6028/NIST.SP.800-185
     17 
     18 import (
     19 	"encoding/binary"
     20 	"io"
     21 )
     22 
     23 // ShakeHash defines the interface to hash functions that
     24 // support arbitrary-length output.
     25 type ShakeHash interface {
     26 	// Write absorbs more data into the hash's state. It panics if input is
     27 	// written to it after output has been read from it.
     28 	io.Writer
     29 
     30 	// Read reads more output from the hash; reading affects the hash's
     31 	// state. (ShakeHash.Read is thus very different from Hash.Sum)
     32 	// It never returns an error.
     33 	io.Reader
     34 
     35 	// Clone returns a copy of the ShakeHash in its current state.
     36 	Clone() ShakeHash
     37 
     38 	// Reset resets the ShakeHash to its initial state.
     39 	Reset()
     40 }
     41 
     42 // cSHAKE specific context
     43 type cshakeState struct {
     44 	*state // SHA-3 state context and Read/Write operations
     45 
     46 	// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
     47 	// by newCShake function and stores concatenation of N followed by S, encoded
     48 	// by the method specified in 3.3 of [1].
     49 	// It is stored here in order for Reset() to be able to put context into
     50 	// initial state.
     51 	initBlock []byte
     52 }
     53 
     54 // Consts for configuring initial SHA-3 state
     55 const (
     56 	dsbyteShake  = 0x1f
     57 	dsbyteCShake = 0x04
     58 	rate128      = 168
     59 	rate256      = 136
     60 )
     61 
     62 func bytepad(input []byte, w int) []byte {
     63 	// leftEncode always returns max 9 bytes
     64 	buf := make([]byte, 0, 9+len(input)+w)
     65 	buf = append(buf, leftEncode(uint64(w))...)
     66 	buf = append(buf, input...)
     67 	padlen := w - (len(buf) % w)
     68 	return append(buf, make([]byte, padlen)...)
     69 }
     70 
     71 func leftEncode(value uint64) []byte {
     72 	var b [9]byte
     73 	binary.BigEndian.PutUint64(b[1:], value)
     74 	// Trim all but last leading zero bytes
     75 	i := byte(1)
     76 	for i < 8 && b[i] == 0 {
     77 		i++
     78 	}
     79 	// Prepend number of encoded bytes
     80 	b[i-1] = 9 - i
     81 	return b[i-1:]
     82 }
     83 
     84 func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
     85 	c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}}
     86 
     87 	// leftEncode returns max 9 bytes
     88 	c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
     89 	c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
     90 	c.initBlock = append(c.initBlock, N...)
     91 	c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
     92 	c.initBlock = append(c.initBlock, S...)
     93 	c.Write(bytepad(c.initBlock, c.rate))
     94 	return &c
     95 }
     96 
     97 // Reset resets the hash to initial state.
     98 func (c *cshakeState) Reset() {
     99 	c.state.Reset()
    100 	c.Write(bytepad(c.initBlock, c.rate))
    101 }
    102 
    103 // Clone returns copy of a cSHAKE context within its current state.
    104 func (c *cshakeState) Clone() ShakeHash {
    105 	b := make([]byte, len(c.initBlock))
    106 	copy(b, c.initBlock)
    107 	return &cshakeState{state: c.clone(), initBlock: b}
    108 }
    109 
    110 // Clone returns copy of SHAKE context within its current state.
    111 func (c *state) Clone() ShakeHash {
    112 	return c.clone()
    113 }
    114 
    115 // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
    116 // Its generic security strength is 128 bits against all attacks if at
    117 // least 32 bytes of its output are used.
    118 func NewShake128() ShakeHash {
    119 	if h := newShake128Asm(); h != nil {
    120 		return h
    121 	}
    122 	return &state{rate: rate128, dsbyte: dsbyteShake}
    123 }
    124 
    125 // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
    126 // Its generic security strength is 256 bits against all attacks if
    127 // at least 64 bytes of its output are used.
    128 func NewShake256() ShakeHash {
    129 	if h := newShake256Asm(); h != nil {
    130 		return h
    131 	}
    132 	return &state{rate: rate256, dsbyte: dsbyteShake}
    133 }
    134 
    135 // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
    136 // a customizable variant of SHAKE128.
    137 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
    138 // desired. S is a customization byte string used for domain separation - two cSHAKE
    139 // computations on same input with different S yield unrelated outputs.
    140 // When N and S are both empty, this is equivalent to NewShake128.
    141 func NewCShake128(N, S []byte) ShakeHash {
    142 	if len(N) == 0 && len(S) == 0 {
    143 		return NewShake128()
    144 	}
    145 	return newCShake(N, S, rate128, dsbyteCShake)
    146 }
    147 
    148 // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
    149 // a customizable variant of SHAKE256.
    150 // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
    151 // desired. S is a customization byte string used for domain separation - two cSHAKE
    152 // computations on same input with different S yield unrelated outputs.
    153 // When N and S are both empty, this is equivalent to NewShake256.
    154 func NewCShake256(N, S []byte) ShakeHash {
    155 	if len(N) == 0 && len(S) == 0 {
    156 		return NewShake256()
    157 	}
    158 	return newCShake(N, S, rate256, dsbyteCShake)
    159 }
    160 
    161 // ShakeSum128 writes an arbitrary-length digest of data into hash.
    162 func ShakeSum128(hash, data []byte) {
    163 	h := NewShake128()
    164 	h.Write(data)
    165 	h.Read(hash)
    166 }
    167 
    168 // ShakeSum256 writes an arbitrary-length digest of data into hash.
    169 func ShakeSum256(hash, data []byte) {
    170 	h := NewShake256()
    171 	h.Write(data)
    172 	h.Read(hash)
    173 }