Skip to content

Commit ea2bf0e

Browse files
authored
chore: use comptime function to unroll loops (#16)
1 parent f64ab3a commit ea2bf0e

File tree

1 file changed

+46
-75
lines changed

1 file changed

+46
-75
lines changed

src/keccak256.nr

Lines changed: 46 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,17 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
4444

4545
let mut sliced = 0;
4646
let mut v = 1;
47-
sliced += v * (block_bytes[limb_start] as Field);
48-
v *= 256;
49-
sliced += v * (block_bytes[limb_start + 1] as Field);
50-
v *= 256;
51-
sliced += v * (block_bytes[limb_start + 2] as Field);
52-
v *= 256;
53-
sliced += v * (block_bytes[limb_start + 3] as Field);
54-
v *= 256;
55-
sliced += v * (block_bytes[limb_start + 4] as Field);
56-
v *= 256;
57-
sliced += v * (block_bytes[limb_start + 5] as Field);
58-
v *= 256;
59-
sliced += v * (block_bytes[limb_start + 6] as Field);
60-
v *= 256;
61-
sliced += v * (block_bytes[limb_start + 7] as Field);
47+
unroll_loop!(
48+
0u32,
49+
WORD_SIZE,
50+
|i: u32| {
51+
quote {
52+
sliced += v * (block_bytes[limb_start + $i] as Field);
53+
v *= 256;
54+
}
55+
},
56+
);
57+
6258
sliced.assert_max_bit_size::<64>();
6359
sliced_buffer[i] = sliced as u64;
6460
}
@@ -68,23 +64,15 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
6864
// `real_max_blocks` is guaranteed to at least be `1`
6965
// We peel out the first block as to avoid a conditional inside of the loop.
7066
// Otherwise, a dynamic predicate can cause a blowup in a constrained runtime.
71-
state[0] = sliced_buffer[0];
72-
state[1] = sliced_buffer[1];
73-
state[2] = sliced_buffer[2];
74-
state[3] = sliced_buffer[3];
75-
state[4] = sliced_buffer[4];
76-
state[5] = sliced_buffer[5];
77-
state[6] = sliced_buffer[6];
78-
state[7] = sliced_buffer[7];
79-
state[8] = sliced_buffer[8];
80-
state[9] = sliced_buffer[9];
81-
state[10] = sliced_buffer[10];
82-
state[11] = sliced_buffer[11];
83-
state[12] = sliced_buffer[12];
84-
state[13] = sliced_buffer[13];
85-
state[14] = sliced_buffer[14];
86-
state[15] = sliced_buffer[15];
87-
state[16] = sliced_buffer[16];
67+
unroll_loop!(
68+
0u32,
69+
LIMBS_PER_BLOCK,
70+
|i: u32| {
71+
quote {
72+
state[$i] = sliced_buffer[$i];
73+
}
74+
},
75+
);
8876
state = keccakf1600(state);
8977

9078
let state = if is_unconstrained() {
@@ -116,49 +104,24 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
116104

117105
//3. sponge_squeeze
118106
let mut result = [0; 32];
119-
let lane = state[0] as Field;
120-
let lane_le: [u8; 8] = lane.to_le_bytes();
121-
result[0] = lane_le[0];
122-
result[1] = lane_le[1];
123-
result[2] = lane_le[2];
124-
result[3] = lane_le[3];
125-
result[4] = lane_le[4];
126-
result[5] = lane_le[5];
127-
result[6] = lane_le[6];
128-
result[7] = lane_le[7];
129-
130-
let lane = state[1] as Field;
131-
let lane_le: [u8; 8] = lane.to_le_bytes();
132-
result[8 * 1] = lane_le[0];
133-
result[8 * 1 + 1] = lane_le[1];
134-
result[8 * 1 + 2] = lane_le[2];
135-
result[8 * 1 + 3] = lane_le[3];
136-
result[8 * 1 + 4] = lane_le[4];
137-
result[8 * 1 + 5] = lane_le[5];
138-
result[8 * 1 + 6] = lane_le[6];
139-
result[8 * 1 + 7] = lane_le[7];
140-
141-
let lane = state[2] as Field;
142-
let lane_le: [u8; 8] = lane.to_le_bytes();
143-
result[8 * 2] = lane_le[0];
144-
result[8 * 2 + 1] = lane_le[1];
145-
result[8 * 2 + 2] = lane_le[2];
146-
result[8 * 2 + 3] = lane_le[3];
147-
result[8 * 2 + 4] = lane_le[4];
148-
result[8 * 2 + 5] = lane_le[5];
149-
result[8 * 2 + 6] = lane_le[6];
150-
result[8 * 2 + 7] = lane_le[7];
151-
152-
let lane = state[3] as Field;
153-
let lane_le: [u8; 8] = lane.to_le_bytes();
154-
result[8 * 3] = lane_le[0];
155-
result[8 * 3 + 1] = lane_le[1];
156-
result[8 * 3 + 2] = lane_le[2];
157-
result[8 * 3 + 3] = lane_le[3];
158-
result[8 * 3 + 4] = lane_le[4];
159-
result[8 * 3 + 5] = lane_le[5];
160-
result[8 * 3 + 6] = lane_le[6];
161-
result[8 * 3 + 7] = lane_le[7];
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+
);
162125

163126
result
164127
}
@@ -182,3 +145,11 @@ pub(crate) fn apply_keccak_padding<let BLOCK_BYTES: u32>(
182145
block_bytes[real_blocks_bytes - 1] = 0x80;
183146
}
184147
}
148+
149+
comptime fn unroll_loop(start: u32, end: u32, body: fn(u32) -> Quoted) -> Quoted {
150+
let mut iterations: [Quoted] = &[];
151+
for i in start..end {
152+
iterations = iterations.push_back(body(i));
153+
}
154+
iterations.join(quote {})
155+
}

0 commit comments

Comments
 (0)