Skip to content

Commit df45e42

Browse files
committed
refactor: dropping now-unnecessary ArgsHasher
I noticed that we can reuse the functionality I extracted out of `derive_serialize` yesterday in [this PR](#17854) also for the hashing of contract function args and return values so I decided to do this PR as well. Now we have a much better code reuse which is great.
1 parent b4a0b44 commit df45e42

File tree

9 files changed

+35
-223
lines changed

9 files changed

+35
-223
lines changed

noir-projects/aztec-nr/aztec/src/context/private_context.nr

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
context::{inputs::PrivateContextInputs, returns_hash::ReturnsHash},
3-
hash::{ArgsHasher, hash_args_array, hash_calldata_array},
3+
hash::{hash_args_array, hash_calldata_array},
44
keys::constants::{NULLIFIER_INDEX, NUM_KEY_TYPES, OUTGOING_INDEX, sk_generators},
55
messaging::process_l1_to_l2_message,
66
oracle::{
@@ -562,11 +562,12 @@ impl PrivateContext {
562562
/// Very low-level function: this is called by the #[private] macro.
563563
///
564564
/// # Arguments
565-
/// * `returns_hasher` - A hasher containing the return values to hash
565+
/// * `serialized_return_values` - The serialized return values as a field array
566566
///
567-
pub fn set_return_hash(&mut self, returns_hasher: ArgsHasher) {
568-
self.return_hash = returns_hasher.hash();
569-
execution_cache::store(returns_hasher.fields, self.return_hash);
567+
pub fn set_return_hash<let N: u32>(&mut self, serialized_return_values: [Field; N]) {
568+
let return_hash = hash_args_array(serialized_return_values);
569+
self.return_hash = return_hash;
570+
execution_cache::store(serialized_return_values, return_hash);
570571
}
571572

572573
/// Builds the PrivateCircuitPublicInputs for this private function, to

noir-projects/aztec-nr/aztec/src/hash.nr

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use dep::protocol_types::{
1010
sha256_to_field,
1111
},
1212
point::Point,
13-
traits::{Hash, ToField},
13+
traits::ToField,
1414
};
1515

1616
pub use dep::protocol_types::hash::{compute_siloed_nullifier, pedersen_hash};
@@ -59,32 +59,6 @@ pub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) ->
5959
poseidon2_hash_with_separator([message_hash, secret], GENERATOR_INDEX__MESSAGE_NULLIFIER)
6060
}
6161

62-
pub struct ArgsHasher {
63-
pub fields: [Field],
64-
}
65-
66-
impl Hash for ArgsHasher {
67-
fn hash(self) -> Field {
68-
hash_args(self.fields)
69-
}
70-
}
71-
72-
impl ArgsHasher {
73-
pub fn new() -> Self {
74-
Self { fields: [] }
75-
}
76-
77-
pub fn add(&mut self, field: Field) {
78-
self.fields = self.fields.push_back(field);
79-
}
80-
81-
pub fn add_multiple<let N: u32>(&mut self, fields: [Field; N]) {
82-
for i in 0..N {
83-
self.fields = self.fields.push_back(fields[i]);
84-
}
85-
}
86-
}
87-
8862
// Computes the hash of input arguments or return values for private functions, or for authwit creation.
8963
pub fn hash_args_array<let N: u32>(args: [Field; N]) -> Field {
9064
if args.len() == 0 {
@@ -149,11 +123,11 @@ pub fn compute_public_bytecode_commitment(
149123

150124
#[test]
151125
unconstrained fn compute_var_args_hash() {
152-
let mut input = ArgsHasher::new();
126+
let mut input = [0; 100];
153127
for i in 0..100 {
154-
input.add(i as Field);
128+
input[i] = i as Field;
155129
}
156-
let hash = input.hash();
130+
let hash = hash_args_array(input);
157131
dep::std::println(hash);
158132
// Used in yarn-project/stdlib test snapshots:
159133
assert(hash == 0x19b0d74feb06ebde19edd85a28986c97063e84b3b351a8b666c7cac963ce655f);

noir-projects/aztec-nr/aztec/src/macros/functions/utils.nr

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use crate::macros::{
44
},
55
notes::NOTES,
66
utils::{
7-
add_to_hasher, fn_has_authorize_once, fn_has_noinitcheck, get_fn_visibility,
8-
is_fn_contract_library_method, is_fn_initializer, is_fn_internal, is_fn_private,
9-
is_fn_public, is_fn_test, is_fn_utility, is_fn_view, modify_fn_body, module_has_initializer,
10-
module_has_storage,
7+
fn_has_authorize_once, fn_has_noinitcheck, get_fn_visibility, is_fn_contract_library_method,
8+
is_fn_initializer, is_fn_internal, is_fn_private, is_fn_public, is_fn_test, is_fn_utility,
9+
is_fn_view, modify_fn_body, module_has_initializer, module_has_storage,
1110
},
1211
};
12+
use dep::protocol_types::meta::utils::derive_serialization_quotes;
1313
use std::meta::{ctstring::AsCtString, type_of};
1414

1515
pub(crate) comptime fn transform_private(f: FunctionDefinition) {
@@ -34,24 +34,13 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
3434

3535
// The original params are hashed and passed to the `context` object, so that the kernel can verify we've received
3636
// the correct values.
37-
// TODO: Optimize args_hasher for small number of arguments
38-
let args_hasher_name = quote { args_hasher };
39-
let args_hasher = original_params.fold(
40-
quote {
41-
let mut $args_hasher_name = dep::aztec::hash::ArgsHasher::new();
42-
},
43-
|args_hasher, param: (Quoted, Type)| {
44-
let (name, typ) = param;
45-
let appended_arg = add_to_hasher(args_hasher_name, name, typ);
46-
quote {
47-
$args_hasher
48-
$appended_arg
49-
}
50-
},
51-
);
37+
let (args_serialization, _, serialized_args_name) =
38+
derive_serialization_quotes(original_params, false);
5239

5340
let context_creation = quote {
54-
let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, dep::aztec::protocol_types::traits::Hash::hash($args_hasher_name));
41+
$args_serialization
42+
let args_hash = dep::aztec::hash::hash_args_array($serialized_args_name);
43+
let mut context = dep::aztec::context::private_context::PrivateContext::new(inputs, args_hash);
5544
};
5645

5746
// Modifications introduced by the different marker attributes.
@@ -116,22 +105,21 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
116105
let return_value = if body.len() == 0 {
117106
quote {}
118107
} else if return_value_type != type_of(()) {
119-
// The original return value is passed to a second args hasher which the context receives.
108+
// The original return value is serialized and hashed before being passed to the context.
120109
let (body_without_return, last_body_expr) = body.pop_back();
121110
let return_value = last_body_expr.quoted();
122111
let return_value_assignment =
123112
quote { let $return_value_var_name: $return_value_type = $return_value; };
124-
let return_hasher_name = quote { return_hasher };
125-
let return_value_into_hasher =
126-
add_to_hasher(return_hasher_name, return_value_var_name, return_value_type);
113+
114+
let (return_serialization, _, serialized_return_name) =
115+
derive_serialization_quotes([(return_value_var_name, return_value_type)], false);
127116

128117
body = body_without_return;
129118

130119
quote {
131-
let mut $return_hasher_name = dep::aztec::hash::ArgsHasher::new();
132120
$return_value_assignment
133-
$return_value_into_hasher
134-
context.set_return_hash($return_hasher_name);
121+
$return_serialization
122+
context.set_return_hash($serialized_return_name);
135123
}
136124
} else {
137125
let (body_without_return, last_body_expr) = body.pop_back();
@@ -154,7 +142,6 @@ pub(crate) comptime fn transform_private(f: FunctionDefinition) {
154142
// A quote to be injected at the beginning of the function body.
155143
let to_prepend = quote {
156144
dep::aztec::oracle::version::assert_compatible_oracle_version();
157-
$args_hasher
158145
$context_creation
159146
$assert_initializer
160147
$init_check

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

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -72,40 +72,6 @@ pub(crate) comptime fn modify_fn_body(body: [Expr], prepend: Quoted, append: Quo
7272
body_expr.expect(f"Body is not an expression: {body_quote}")
7373
}
7474

75-
/// Adds a value to a hash::ArgsHasher. Structs and values inside arrays are required to implement the Serialize trait.
76-
pub(crate) comptime fn add_to_hasher(hasher_name: Quoted, name: Quoted, typ: Type) -> Quoted {
77-
if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() {
78-
quote { $hasher_name.add($name as Field); }
79-
} else if typ.as_data_type().is_some() {
80-
quote { $hasher_name.add_multiple(dep::aztec::protocol_types::traits::Serialize::serialize($name)); }
81-
} else if typ.as_array().is_some() {
82-
let (element_type, _) = typ.as_array().unwrap();
83-
let serialized_name = f"{name}_serialized".quoted_contents();
84-
quote {
85-
let $serialized_name = $name.map(|x: $element_type | dep::aztec::protocol_types::traits::Serialize::serialize(x));
86-
for i in 0..$name.len() {
87-
$hasher_name.add_multiple($serialized_name[i]);
88-
}
89-
}
90-
} else if typ.as_tuple().is_some() {
91-
let tuple_len = typ.as_tuple().unwrap().len();
92-
let mut tuple_quotes: [Quoted] = [];
93-
for i in 0..tuple_len {
94-
let element_quote = quote { $hasher_name.add_multiple(dep::aztec::protocol_types::traits::Serialize::serialize($name.$i)); };
95-
tuple_quotes = tuple_quotes.push_back(element_quote);
96-
}
97-
tuple_quotes.join(quote {})
98-
} else if typ.as_str().is_some() {
99-
quote {
100-
$hasher_name.add_multiple($name.as_bytes().map(| byte: u8 | byte as Field));
101-
}
102-
} else {
103-
panic(
104-
f"Cannot add to hasher: unsupported type {typ} of variable {name}",
105-
)
106-
}
107-
}
108-
10975
comptime fn signature_of_type(typ: Type) -> Quoted {
11076
if typ.is_field() {
11177
quote {Field}

noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub contract DocsExample {
1212
macros::{functions::{private, public, utility}, storage::{storage, storage_no_init}},
1313
messages::message_delivery::MessageDelivery,
1414
note::{note_interface::NoteProperties, note_viewer_options::NoteViewerOptions},
15-
protocol_types::{address::AztecAddress, traits::Hash},
15+
protocol_types::address::AztecAddress,
1616
state_vars::{
1717
Map, PrivateImmutable, PrivateMutable, PrivateSet, PublicImmutable, PublicMutable,
1818
},
@@ -143,15 +143,14 @@ pub contract DocsExample {
143143
) -> PrivateCircuitPublicInputs {
144144
// docs:end:context-example-return
145145
// ************************************************************
146-
// The hasher is a structure used to generate a hash of the circuits inputs.
146+
// The args are serialized and hashed to generate the args hash for the circuit inputs.
147147
// docs:start:context-example-hasher
148-
let mut args_hasher = dep::aztec::hash::ArgsHasher::new();
149-
args_hasher.add(a);
150-
args_hasher.add(b);
148+
let serialized_args = [a, b];
149+
let args_hash = dep::aztec::hash::hash_args_array(serialized_args);
151150
// docs:end:context-example-hasher
152151
// The context object is created with the inputs and the hash of the inputs
153152
// docs:start:context-example-context
154-
let mut context = PrivateContext::new(inputs, args_hasher.hash());
153+
let mut context = PrivateContext::new(inputs, args_hash);
155154
// docs:end:context-example-context
156155
// docs:start:storage-example-context
157156
#[allow(unused_variables)]
@@ -161,11 +160,10 @@ pub contract DocsExample {
161160
// Our actual program
162161
let result = a + b;
163162
// ************************************************************
164-
// Return values are pushed into the context
163+
// Return values are serialized and passed to the context
165164
// docs:start:context-example-context-return
166-
let mut return_hasher = dep::aztec::hash::ArgsHasher::new();
167-
return_hasher.add(result);
168-
context.set_return_hash(return_hasher);
165+
let serialized_return = [result];
166+
context.set_return_hash(serialized_return);
169167
// docs:end:context-example-context-return
170168
// The context is returned to be consumed by the kernel circuit!
171169
// docs:start:context-example-finish

noir-projects/noir-contracts/contracts/test/import_test_contract/src/main.nr

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,10 @@ use dep::aztec::macros::aztec;
66
pub contract ImportTest {
77
use dep::aztec::protocol_types::address::AztecAddress;
88

9-
use dep::test::Test::{self, DeepStruct, DummyNote};
9+
use dep::test::Test;
1010

1111
use dep::aztec::macros::functions::{private, public};
1212

13-
// Calls the test_code_gen on the Test contract at the target address
14-
// Used for testing calling a function with arguments of multiple types
15-
// See yarn-project/simulator/src/client/private_execution.ts
16-
// See yarn-project/end-to-end/src/e2e_nested_contract.test.ts
17-
#[private]
18-
fn main_contract(target: AztecAddress) -> Field {
19-
Test::at(target)
20-
.test_code_gen(
21-
1,
22-
true,
23-
1 as u32,
24-
[1, 2],
25-
DummyNote { amount: 1, secret_hash: 2 },
26-
DeepStruct {
27-
a_field: 1,
28-
a_bool: true,
29-
a_note: DummyNote { amount: 1, secret_hash: 2 },
30-
many_notes: [
31-
DummyNote { amount: 1, secret_hash: 2 },
32-
DummyNote { amount: 1, secret_hash: 2 },
33-
DummyNote { amount: 1, secret_hash: 2 },
34-
],
35-
},
36-
)
37-
.call(&mut context)
38-
}
39-
4013
// Calls the get_this_address on the Test contract at the target address
4114
// Used for testing calling a function with no arguments
4215
// See yarn-project/end-to-end/src/e2e_nested_contract.test.ts

noir-projects/noir-contracts/contracts/test/test_contract/src/main.nr

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub contract Test {
3737
event::event_emission::emit_event_in_private,
3838
messages::message_delivery::MessageDelivery,
3939
// Hashing
40-
hash::{ArgsHasher, pedersen_hash},
40+
hash::pedersen_hash,
4141
// History and inclusion proofs
4242
history::note_inclusion::ProveNoteInclusion,
4343
// Key management
@@ -264,33 +264,6 @@ pub contract Test {
264264
header.prove_note_inclusion(retrieved_notes.get(0), storage_slot);
265265
}
266266

267-
#[private]
268-
fn test_code_gen(
269-
a_field: Field,
270-
a_bool: bool,
271-
a_number: u32,
272-
an_array: [Field; 2],
273-
a_struct: DummyNote,
274-
a_deep_struct: DeepStruct,
275-
) -> Field {
276-
let mut args = ArgsHasher::new();
277-
args.add(a_field);
278-
args.add(a_bool as Field);
279-
args.add(a_number as Field);
280-
args.add_multiple(an_array);
281-
args.add(a_struct.amount);
282-
args.add(a_struct.secret_hash);
283-
args.add(a_deep_struct.a_field);
284-
args.add(a_deep_struct.a_bool as Field);
285-
args.add(a_deep_struct.a_note.amount);
286-
args.add(a_deep_struct.a_note.secret_hash);
287-
for note in a_deep_struct.many_notes {
288-
args.add(note.amount);
289-
args.add(note.secret_hash);
290-
}
291-
args.hash()
292-
}
293-
294267
#[private]
295268
fn test_setting_teardown() {
296269
context.set_public_teardown_function(

yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ describe('e2e_nested_contract manual', () => {
2424
await t.teardown();
2525
});
2626

27-
it('calls a method with multiple arguments', async () => {
28-
logger.info(`Calling main on importer contract`);
29-
await importerContract.methods.main_contract(testContract.address).send({ from: defaultAccountAddress }).wait();
30-
});
31-
3227
it('calls a method no arguments', async () => {
3328
logger.info(`Calling noargs on importer contract`);
3429
await importerContract.methods.call_no_args(testContract.address).send({ from: defaultAccountAddress }).wait();

0 commit comments

Comments
 (0)