keccakf1600

package
v1.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2023 License: BSD-3-Clause Imports: 4 Imported by: 0

Documentation

Overview

Package keccakf1600 provides a two and four-way Keccak-f[1600] permutation in parallel.

Keccak-f[1600] is the permutation underlying several algorithms such as Keccak, SHA3 and SHAKE. Running two or four permutations in parallel is useful in some scenarios like in hash-based signatures.

Limitations

Note that not all the architectures support SIMD instructions. This package uses AVX2 instructions that are available in some AMD64 architectures and NEON instructions that are available in some ARM64 architectures.

For those systems not supporting these, the package still provides the expected functionality by means of a generic and slow implementation. The recommendation is to beforehand verify IsEnabledX4() and IsEnabledX2() to determine if the current system supports the SIMD implementation.

Example
package main

import (
	"encoding/binary"
	"fmt"

	"github.com/ReallyMeLabs/circl/internal/sha3"
	"github.com/ReallyMeLabs/circl/simd/keccakf1600"
)

func main() {
	// As an example, computes the (first 32 bytes of a) SHAKE-256 stream of
	// four short strings at the same time.
	msgs := [4][]byte{
		[]byte("These are some short"),
		[]byte("strings of the same "),
		[]byte("length that fit in a"),
		[]byte("single block.       "),
	}
	var hashes [4][32]byte

	// The user could branch to a fast non-SIMD implementation if this function
	// returns false.
	if !keccakf1600.IsEnabledX4() {
		// Compute hashes separately using golang.org/x/crypto/sha3 instead
		// when a fast four-way implementation is not available.  A generic
		// keccakf1600 implementation is quite a bit slower than using
		// the non-interleaved hashes because of the need to interleave and
		// deinterleave the state.
		for i := 0; i < 4; i++ {
			h := sha3.NewShake256()
			_, _ = h.Write(msgs[i])
			_, _ = h.Read(hashes[i][:])
		}
	} else {
		// f1600 acts on 1600 bits arranged as 25 uint64s.  Our fourway f1600
		// acts on four interleaved states; that is a [100]uint64.  (A separate
		// type is used to ensure that the encapsulated [100]uint64 is aligned
		// properly to be used efficiently with vector instructions.)
		var perm keccakf1600.StateX4
		state := perm.Initialize(false)

		// state is initialized with zeroes.  As the messages fit within one
		// block, we only need to write the messages, domain separators
		// and padding.
		for i := 0; i < 4; i++ {
			// The messages.
			state[i] = binary.LittleEndian.Uint64(msgs[i][:8])
			state[4+i] = binary.LittleEndian.Uint64(msgs[i][8:16])

			// Final bit of the message together with the SHAKE-256 domain
			// separator (0b1111) and the start of the padding (0b10....)
			state[8+i] = uint64(binary.LittleEndian.Uint32(msgs[i][16:])) |
				(uint64(0x1f) << 32)
			state[16*4+i] = 0x80 << 56 // end of padding (0b...01)
		}

		// Executes the permutation on state.
		perm.Permute()

		// As our desired output fits within one block, we can read it without
		// repeating the permutation.
		for i := 0; i < 4; i++ {
			for j := 0; j < 4; j++ {
				binary.LittleEndian.PutUint64(
					hashes[i][8*j:8*(j+1)],
					state[4*j+i],
				)
			}
		}
	}

	fmt.Printf("\n%x\n%x\n%x\n%x\n", hashes[0], hashes[1], hashes[2], hashes[3])
}
Output:

9b48efc4f4e562fe28c510b2ad3966b101ac20066dc88117d85a595cc965f7e4
19333d8bb71edce81f0630e4154abea83bf7d2f7e709d62fda878b6e9db9c9c1
28f31cc0b8d95185fbba5c4ed5cd94ed7dba0e13c21ca830d1325a212defdfc5
51392299d6b10e62b98eb02c9540784046cc9c83e46eddd2ce57cddc2037f917

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsEnabledX2

func IsEnabledX2() bool

IsEnabledX2 returns true if the architecture supports a two-way SIMD implementation provided in this package.

func IsEnabledX4

func IsEnabledX4() bool

IsEnabledX4 returns true if the architecture supports a four-way SIMD implementation provided in this package.

Types

type StateX2

type StateX2 struct {
	// contains filtered or unexported fields
}

StateX2 contains state for the two-way permutation including the two interleaved [25]uint64 buffers. Call Initialize() before use to initialize and get a pointer to the interleaved buffer.

func (*StateX2) Initialize

func (s *StateX2) Initialize(turbo bool) []uint64

Initialize the state and returns the buffer on which the two permutations will act: a uint64 slice of length 50. The first permutation will act on {a[0], a[2], ..., a[48]} and the second on {a[1], a[3], ..., a[49]}. If turbo is true, applies 12-round variant instead of the usual 24.

func (*StateX2) Permute

func (s *StateX2) Permute()

Permute performs the two parallel Keccak-f[1600]s interleaved on the slice returned from Initialize().

type StateX4

type StateX4 struct {
	// contains filtered or unexported fields
}

StateX4 contains state for the four-way permutation including the four interleaved [25]uint64 buffers. Call Initialize() before use to initialize and get a pointer to the interleaved buffer.

func (*StateX4) Initialize

func (s *StateX4) Initialize(turbo bool) []uint64

Initialize the state and returns the buffer on which the four permutations will act: a uint64 slice of length 100. The first permutation will act on {a[0], a[4], ..., a[96]}, the second on {a[1], a[5], ..., a[97]}, etc. If turbo is true, applies 12-round variant instead of the usual 24.

func (*StateX4) Permute

func (s *StateX4) Permute()

Permute performs the four parallel Keccak-f[1600]s interleaved on the slice returned from Initialize().

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL