@@ -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+ 0 u32 ,
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+ 0 u32 ,
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+ 0 u32 ,
109+ 4 u32 ,
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