github.com/cloudflare/circl@v1.5.0/simd/keccakf1600/example_test.go (about)

     1  package keccakf1600_test
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	"github.com/cloudflare/circl/internal/sha3"
     8  	"github.com/cloudflare/circl/simd/keccakf1600"
     9  )
    10  
    11  func Example() {
    12  	// As an example, computes the (first 32 bytes of a) SHAKE-256 stream of
    13  	// four short strings at the same time.
    14  	msgs := [4][]byte{
    15  		[]byte("These are some short"),
    16  		[]byte("strings of the same "),
    17  		[]byte("length that fit in a"),
    18  		[]byte("single block.       "),
    19  	}
    20  	var hashes [4][32]byte
    21  
    22  	// The user could branch to a fast non-SIMD implementation if this function
    23  	// returns false.
    24  	if !keccakf1600.IsEnabledX4() {
    25  		// Compute hashes separately using golang.org/x/crypto/sha3 instead
    26  		// when a fast four-way implementation is not available.  A generic
    27  		// keccakf1600 implementation is quite a bit slower than using
    28  		// the non-interleaved hashes because of the need to interleave and
    29  		// deinterleave the state.
    30  		for i := 0; i < 4; i++ {
    31  			h := sha3.NewShake256()
    32  			_, _ = h.Write(msgs[i])
    33  			_, _ = h.Read(hashes[i][:])
    34  		}
    35  	} else {
    36  		// f1600 acts on 1600 bits arranged as 25 uint64s.  Our fourway f1600
    37  		// acts on four interleaved states; that is a [100]uint64.  (A separate
    38  		// type is used to ensure that the encapsulated [100]uint64 is aligned
    39  		// properly to be used efficiently with vector instructions.)
    40  		var perm keccakf1600.StateX4
    41  		state := perm.Initialize(false)
    42  
    43  		// state is initialized with zeroes.  As the messages fit within one
    44  		// block, we only need to write the messages, domain separators
    45  		// and padding.
    46  		for i := 0; i < 4; i++ {
    47  			// The messages.
    48  			state[i] = binary.LittleEndian.Uint64(msgs[i][:8])
    49  			state[4+i] = binary.LittleEndian.Uint64(msgs[i][8:16])
    50  
    51  			// Final bit of the message together with the SHAKE-256 domain
    52  			// separator (0b1111) and the start of the padding (0b10....)
    53  			state[8+i] = uint64(binary.LittleEndian.Uint32(msgs[i][16:])) |
    54  				(uint64(0x1f) << 32)
    55  			state[16*4+i] = 0x80 << 56 // end of padding (0b...01)
    56  		}
    57  
    58  		// Executes the permutation on state.
    59  		perm.Permute()
    60  
    61  		// As our desired output fits within one block, we can read it without
    62  		// repeating the permutation.
    63  		for i := 0; i < 4; i++ {
    64  			for j := 0; j < 4; j++ {
    65  				binary.LittleEndian.PutUint64(
    66  					hashes[i][8*j:8*(j+1)],
    67  					state[4*j+i],
    68  				)
    69  			}
    70  		}
    71  	}
    72  
    73  	fmt.Printf("\n%x\n%x\n%x\n%x\n", hashes[0], hashes[1], hashes[2], hashes[3])
    74  	// Output:
    75  	// 9b48efc4f4e562fe28c510b2ad3966b101ac20066dc88117d85a595cc965f7e4
    76  	// 19333d8bb71edce81f0630e4154abea83bf7d2f7e709d62fda878b6e9db9c9c1
    77  	// 28f31cc0b8d95185fbba5c4ed5cd94ed7dba0e13c21ca830d1325a212defdfc5
    78  	// 51392299d6b10e62b98eb02c9540784046cc9c83e46eddd2ce57cddc2037f917
    79  }