Skip to content

Commit c146030

Browse files
committed
chore: split up keccak into multiple functions
1 parent ea2bf0e commit c146030

File tree

1 file changed

+54
-38
lines changed

1 file changed

+54
-38
lines changed

src/keccak256.nr

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod benchmarks;
44

55
use std::hash::keccakf1600;
66
use std::runtime::is_unconstrained;
7+
use std::static_assert;
78

89
global BLOCK_SIZE_IN_BYTES: u32 = 136; //(1600 - BITS * 2) / WORD_SIZE;
910
global WORD_SIZE: u32 = 8; // Limbs are made up of u64s so 8 bytes each.
@@ -30,15 +31,46 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
3031
}
3132

3233
//1. format_input_lanes and apply padding
33-
let max_blocks = (N + BLOCK_SIZE_IN_BYTES) / BLOCK_SIZE_IN_BYTES;
3434
let real_max_blocks = (message_size + BLOCK_SIZE_IN_BYTES) / BLOCK_SIZE_IN_BYTES;
3535

3636
// Apply Keccak padding (0x01 after message, 0x80 at block end)
3737
apply_keccak_padding(&mut block_bytes, message_size, real_max_blocks);
3838

39+
let block_array = convert_to_u64_array(block_bytes);
40+
41+
let state = apply_keccak_permutations(block_array, real_max_blocks);
42+
43+
//3. sponge_squeeze
44+
let mut result = [0; 32];
45+
unroll_loop!(
46+
0u32,
47+
4u32,
48+
|i: u32| {
49+
quote {
50+
let lane = state[$i] as Field;
51+
let lane_le: [u8; 8] = lane.to_le_bytes();
52+
result[8 * $i] = lane_le[0];
53+
result[8 * $i + 1] = lane_le[1];
54+
result[8 * $i + 2] = lane_le[2];
55+
result[8 * $i + 3] = lane_le[3];
56+
result[8 * $i + 4] = lane_le[4];
57+
result[8 * $i + 5] = lane_le[5];
58+
result[8 * $i + 6] = lane_le[6];
59+
result[8 * $i + 7] = lane_le[7];
60+
}
61+
},
62+
);
63+
64+
result
65+
}
66+
67+
fn convert_to_u64_array<let N: u32>(input: [u8; N]) -> [u64; N / WORD_SIZE] {
68+
static_assert(
69+
N % WORD_SIZE == 0,
70+
"Byte array is expected to cleanly divide into chunks",
71+
);
3972
// populate a vector of 64-bit limbs from our byte array
40-
let mut sliced_buffer =
41-
[0; (((N / BLOCK_SIZE_IN_BYTES) + 1) * BLOCK_SIZE_IN_BYTES) / WORD_SIZE];
73+
let mut sliced_buffer = [0; N / WORD_SIZE];
4274
for i in 0..sliced_buffer.len() {
4375
let limb_start = WORD_SIZE * i;
4476

@@ -49,7 +81,7 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
4981
WORD_SIZE,
5082
|i: u32| {
5183
quote {
52-
sliced += v * (block_bytes[limb_start + $i] as Field);
84+
sliced += v * (input[limb_start + $i] as Field);
5385
v *= 256;
5486
}
5587
},
@@ -58,29 +90,36 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
5890
sliced.assert_max_bit_size::<64>();
5991
sliced_buffer[i] = sliced as u64;
6092
}
93+
sliced_buffer
94+
}
6195

