github.com/onflow/flow-go/crypto@v0.24.8/hash/keccak.go (about)

     1  package hash
     2  
     3  // Size returns the output size of the hash function in bytes.
     4  func (d *spongeState) Size() int {
     5  	return d.outputLen
     6  }
     7  
     8  // Algorithm returns the hashing algorithm of the instance.
     9  func (s *spongeState) Algorithm() HashingAlgorithm {
    10  	return s.algo
    11  }
    12  
    13  // ComputeHash calculates and returns the digest of the input.
    14  // It updates the state (and therefore not thread-safe) and doesn't allow
    15  // further writing without calling Reset().
    16  func (s *spongeState) ComputeHash(data []byte) Hash {
    17  	s.Reset()
    18  	s.write(data)
    19  	return s.sum()
    20  }
    21  
    22  // SumHash returns the digest of the data written to the state.
    23  // It updates the state and doesn't allow further writing without
    24  // calling Reset().
    25  func (s *spongeState) SumHash() Hash {
    26  	return s.sum()
    27  }
    28  
    29  // Write absorbs more data into the hash's state.
    30  // It returns the number of bytes written and never errors.
    31  func (d *spongeState) Write(p []byte) (int, error) {
    32  	d.write(p)
    33  	return len(p), nil
    34  }
    35  
    36  // The functions below were copied and modified from golang.org/x/crypto/sha3.
    37  //
    38  // Copyright (c) 2009 The Go Authors. All rights reserved.
    39  
    40  // Redistribution and use in source and binary forms, with or without
    41  // modification, are permitted provided that the following conditions are
    42  // met:
    43  
    44  //    * Redistributions of source code must retain the above copyright
    45  // notice, this list of conditions and the following disclaimer.
    46  //    * Redistributions in binary form must reproduce the above
    47  // copyright notice, this list of conditions and the following disclaimer
    48  // in the documentation and/or other materials provided with the
    49  // distribution.
    50  //    * Neither the name of Google Inc. nor the names of its
    51  // contributors may be used to endorse or promote products derived from
    52  // this software without specific prior written permission.
    53  
    54  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    55  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    56  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    57  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    58  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    59  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    60  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    61  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    62  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    63  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    64  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    65  
    66  type spongeState struct {
    67  	// the hashing algorithm name
    68  	algo HashingAlgorithm
    69  
    70  	a       [25]uint64 // main state of the hash
    71  	storage storageBuf // constant size array
    72  	// `buf` is a sub-slice that points into `storage` using `bufIndex` and `bufSize`:
    73  	// - `bufIndex` is the index of the first element of buf
    74  	// - `bufSize` is the size of buf
    75  	bufIndex int
    76  	bufSize  int
    77  	rate     int // the number of bytes of state to use
    78  	// dsbyte contains the domain separation bits (if any are defined)
    79  	// and the first bit of the 10*1 padding.
    80  	// Using a little-endian bit-ordering convention, it is 0b01 for SHA-3
    81  	// and not defined for legacy Keccak.
    82  	// The padding 10*1 is applied to pad the message to a multiple
    83  	// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
    84  	// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
    85  	// ( giving 0b00000110 for SHA-3 and 0b00000001 for legacy Keccak)
    86  	// [1] https://keccak.team/sponge_duplex.html
    87  	//     "The sponge and duplex constructions"
    88  	dsByte    byte // the domain separation byte with one bit padding
    89  	outputLen int  // the default output size in bytes
    90  }
    91  
    92  const (
    93  	// maxRate is the maximum size of the internal buffer. SHA3-256
    94  	// currently needs the largest buffer among supported sponge-based
    95  	// algorithms.
    96  	maxRate = rateSHA3_256
    97  
    98  	// initialization value of the buffer index
    99  	bufNilValue = -1
   100  )
   101  
   102  // returns the current buf
   103  func (d *spongeState) buf() []byte {
   104  	return d.storage.asBytes()[d.bufIndex : d.bufIndex+d.bufSize]
   105  }
   106  
   107  // setBuf assigns `buf` (sub-slice of `storage`) to a sub-slice of `storage`
   108  // defined by a starting index and size.
   109  func (d *spongeState) setBuf(start, size int) {
   110  	d.bufIndex = start
   111  	d.bufSize = size
   112  }
   113  
   114  // checks if `buf` is nil (not yet set)
   115  func (d *spongeState) bufIsNil() bool {
   116  	return d.bufSize == bufNilValue
   117  }
   118  
   119  // appendBuf appends a slice to `buf` (sub-slice of `storage`)
   120  // The function assumes the appended buffer still fits into `storage`.
   121  func (d *spongeState) appendBuf(slice []byte) {
   122  	copy(d.storage.asBytes()[d.bufIndex+d.bufSize:], slice)
   123  	d.bufSize += len(slice)
   124  }
   125  
   126  // Reset clears the internal state.
   127  func (d *spongeState) Reset() {
   128  	// Zero the permutation's state.
   129  	for i := range d.a {
   130  		d.a[i] = 0
   131  	}
   132  	d.setBuf(0, 0)
   133  }
   134  
   135  // permute applies the KeccakF-1600 permutation.
   136  func (d *spongeState) permute() {
   137  	// xor the input into the state before applying the permutation.
   138  	xorIn(d, d.buf())
   139  	d.setBuf(0, 0)
   140  	keccakF1600(&d.a)
   141  }
   142  
   143  func (d *spongeState) write(p []byte) {
   144  	if d.bufIsNil() {
   145  		d.setBuf(0, 0)
   146  	}
   147  
   148  	for len(p) > 0 {
   149  		if d.bufSize == 0 && len(p) >= d.rate {
   150  			// The fast path; absorb a full "rate" bytes of input and apply the permutation.
   151  			xorIn(d, p[:d.rate])
   152  			p = p[d.rate:]
   153  			keccakF1600(&d.a)
   154  		} else {
   155  			// The slow path; buffer the input until we can fill the sponge, and then xor it in.
   156  			todo := d.rate - d.bufSize
   157  			if todo > len(p) {
   158  				todo = len(p)
   159  			}
   160  			d.appendBuf(p[:todo])
   161  			p = p[todo:]
   162  
   163  			// If the sponge is full, apply the permutation.
   164  			if d.bufSize == d.rate {
   165  				d.permute()
   166  			}
   167  		}
   168  	}
   169  }
   170  
   171  // pads appends the domain separation bits in dsbyte, applies
   172  // the multi-bitrate 10..1 padding rule, and permutes the state.
   173  func (d *spongeState) padAndPermute() {
   174  	if d.bufIsNil() {
   175  		d.setBuf(0, 0)
   176  	}
   177  	// Pad with this instance with dsbyte. We know that there's
   178  	// at least one byte of space in d.buf because, if it were full,
   179  	// permute would have been called to empty it. dsbyte also contains the
   180  	// first one bit for the padding. See the comment in the state struct.
   181  	d.appendBuf([]byte{d.dsByte})
   182  	zerosStart := d.bufSize
   183  	d.setBuf(0, d.rate)
   184  	buf := d.buf()
   185  	for i := zerosStart; i < d.rate; i++ {
   186  		buf[i] = 0
   187  	}
   188  	// This adds the final one bit for the padding. Because of the way that
   189  	// bits are numbered from the LSB upwards, the final bit is the MSB of
   190  	// the last byte.
   191  	buf[d.rate-1] ^= 0x80
   192  	// Apply the permutation
   193  	d.permute()
   194  	d.setBuf(0, d.rate)
   195  }
   196  
   197  // Sum applies padding to the hash state and then squeezes out the desired
   198  // number of output bytes.
   199  func (d *spongeState) sum() []byte {
   200  	hash := make([]byte, d.outputLen)
   201  	d.padAndPermute()
   202  	copyOut(hash, d)
   203  	return hash
   204  }