sha3_test.gno
9.80 Kb ยท 304 lines
1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package keccak256
6
7// Tests include all the ShortMsgKATs provided by the Keccak team at
8// https://github.com/gvanas/KeccakCodePackage
9//
10// They only include the zero-bit case of the bitwise testvectors
11// published by NIST in the draft of FIPS-202.
12
13import (
14 "bytes"
15 "encoding/hex"
16 "hash"
17 "math/rand"
18 "testing"
19)
20
21const (
22 testString = "brekeccakkeccak koax koax"
23 katFilename = "testdata/keccakKats.json.deflate"
24)
25
26// testDigests contains functions returning hash.Hash instances
27// with output-length equal to the KAT length for SHA-3, Keccak
28// and SHAKE instances.
29var testDigests = map[string]func() hash.Hash{
30 "Keccak-256": NewLegacyKeccak256,
31}
32
33// decodeHex converts a hex-encoded string into a raw byte string.
34func decodeHex(s string) []byte {
35 b, err := hex.DecodeString(s)
36 if err != nil {
37 panic(err)
38 }
39 return b
40}
41
42// structs used to marshal JSON test-cases.
43type KeccakKats struct {
44 Kats map[string][]struct {
45 Digest string `json:"digest"`
46 Length int64 `json:"length"`
47 Message string `json:"message"`
48
49 // Defined only for cSHAKE
50 N string `json:"N"`
51 S string `json:"S"`
52 }
53}
54
55// TestKeccakKats tests the SHA-3 and Shake implementations against all the
56// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
57// (The testvectors are stored in keccakKats.json.deflate due to their length.)
58//XXX Do not use "compress/flate"
59/*func TestKeccakKats(t *testing.T) {
60 // Read the KATs.
61 deflated, err := os.Open(katFilename)
62 if err != nil {
63 t.Errorf("error opening %s: %s", katFilename, err)
64 }
65 file := flate.NewReader(deflated)
66 dec := json.NewDecoder(file)
67 var katSet KeccakKats
68 err = dec.Decode(&katSet)
69 if err != nil {
70 t.Errorf("error decoding KATs: %s", err)
71 }
72
73 for algo, function := range testDigests {
74 d := function()
75 for _, kat := range katSet.Kats[algo] {
76 d.Reset()
77 in, err := hex.DecodeString(kat.Message)
78 if err != nil {
79 t.Errorf("error decoding KAT: %s", err)
80 }
81 d.Write(in[:kat.Length/8])
82 got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
83 if got != kat.Digest {
84 t.Errorf("function=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
85 algo, kat.Length, kat.Message, got, kat.Digest)
86 t.Logf("wanted %+v", kat)
87 t.FailNow()
88 }
89 continue
90 }
91 }
92
93 for algo, v := range testShakes {
94 for _, kat := range katSet.Kats[algo] {
95 N, err := hex.DecodeString(kat.N)
96 if err != nil {
97 t.Errorf("error decoding KAT: %s", err)
98 }
99
100 S, err := hex.DecodeString(kat.S)
101 if err != nil {
102 t.Errorf("error decoding KAT: %s", err)
103 }
104 d := v.constructor(N, S)
105 in, err := hex.DecodeString(kat.Message)
106 if err != nil {
107 t.Errorf("error decoding KAT: %s", err)
108 }
109
110 d.Write(in[:kat.Length/8])
111 out := make([]byte, len(kat.Digest)/2)
112 d.Read(out)
113 got := strings.ToUpper(hex.EncodeToString(out))
114 if got != kat.Digest {
115 t.Errorf("function=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n %s\nwanted:\n %s",
116 algo, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest)
117 t.Logf("wanted %+v", kat)
118 t.FailNow()
119 }
120 continue
121 }
122 }
123}*/
124
125// TestKeccak does a basic test of the non-standardized Keccak hash functions.
126func TestKeccak(t *testing.T) {
127 tests := []struct {
128 fn func() hash.Hash
129 data []byte
130 want string
131 }{
132
133 {
134 NewLegacyKeccak256,
135 []byte("There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text"),
136 "39670cbdfbfc25519e9834899e13569e5f5802b77df3d8259961f713ad09745d",
137 },
138 {
139 NewLegacyKeccak256,
140 []byte("abc"),
141 "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
142 },
143 {
144 NewLegacyKeccak256,
145 []byte("916889520661998333947422699691"),
146 "c5b223cc231dd56389ca19435758fba38e79f3c461d989d818ceb96595d310d1",
147 },
148 {
149 NewLegacyKeccak256,
150 []byte("6R1Q2KvQNGxI4OtUGDS1rSCbJXkp1H"),
151 "8e94c6d49ca23597ee1d4a317b17a85ae38f6f3241e11c3ace4abe756287839a",
152 },
153 {
154 NewLegacyKeccak256,
155 []byte("SOMERANDOMSTRING"),
156 "59f47b8dc1ffdfb716d2fcb313c070040f6049bd23c321c6cb8adb3f79eb720f",
157 },
158 {
159 NewLegacyKeccak256,
160 []byte("Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC"),
161 "da5293ad50619d7fdac8b4c8dc2f80e0cd40b6571be14740229d0a1d6e2fc232",
162 },
163 {
164 NewLegacyKeccak256,
165 []byte("There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."),
166 "a84506d23b7246dc18805c8bf60316fb6f677934a546ee8d8650495929f21eef",
167 },
168 }
169
170 for _, u := range tests {
171 h := u.fn()
172 h.Write(u.data)
173 got := h.Sum(nil)
174 want := decodeHex(u.want)
175 if !bytes.Equal(got, want) {
176 t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want)
177 }
178 }
179}
180
181func TestHash(t *testing.T) {
182 tests := []struct {
183 data []byte
184 want string
185 }{
186
187 {
188
189 []byte("There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text"),
190 "39670cbdfbfc25519e9834899e13569e5f5802b77df3d8259961f713ad09745d",
191 },
192 {
193
194 []byte("abc"),
195 "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
196 },
197 {
198
199 []byte("916889520661998333947422699691"),
200 "c5b223cc231dd56389ca19435758fba38e79f3c461d989d818ceb96595d310d1",
201 },
202 {
203
204 []byte("6R1Q2KvQNGxI4OtUGDS1rSCbJXkp1H"),
205 "8e94c6d49ca23597ee1d4a317b17a85ae38f6f3241e11c3ace4abe756287839a",
206 },
207 {
208
209 []byte("SOMERANDOMSTRING"),
210 "59f47b8dc1ffdfb716d2fcb313c070040f6049bd23c321c6cb8adb3f79eb720f",
211 },
212 {
213
214 []byte("Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC"),
215 "da5293ad50619d7fdac8b4c8dc2f80e0cd40b6571be14740229d0a1d6e2fc232",
216 },
217 {
218
219 []byte("There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."),
220 "a84506d23b7246dc18805c8bf60316fb6f677934a546ee8d8650495929f21eef",
221 },
222 }
223
224 for _, u := range tests {
225 got := Hash(u.data)
226 want := decodeHex(u.want)
227 if !bytes.Equal(got[:], want) {
228 t.Errorf("unexpected hash: got '%x' want '%s'", got, u.want)
229 }
230 }
231}
232
233// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
234//
235// The alignment of each slice is intentionally randomized to detect alignment
236// issues in the implementation. See https://golang.org/issue/37644.
237// Ideally, the compiler should fuzz the alignment itself.
238// (See https://golang.org/issue/35128.)
239func sequentialBytes(size int) []byte {
240 alignmentOffset := rand.IntN(8)
241 result := make([]byte, size+alignmentOffset)[alignmentOffset:]
242 for i := range result {
243 result[i] = byte(i)
244 }
245 return result
246}
247
248/*func TestMarshalUnmarshal(t *testing.T) {
249 t.Run("Keccak-256", func(t *testing.T) { testMarshalUnmarshal(t, NewLegacyKeccak256()) })
250}*/
251
252// TODO(filippo): move this to crypto/internal/cryptotest.
253//XX: remove rand.Read
254/*func testMarshalUnmarshal(t *testing.T, h hash.Hash) {
255 buf := make([]byte, 200)
256 rand.Read(buf)
257 n := rand.IntN(200)
258 h.Write(buf)
259 want := h.Sum(nil)
260 h.Reset()
261 h.Write(buf[:n])
262 b, err := h.(encoding.BinaryMarshaler).MarshalBinary()
263 if err != nil {
264 t.Errorf("MarshalBinary: %v", err)
265 }
266 h.Write(bytes.Repeat([]byte{0}, 200))
267 if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary(b); err != nil {
268 t.Errorf("UnmarshalBinary: %v", err)
269 }
270 h.Write(buf[n:])
271 got := h.Sum(nil)
272 if !bytes.Equal(got, want) {
273 t.Errorf("got %x, want %x", got, want)
274 }
275}*/
276
277// BenchmarkPermutationFunction measures the speed of the permutation function
278// with no input data.
279func BenchmarkPermutationFunction(b *testing.B) {
280 b.SetBytes(int64(200))
281 var lanes [25]uint64
282 for i := 0; i < b.N; i++ {
283 keccakF1600(&lanes)
284 }
285}
286
287// benchmarkHash tests the speed to hash num buffers of buflen each.
288func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
289 b.StopTimer()
290 h.Reset()
291 data := sequentialBytes(size)
292 b.SetBytes(int64(size * num))
293 b.StartTimer()
294
295 var state []byte
296 for i := 0; i < b.N; i++ {
297 for j := 0; j < num; j++ {
298 h.Write(data)
299 }
300 state = h.Sum(state[:0])
301 }
302 b.StopTimer()
303 h.Reset()
304}