96+
fn apply_keccak_permutations<let N: u32>(
97+
flattened_blocks_array: [u64; N],
98+
num_blocks: u32,
99+
) -> [u64; NUM_KECCAK_LANES] {
62100
//2. sponge_absorb
63101
let mut state: [u64; NUM_KECCAK_LANES] = [0; NUM_KECCAK_LANES];
64-
// `real_max_blocks` is guaranteed to at least be `1`
102+
// `num_blocks` is guaranteed to at least be `1`
65103
// We peel out the first block as to avoid a conditional inside of the loop.
66104
// Otherwise, a dynamic predicate can cause a blowup in a constrained runtime.
67105
unroll_loop!(
68106
0u32,
69107
LIMBS_PER_BLOCK,
70108
|i: u32| {
71109
quote {
72-
state[$i] = sliced_buffer[$i];
110+
state[$i] = flattened_blocks_array[$i];
73111
}
74112
},
75113
);
76114
state = keccakf1600(state);
77115

78-
let state = if is_unconstrained() {
116+
let max_blocks = N / LIMBS_PER_BLOCK;
117+
if is_unconstrained() {
79118
// When in an unconstrained runtime we can take advantage of runtime loop bounds,
80119
// thus allowing us to simplify the loop body.
81-
for i in 1..real_max_blocks {
120+
for i in 1..num_blocks {
82121
for j in 0..LIMBS_PER_BLOCK {
83-
state[j] = state[j] ^ sliced_buffer[i * LIMBS_PER_BLOCK + j];
122+
state[j] = state[j] ^ flattened_blocks_array[i * LIMBS_PER_BLOCK + j];
84123
}
85124
state = keccakf1600(state);
86125
}
@@ -89,41 +128,18 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
89128
} else {
90129
// We store the intermediate states in an array to avoid having a dynamic predicate
91130
// inside the loop, which can cause a blowup in a constrained runtime.
92-
let mut intermediate_states = [state; (N + BLOCK_SIZE_IN_BYTES) / BLOCK_SIZE_IN_BYTES + 1];
131+
let mut intermediate_states = [state; N / LIMBS_PER_BLOCK + 1];
93132
for i in 1..max_blocks {
94133
let mut previous_state = intermediate_states[i - 1];
95134
for j in 0..LIMBS_PER_BLOCK {
96-
previous_state[j] = previous_state[j] ^ sliced_buffer[i * LIMBS_PER_BLOCK + j];
135+
previous_state[j] = previous_state[j] ^ flattened_blocks_array[i * LIMBS_PER_BLOCK + j];
97136
}
98137
intermediate_states[i] = keccakf1600(previous_state);
99138
}
100139

101-
// We can then take the state as of `real_max_blocks`, ignoring later permutations.
102-
intermediate_states[real_max_blocks - 1]
103-
};
104-
105-
//3. sponge_squeeze
106-
let mut result = [0; 32];
107-
unroll_loop!(
108-
0u32,
109-
4u32,
110-
|i: u32| {
111-
quote {
112-
let lane = state[$i] as Field;
113-
let lane_le: [u8; 8] = lane.to_le_bytes();
114-
result[8 * $i] = lane_le[0];
115-
result[8 * $i + 1] = lane_le[1];
116-
result[8 * $i + 2] = lane_le[2];
117-
result[8 * $i + 3] = lane_le[3];
118-
result[8 * $i + 4] = lane_le[4];
119-
result[8 * $i + 5] = lane_le[5];
120-
result[8 * $i + 6] = lane_le[6];
121-
result[8 * $i + 7] = lane_le[7];
122-
}
123-
},
124-
);
125-
126-
result
140+
// We can then take the state as of `num_blocks`, ignoring later permutations.
141+
intermediate_states[num_blocks - 1]
142+
}
127143
}
128144

129145
// Apply Keccak padding to the block_bytes array
@@ -147,7 +163,7 @@ pub(crate) fn apply_keccak_padding<let BLOCK_BYTES: u32>(
147163
}
148164

149165
comptime fn unroll_loop(start: u32, end: u32, body: fn(u32) -> Quoted) -> Quoted {
150-
let mut iterations: [Quoted] = &[];
166+
let mut iterations: [Quoted] = @[];
151167
for i in start..end {
152168
iterations = iterations.push_back(body(i));
153169
}

0 commit comments

Comments
 (0)