-
Notifications
You must be signed in to change notification settings - Fork 135
/
example_test.go
79 lines (70 loc) · 2.61 KB
/
example_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package keccakf1600_test
import (
"encoding/binary"
"fmt"
"github.com/cloudflare/circl/internal/sha3"
"github.com/cloudflare/circl/simd/keccakf1600"
)
func Example() {
// 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
}