Skip to content

Commit fc926f5

Browse files
committed
chore: apply keccak padding to blocks rather than bytes
1 parent ea2bf0e commit fc926f5

File tree

2 files changed

+39
-45
lines changed

2 files changed

+39
-45
lines changed

src/keccak256.nr

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
3333
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

36-
// Apply Keccak padding (0x01 after message, 0x80 at block end)
37-
apply_keccak_padding(&mut block_bytes, message_size, real_max_blocks);
38-
3936
// populate a vector of 64-bit limbs from our byte array
4037
let mut sliced_buffer =
4138
[0; (((N / BLOCK_SIZE_IN_BYTES) + 1) * BLOCK_SIZE_IN_BYTES) / WORD_SIZE];
@@ -59,6 +56,9 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
5956
sliced_buffer[i] = sliced as u64;
6057
}
6158

59+
// Apply Keccak padding (0x01 after message, 0x80 at block end)
60+
apply_keccak_padding( &mut sliced_buffer, message_size, real_max_blocks);
61+
6262
//2. sponge_absorb
6363
let mut state: [u64; NUM_KECCAK_LANES] = [0; NUM_KECCAK_LANES];
6464
// `real_max_blocks` is guaranteed to at least be `1`
@@ -126,24 +126,22 @@ pub fn keccak256<let N: u32>(input: [u8; N], message_size: u32) -> [u8; 32] {
126126
result
127127
}
128128

129-
// Apply Keccak padding to the block_bytes array
129+
// Apply Keccak padding to the u64 block array
130130
// Append 0x01 after message, then 0x80 at end of block
131131
// If both padding bytes collide at the same byte, combine them as 0x81
132132
#[inline_always]
133-
pub(crate) fn apply_keccak_padding<let BLOCK_BYTES: u32>(
134-
block_bytes: &mut [u8; BLOCK_BYTES],
133+
pub(crate) fn apply_keccak_padding<let N: u32>(
134+
block_array: &mut [u64; N],
135135
message_size: u32,
136136
real_max_blocks: u32,
137-
) {
138-
let real_blocks_bytes = real_max_blocks * BLOCK_SIZE_IN_BYTES;
139-
140-
if message_size == real_blocks_bytes - 1 {
141-
// Combine both padding bits: 0x01 | 0x80 = 0x81
142-
block_bytes[message_size] = 0x81;
143-
} else {
144-
block_bytes[message_size] = 0x01;
145-
block_bytes[real_blocks_bytes - 1] = 0x80;
146-
}
137+
) {
138+
// Calculate limb index and byte offset within the limb (little-endian)
139+
let start_limb_index = message_size / WORD_SIZE;
140+
let start_byte_offset = message_size % WORD_SIZE;
141+
142+
block_array[start_limb_index] += 0x01 << (8 * (start_byte_offset as u64));
143+
// The end padding byte (0x80) always goes at byte 7 of the last limb
144+
block_array[real_max_blocks * LIMBS_PER_BLOCK - 1] += 0x80 << 56;
147145
}
148146

149147
comptime fn unroll_loop(start: u32, end: u32, body: fn(u32) -> Quoted) -> Quoted {

src/keccak256/tests.nr

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,48 @@ use super::{apply_keccak_padding, keccak256};
33
#[test]
44
fn test_padding_no_collision() {
55
// Message size 134: padding bytes don't collide
6-
// Expected: block_bytes[134] = 0x01, block_bytes[135] = 0x80
7-
let mut block_bytes = [0; 136];
8-
let real_max_blocks = (134 + 136) / 136;
9-
apply_keccak_padding(&mut block_bytes, 134, real_max_blocks);
6+
// Limb 16, byte offsets 6 and 7
7+
// block_array[16] = 0x01 << 48 (start) + 0x80 << 56 (end)
8+
let mut block_array = [0; 17]; // 1 block = 17 limbs
9+
let real_max_blocks = 1;
10+
apply_keccak_padding(&mut block_array, 134, real_max_blocks);
1011

11-
assert_eq(block_bytes[134], 0x01, "First padding byte should be 0x01");
12-
assert_eq(block_bytes[135], 0x80, "Second padding byte should be 0x80");
12+
assert_eq(block_array[16], 0x8001000000000000);
1313
}
1414

1515
#[test]
1616
fn test_padding_collision_135() {
17-
// Message size 135: padding bytes collide at position 135
18-
// Expected: block_bytes[135] = 0x81
19-
let mut block_bytes = [0; 272];
20-
let real_max_blocks = (135 + 136) / 136;
21-
apply_keccak_padding(&mut block_bytes, 135, real_max_blocks);
22-
23-
assert_eq(block_bytes[135], 0x81, "Combined padding byte should be 0x81");
24-
// Ensure no stray 0x80 elsewhere
25-
for i in 136..272 {
26-
assert_eq(block_bytes[i], 0x00, "No padding beyond position 135");
27-
}
17+
// Message size 135: padding bytes collide at byte 135 (offset 7 in limb 16)
18+
// block_array[16] = 0x01 << 56 + 0x80 << 56 = 0x81 << 56
19+
let mut block_array = [0; 17]; // 1 block = 17 limbs
20+
let real_max_blocks = 1;
21+
apply_keccak_padding(&mut block_array, 135, real_max_blocks);
22+
23+
assert_eq(block_array[16], 0x8100000000000000);
2824
}
2925

3026
#[test]
3127
fn test_padding_zero_length() {
3228
// Message size 0: padding starts immediately
33-
// Expected: block_bytes[0] = 0x01, block_bytes[135] = 0x80
34-
let mut block_bytes = [0; 136];
35-
let real_max_blocks = (0 + 136) / 136;
36-
apply_keccak_padding(&mut block_bytes, 0, real_max_blocks);
29+
// block_array[0] = 0x01, block_array[16] = 0x80 << 56
30+
let mut block_array = [0; 17]; // 1 block = 17 limbs
31+
let real_max_blocks = 1;
32+
apply_keccak_padding(&mut block_array, 0, real_max_blocks);
3733

38-
assert_eq(block_bytes[0], 0x01, "First padding byte at position 0");
39-
assert_eq(block_bytes[135], 0x80, "Second padding byte at end of block");
34+
assert_eq(block_array[0], 0x01);
35+
assert_eq(block_array[16], 0x8000000000000000);
4036
}
4137

4238
#[test]
4339
fn test_padding_full_block() {
4440
// Message size 136: exactly fills one block, needs another for padding
45-
// Expected: block_bytes[136] = 0x01, block_bytes[271] = 0x80
46-
let mut block_bytes = [0; 272];
47-
let real_max_blocks = (136 + 136) / 136;
48-
apply_keccak_padding(&mut block_bytes, 136, real_max_blocks);
41+
// block_array[17] = 0x01, block_array[33] = 0x80 << 56
42+
let mut block_array = [0; 34]; // 2 blocks = 34 limbs
43+
let real_max_blocks = 2;
44+
apply_keccak_padding(&mut block_array, 136, real_max_blocks);
4945

50-
assert_eq(block_bytes[136], 0x01, "First padding byte after full block");
51-
assert_eq(block_bytes[271], 0x80, "Second padding byte at end of next block");
46+
assert_eq(block_array[17], 0x01);
47+
assert_eq(block_array[33], 0x8000000000000000);
5248
}
5349

5450
#[test]

0 commit comments

Comments
 (0)