diff --git a/noir-projects/aztec-nr/aztec/src/capsules/mod.nr b/noir-projects/aztec-nr/aztec/src/capsules/mod.nr index 10595a6b87b0..c8d88aada5a8 100644 --- a/noir-projects/aztec-nr/aztec/src/capsules/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/capsules/mod.nr @@ -12,10 +12,7 @@ pub struct CapsuleArray { base_slot: Field, } -impl CapsuleArray -where - T: Serialize + Deserialize, -{ +impl CapsuleArray { /// Returns a CapsuleArray connected to a contract's capsules at a base slot. Array elements are stored in /// contiguous slots following the base slot, so there should be sufficient space between array base slots to /// accommodate elements. A reasonable strategy is to make the base slot a hash of a unique value. @@ -30,7 +27,10 @@ where } /// Stores a value at the end of the array. - pub unconstrained fn push(self, value: T) { + pub unconstrained fn push(self, value: T) + where + T: Serialize, + { let current_length = self.len(); // The slot corresponding to the index `current_length` is the first slot immediately after the end of the @@ -43,7 +43,10 @@ where } /// Retrieves the value stored in the array at `index`. Throws if the index is out of bounds. - pub unconstrained fn get(self, index: u32) -> T { + pub unconstrained fn get(self, index: u32) -> T + where + T: Deserialize, + { assert(index < self.len(), "Attempted to read past the length of a CapsuleArray"); capsules::load(self.contract_address, self.slot_at(index)).unwrap() diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 9365d530aa84..b203ce3aa7fb 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -82,9 +82,9 @@ impl PrivateImmutable { // docs:end:get_note } -impl PrivateImmutable +impl PrivateImmutable where - Note: NoteType + NoteHash + Packable + Eq, + Note: NoteType + NoteHash + Eq, { // docs:start:is_initialized pub unconstrained fn is_initialized(self) -> bool { @@ -95,7 +95,10 @@ where // view_note does not actually use the context, but it calls oracles that are only available in private // docs:start:view_note - pub unconstrained fn view_note(self) -> Note { + pub unconstrained fn view_note(self) -> Note + where + Note: Packable, + { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index e4cab365aa4c..d8a378c7ceb8 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -57,12 +57,15 @@ impl PrivateMutable { } } -impl PrivateMutable +impl PrivateMutable where - Note: NoteType + NoteHash + Packable, + Note: NoteType + NoteHash, { // docs:start:initialize - pub fn initialize(self, note: Note) -> NoteEmission { + pub fn initialize(self, note: Note) -> NoteEmission + where + Note: Packable, + { // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); self.context.push_nullifier(nullifier); @@ -72,7 +75,10 @@ where // docs:end:initialize // docs:start:replace - pub fn replace(self, new_note: Note) -> NoteEmission { + pub fn replace(self, new_note: Note) -> NoteEmission + where + Note: Packable, + { let (prev_retrieved_note, note_hash_for_read_request): (RetrievedNote, Field) = get_note(self.context, self.storage_slot); @@ -88,7 +94,10 @@ where } // docs:end:replace - pub fn initialize_or_replace(self, note: Note) -> NoteEmission { + pub fn initialize_or_replace(self, note: Note) -> NoteEmission + where + Note: Packable, + { // Safety: `check_nullifier_exists` is an unconstrained function - we can constrain a true value // by providing an inclusion proof of the nullifier, but cannot constrain a false value since // a non-inclusion proof would only be valid if done in public. @@ -111,7 +120,10 @@ where } // docs:start:get_note - pub fn get_note(self) -> NoteEmission { + pub fn get_note(self) -> NoteEmission + where + Note: Packable, + { let mut (retrieved_note, note_hash_for_read_request) = get_note(self.context, self.storage_slot); @@ -125,9 +137,9 @@ where // docs:end:get_note } -impl PrivateMutable +impl PrivateMutable where - Note: NoteType + NoteHash + Packable + Eq, + Note: NoteType + NoteHash + Eq, { pub unconstrained fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); @@ -135,7 +147,10 @@ where } // docs:start:view_note - pub unconstrained fn view_note(self) -> Note { + pub unconstrained fn view_note(self) -> Note + where + Note: Packable, + { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(0) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 7492ca8e6859..616d42a56dbf 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -41,20 +41,26 @@ impl PrivateSet { // docs:end:new } -impl PrivateSet +impl PrivateSet where - Note: NoteType + NoteHash + Eq + Packable, + Note: NoteType + NoteHash + Eq, { // docs:start:insert - pub fn insert(self, note: Note) -> NoteEmission { + pub fn insert(self, note: Note) -> NoteEmission + where + Note: Packable, + { create_note(self.context, self.storage_slot, note) } // docs:end:insert - pub fn pop_notes( + pub fn pop_notes( self, options: NoteGetterOptions, - ) -> BoundedVec { + ) -> BoundedVec + where + Note: Packable, + { let (retrieved_notes, note_hashes) = get_notes(self.context, self.storage_slot, options); // We iterate in a range 0..options.limit instead of 0..notes.len() because options.limit is known at compile // time and hence will result in less constraints when set to a lower value than @@ -87,23 +93,29 @@ where /// Note that if you later on remove the note it's much better to use `pop_notes` as `pop_notes` results /// in significantly less constrains due to avoiding 1 read request check. - pub fn get_notes( + pub fn get_notes( self, options: NoteGetterOptions, - ) -> BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL> { + ) -> BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL> + where + Note: Packable, + { get_notes(self.context, self.storage_slot, options).0 } } -impl PrivateSet +impl PrivateSet where - Note: NoteType + NoteHash + Packable + Eq, + Note: NoteType + NoteHash + Eq, { // docs:start:view_notes - pub unconstrained fn view_notes( + pub unconstrained fn view_notes( self, options: NoteViewerOptions, - ) -> BoundedVec { + ) -> BoundedVec + where + Note: Packable, + { view_notes(self.storage_slot, options) } // docs:end:view_notes diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index 7e1e77a575ff..1eb3ecc8420b 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -64,12 +64,12 @@ impl PublicImmutable { // docs:end:public_immutable_struct_new } -impl PublicImmutable -where - T: Packable + Eq, -{ +impl PublicImmutable { // docs:start:public_immutable_struct_write - pub fn initialize(self, value: T) { + pub fn initialize(self, value: T) + where + T: Packable + Eq, + { // We check that the struct is not yet initialized by checking if the initialization slot is 0 let initialization_slot = INITIALIZATION_SLOT_SEPARATOR + self.storage_slot; let init_field: Field = self.context.storage_read(initialization_slot); @@ -83,26 +83,29 @@ where // Note that we don't access the context, but we do call oracles that are only available in public // docs:start:public_immutable_struct_read - pub fn read(self) -> T { + pub fn read(self) -> T + where + T: Packable + Eq, + { WithHash::public_storage_read(*self.context, self.storage_slot) } // docs:end:public_immutable_struct_read } -impl PublicImmutable -where - T: Packable + Eq, -{ - pub unconstrained fn read(self) -> T { +impl PublicImmutable { + pub unconstrained fn read(self) -> T + where + T: Packable + Eq, + { WithHash::unconstrained_public_storage_read(self.context, self.storage_slot) } } -impl PublicImmutable -where - T: Packable + Eq, -{ - pub fn read(self) -> T { +impl PublicImmutable { + pub fn read(self) -> T + where + T: Packable + Eq, + { WithHash::historical_public_storage_read( self.context.get_block_header(), self.context.this_address(), diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 755dd941d020..49936041e9ad 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -31,28 +31,31 @@ impl PublicMutable { // docs:end:public_mutable_struct_new } -impl PublicMutable -where - T: Packable, -{ +impl PublicMutable { // docs:start:public_mutable_struct_read - pub fn read(self) -> T { + pub fn read(self) -> T + where + T: Packable, + { self.context.storage_read(self.storage_slot) } // docs:end:public_mutable_struct_read // docs:start:public_mutable_struct_write - pub fn write(self, value: T) { + pub fn write(self, value: T) + where + T: Packable, + { self.context.storage_write(self.storage_slot, value); } // docs:end:public_mutable_struct_write } -impl PublicMutable -where - T: Packable, -{ - pub unconstrained fn read(self) -> T { +impl PublicMutable { + pub unconstrained fn read(self) -> T + where + T: Packable, + { self.context.storage_read(self.storage_slot) } } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr index 60d099e9f8eb..08c40f7c6e4e 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable.nr @@ -38,26 +38,32 @@ where // future, so that they can guarantee the value will not have possibly changed by then (because of the delay). // The delay for changing a value is initially equal to INITIAL_DELAY, but can be changed by calling // `schedule_delay_change`. -impl SharedMutable -where - T: Packable + Eq, -{ +impl SharedMutable { pub fn new(context: Context, storage_slot: Field) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { context, storage_slot } } } -impl SharedMutable +impl SharedMutable where - T: Packable + Eq, + T: Eq, { - pub fn schedule_value_change(self, new_value: T) { + pub fn schedule_value_change(self, new_value: T) + where + T: Packable, + { let _value_change = self.schedule_and_return_value_change(new_value); } - pub fn schedule_and_return_value_change(self, new_value: T) -> ScheduledValueChange { + pub fn schedule_and_return_value_change( + self, + new_value: T, + ) -> ScheduledValueChange + where + T: Packable, + { let mut value_change = self.read_value_change(); let delay_change = self.read_delay_change(); @@ -74,7 +80,10 @@ where value_change } - pub fn schedule_delay_change(self, new_delay: u32) { + pub fn schedule_delay_change(self, new_delay: u32) + where + T: Packable, + { let mut delay_change = self.read_delay_change(); let block_number = self.context.block_number() as u32; @@ -84,32 +93,50 @@ where self.write(self.read_value_change(), delay_change); } - pub fn get_current_value(self) -> T { + pub fn get_current_value(self) -> T + where + T: Packable, + { let block_number = self.context.block_number() as u32; self.read_value_change().get_current_at(block_number) } - pub fn get_current_delay(self) -> u32 { + pub fn get_current_delay(self) -> u32 + where + T: Packable, + { let block_number = self.context.block_number() as u32; self.read_delay_change().get_current(block_number) } - pub fn get_scheduled_value(self) -> (T, u32) { + pub fn get_scheduled_value(self) -> (T, u32) + where + T: Packable, + { self.read_value_change().get_scheduled() } - pub fn get_scheduled_delay(self) -> (u32, u32) { + pub fn get_scheduled_delay(self) -> (u32, u32) + where + T: Packable, + { self.read_delay_change().get_scheduled() } - fn read_value_change(self) -> ScheduledValueChange { + fn read_value_change(self) -> ScheduledValueChange + where + T: Packable, + { // We don't read ScheduledValueChange directly by having it implement Packable because ScheduledValueChange // and ScheduledDelayChange are packed together (sdc and svc.block_of_change are stored in the same slot). let packed = self.context.storage_read(self.storage_slot); SharedMutableValues::unpack_value_change(packed) } - fn read_delay_change(self) -> ScheduledDelayChange { + fn read_delay_change(self) -> ScheduledDelayChange + where + T: Packable, + { // Since all ScheduledDelayChange member are packed into a single field, we can read a single storage slot // here and skip the ones that correspond to ScheduledValueChange members. We are abusing the fact that // the field containing the ScheduledDelayChange data is the first one in the storage layout - otherwise we'd @@ -121,11 +148,14 @@ where SharedMutableValues::::unpack_delay_change(packed) } - fn write( + fn write( self, value_change: ScheduledValueChange, delay_change: ScheduledDelayChange, - ) { + ) + where + T: Packable, + { // Whenever we write to public storage, we write both the value change and delay change to storage at once. // We do so by wrapping them in a single struct (`SharedMutableValues`). Then we wrap the resulting struct in // `WithHash`. @@ -139,11 +169,14 @@ where } } -impl SharedMutable +impl SharedMutable where - T: Packable + Eq, + T: Eq, { - pub fn get_current_value(self) -> T { + pub fn get_current_value(self) -> T + where + T: Packable, + { // When reading the current value in private we construct a historical state proof for the public value. // However, since this value might change, we must constrain the maximum transaction block number as this proof // will only be valid for however many blocks we can ensure the value will not change, which will depend on the @@ -169,9 +202,12 @@ where value_change.get_current_at(historical_block_number) } - fn historical_read_from_public_storage( + fn historical_read_from_public_storage( self, - ) -> (ScheduledValueChange, ScheduledDelayChange, u32) { + ) -> (ScheduledValueChange, ScheduledDelayChange, u32) + where + T: Packable, + { let header = self.context.get_block_header(); let address = self.context.this_address(); @@ -184,11 +220,14 @@ where } } -impl SharedMutable +impl SharedMutable where - T: Packable + Eq, + T: Eq, { - pub unconstrained fn get_current_value(self) -> T { + pub unconstrained fn get_current_value(self) -> T + where + T: Packable, + { let smv: SharedMutableValues = WithHash::unconstrained_public_storage_read(self.context, self.storage_slot); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/shared_mutable/shared_mutable_values.nr b/noir-projects/noir-protocol-circuits/crates/types/src/shared_mutable/shared_mutable_values.nr index 8242e498f133..2a0e4535b991 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/shared_mutable/shared_mutable_values.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/shared_mutable/shared_mutable_values.nr @@ -25,15 +25,15 @@ pub struct SharedMutableValues { pub sdc: ScheduledDelayChange, } -impl SharedMutableValues -where - T: Packable, -{ +impl SharedMutableValues { pub fn new(svc: ScheduledValueChange, sdc: ScheduledDelayChange) -> Self { SharedMutableValues { svc, sdc } } - pub fn unpack_value_change(packed: [Field; 2 * N + 1]) -> ScheduledValueChange { + pub fn unpack_value_change(packed: [Field; 2 * N + 1]) -> ScheduledValueChange + where + T: Packable, + { let svc_pre_packed = arrays::subarray(packed, 1); let svc_post_packed = arrays::subarray(packed, N + 1); ScheduledValueChange::new(