github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/common/hash/sha3.go (about)

     1  package hash
     2  
     3  import (
     4  	"encoding/binary"
     5  )
     6  
     7  // All functions are copied and modified from golang.org/x/crypto/sha3
     8  // This is a specific version of sha3 optimized only for the functions in
     9  // this package and must not be used elsewhere
    10  //
    11  // Copyright (c) 2009 The Go Authors. All rights reserved.
    12  
    13  // Redistribution and use in source and binary forms, with or without
    14  // modification, are permitted provided that the following conditions are
    15  // met:
    16  
    17  //    * Redistributions of source code must retain the above copyright
    18  // notice, this list of conditions and the following disclaimer.
    19  //    * Redistributions in binary form must reproduce the above
    20  // copyright notice, this list of conditions and the following disclaimer
    21  // in the documentation and/or other materials provided with the
    22  // distribution.
    23  //    * Neither the name of Google Inc. nor the names of its
    24  // contributors may be used to endorse or promote products derived from
    25  // this software without specific prior written permission.
    26  
    27  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    28  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    29  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    30  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    31  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    32  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    33  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    34  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    35  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    36  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    37  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    38  
    39  const (
    40  	// rate is size of the internal buffer.
    41  	rate = 136
    42  
    43  	// state size in 64-bit words
    44  	stateSize = 1600 / 64
    45  
    46  	// dsbyte contains the "domain separation" bits and the first bit of
    47  	// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
    48  	// SHA-3 and SHAKE functions by appending bitstrings to the message.
    49  	// Using a little-endian bit-ordering convention, these are "01" for SHA-3
    50  	// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
    51  	// padding rule from section 5.1 is applied to pad the message to a multiple
    52  	// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
    53  	// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
    54  	// giving 00000110b (0x06) and 00011111b (0x1f).
    55  	// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
    56  	//     "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
    57  	//      Extendable-Output Functions (May 2014)"
    58  	dsbyte     = byte(0x06)
    59  	paddingEnd = uint64(1 << 63)
    60  )
    61  
    62  type state struct {
    63  	a [stateSize]uint64 // main state of the hash
    64  }
    65  
    66  // xor a buffer into the state at a given index.
    67  func xorInAtIndex(d *state, buf []byte, index int) {
    68  	n := len(buf) >> 3
    69  	aAtIndex := d.a[index:]
    70  
    71  	for i := 0; i < n; i++ {
    72  		a := binary.LittleEndian.Uint64(buf)
    73  		aAtIndex[i] ^= a
    74  		buf = buf[8:]
    75  	}
    76  }
    77  
    78  func (d *state) hash256Plus(p1 Hash, p2 []byte) Hash {
    79  	//write p1 into the state
    80  	copyIn256(d, p1)
    81  	written := 32 // written bytes in the state
    82  
    83  	for len(p2)+written >= rate {
    84  		xorInAtIndex(d, p2[:rate-written], written>>3)
    85  		keccakF1600(&d.a)
    86  		p2 = p2[rate-written:]
    87  		written = 0
    88  	}
    89  
    90  	// xorIn the left over bytes of p2, 64 bits at a time
    91  	for len(p2) >= 8 {
    92  		a := binary.LittleEndian.Uint64(p2[:8])
    93  		d.a[written>>3] ^= a
    94  		p2 = p2[8:]
    95  		written += 8
    96  	}
    97  
    98  	var tmp [8]byte
    99  	copy(tmp[:], p2)
   100  	tmp[len(p2)] = dsbyte
   101  	a := binary.LittleEndian.Uint64(tmp[:])
   102  	d.a[written>>3] ^= a
   103  
   104  	// the last padding
   105  	d.a[16] ^= paddingEnd
   106  
   107  	// permute
   108  	keccakF1600(&d.a)
   109  
   110  	// reverse and output
   111  	return copyOut(d)
   112  }
   113  
   114  // hash256plus256 absorbs two 256 bits slices of data into the hash's state
   115  // applies the permutation, and outpute the result in out
   116  func (d *state) hash256plus256(p1, p2 Hash) Hash {
   117  	copyIn512(d, p1, p2)
   118  	// permute
   119  	keccakF1600(&d.a)
   120  	// reverse the endianess to the output
   121  	return copyOut(d)
   122  }