| 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 |
| 9 | module sha3 |
| 10 | |
| 11 | import encoding.binary |
| 12 | import math.bits |
| 13 | |
| 14 | // when the state is 1600 bits, a lane is 64 bits |
| 15 | type Lane = u64 |
| 16 | |
| 17 | // the state is a 5 x 5 array of lanes |
| 18 | struct State { |
| 19 | mut: |
| 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] |
| 32 | fn (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] |
| 55 | fn (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] |
| 77 | fn (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] |
| 95 | fn (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 |
| 171 | const 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 | |
| 179 | fn (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 | |