Skip to content

Commit

Permalink
feat: bytes_to_fields requiring only 1 generic param (#9417)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan authored Oct 25, 2024
1 parent 6d77dd0 commit 2217da6
Showing 1 changed file with 16 additions and 25 deletions.
41 changes: 16 additions & 25 deletions noir-projects/aztec-nr/aztec/src/utils/bytes.nr
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
use std::static_assert;

// Converts the input bytes into an array of fields. A Field is ~254 bits meaning that each field can store 31 bytes.
// This implies that M = ceil(N / 31).
//
// Each 31 byte chunk is converted into a Field as if the chunk was the Field's big endian representation. If the last chunk
// is less than 31 bytes long, then only the relevant bytes are conisdered.
// For example, [1, 10, 3] is encoded as [1 * 256^2 + 10 * 256 + 3]
pub fn bytes_to_fields<let N: u32, let M: u32>(input: [u8; N]) -> [Field; M] {
static_assert(N <= 31 * M, "Bytes do not fit into fields");
let mut dst = [0; M];
pub fn bytes_to_fields<let N: u32>(input: [u8; N]) -> [Field; (N + 30) / 31] {
let mut dst = [0; (N + 30) / 31];

for dst_index in 0..M {
for dst_index in 0..((N + 30) / 31) {
let mut field_value = 0;

for i in 0..31 {
Expand Down Expand Up @@ -78,15 +76,15 @@ mod test {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31,
];
let output = bytes_to_fields::<31, 1>(input);
let output = bytes_to_fields(input);

assert_eq(output[0], 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f);
}

#[test]
fn test_1_field_to_bytes() {
let input = [0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f];
let output = fields_to_bytes::<31, 1>(input);
let output: [u8; 31] = fields_to_bytes(input);

assert_eq(
output,
Expand All @@ -100,7 +98,7 @@ mod test {
#[test]
fn test_3_small_fields_to_bytes() {
let input = [1, 2, 3];
let output = fields_to_bytes::<93, 3>(input);
let output: [u8; 93] = fields_to_bytes(input);

// Each field should occupy 31 bytes with the non-zero value being placed in the last one.
assert_eq(
Expand All @@ -117,7 +115,7 @@ mod test {
#[test]
fn test_3_small_fields_to_less_bytes() {
let input = [1, 2, 3];
let output = fields_to_bytes::<63, 3>(input);
let output: [u8; 63] = fields_to_bytes(input);

// First 2 fields should occupy 31 bytes with the non-zero value being placed in the last one while the last
// field should occupy 1 byte. There is not information destruction here because the last field fits into
Expand All @@ -139,7 +137,7 @@ mod test {
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
];
let output = bytes_to_fields::<59, 2>(input);
let output = bytes_to_fields(input);

assert_eq(output[0], 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f);
assert_eq(output[1], 0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b);
Expand All @@ -151,7 +149,7 @@ mod test {
0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f,
0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b,
];
let output = fields_to_bytes::<62, 2>(input);
let output: [u8; 62] = fields_to_bytes(input);

assert_eq(
output,
Expand All @@ -165,8 +163,8 @@ mod test {

#[test]
fn test_large_random_input_to_fields_and_back(input: [u8; 128]) {
let output = bytes_to_fields::<128, 5>(input);
let input_back = fields_to_bytes::<128, 5>(output);
let output = bytes_to_fields(input);
let input_back: [u8; 128] = fields_to_bytes(output);

assert_eq(input, input_back);
}
Expand All @@ -193,37 +191,30 @@ mod test {
+ input6[i] as Field;
}

let output = fields_to_bytes::<155, 5>(input);
let input_back = bytes_to_fields::<155, 5>(output);
let output: [u8; 155] = fields_to_bytes(input);
let input_back = bytes_to_fields(output);

assert_eq(input, input_back);
}

#[test(should_fail_with = "Argument is false")]
fn test_too_few_destination_fields() {
// This should fail because we need 2 fields to store 32 bytes but we only provide 1.
let input = [0 as u8; 32];
let _ignored_result = bytes_to_fields::<32, 1>(input);
}

#[test(should_fail_with = "Field does not fit into remaining bytes")]
fn test_too_few_destination_bytes() {
// We should get an error here because first field gets converted to 31 bytes and the second field needs
// at least 2 bytes but we provide it with 1.
let input = [1, 256];
let _ignored_result = fields_to_bytes::<32, 2>(input);
let _ignored_result: [u8; 32] = fields_to_bytes(input);
}

#[test(should_fail_with = "call to assert_max_bit_size")]
fn test_fields_to_bytes_value_too_large() {
let input = [2.pow_32(248)];
let _ignored_result = fields_to_bytes::<31, 1>(input);
let _ignored_result: [u8; 31] = fields_to_bytes(input);
}

#[test]
fn test_fields_to_bytes_max_value() {
let input = [2.pow_32(248) - 1];
let result = fields_to_bytes::<31, 1>(input);
let result: [u8; 31] = fields_to_bytes(input);

// We check that all the bytes were set to max value (255)
for i in 0..31 {
Expand Down

0 comments on commit 2217da6

Please sign in to comment.