Skip to content

Commit bde6715

Browse files
committed
u64s_packing utils
1 parent e81ce8a commit bde6715

File tree

4 files changed

+93
-6
lines changed

4 files changed

+93
-6
lines changed

noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
log_type::{PARTIAL_NOTE_PRIVATE_LOG_TYPE_ID, PRIVATE_NOTE_LOG_TYPE_ID},
1111
},
1212
oracle::message_discovery::sync_notes,
13-
utils::array,
13+
utils::{array, u64s_packing::unpack_two_u64s},
1414
};
1515

1616
use protocol_types::{
@@ -134,10 +134,7 @@ unconstrained fn decode_log_plaintext(
134134

135135
// See the documentation of this function for a description of the log layout
136136
let expanded_log_metadata = log_plaintext.get(0);
137-
138-
let log_metadata = ((expanded_log_metadata as u128) >> 64) as u64;
139-
let log_type_id = (expanded_log_metadata as u64);
140-
137+
let (log_type_id, log_metadata) = unpack_two_u64s(expanded_log_metadata);
141138
let log_content = array::subbvec(log_plaintext, PRIVATE_LOG_EXPANDED_METADATA_LEN);
142139

143140
(log_type_id, log_metadata, log_content)

noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
},
88
note::{note_emission::NoteEmission, note_interface::NoteType},
99
oracle::notes::{get_app_tag_as_sender, increment_app_tagging_secret_index_as_sender},
10+
utils::u64s_packing::pack_two_u64s,
1011
};
1112
use dep::protocol_types::{
1213
abis::note_hash::NoteHash, address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_FIELDS,
@@ -39,7 +40,7 @@ where
3940

4041
// We pack log type id and log metadata into the first field. Search for `decode_log_plaintext` function to see
4142
// where the value gets decoded.
42-
fields[0] = (Note::get_id() * 2.pow_32(64)) + log_type_id as Field;
43+
fields[0] = pack_two_u64s(log_type_id, Note::get_id() as u64);
4344
fields[1] = storage_slot;
4445
for i in 0..packed_note.len() {
4546
fields[i + 2] = packed_note[i];

noir-projects/aztec-nr/aztec/src/utils/mod.nr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ pub mod point;
66
pub mod random;
77
pub mod to_bytes;
88
pub mod secrets;
9+
pub mod u64s_packing;
910
pub mod with_hash;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
global U64_SHIFT_MULTIPLIER: Field = 2.pow_32(64);
2+
3+
pub fn pack_two_u64s(high: u64, low: u64) -> Field {
4+
let low_field = low as Field;
5+
// We use multiplication instead of bit shifting operations to shift the high bits as bit shift operations are
6+
// expensive in circuits.
7+
let high_field: Field = (high as Field) * U64_SHIFT_MULTIPLIER;
8+
high_field + low_field
9+
}
10+
11+
pub fn unpack_two_u64s(input: Field) -> (u64, u64) {
12+
input.assert_max_bit_size::<128>();
13+
let low = (input as u64);
14+
// Use division instead of bit shift since bit shifts are expensive in circuits
15+
let high = ((input - (low as Field)) / U64_SHIFT_MULTIPLIER) as u64;
16+
(high, low)
17+
}
18+
19+
mod tests {
20+
use super::{pack_two_u64s, unpack_two_u64s};
21+
22+
global U64_MAX: Field = 2.pow_32(64) - 1;
23+
global U128_MAX: Field = 2.pow_32(128) - 1;
24+
25+
#[test]
26+
fn packing_two_u64s() {
27+
// Test case 1: All bits set
28+
let packed = pack_two_u64s(U64_MAX as u64, U64_MAX as u64);
29+
let (upper, lower) = unpack_two_u64s(packed);
30+
assert(lower == U64_MAX as u64, "Lower 64 bits should be all 1s");
31+
assert(upper == U64_MAX as u64, "Upper 64 bits should be all 1s");
32+
33+
// Test case 2: Only upper 64 bits set
34+
let packed = pack_two_u64s(U64_MAX as u64, 0);
35+
let (upper, lower) = unpack_two_u64s(packed);
36+
assert(lower == 0, "Lower 64 bits should be 0");
37+
assert(upper == U64_MAX as u64, "Upper 64 bits should be all 1s");
38+
39+
// Test case 3: Only lower 64 bits set
40+
let packed = pack_two_u64s(0, U64_MAX as u64);
41+
let (upper, lower) = unpack_two_u64s(packed);
42+
assert(lower == U64_MAX as u64, "Lower 64 bits should be all 1s");
43+
assert(upper == 0, "Upper 64 bits should be 0");
44+
45+
// Test case 4: Zero
46+
let packed = pack_two_u64s(0, 0);
47+
let (upper, lower) = unpack_two_u64s(packed);
48+
assert(lower == 0, "Lower 64 bits should be 0");
49+
assert(upper == 0, "Upper 64 bits should be 0");
50+
}
51+
52+
#[test]
53+
fn unpacking_two_u64s() {
54+
// Test case 1: All bits set
55+
let input = U128_MAX;
56+
let (upper, lower) = unpack_two_u64s(input);
57+
assert(lower == U64_MAX as u64, "Lower 64 bits should be all 1s");
58+
assert(upper == U64_MAX as u64, "Upper 64 bits should be all 1s");
59+
60+
// Test case 2: Only upper 64 bits set
61+
let input = U128_MAX - U64_MAX;
62+
let (upper, lower) = unpack_two_u64s(input);
63+
assert(lower == 0, "Lower 64 bits should be 0");
64+
assert(upper == U64_MAX as u64, "Upper 64 bits should be all 1s");
65+
66+
// Test case 3: Only lower 64 bits set
67+
let input = U64_MAX;
68+
let (upper, lower) = unpack_two_u64s(input);
69+
assert(lower == U64_MAX as u64, "Lower 64 bits should be all 1s");
70+
assert(upper == 0, "Upper 64 bits should be 0");
71+
72+
// Test case 4: Zero
73+
let input = 0;
74+
let (upper, lower) = unpack_two_u64s(input);
75+
assert(lower == 0, "Lower 64 bits should be 0");
76+
assert(upper == 0, "Upper 64 bits should be 0");
77+
}
78+
79+
#[test]
80+
fn roundtrip_two_u64s() {
81+
let original_upper = 12345;
82+
let original_lower = 67890;
83+
let packed = pack_two_u64s(original_upper, original_lower);
84+
let (unpacked_upper, unpacked_lower) = unpack_two_u64s(packed);
85+
assert(original_upper == unpacked_upper, "Upper 64 bits should match after roundtrip");
86+
assert(original_lower == unpacked_lower, "Lower 64 bits should match after roundtrip");
87+
}
88+
}

0 commit comments

Comments
 (0)