v2 / vlib / crypto / sha3 / sha3_state_generic.v
186 lines · 162 sloc · 5.95 KB · 65cf633e76e1786f352e689856d6b38ec0ce7334
Raw
1// Copyright (c) 2023 Kim Shrier. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// Package sha3 implements the 512, 384, 256, and 224
5// bit hash algorithms and the 128 and 256 bit
6// extended output functions as defined in
7// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf.
8// Last updated: August 2015
9module sha3
10
11import encoding.binary
12import math.bits
13
14// when the state is 1600 bits, a lane is 64 bits
15type Lane = u64
16
17// the state is a 5 x 5 array of lanes
18struct State {
19mut:
20 a [5][5]Lane
21}
22
23// to_bytes converts the state into a byte array
24//
25// A 1600 bit state fits into 200 bytes.
26//
27// The state consists of 25 u64 values arranged in a
28// 5 x 5 array.
29//
30// The state is not modified by this method.
31@[direct_array_access]
32fn (s State) to_bytes() []u8 {
33 mut byte_array := []u8{len: 200}
34 mut index := 0
35
36 for y in 0 .. 5 {
37 for x in 0 .. 5 {
38 unsafe {
39 binary.little_endian_put_u64_at(mut byte_array, s.a[x][y], index)
40 }
41 index += 8
42 }
43 }
44
45 return byte_array
46}
47
48// from_bytes sets the state from an array of bytes
49//
50// A 1600 bit state fits into 200 bytes. It is expected
51// that the input byte array is 200 bytes long.
52//
53// All 25 u64 values are set from the input byte array.
54@[direct_array_access]
55fn (mut s State) from_bytes(byte_array []u8) {
56 mut index := 0
57
58 for y in 0 .. 5 {
59 for x in 0 .. 5 {
60 s.a[x][y] = binary.little_endian_u64_at(byte_array, index)
61 index += 8
62 }
63 }
64}
65
66// xor_bytes xor's an array of bytes into the state
67//
68// This is how new data gets absorbed into the sponge.
69//
70// It is expected that the length of the byte array is
71// the same as the rate. The rate is how many bytes
72// can be absorbed at one permutation of the state.
73//
74// The rate must be less than the size of the state
75// in bytes.
76@[direct_array_access]
77fn (mut s State) xor_bytes(byte_array []u8, rate int) {
78 mut index := 0
79
80 for y in 0 .. 5 {
81 for x in 0 .. 5 {
82 s.a[x][y] ^= binary.little_endian_u64_at(byte_array, index)
83 index += 8
84
85 if index >= rate {
86 return
87 }
88 }
89 }
90}
91
92// kaccak_p_1600_24 performs 24 rounnds on a 1600 bit state.
93//
94@[direct_array_access]
95fn (mut s State) kaccak_p_1600_24() {
96 mut b := [5][5]Lane{}
97 for round_index in 0 .. 24 {
98 // theta
99 // C[x] = A[x,0] xor A[x,1] xor A[x,2] xor A[x,3] xor A[x,4], for x in 0…4
100 // D[x] = C[x-1] xor rot(C[x+1],1), for x in 0…4
101 // A[x,y] = A[x,y] xor D[x], for (x,y) in (0…4,0…4)
102 c0 := s.a[0][0] ^ s.a[0][1] ^ s.a[0][2] ^ s.a[0][3] ^ s.a[0][4]
103 c1 := s.a[1][0] ^ s.a[1][1] ^ s.a[1][2] ^ s.a[1][3] ^ s.a[1][4]
104 c2 := s.a[2][0] ^ s.a[2][1] ^ s.a[2][2] ^ s.a[2][3] ^ s.a[2][4]
105 c3 := s.a[3][0] ^ s.a[3][1] ^ s.a[3][2] ^ s.a[3][3] ^ s.a[3][4]
106 c4 := s.a[4][0] ^ s.a[4][1] ^ s.a[4][2] ^ s.a[4][3] ^ s.a[4][4]
107
108 d0 := c4 ^ bits.rotate_left_64(c1, 1)
109 d1 := c0 ^ bits.rotate_left_64(c2, 1)
110 d2 := c1 ^ bits.rotate_left_64(c3, 1)
111 d3 := c2 ^ bits.rotate_left_64(c4, 1)
112 d4 := c3 ^ bits.rotate_left_64(c0, 1)
113
114 // vfmt off
115 s.a[0][0] ^= d0 s.a[0][1] ^= d0 s.a[0][2] ^= d0 s.a[0][3] ^= d0 s.a[0][4] ^= d0
116 s.a[1][0] ^= d1 s.a[1][1] ^= d1 s.a[1][2] ^= d1 s.a[1][3] ^= d1 s.a[1][4] ^= d1
117 s.a[2][0] ^= d2 s.a[2][1] ^= d2 s.a[2][2] ^= d2 s.a[2][3] ^= d2 s.a[2][4] ^= d2
118 s.a[3][0] ^= d3 s.a[3][1] ^= d3 s.a[3][2] ^= d3 s.a[3][3] ^= d3 s.a[3][4] ^= d3
119 s.a[4][0] ^= d4 s.a[4][1] ^= d4 s.a[4][2] ^= d4 s.a[4][3] ^= d4 s.a[4][4] ^= d4
120 // vfmt on
121
122 // rho and pi
123 // B[y,2*x+3*y] = rot(A[x,y], r[x,y]), for (x,y) in (0…4,0…4)
124 b[0][0] = s.a[0][0]
125 b[0][1] = bits.rotate_left_64(s.a[3][0], 28)
126 b[0][2] = bits.rotate_left_64(s.a[1][0], 1)
127 b[0][3] = bits.rotate_left_64(s.a[4][0], 27)
128 b[0][4] = bits.rotate_left_64(s.a[2][0], 62)
129
130 b[1][0] = bits.rotate_left_64(s.a[1][1], 44)
131 b[1][1] = bits.rotate_left_64(s.a[4][1], 20)
132 b[1][2] = bits.rotate_left_64(s.a[2][1], 6)
133 b[1][3] = bits.rotate_left_64(s.a[0][1], 36)
134 b[1][4] = bits.rotate_left_64(s.a[3][1], 55)
135
136 b[2][0] = bits.rotate_left_64(s.a[2][2], 43)
137 b[2][1] = bits.rotate_left_64(s.a[0][2], 3)
138 b[2][2] = bits.rotate_left_64(s.a[3][2], 25)
139 b[2][3] = bits.rotate_left_64(s.a[1][2], 10)
140 b[2][4] = bits.rotate_left_64(s.a[4][2], 39)
141
142 b[3][0] = bits.rotate_left_64(s.a[3][3], 21)
143 b[3][1] = bits.rotate_left_64(s.a[1][3], 45)
144 b[3][2] = bits.rotate_left_64(s.a[4][3], 8)
145 b[3][3] = bits.rotate_left_64(s.a[2][3], 15)
146 b[3][4] = bits.rotate_left_64(s.a[0][3], 41)
147
148 b[4][0] = bits.rotate_left_64(s.a[4][4], 14)
149 b[4][1] = bits.rotate_left_64(s.a[2][4], 61)
150 b[4][2] = bits.rotate_left_64(s.a[0][4], 18)
151 b[4][3] = bits.rotate_left_64(s.a[3][4], 56)
152 b[4][4] = bits.rotate_left_64(s.a[1][4], 2)
153
154 // chi
155 // A[x,y] = B[x,y] xor ((not B[x+1,y]) and B[x+2,y]), for (x,y) in (0…4,0…4)
156 for y in 0 .. 5 {
157 s.a[0][y] = b[0][y] ^ (~b[1][y] & b[2][y])
158 s.a[1][y] = b[1][y] ^ (~b[2][y] & b[3][y])
159 s.a[2][y] = b[2][y] ^ (~b[3][y] & b[4][y])
160 s.a[3][y] = b[3][y] ^ (~b[4][y] & b[0][y])
161 s.a[4][y] = b[4][y] ^ (~b[0][y] & b[1][y])
162 }
163
164 // iota
165 // A[0,0] = A[0,0] xor RC
166 s.a[0][0] ^= iota_round_constants[round_index]
167 }
168}
169
170// iota_round_constants are precomputed xor masks for the iota function
171const iota_round_constants = [u64(0x0000000000000001), 0x0000000000008082, 0x800000000000808a,
172 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081,
173 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009,
174 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
175 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a,
176 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001,
177 0x8000000080008008]
178
179fn (s State) str() string {
180 mut output := '\n y = 0 y = 1 y = 2 y = 3 y = 4\n'
181 for x in 0 .. 5 {
182 output += 'x = ${x}: ${s.a[x][0]:016x} ${s.a[x][1]:016x} ${s.a[x][2]:016x} ${s.a[x][3]:016x} ${s.a[x][4]:016x}\n'
183 }
184
185 return output
186}
187