← aztec-testnet-frames0x0a807e…0592Succeededblock 69361
Engine loading — 18 MB107 / 459
FetchingOpeningPositioning
Narrow session: Code, Call Trace and Values only, read-only. The event log and stepping need a wider viewport.
Code
1 use crate::{
2 context::{inputs::PrivateContextInputs, NullifierExistenceRequest, ReturnsHash},
3 hash::hash_args,
4 messaging::process_l1_to_l2_message,
5 oracle::{
6 call_private_function::call_private_function_internal,
7 public_call::validate_public_calldata,
8 tx_phase::{in_revertible_phase, notify_revertible_phase_start},
9 execution_cache,
10 logs::notify_created_contract_class_log,
11 nullifiers::notify_created_nullifier,
12 },
13 };
14 use crate::protocol::{
15 abis::{
16 block_header::BlockHeader,
17 call_context::CallContext,
18 function_selector::FunctionSelector,
19 gas_settings::GasSettings,
20 log_hash::LogHash,
21 nullifier::Nullifier,
22 private_call_request::PrivateCallRequest,
23 private_circuit_public_inputs::PrivateCircuitPublicInputs,
24 private_log::{PrivateLog, PrivateLogData},
25 public_call_request::PublicCallRequest,
26 },
27 address::{AztecAddress, EthAddress},
28 constants::{
29 CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, MAX_CONTRACT_CLASS_LOGS_PER_CALL,
30 MAX_ENQUEUED_CALLS_PER_CALL, MAX_TX_LIFETIME, MAX_L2_TO_L1_MSGS_PER_CALL,
31 MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL,
32 MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_LOGS_PER_CALL,
33 NULL_MSG_SENDER_CONTRACT_ADDRESS, PRIVATE_LOG_SIZE_IN_FIELDS,
34 },
35 hash::poseidon2_hash,
36 messaging::l2_to_l1_message::L2ToL1Message,
37 side_effect::{Counted, scoped::Scoped},
38 traits::Empty,
39 utils::arrays::{ClaimedLengthArray, trimmed_array_length_hint},
40 };
41
42 /// Minimal PrivateContext for protocol contracts going to audit.
43 /// Contains only the methods actually used by: fee_juice, auth_registry, contract_class_registry, contract_instance_registry
44 #[derive(Eq)]
45 pub struct PrivateContext {
46 pub inputs: PrivateContextInputs,
47 pub side_effect_counter: u32,
48
49 pub min_revertible_side_effect_counter: u32,
50 pub is_fee_payer: bool,
51
52 pub args_hash: Field,
53 pub return_hash: Field,
54
55 pub expiration_timestamp: u64,
56
57 pub nullifier_read_requests: BoundedVec<Scoped<Counted<Field>>, MAX_NULLIFIER_READ_REQUESTS_PER_CALL>,
58
59 pub nullifiers: BoundedVec<Counted<Nullifier>, MAX_NULLIFIERS_PER_CALL>,
60
61 pub private_call_requests: BoundedVec<PrivateCallRequest, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL>,
62 pub public_call_requests: BoundedVec<Counted<PublicCallRequest>, MAX_ENQUEUED_CALLS_PER_CALL>,
63 pub public_teardown_call_request: PublicCallRequest,
64 pub l2_to_l1_msgs: BoundedVec<Counted<L2ToL1Message>, MAX_L2_TO_L1_MSGS_PER_CALL>,
65
66 // Header of a block whose state is used during private execution (not the block the transaction is included in).
67 pub anchor_block_header: BlockHeader,
68
69 pub private_logs: BoundedVec<Counted<PrivateLogData>, MAX_PRIVATE_LOGS_PER_CALL>,
70 pub contract_class_logs_hashes: BoundedVec<Counted<LogHash>, MAX_CONTRACT_CLASS_LOGS_PER_CALL>,
71
72 pub expected_non_revertible_side_effect_counter: u32,
73 pub expected_revertible_side_effect_counter: u32,
74 }
75
76 impl PrivateContext {
77 pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext {
78 PrivateContext {
79 inputs,
80 side_effect_counter: inputs.start_side_effect_counter + 1,
81 min_revertible_side_effect_counter: 0,
82 is_fee_payer: false,
83 args_hash,
84 return_hash: 0,
85 expiration_timestamp: inputs.anchor_block_header.global_variables.timestamp
86 + MAX_TX_LIFETIME,
87 nullifier_read_requests: BoundedVec::new(),
88 nullifiers: BoundedVec::new(),
89 anchor_block_header: inputs.anchor_block_header,
90 private_call_requests: BoundedVec::new(),
91 public_call_requests: BoundedVec::new(),
92 public_teardown_call_request: PublicCallRequest::empty(),
93 l2_to_l1_msgs: BoundedVec::new(),
94 private_logs: BoundedVec::new(),
95 contract_class_logs_hashes: BoundedVec::new(),
96 expected_non_revertible_side_effect_counter: 0,
97 expected_revertible_side_effect_counter: 0,
98 }
99 }
100
101 /// Returns the contract address that initiated this function call (similar to msg.sender in Solidity).
102 pub fn maybe_msg_sender(self) -> Option<AztecAddress> {
103 let maybe_msg_sender = self.inputs.call_context.msg_sender;
104 if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {
105 Option::none()
106 } else {
107 Option::some(maybe_msg_sender)
108 }
109 }
110
111 /// Returns the contract address of the current function being executed.
112 pub fn this_address(self) -> AztecAddress {
113 self.inputs.call_context.contract_address
114 }
115
116 /// Returns the chain ID of the current network.
117 pub fn chain_id(self) -> Field {
118 self.inputs.tx_context.chain_id
119 }
120
121 /// Returns the protocol version.
122 pub fn version(self) -> Field {
123 self.inputs.tx_context.version
124 }
125
126 /// Returns the gas settings for the current transaction.
127 pub fn gas_settings(self) -> GasSettings {
128 self.inputs.tx_context.gas_settings
129 }
130
131 /// Returns the function selector of the currently executing function.
132 pub fn selector(self) -> FunctionSelector {
133 self.inputs.call_context.function_selector
134 }
135
136 /// Returns the hash of the arguments passed to the current function.
137 pub fn get_args_hash(self) -> Field {
138 self.args_hash
139 }
140
141 /// Returns the anchor block header.
142 pub fn get_anchor_block_header(self) -> BlockHeader {
143 self.anchor_block_header
144 }
145
146 /// Sets the hash of the return values for this private function.
147 pub fn set_return_hash<let N: u32>(&mut self, serialized_return_values: [Field; N]) {
148 let return_hash = hash_args(serialized_return_values);
149 self.return_hash = return_hash;
150 execution_cache::store(serialized_return_values, return_hash);
151 }
152
153 /// Builds the PrivateCircuitPublicInputs for this private function.
154 pub fn finish(self) -> PrivateCircuitPublicInputs {
155 PrivateCircuitPublicInputs {
156 call_context: self.inputs.call_context,
157 args_hash: self.args_hash,
158 returns_hash: self.return_hash,
159 min_revertible_side_effect_counter: self.min_revertible_side_effect_counter,
160 is_fee_payer: self.is_fee_payer,
161 expiration_timestamp: self.expiration_timestamp,
162 note_hash_read_requests: ClaimedLengthArray::empty(), // Not used by protocol contracts
163 nullifier_read_requests: ClaimedLengthArray::from_bounded_vec(
164 self.nullifier_read_requests,
165 ),
166 key_validation_requests_and_separators: ClaimedLengthArray::empty(), // Not used by protocol contracts
167 note_hashes: ClaimedLengthArray::empty(), // Not used by protocol contracts
168 nullifiers: ClaimedLengthArray::from_bounded_vec(self.nullifiers),
169 private_call_requests: ClaimedLengthArray::from_bounded_vec(self.private_call_requests),
170 public_call_requests: ClaimedLengthArray::from_bounded_vec(self.public_call_requests),
171 public_teardown_call_request: self.public_teardown_call_request,
172 l2_to_l1_msgs: ClaimedLengthArray::from_bounded_vec(self.l2_to_l1_msgs),
173 start_side_effect_counter: self.inputs.start_side_effect_counter,
174 end_side_effect_counter: self.side_effect_counter,
175 private_logs: ClaimedLengthArray::from_bounded_vec(self.private_logs),
176 contract_class_logs_hashes: ClaimedLengthArray::from_bounded_vec(
177 self.contract_class_logs_hashes,
178 ),
179 anchor_block_header: self.anchor_block_header,
180 tx_context: self.inputs.tx_context,
181 expected_non_revertible_side_effect_counter: self
182 .expected_non_revertible_side_effect_counter,
183 expected_revertible_side_effect_counter: self.expected_revertible_side_effect_counter,
184 tx_request_salt: self.inputs.tx_request_salt,
185 }
186 }
187
188 /// Declares the end of the "setup phase" of this tx. Used by fee_juice.
189 pub fn end_setup(&mut self) {
190 self.side_effect_counter += 1;
191 self.min_revertible_side_effect_counter = self.next_counter();
192 notify_revertible_phase_start(self.min_revertible_side_effect_counter);
193 }
194
195 pub fn in_revertible_phase(&mut self) -> bool {
196 let current_counter = self.side_effect_counter;
197
198 // Safety: Kernel will validate that the claim is correct by validating the expected counters.
199 let is_revertible =
200 unsafe { in_revertible_phase(current_counter) };
201
202 if is_revertible {
203 if (self.expected_revertible_side_effect_counter == 0)
204 | (current_counter < self.expected_revertible_side_effect_counter) {
205 self.expected_revertible_side_effect_counter = current_counter;
206 }
207 } else if current_counter > self.expected_non_revertible_side_effect_counter {
208 self.expected_non_revertible_side_effect_counter = current_counter;
209 }
210
211 is_revertible
212 }
213
214 /// Sets a deadline for when this transaction must be included in a block.
215 pub fn set_expiration_timestamp(&mut self, expiration_timestamp: u64) {
216 self.expiration_timestamp = std::cmp::min(self.expiration_timestamp, expiration_timestamp);
217 }
218
219 /// Pushes a new nullifier. Used by class_registry and instance_registry.
220 pub fn push_nullifier(&mut self, nullifier: Field) {
221 notify_created_nullifier(nullifier);
222 self.nullifiers.push(Nullifier { value: nullifier, note_hash: 0 }.count(self.next_counter()));
223 }
224
225 /// Asserts that a nullifier has been emitted. Used by instance_registry.
226 pub fn assert_nullifier_exists(
227 &mut self,
228 nullifier_existence_request: NullifierExistenceRequest,
229 ) {
230 let nullifier = nullifier_existence_request.nullifier();
231 let contract_address =
232 nullifier_existence_request.maybe_contract_address().unwrap_or(AztecAddress::zero());
233
234 let request = Scoped::new(
235 Counted::new(nullifier, self.next_counter()),
236 contract_address,
237 );
238
239 self.nullifier_read_requests.push(request);
240 }
241
242 /// Consumes a message sent from Ethereum (L1) to Aztec (L2). Used by fee_juice.
243 pub fn consume_l1_to_l2_message(
244 &mut self,
245 content: Field,
246 secret: Field,
247 sender: EthAddress,
248 leaf_index: Field,
249 ) {
250 let nullifier = process_l1_to_l2_message(
251 self.anchor_block_header.state.l1_to_l2_message_tree.root,
252 self.this_address(),
253 sender,
254 self.chain_id(),
255 self.version(),
256 content,
257 secret,
258 leaf_index,
259 );
260
261 // Push nullifier (and the "commitment" corresponding to this can be "empty")
262 self.push_nullifier(nullifier)
263 }
264
265 /// Emits a private log. Used by instance_registry.
266 pub fn emit_private_log(&mut self, log: [Field; PRIVATE_LOG_SIZE_IN_FIELDS], length: u32) {
267 let counter = self.next_counter();
268 let private_log = PrivateLogData { log: PrivateLog::new(log, length), note_hash_counter: 0 }
269 .count(counter);
270 self.private_logs.push(private_log);
271 }
272
273 /// Emits a contract class log. Used by class_registry.
274 pub fn emit_contract_class_log<let N: u32>(&mut self, log: [Field; N]) {
275 let contract_address = self.this_address();
276 let counter = self.next_counter();
277
278 let log_to_emit: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS] =
279 log.concat([0; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS - N]);
280 // Safety: The below length is constrained in the base rollup, which will make sure that all the fields beyond
281 // length are zero. However, it won't be able to check that we didn't add extra padding (trailing zeroes) or
282 // that we cut trailing zeroes from the end.
283 let length = unsafe { trimmed_array_length_hint(log_to_emit) };
284 // We hash the entire padded log to ensure a user cannot pass a shorter length and so emit incorrect shorter
285 // bytecode.
286 let log_hash = poseidon2_hash(log_to_emit);
287 // Safety: the below only exists to broadcast the raw log, so we can provide it to the base rollup later to be
288 // constrained.
289 unsafe {
290 notify_created_contract_class_log(contract_address, log_to_emit, length, counter);
291 }
292
293 self.contract_class_logs_hashes.push(LogHash { value: log_hash, length: length }.count(
294 counter,
295 ));
296 }
297
298 /// Makes a read-only call to a private function. Used by auth_registry for authwit.
299 pub fn static_call_private_function<let ArgsCount: u32>(
300 &mut self,
301 contract_address: AztecAddress,
302 function_selector: FunctionSelector,
303 args: [Field; ArgsCount],
304 ) -> ReturnsHash {
305 let args_hash = hash_args(args);
306 execution_cache::store(args, args_hash);
307 self.call_private_function_with_args_hash(
308 contract_address,
309 function_selector,
310 args_hash,
311 true,
312 )
313 }
314
315 fn call_private_function_with_args_hash(
316 &mut self,
317 contract_address: AztecAddress,
318 function_selector: FunctionSelector,
319 args_hash: Field,
320 is_static_call: bool,
321 ) -> ReturnsHash {
322 let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call;
323 let start_side_effect_counter = self.side_effect_counter;
324
325 // Safety: The oracle simulates the private call and returns the value of the side effects counter after
326 // execution of the call.
327 let (end_side_effect_counter, returns_hash) = unsafe {
328 call_private_function_internal(
329 contract_address,
330 function_selector,
331 args_hash,
332 start_side_effect_counter,
333 is_static_call,
334 )
335 };
336
337 self.private_call_requests.push(
338 PrivateCallRequest {
339 call_context: CallContext {
340 msg_sender: self.this_address(),
341 contract_address,
342 function_selector,
343 is_static_call,
344 },
345 args_hash,
346 returns_hash,
347 start_side_effect_counter,
348 end_side_effect_counter,
349 },
350 );
351
352 self.side_effect_counter = end_side_effect_counter + 1;
353 ReturnsHash::new(returns_hash)
354 }
355
356 /// Enqueues a call to a public function with a calldata hash. Used by fee_juice and auth_registry.
357 pub fn call_public_function_with_calldata_hash(
358 &mut self,
359 contract_address: AztecAddress,
360 calldata_hash: Field,
361 is_static_call: bool,
362 hide_msg_sender: bool,
363 ) {
364 let counter = self.next_counter();
365
366 let is_static_call = is_static_call | self.inputs.call_context.is_static_call;
367
368 validate_public_calldata(calldata_hash);
369
370 let msg_sender = if hide_msg_sender {
371 NULL_MSG_SENDER_CONTRACT_ADDRESS
372 } else {
373 self.this_address()
374 };
375
376 let call_request =
377 PublicCallRequest { msg_sender, contract_address, is_static_call, calldata_hash };
378
379 self.public_call_requests.push(Counted::new(call_request, counter));
380 }
381
382 fn next_counter(&mut self) -> u32 {
383 let counter = self.side_effect_counter;
384 self.side_effect_counter += 1;
385 counter
386 }
387 }
388
389 impl Empty for PrivateContext {
390 fn empty() -> Self {
391 PrivateContext {
392 inputs: PrivateContextInputs::empty(),
393 side_effect_counter: 0 as u32,
394 min_revertible_side_effect_counter: 0 as u32,
395 is_fee_payer: false,
396 args_hash: 0,
397 return_hash: 0,
398 expiration_timestamp: 0,
399 nullifier_read_requests: BoundedVec::new(),
400 nullifiers: BoundedVec::new(),
401 private_call_requests: BoundedVec::new(),
402 public_call_requests: BoundedVec::new(),
403 public_teardown_call_request: PublicCallRequest::empty(),
404 l2_to_l1_msgs: BoundedVec::new(),
405 anchor_block_header: BlockHeader::empty(),
406 private_logs: BoundedVec::new(),
407 contract_class_logs_hashes: BoundedVec::new(),
408 expected_non_revertible_side_effect_counter: 0,
409 expected_revertible_side_effect_counter: 0,
410 }
411 }
412 }
1 use crate::{
2 context::gas::GasOpts,
3 hash::{
4 compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash,
5 compute_siloed_nullifier,
6 },
7 oracle::avm,
8 };
9 use crate::protocol::{
10 abis::function_selector::FunctionSelector,
11 address::{AztecAddress, EthAddress},
12 constants::{MAX_U32_VALUE, NULL_MSG_SENDER_CONTRACT_ADDRESS},
13 traits::{Empty, FromField, Packable, Serialize, ToField},
14 };
15
16 /// Minimal PublicContext for protocol contracts going to audit.
17 pub struct PublicContext {
18 pub args_hash: Option<Field>,
19 pub compute_args_hash: fn() -> Field,
20 }
21
22 impl Eq for PublicContext {
23 fn eq(self, other: Self) -> bool {
24 (self.args_hash == other.args_hash)
25 // Can't compare the function compute_args_hash
26 }
27 }
28
29 impl PublicContext {
30 pub fn new(compute_args_hash: fn() -> Field) -> Self {
31 PublicContext { args_hash: Option::none(), compute_args_hash }
32 }
33
34 /// Emits a _public_ log that will be visible onchain to everyone.
35 pub fn emit_public_log<T>(_self: Self, log: T)
36 where
37 T: Serialize,
38 {
39 // Safety: AVM opcodes are constrained by the AVM itself
40 unsafe { avm::emit_public_log(Serialize::serialize(log).as_vector()) };
41 }
42
43 /// Checks if a given note hash exists in the note hash tree at a particular leaf_index.
44 pub fn note_hash_exists(_self: Self, note_hash: Field, leaf_index: u64) -> bool {
45 // Safety: AVM opcodes are constrained by the AVM itself
46 unsafe { avm::note_hash_exists(note_hash, leaf_index) }
47 }
48
49 /// Checks if a specific L1-to-L2 message exists in the L1-to-L2 message tree at a particular leaf index.
50 pub fn l1_to_l2_msg_exists(_self: Self, msg_hash: Field, msg_leaf_index: Field) -> bool {
51 // Safety: AVM opcodes are constrained by the AVM itself TODO(alvaro): Make l1l2msg leaf index a u64 upstream
52 unsafe { avm::l1_to_l2_msg_exists(msg_hash, msg_leaf_index as u64) }
53 }
54
55 /// Returns `true` if an `unsiloed_nullifier` has been emitted by `contract_address`.
56 pub fn nullifier_exists_unsafe(
57 _self: Self,
58 unsiloed_nullifier: Field,
59 contract_address: AztecAddress,
60 ) -> bool {
61 let siloed_nullifier = compute_siloed_nullifier(contract_address, unsiloed_nullifier);
62 // Safety: AVM opcodes are constrained by the AVM itself
63 unsafe { avm::nullifier_exists(siloed_nullifier) }
64 }
65
66 /// Consumes a message sent from Ethereum (L1) to Aztec (L2).
67 pub fn consume_l1_to_l2_message(
68 self: Self,
69 content: Field,
70 secret: Field,
71 sender: EthAddress,
72 leaf_index: Field,
73 ) {
74 let secret_hash = compute_secret_hash(secret);
75 let message_hash = compute_l1_to_l2_message_hash(
76 sender,
77 self.chain_id(),
78 /*recipient=*/
79 self.this_address(),
80 self.version(),
81 content,
82 secret_hash,
83 leaf_index,
84 );
85 let nullifier = compute_l1_to_l2_message_nullifier(message_hash, secret);
86
87 assert(
88 !self.nullifier_exists_unsafe(nullifier, self.this_address()),
89 "L1-to-L2 message is already nullified",
90 );
91 assert(
92 self.l1_to_l2_msg_exists(message_hash, leaf_index),
93 "Tried to consume nonexistent L1-to-L2 message",
94 );
95
96 self.push_nullifier(nullifier);
97 }
98
99 /// Sends an "L2 -> L1 message".
100 pub fn message_portal(_self: Self, recipient: EthAddress, content: Field) {
101 // Safety: AVM opcodes are constrained by the AVM itself
102 unsafe { avm::send_l2_to_l1_msg(recipient, content) };
103 }
104
105 /// Calls a public function on another contract.
106 pub unconstrained fn call_public_function<let N: u32>(
107 _self: Self,
108 contract_address: AztecAddress,
109 function_selector: FunctionSelector,
110 args: [Field; N],
111 gas_opts: GasOpts,
112 ) -> [Field] {
113 let calldata = [function_selector.to_field()].concat(args);
114
115 avm::call(
116 gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),
117 gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),
118 contract_address,
119 calldata,
120 );
121 // Use success_copy to determine whether the call succeeded
122 let success = avm::success_copy();
123
124 let result_data = avm::returndata_copy(0, avm::returndata_size());
125 if !success {
126 // Rethrow the revert data.
127 avm::revert(result_data);
128 }
129 result_data
130 }
131
132 /// Makes a read-only call to a public function on another contract.
133 pub unconstrained fn static_call_public_function<let N: u32>(
134 _self: Self,
135 contract_address: AztecAddress,
136 function_selector: FunctionSelector,
137 args: [Field; N],
138 gas_opts: GasOpts,
139 ) -> [Field] {
140 let calldata = [function_selector.to_field()].concat(args);
141
142 avm::call_static(
143 gas_opts.l2_gas.unwrap_or(MAX_U32_VALUE),
144 gas_opts.da_gas.unwrap_or(MAX_U32_VALUE),
145 contract_address,
146 calldata,
147 );
148 // Use success_copy to determine whether the call succeeded
149 let success = avm::success_copy();
150
151 let result_data = avm::returndata_copy(0, avm::returndata_size());
152 if !success {
153 // Rethrow the revert data.
154 avm::revert(result_data);
155 }
156 result_data
157 }
158
159 /// Adds a new note hash to the Note Hash Tree.
160 pub fn push_note_hash(_self: Self, note_hash: Field) {
161 // Safety: AVM opcodes are constrained by the AVM itself
162 unsafe { avm::emit_note_hash(note_hash) };
163 }
164
165 /// Adds a new nullifier to the Nullifier Tree.
166 pub fn push_nullifier(_self: Self, nullifier: Field) {
167 // Safety: AVM opcodes are constrained by the AVM itself
168 unsafe { avm::emit_nullifier(nullifier) };
169 }
170
171 /// Returns the address of the current contract being executed.
172 pub fn this_address(_self: Self) -> AztecAddress {
173 // Safety: AVM opcodes are constrained by the AVM itself
174 unsafe {
175 avm::address()
176 }
177 }
178
179 /// Returns the contract address that initiated this function call.
180 pub fn maybe_msg_sender(_self: Self) -> Option<AztecAddress> {
181 // Safety: AVM opcodes are constrained by the AVM itself
182 let maybe_msg_sender = unsafe { avm::sender() };
183 if maybe_msg_sender == NULL_MSG_SENDER_CONTRACT_ADDRESS {
184 Option::none()
185 } else {
186 Option::some(maybe_msg_sender)
187 }
188 }
189
190 /// Returns the function selector of the currently-executing function.
191 pub fn selector(_self: Self) -> FunctionSelector {
192 // The selector is the first element of the calldata when calling a public function through dispatch.
193 // Safety: AVM opcodes are constrained by the AVM itself.
194 let raw_selector: [Field; 1] = unsafe { avm::calldata_copy(0, 1) };
195 FunctionSelector::from_field(raw_selector[0])
196 }
197
198 /// Returns the hash of the arguments passed to the current function.
199 pub fn get_args_hash(mut self) -> Field {
200 if !self.args_hash.is_some() {
201 self.args_hash = Option::some((self.compute_args_hash)());
202 }
203
204 self.args_hash.unwrap_unchecked()
205 }
206
207 /// Returns the "transaction fee" for the current transaction.
208 pub fn transaction_fee(_self: Self) -> Field {
209 // Safety: AVM opcodes are constrained by the AVM itself
210 unsafe {
211 avm::transaction_fee()
212 }
213 }
214
215 /// Returns the chain ID of the current network.
216 pub fn chain_id(_self: Self) -> Field {
217 // Safety: AVM opcodes are constrained by the AVM itself
218 unsafe {
219 avm::chain_id()
220 }
221 }
222
223 /// Returns the protocol version.
224 pub fn version(_self: Self) -> Field {
225 // Safety: AVM opcodes are constrained by the AVM itself
226 unsafe {
227 avm::version()
228 }
229 }
230
231 /// Returns the current block number.
232 pub fn block_number(_self: Self) -> u32 {
233 // Safety: AVM opcodes are constrained by the AVM itself
234 unsafe {
235 avm::block_number()
236 }
237 }
238
239 /// Returns the timestamp of the current block.
240 pub fn timestamp(_self: Self) -> u64 {
241 // Safety: AVM opcodes are constrained by the AVM itself
242 unsafe {
243 avm::timestamp()
244 }
245 }
246
247 /// Returns the fee per unit of L2 gas.
248 pub fn min_fee_per_l2_gas(_self: Self) -> u128 {
249 // Safety: AVM opcodes are constrained by the AVM itself
250 unsafe {
251 avm::min_fee_per_l2_gas()
252 }
253 }
254
255 /// Returns the fee per unit of DA gas.
256 pub fn min_fee_per_da_gas(_self: Self) -> u128 {
257 // Safety: AVM opcodes are constrained by the AVM itself
258 unsafe {
259 avm::min_fee_per_da_gas()
260 }
261 }
262
263 /// Returns the remaining L2 gas available.
264 pub fn l2_gas_left(_self: Self) -> u32 {
265 // Safety: AVM opcodes are constrained by the AVM itself
266 unsafe {
267 avm::l2_gas_left()
268 }
269 }
270
271 /// Returns the remaining DA gas available.
272 pub fn da_gas_left(_self: Self) -> u32 {
273 // Safety: AVM opcodes are constrained by the AVM itself
274 unsafe {
275 avm::da_gas_left()
276 }
277 }
278
279 /// Checks if the current execution is within a staticcall context.
280 pub fn is_static_call(_self: Self) -> bool {
281 // Safety: AVM opcodes are constrained by the AVM itself
282 unsafe { avm::is_static_call() }
283 }
284
285 /// Reads raw field values from public storage.
286 pub fn raw_storage_read<let N: u32>(self: Self, storage_slot: Field) -> [Field; N] {
287 let mut out = [0; N];
288 for i in 0..N {
289 // Safety: AVM opcodes are constrained by the AVM itself
290 out[i] = unsafe {
291 avm::storage_read(storage_slot + i as Field, self.this_address().to_field())
292 };
293 }
294 out
295 }
296
297 /// Reads a typed value from public storage.
298 pub fn storage_read<T>(self, storage_slot: Field) -> T
299 where
300 T: Packable,
301 {
302 T::unpack(self.raw_storage_read(storage_slot))
303 }
304
305 /// Writes raw field values to public storage.
306 pub fn raw_storage_write<let N: u32>(_self: Self, storage_slot: Field, values: [Field; N]) {
307 for i in 0..N {
308 // Safety: AVM opcodes are constrained by the AVM itself
309 unsafe { avm::storage_write(storage_slot + i as Field, values[i]) };
310 }
311 }
312
313 /// Writes a typed value to public storage.
314 pub fn storage_write<T>(self, storage_slot: Field, value: T)
315 where
316 T: Packable,
317 {
318 self.raw_storage_write(storage_slot, value.pack());
319 }
320 }
321
322 impl Empty for PublicContext {
323 fn empty() -> Self {
324 PublicContext::new(|| 0)
325 }
326 }
1 //! Aztec hash functions.
2
3 use crate::protocol::{
4 address::{AztecAddress, EthAddress},
5 constants::{
6 DOM_SEP__FUNCTION_ARGS, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__PUBLIC_BYTECODE,
7 DOM_SEP__PUBLIC_CALLDATA, DOM_SEP__SECRET_HASH, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS,
8 },
9 hash::{poseidon2_hash_subarray, poseidon2_hash_with_separator, sha256_to_field},
10 traits::ToField,
11 };
12
13 pub use crate::protocol::hash::compute_siloed_nullifier;
14
15 pub fn compute_secret_hash(secret: Field) -> Field {
16 poseidon2_hash_with_separator([secret], DOM_SEP__SECRET_HASH)
17 }
18
19 pub fn compute_l1_to_l2_message_hash(
20 sender: EthAddress,
21 chain_id: Field,
22 recipient: AztecAddress,
23 version: Field,
24 content: Field,
25 secret_hash: Field,
26 leaf_index: Field,
27 ) -> Field {
28 let mut hash_bytes = [0 as u8; 224];
29 let sender_bytes: [u8; 32] = sender.to_field().to_be_bytes();
30 let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();
31 let recipient_bytes: [u8; 32] = recipient.to_field().to_be_bytes();
32 let version_bytes: [u8; 32] = version.to_be_bytes();
33 let content_bytes: [u8; 32] = content.to_be_bytes();
34 let secret_hash_bytes: [u8; 32] = secret_hash.to_be_bytes();
35 let leaf_index_bytes: [u8; 32] = leaf_index.to_be_bytes();
36
37 for i in 0..32 {
38 hash_bytes[i] = sender_bytes[i];
39 hash_bytes[i + 32] = chain_id_bytes[i];
40 hash_bytes[i + 64] = recipient_bytes[i];
41 hash_bytes[i + 96] = version_bytes[i];
42 hash_bytes[i + 128] = content_bytes[i];
43 hash_bytes[i + 160] = secret_hash_bytes[i];
44 hash_bytes[i + 192] = leaf_index_bytes[i];
45 }
46
47 sha256_to_field(hash_bytes)
48 }
49
50 // The nullifier of a l1 to l2 message is the hash of the message salted with the secret
51 pub fn compute_l1_to_l2_message_nullifier(message_hash: Field, secret: Field) -> Field {
52 poseidon2_hash_with_separator([message_hash, secret], DOM_SEP__MESSAGE_NULLIFIER)
53 }
54
55 // Computes the hash of input arguments or return values for private functions, or for authwit creation.
56 pub fn hash_args<let N: u32>(args: [Field; N]) -> Field {
57 if args.len() == 0 {
58 0
59 } else {
60 poseidon2_hash_with_separator(args, DOM_SEP__FUNCTION_ARGS)
61 }
62 }
63
64 // Computes the hash of calldata for public functions.
65 pub fn hash_calldata_array<let N: u32>(calldata: [Field; N]) -> Field {
66 poseidon2_hash_with_separator(calldata, DOM_SEP__PUBLIC_CALLDATA)
67 }
68
69 /// Computes the public bytecode commitment for a contract class. The commitment is `hash([(length | separator),
70 /// ...bytecode])`.
71 ///
72 /// @param packed_bytecode - The packed bytecode of the contract class. 0th word is the length in bytes.
73 /// packed_bytecode is mutable so that we can avoid copying the array to construct one starting with first_field
74 /// instead of length. @returns The public bytecode commitment.
75 pub fn compute_public_bytecode_commitment(
76 mut packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS],
77 ) -> Field {
78 // First field element contains the length of the bytecode
79 let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32;
80 let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32;
81 // Don't allow empty public bytecode. AVM doesn't handle execution of contracts that exist with empty bytecode.
82 assert(bytecode_length_in_fields != 0);
83 assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS);
84
85 // Packed_bytecode's 0th entry is the length. Append it to the separator before hashing.
86 let first_field = DOM_SEP__PUBLIC_BYTECODE.to_field() + (packed_public_bytecode[0] as u64 << 32) as Field;
87 packed_public_bytecode[0] = first_field;
88
89 // `fields_to_hash` is the number of fields from the start of `packed_public_bytecode` that should be included in
90 // the hash. Fields after this length are ignored. +1 to account for the separator.
91 let num_fields_to_hash = bytecode_length_in_fields + 1;
92
93 poseidon2_hash_subarray(packed_public_bytecode, num_fields_to_hash)
94 }
1 use crate::{
2 hash::{compute_l1_to_l2_message_hash, compute_l1_to_l2_message_nullifier, compute_secret_hash},
3 oracle::get_l1_to_l2_membership_witness::get_l1_to_l2_membership_witness,
4 };
5
6 use crate::protocol::{
7 address::{AztecAddress, EthAddress},
8 merkle_tree::root::root_from_sibling_path,
9 };
10
11 pub fn process_l1_to_l2_message(
12 l1_to_l2_root: Field,
13 contract_address: AztecAddress,
14 portal_contract_address: EthAddress,
15 chain_id: Field,
16 version: Field,
17 content: Field,
18 secret: Field,
19 leaf_index: Field,
20 ) -> Field {
21 let secret_hash = compute_secret_hash(secret);
22 let message_hash = compute_l1_to_l2_message_hash(
23 portal_contract_address,
24 chain_id,
25 contract_address,
26 version,
27 content,
28 secret_hash,
29 leaf_index,
30 );
31
32 // We prove that `message_hash` is in the tree by showing the derivation of the tree root, using a merkle path we
33 // get from an oracle.
34 // Safety: The witness is only used as a "magical value" that makes the merkle proof below pass. Hence it's safe.
35 let (_leaf_index, sibling_path) =
36 unsafe { get_l1_to_l2_membership_witness(contract_address, message_hash, secret) };
37
38 let root = root_from_sibling_path(message_hash, leaf_index, sibling_path);
39 assert_eq(root, l1_to_l2_root, "Message not in state");
40
41 compute_l1_to_l2_message_nullifier(message_hash, secret)
42 }
1 /// Stores values represented as slice in execution cache to be later obtained by its hash.
2 pub fn store<let N: u32>(values: [Field; N], hash: Field) {
3 // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to
4 // call. When loading the values, however, the caller must check that the values are indeed the preimage.
5 unsafe { store_in_execution_cache_oracle_wrapper(values, hash) };
6 }
7
8 unconstrained fn store_in_execution_cache_oracle_wrapper<let N: u32>(
9 values: [Field; N],
10 hash: Field,
11 ) {
12 store_in_execution_cache_oracle(values, hash);
13 }
14
15 pub unconstrained fn load<let N: u32>(hash: Field) -> [Field; N] {
16 load_from_execution_cache_oracle(hash)
17 }
18
19 // TODO(F-498): review naming consistency
20 #[oracle(aztec_prv_setHashPreimage)]
21 unconstrained fn store_in_execution_cache_oracle<let N: u32>(_values: [Field; N], _hash: Field) {}
22
23 // TODO(F-498): review naming consistency
24 #[oracle(aztec_prv_getHashPreimage)]
25 unconstrained fn load_from_execution_cache_oracle<let N: u32>(_hash: Field) -> [Field; N] {}
1 use crate::protocol::{address::AztecAddress, constants::L1_TO_L2_MSG_TREE_HEIGHT};
2
3 /// Returns the leaf index and sibling path of an entry in the L1 to L2 messaging tree, which can then be used to prove
4 /// its existence.
5 pub unconstrained fn get_l1_to_l2_membership_witness(
6 contract_address: AztecAddress,
7 message_hash: Field,
8 secret: Field,
9 ) -> (Field, [Field; L1_TO_L2_MSG_TREE_HEIGHT]) {
10 get_l1_to_l2_membership_witness_oracle(contract_address, message_hash, secret)
11 }
12
13 // Obtains membership witness (index and sibling path) for a message in the L1 to L2 message tree.
14 #[oracle(aztec_utl_getL1ToL2MembershipWitness)]
15 unconstrained fn get_l1_to_l2_membership_witness_oracle(
16 _contract_address: AztecAddress,
17 _message_hash: Field,
18 _secret: Field,
19 ) -> (Field, [Field; L1_TO_L2_MSG_TREE_HEIGHT]) {}
1 //! Nullifier creation, existence checks, etc.
2
3 use crate::protocol::address::aztec_address::AztecAddress;
4
5 /// Notifies the simulator that a nullifier has been created, so that its correct status (pending or settled) can be
6 /// determined when reading nullifiers in subsequent private function calls. The first non-revertible nullifier emitted
7 /// is also used to compute note nonces.
8 pub fn notify_created_nullifier(inner_nullifier: Field) {
9 // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to
10 // call.
11 unsafe { notify_created_nullifier_oracle(inner_nullifier) };
12 }
13
14 #[oracle(aztec_prv_notifyCreatedNullifier)]
15 unconstrained fn notify_created_nullifier_oracle(_inner_nullifier: Field) {}
16
17 /// Returns true if the nullifier has been emitted in the same transaction, i.e. if [notify_created_nullifier] has been
18 /// called for this inner nullifier from the contract with the specified address.
19 ///
20 /// Note that despite sharing pending transaction information with the app, this is not a privacy leak: anyone in the
21 /// network can always determine in which transaction a inner nullifier was emitted by a given contract by simply
22 /// inspecting transaction effects. What _would_ constitute a leak would be to share the list of inner pending
23 /// nullifiers, as that would reveal their preimages.
24 pub unconstrained fn is_nullifier_pending(
25 inner_nullifier: Field,
26 contract_address: AztecAddress,
27 ) -> bool {
28 is_nullifier_pending_oracle(inner_nullifier, contract_address)
29 }
30
31 #[oracle(aztec_prv_isNullifierPending)]
32 unconstrained fn is_nullifier_pending_oracle(
33 _inner_nullifier: Field,
34 _contract_address: AztecAddress,
35 ) -> bool {}
36
37 /// Returns true if the nullifier exists. Note that a `true` value can be constrained by proving existence of the
38 /// nullifier, but a `false` value should not be relied upon since other transactions may emit this nullifier before
39 /// the current transaction is included in a block. While this might seem of little use at first, certain design
40 /// patterns benefit from this abstraction (see e.g. `PrivateMutable`).
41 pub unconstrained fn check_nullifier_exists(inner_nullifier: Field) -> bool {
42 check_nullifier_exists_oracle(inner_nullifier)
43 }
44
45 // TODO(F-498): review naming consistency
46 #[oracle(aztec_utl_doesNullifierExist)]
47 unconstrained fn check_nullifier_exists_oracle(_inner_nullifier: Field) -> bool {}
1 /// Validates public calldata by checking that the preimage exists and the cumulative size is within limits.
2 ///
3 /// The check is unconstrained and the only purpose of it is to fail early in case of calldata overflow or a bug in
4 /// calldata hashing.
5 pub(crate) fn validate_public_calldata(calldata_hash: Field) {
6 // Safety: This oracle call returns nothing: we only call it for its side effects (validating the calldata).
7 // It is therefore always safe to call.
8 unsafe {
9 validate_public_calldata_wrapper(calldata_hash)
10 }
11 }
12
13 unconstrained fn validate_public_calldata_wrapper(calldata_hash: Field) {
14 validate_public_calldata_oracle(calldata_hash)
15 }
16
17 // TODO(F-498): review naming consistency
18 #[oracle(aztec_prv_assertValidPublicCalldata)]
19 unconstrained fn validate_public_calldata_oracle(_calldata_hash: Field) {}
1 /// Notifies PXE of the side effect counter at which the revertible phase begins.
2 ///
3 /// PXE uses it to classify notes and nullifiers as revertible or non-revertible in its note cache. This information is
4 /// then fed to kernels as hints.
5 pub(crate) fn notify_revertible_phase_start(counter: u32) {
6 // Safety: This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to
7 // call.
8 unsafe { notify_revertible_phase_start_oracle_wrapper(counter) };
9 }
10
11 /// Returns whether a side effect counter falls in the revertible phase of the transaction.
12 pub(crate) unconstrained fn in_revertible_phase(current_counter: u32) -> bool {
13 in_revertible_phase_oracle(current_counter)
14 }
15
16 unconstrained fn notify_revertible_phase_start_oracle_wrapper(counter: u32) {
17 notify_revertible_phase_start_oracle(counter);
18 }
19
20 #[oracle(aztec_prv_notifyRevertiblePhaseStart)]
21 unconstrained fn notify_revertible_phase_start_oracle(_counter: u32) {}
22
23 // TODO(F-498): review naming consistency
24 #[oracle(aztec_prv_isExecutionInRevertiblePhase)]
25 unconstrained fn in_revertible_phase_oracle(current_counter: u32) -> bool {}
1 /// The oracle version constants are used to check that the oracle interface is in sync between PXE and Aztec.nr.
2 /// We version the oracle interface as `major.minor` where:
3 /// - `major` = backward-breaking changes (must match exactly between PXE and Aztec.nr)
4 /// - `minor` = oracle additions (non-breaking; PXE minor >= contract minor)
5 ///
6 /// The TypeScript counterparts are in `oracle_version.ts`.
7 ///
8 /// @dev Whenever a contract function or Noir test is run, the `aztec_misc_assertCompatibleOracleVersion` oracle is
9 /// called. If the major version is incompatible, an error is thrown immediately. The minor version is recorded by
10 /// the PXE and used to provide helpful error messages if a contract calls an oracle that doesn't exist. We don't throw
11 /// immediately if AZTEC_NR_MINOR > PXE_MINOR because if a contract is updated to use a newer Aztec.nr dependency
12 /// without actually using any of the new oracles then there is no reason to throw.
13 pub global ORACLE_VERSION_MAJOR: Field = 30;
14 pub global ORACLE_VERSION_MINOR: Field = 0;
15
16 /// Asserts that the version of the oracle is compatible with the version expected by the contract.
17 pub fn assert_compatible_oracle_version() {
18 // Safety: This oracle call returns nothing: we only call it to check Aztec.nr and Oracle interface versions are
19 // compatible. It is therefore always safe to call.
20 unsafe {
21 assert_compatible_oracle_version_wrapper();
22 }
23 }
24
25 unconstrained fn assert_compatible_oracle_version_wrapper() {
26 assert_compatible_oracle_version_oracle(ORACLE_VERSION_MAJOR, ORACLE_VERSION_MINOR);
27 }
28
29 #[oracle(aztec_misc_assertCompatibleOracleVersion)]
30 unconstrained fn assert_compatible_oracle_version_oracle(major: Field, minor: Field) {}
31
32 mod test {
33 use super::{
34 assert_compatible_oracle_version_oracle, ORACLE_VERSION_MAJOR, ORACLE_VERSION_MINOR,
35 };
36
37 #[test]
38 unconstrained fn compatible_oracle_version() {
39 assert_compatible_oracle_version_oracle(ORACLE_VERSION_MAJOR, ORACLE_VERSION_MINOR);
40 }
41
42 #[test(should_fail_with = "Incompatible aztec cli version:")]
43 unconstrained fn incompatible_oracle_version_major() {
44 let arbitrary_incorrect_major = 318183437;
45 assert_compatible_oracle_version_oracle(arbitrary_incorrect_major, ORACLE_VERSION_MINOR);
46 }
47 }
1 use crate::protocol::{storage::map::derive_storage_slot_in_map, traits::ToField};
2 use crate::state_vars::StateVariable;
3
4 /// A key-value container for state variables.
5 ///
6 /// A key-value storage container that maps keys to state variables, similar to Solidity mappings.
7 pub struct Map<K, V, Context> {
8 pub context: Context,
9 storage_slot: Field,
10 }
11
12 // Map reserves a single storage slot regardless of what it stores because nothing is stored at said slot: it is only
13 // used to derive the storage slots of nested state variables.
14 impl<K, V, Context> StateVariable<1, Context> for Map<K, V, Context> {
15 fn new(context: Context, storage_slot: Field) -> Self {
16 assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
17 Map { context, storage_slot }
18 }
19
20 fn get_storage_slot(self) -> Field {
21 self.storage_slot
22 }
23 }
24
25 impl<K, V, Context> Map<K, V, Context> {
26 /// Returns the state variable associated with the given key.
27 ///
28 /// This is equivalent to accessing `mapping[key]` in Solidity.
29 pub fn at<let N: u32>(self, key: K) -> V
30 where
31 K: ToField,
32 V: StateVariable<N, Context>,
33 {
34 V::new(
35 self.context,
36 derive_storage_slot_in_map(self.storage_slot, key),
37 )
38 }
39 }
1 use crate::context::{PublicContext, UtilityContext};
2 use crate::protocol::traits::Packable;
3 use crate::state_vars::StateVariable;
4
5 /// Mutable public values.
6 ///
7 /// This is one of the most basic public state variables. It is equivalent to a non-`immutable` non-`constant` Solidity
8 /// state variable.
9 pub struct PublicMutable<T, Context> {
10 context: Context,
11 storage_slot: Field,
12 }
13
14 impl<T, Context, let M: u32> StateVariable<M, Context> for PublicMutable<T, Context>
15 where
16 T: Packable<N = M>,
17 {
18 fn new(context: Context, storage_slot: Field) -> Self {
19· assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1.");
20 PublicMutable { context, storage_slot }
21 }
22
23 fn get_storage_slot(self) -> Field {
24 self.storage_slot
25 }
26 }
27
28 impl<T> PublicMutable<T, PublicContext> {
29 /// Returns the current value.
30 pub fn read(self) -> T
31 where
32 T: Packable,
33 {
34 self.context.storage_read(self.storage_slot)
35 }
36
37 /// Stores a new value.
38 pub fn write(self, value: T)
39 where
40 T: Packable,
41 {
42 self.context.storage_write(self.storage_slot, value);
43 }
44 }
45
46 impl<T> PublicMutable<T, UtilityContext> {
47 /// Returns the value at the anchor block.
48 pub unconstrained fn read(self) -> T
49 where
50 T: Packable,
51 {
52 self.context.storage_read(self.storage_slot)
53 }
54 }
1 use aztec::context::PublicContext;
2 use aztec::protocol::address::AztecAddress;
3 use aztec::protocol::hash::sha256_to_field;
4 use aztec::protocol::traits::ToField;
5
6 pub fn calculate_fee<TPublicContext>(context: PublicContext) -> Field {
7 context.transaction_fee()
8 }
9
10 /// Computes the content hash for an L1-to-L2 "bridge gas" message, matching the hash produced on L1 by
11 /// `FeeJuicePortal.depositToAztecPublic`: `sha256ToField(abi.encodeWithSignature("claim(bytes32,uint256)", to,
12 /// amount))`.
13 ///
14 /// The 68-byte buffer is: [4-byte selector of "claim(bytes32,uint256)"][32-byte recipient][32-byte amount], hashed
15 /// with `sha256_to_field` to produce a single Field.
16 pub fn get_bridge_gas_msg_hash(owner: AztecAddress, amount: u128) -> Field {
17 let mut hash_bytes = [0; 68];
18 let recipient_bytes: [u8; 32] = owner.to_field().to_be_bytes();
19 let amount_bytes: [u8; 32] = (amount as Field).to_be_bytes();
20
21 // The purpose of including the following selector is to make the message unique to that specific call. Note that
22 // it has nothing to do with calling the function.
23 let selector = comptime { keccak256::keccak256("claim(bytes32,uint256)".as_bytes(), 22) };
24
25 for i in 0..4 {
26 hash_bytes[i] = selector[i];
27 }
28
29 for i in 0..32 {
30 hash_bytes[i + 4] = recipient_bytes[i];
31 hash_bytes[i + 36] = amount_bytes[i];
32 }
33
34 let content_hash = sha256_to_field(hash_bytes);
35 content_hash
36 }
1 /// Protocol contract that manages the native gas token ("Fee Juice") used to pay transaction fees.
2 ///
3 /// Fee Juice is minted on L2 by bridging from L1: a user deposits ERC-20 tokens into the L1 FeeJuicePortal, which
4 /// sends an L1-to-L2 message. On L2, `claim` or `claim_and_end_setup` consumes that message and credits the
5 /// recipient's balance via an enqueued public call to `_increase_public_balance`.
6 ///
7 /// The protocol's base rollup circuits read directly from this contract's `balances` storage map (at slot 1) to verify
8 /// fee payers can cover their transaction costs. This storage layout is protocol-critical and must not change without
9 /// updating the base rollup circuits.
10 ///
11 /// There is no withdrawal mechanism -- Fee Juice can only be bridged in, not withdrawn or transferred by users. Tokens
12 /// leave the L1 portal only via `distributeFees` called by the Rollup contract to pay sequencers.
13
14 mod lib;
15
16 pub contract FeeJuice {
17 use crate::lib::get_bridge_gas_msg_hash;
18 use aztec::{
19 protocol::{
20 abis::function_selector::FunctionSelector,
21 address::{AztecAddress, EthAddress},
22 constants::FEE_JUICE_ADDRESS,
23 traits::{Deserialize, ToField},
24 },
25 state_vars::{Map, PublicMutable},
26 };
27 use std::ops::Add;
28
29 struct Storage<Context> {
30 // contract address --> public fee juice balance
31 balances: Map<AztecAddress, PublicMutable<u128, Context>, Context>,
32 }
33
34 global INCREASE_PUBLIC_BALANCE_SELECTOR: Field =
35 comptime { FunctionSelector::from_signature("_increase_public_balance((Field),u128)").to_field() };
36
37 global CHECK_BALANCE_SELECTOR: Field =
38 comptime { FunctionSelector::from_signature("check_balance(u128)").to_field() };
39
40 global BALANCE_OF_PUBLIC_SELECTOR: Field =
41 comptime { FunctionSelector::from_signature("balance_of_public((Field))").to_field() };
42
43 /// A helper implementing the core L1-to-L2 message claim logic shared by `claim` and `claim_and_end_setup`.
44 /// Computes the expected content hash, consumes the L1-to-L2 message (emitting a nullifier to prevent
45 /// double-claiming), and enqueues a public call to `_increase_public_balance` to credit the recipient.
46 #[contract_library_method]
47 fn claim_helper(
48 context: &mut aztec::context::PrivateContext,
49 to: AztecAddress,
50 amount: u128,
51 secret: Field,
52 message_leaf_index: Field,
53 ) {
54 let content_hash: Field = get_bridge_gas_msg_hash(to, amount);
55 // The Inbox changes the sender's address to `FEE_JUICE_ADDRESS` if it's from the FeeJuicePortal.
56 // This avoids the need to store the L1 address on L2 and prevents friction if the address changes.
57 let portal_address: EthAddress = EthAddress::from_field(FEE_JUICE_ADDRESS.to_field());
58 assert(!portal_address.is_zero());
59
60 // Consume the L1-to-L2 message (verifies existence + emits nullifier to prevent replay).
61 context.consume_l1_to_l2_message(content_hash, secret, portal_address, message_leaf_index);
62
63 // Enqueue a public call to _increase_public_balance to credit the recipient.
64 let serialized_params: [Field; 2] = [to.to_field(), amount.to_field()];
65 let calldata: [Field; 1 + 2] = [INCREASE_PUBLIC_BALANCE_SELECTOR].concat(serialized_params);
66 let calldata_hash: Field = aztec::hash::hash_calldata_array(calldata);
67 aztec::oracle::execution_cache::store(calldata, calldata_hash);
68 context.call_public_function_with_calldata_hash(context.this_address(), calldata_hash, false, false);
69 }
70
71 /// Claims Fee Juice by consuming an L1-to-L2 message from the FeeJuicePortal.
72 ///
73 /// Use this variant when the claimed Fee Juice is NOT intended to pay for the current transaction's fees (e.g.,
74 /// pre-funding an account for future transactions).
75 #[aztec::macros::internals_functions_generation::abi_attributes::abi_private]
76 fn claim(
77 inputs: aztec::context::inputs::PrivateContextInputs,
78 to: AztecAddress,
79 amount: u128,
80 secret: Field,
81 message_leaf_index: Field,
82 ) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs {
83 // MACRO CODE START
84 // Note: The macros initially inserted a phase check here, but since there is no phase change in this function
85 // nor in the claim helper function or the enqueued public function call, I have removed that check.
86 aztec::oracle::version::assert_compatible_oracle_version();
87 let serialized_params: [Field; 4] = [to.to_field(), amount.to_field(), secret, message_leaf_index];
88 let args_hash: Field = aztec::hash::hash_args(serialized_params);
89 let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash);
90 // MACRO CODE END
91
92 claim_helper(&mut context, to, amount, secret, message_leaf_index);
93
94 // MACRO CODE START
95 context.finish()
96 // MACRO CODE END
97 }
98
99 /// Claims Fee Juice and ends the transaction setup phase.
100 ///
101 /// Use this variant when the claimed Fee Juice is intended to pay for THIS transaction's fees. By ending setup
102 /// after the claim, the balance increase is placed in the non-revertible phase, ensuring the fee payer's balance
103 /// is credited even if the revertible portion of the transaction fails. This guarantees the sequencer can collect
104 /// fees.
105 #[aztec::macros::internals_functions_generation::abi_attributes::abi_private]
106 fn claim_and_end_setup(
107 inputs: aztec::context::inputs::PrivateContextInputs,
108 to: AztecAddress,
109 amount: u128,
110 secret: Field,
111 message_leaf_index: Field,
112 ) -> return_data aztec::protocol::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs {
113 // MACRO CODE START
114 aztec::oracle::version::assert_compatible_oracle_version();
115 let serialized_params: [Field; 4] = [to.to_field(), amount.to_field(), secret, message_leaf_index];
116 let args_hash: Field = aztec::hash::hash_args(serialized_params);
117 let mut context: aztec::context::PrivateContext = aztec::context::PrivateContext::new(inputs, args_hash);
118 // MACRO CODE END
119
120 claim_helper(&mut context, to, amount, secret, message_leaf_index);
121
122 // MACRO CODE START
123 // End setup: everything before this point (including the enqueued _increase_public_balance
124 // call) is non-revertible. Everything after is revertible.
125 context.end_setup();
126 context.finish()
127 // MACRO CODE END
128 }
129
130 /// Internal function that credits a recipient's Fee Juice balance. Only callable by this contract itself
131 /// (`#[only_self]`), enqueued by `claim` / `claim_and_end_setup` after consuming an L1-to-L2 message.
132 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
133 #[aztec::macros::internals_functions_generation::abi_attributes::abi_only_self]
134 unconstrained fn _increase_public_balance(to: AztecAddress, amount: u128) {
135 // MACRO CODE START
136 let context: aztec::context::PublicContext = aztec::context::PublicContext::new(
137 || -> Field {
138 let serialized_args: [Field; 2] = aztec::oracle::avm::calldata_copy(
139 1,
140 <AztecAddress as aztec::protocol::traits::Serialize>::N
141 + <u128 as aztec::protocol::traits::Serialize>::N,
142 );
143 aztec::hash::hash_args(serialized_args)
144 },
145 );
146 let storage: Storage<aztec::context::PublicContext> = Storage::<aztec::context::PublicContext>::init(context);
147
148· assert(
149 context.maybe_msg_sender().unwrap() == context.this_address(),
150 "Function _increase_public_balance can only be called by the same contract",
151 );
152 // MACRO CODE END
153
154 let new_balance = storage.balances.at(to).read().add(amount);
155 storage.balances.at(to).write(new_balance);
156 }
157
158 /// Asserts the caller has at least `fee_limit` Fee Juice. Used during transaction validation to verify the fee
159 /// payer can cover the transaction's fee limit.
160 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
161 #[aztec::macros::internals_functions_generation::abi_attributes::abi_view]
162 unconstrained fn check_balance(fee_limit: u128) {
163 // MACRO CODE START
164 let context: aztec::context::PublicContext = aztec::context::PublicContext::new(
165 || -> Field {
166 let serialized_args: [Field; 1] =
167 aztec::oracle::avm::calldata_copy(1, <u128 as aztec::protocol::traits::Serialize>::N);
168 aztec::hash::hash_args(serialized_args)
169 },
170 );
171 let storage: Storage<aztec::context::PublicContext> = Storage::<aztec::context::PublicContext>::init(context);
172
173 assert(context.is_static_call(), "Function check_balance can only be called statically");
174 // MACRO CODE END
175
176 assert(storage.balances.at(context.maybe_msg_sender().unwrap()).read() >= fee_limit, "Balance too low");
177 }
178
179 /// Returns the Fee Juice balance of the given address.
180 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
181 #[aztec::macros::internals_functions_generation::abi_attributes::abi_view]
182 unconstrained fn balance_of_public(owner: AztecAddress) -> pub u128 {
183 // MACRO CODE START
184 let context: aztec::context::PublicContext = aztec::context::PublicContext::new(
185 || -> Field {
186 let serialized_args: [Field; 1] =
187 aztec::oracle::avm::calldata_copy(1, <AztecAddress as aztec::protocol::traits::Serialize>::N);
188 aztec::hash::hash_args(serialized_args)
189 },
190 );
191 let storage: Storage<aztec::context::PublicContext> = Storage::<aztec::context::PublicContext>::init(context);
192
193 assert(context.is_static_call(), "Function balance_of_public can only be called statically");
194 // MACRO CODE END
195
196 storage.balances.at(owner).read()
197 }
198
199 // THE REST OF THE CODE IN THIS CONTRACT WAS ORIGINALLY INJECTED BY THE #[aztec] MACRO.
200
201 #[aztec::macros::internals_functions_generation::abi_attributes::abi_public]
202 pub unconstrained fn public_dispatch(selector: Field) {
203· if selector == INCREASE_PUBLIC_BALANCE_SELECTOR {
204 let input_calldata: [Field; 2] = aztec::oracle::avm::calldata_copy(
205 1,
206 <AztecAddress as aztec::protocol::traits::Serialize>::N
207 + <u128 as aztec::protocol::traits::Serialize>::N,
208 );
209 let mut reader: aztec::protocol::utils::reader::Reader<2> =
210 aztec::protocol::utils::reader::Reader::<2>::new(input_calldata);
211 let arg0: AztecAddress = <AztecAddress as Deserialize>::stream_deserialize(&mut reader);
212 let arg1: u128 = <u128 as Deserialize>::stream_deserialize(&mut reader);
213 _increase_public_balance(arg0, arg1);
214· aztec::oracle::avm::avm_return([].as_vector());
215 };
216 if selector == CHECK_BALANCE_SELECTOR {
217 let input_calldata: [Field; 1] =
218 aztec::oracle::avm::calldata_copy(1, <u128 as aztec::protocol::traits::Serialize>::N);
219 let mut reader: aztec::protocol::utils::reader::Reader<1> =
220 aztec::protocol::utils::reader::Reader::<1>::new(input_calldata);
221 let arg0: u128 = <u128 as Deserialize>::stream_deserialize(&mut reader);
222 check_balance(arg0);
223· aztec::oracle::avm::avm_return([].as_vector());
224 };
225 if selector == BALANCE_OF_PUBLIC_SELECTOR {
226 let input_calldata: [Field; 1] =
227 aztec::oracle::avm::calldata_copy(1, <AztecAddress as aztec::protocol::traits::Serialize>::N);
228 let mut reader: aztec::protocol::utils::reader::Reader<1> =
229 aztec::protocol::utils::reader::Reader::<1>::new(input_calldata);
230 let arg0: AztecAddress = <AztecAddress as Deserialize>::stream_deserialize(&mut reader);
231 let return_value: [Field; 1] =
232 <u128 as aztec::protocol::traits::Serialize>::serialize(balance_of_public(arg0));
233 aztec::oracle::avm::avm_return(return_value.as_vector());
234 };
235 panic(f"Unknown selector {selector}")
236 }
237
238 pub struct StorageLayoutFields {
239 pub balances: aztec::state_vars::Storable,
240 }
241
242 pub struct StorageLayout<let N: u32> {
243 pub contract_name: str<N>,
244 pub fields: StorageLayoutFields,
245 }
246
247 #[abi(storage)]
248 pub global STORAGE_LAYOUT_FeeJuice: StorageLayout<8> = StorageLayout::<8> {
249 contract_name: "FeeJuice",
250 fields: StorageLayoutFields { balances: aztec::state_vars::Storable { slot: 1 } },
251 };
252
253 impl<Context> Storage<Context> {
254 fn init(context: Context) -> Self {
255 Self {
256 balances: <Map<AztecAddress, PublicMutable<u128, Context>, Context> as aztec::state_vars::StateVariable<1, Context>>::new(
257 context,
258 1,
259 ),
260 }
261 }
262 }
263
264 pub struct _increase_public_balance_parameters {
265 pub _to: AztecAddress,
266 pub _amount: u128,
267 }
268
269 pub struct balance_of_public_parameters {
270 pub _owner: AztecAddress,
271 }
272
273 pub struct check_balance_parameters {
274 pub _fee_limit: u128,
275 }
276
277 pub struct claim_and_end_setup_parameters {
278 pub _to: AztecAddress,
279 pub _amount: u128,
280 pub _secret: Field,
281 pub _message_leaf_index: Field,
282 }
283
284 pub struct claim_parameters {
285 pub _to: AztecAddress,
286 pub _amount: u128,
287 pub _secret: Field,
288 pub _message_leaf_index: Field,
289 }
290
291 #[abi(functions)]
292 pub struct _increase_public_balance_abi {
293 parameters: _increase_public_balance_parameters,
294 }
295
296 #[abi(functions)]
297 pub struct balance_of_public_abi {
298 parameters: balance_of_public_parameters,
299 return_type: u128,
300 }
301
302 #[abi(functions)]
303 pub struct check_balance_abi {
304 parameters: check_balance_parameters,
305 }
306
307 #[abi(functions)]
308 pub struct claim_abi {
309 parameters: claim_parameters,
310 }
311
312 #[abi(functions)]
313 pub struct claim_and_end_setup_abi {
314 parameters: claim_and_end_setup_parameters,
315 }
316 }
1 pub struct Reader<let N: u32> {
2 data: [Field; N],
3 offset: u32,
4 }
5
6 impl<let N: u32> Reader<N> {
7 pub fn new(data: [Field; N]) -> Self {
8 Self { data, offset: 0 }
9 }
10
11 pub fn read(&mut self) -> Field {
12· let result = self.data[self.offset];
13 self.offset += 1;
14 result
15 }
16
17 pub fn read_u32(&mut self) -> u32 {
18 self.read() as u32
19 }
20
21 pub fn read_u64(&mut self) -> u64 {
22 self.read() as u64
23 }
24
25 pub fn read_bool(&mut self) -> bool {
26 self.read() != 0
27 }
28
29 pub fn read_array<let K: u32>(&mut self) -> [Field; K] {
30 let mut result = [0; K];
31 for i in 0..K {
32 result[i] = self.data[self.offset + i];
33 }
34 self.offset += K;
35 result
36 }
37
38 pub fn read_struct<T, let K: u32>(&mut self, deserialise: fn([Field; K]) -> T) -> T {
39 let result = deserialise(self.read_array());
40 result
41 }
42
43 pub fn read_struct_array<T, let K: u32, let C: u32>(
44 &mut self,
45 deserialise: fn([Field; K]) -> T,
46 mut result: [T; C],
47 ) -> [T; C] {
48 for i in 0..C {
49 result[i] = self.read_struct(deserialise);
50 }
51 result
52 }
53
54 pub fn peek_offset(&mut self, offset: u32) -> Field {
55 self.data[self.offset + offset]
56 }
57
58 pub fn advance_offset(&mut self, offset: u32) {
59 self.offset += offset;
60 }
61
62 pub fn finish(self) {
63 assert_eq(self.offset, self.data.len(), "Reader did not read all data");
64 }
65 }
1 use crate::{reader::Reader, writer::Writer};
2
3 /// Trait for serializing Noir types into arrays of Fields.
4 ///
5 /// An implementation of the Serialize trait has to follow Noir's intrinsic serialization (each member of a struct
6 /// converted directly into one or more Fields without any packing or compression). This trait (and Deserialize) are
7 /// typically used to communicate between Noir and TypeScript (via oracles and function arguments).
8 ///
9 /// # On Following Noir's Intrinsic Serialization
10 /// When calling a Noir function from TypeScript (TS), first the function arguments are serialized into an array
11 /// of fields. This array is then included in the initial witness. Noir's intrinsic serialization is then used
12 /// to deserialize the arguments from the witness. When the same Noir function is called from Noir this Serialize trait
13 /// is used instead of the serialization in TS. For this reason we need to have a match between TS serialization,
14 /// Noir's intrinsic serialization and the implementation of this trait. If there is a mismatch, the function calls
15 /// fail with an arguments hash mismatch error message.
16 ///
17 /// # Associated Constants
18 /// * `N` - The length of the output Field array, known at compile time
19 ///
20 /// # Example
21 /// ```
22 /// impl<let N: u32> Serialize for str<N> {
23 /// let N: u32 = N;
24 ///
25 /// fn serialize(self) -> [Field; Self::N] {
26 /// let mut writer: Writer<Self::N> = Writer::new();
27 /// self.stream_serialize(&mut writer);
28 /// writer.finish()
29 /// }
30 ///
31 /// fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
32 /// let bytes = self.as_bytes();
33 /// for i in 0..bytes.len() {
34 /// writer.write(bytes[i] as Field);
35 /// }
36 /// }
37 /// }
38 /// ```
39 #[derive_via(derive_serialize)]
40 pub trait Serialize {
41 let N: u32;
42
43 fn serialize(self) -> [Field; Self::N];
44
45 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>);
46 }
47
48 /// Generates a `Serialize` trait implementation for a struct type.
49 ///
50 /// # Parameters
51 /// - `s`: The struct type definition to generate the implementation for
52 ///
53 /// # Returns
54 /// A quoted code block containing the trait implementation
55 ///
56 /// # Example
57 /// For a struct defined as:
58 /// ```
59 /// struct Log<N> {
60 /// fields: [Field; N],
61 /// length: u32
62 /// }
63 /// ```
64 ///
65 /// This function generates code equivalent to:
66 /// ```
67 /// impl<let N: u32> Serialize for Log<N> {
68 /// let N: u32 = <[Field; N] as Serialize>::N + <u32 as Serialize>::N;
69 ///
70 /// fn serialize(self) -> [Field; Self::N] {
71 /// let mut writer: Writer<Self::N> = Writer::new();
72 /// self.stream_serialize(&mut writer);
73 /// writer.finish()
74 /// }
75 ///
76 /// #[inline_always]
77 /// fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
78 /// Serialize::stream_serialize(self.fields, writer);
79 /// Serialize::stream_serialize(self.length, writer);
80 /// }
81 /// }
82 /// ```
83 pub comptime fn derive_serialize(s: TypeDefinition) -> Quoted {
84 let typ = s.as_type();
85 let nested_struct = typ.as_data_type().unwrap();
86
87 // We care only about the name and type so we drop the last item of the tuple
88 let params = nested_struct.0.fields(nested_struct.1).map(|(name, typ, _)| (name, typ));
89
90 // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause
91 // for the `Serialize` trait.
92 let generics_declarations = get_generics_declarations(s);
93 let where_serialize_clause = get_where_trait_clause(s, quote { Serialize });
94
95 let params_len_quote = get_params_len_quote(params);
96
97 let function_body = params
98 .map(|(name, _typ): (Quoted, Type)| {
99 quote {
100 $crate::serialization::Serialize::stream_serialize(self.$name, writer);
101 }
102 })
103 .join(quote {});
104
105 quote {
106 impl$generics_declarations $crate::serialization::Serialize for $typ
107 $where_serialize_clause
108 {
109 let N: u32 = $params_len_quote;
110
111
112 fn serialize(self) -> [Field; Self::N] {
113 let mut writer: $crate::writer::Writer<Self::N> = $crate::writer::Writer::new();
114 $crate::serialization::Serialize::stream_serialize(self, &mut writer);
115 writer.finish()
116 }
117
118
119 #[inline_always]
120 fn stream_serialize<let K: u32>(self, writer: &mut $crate::writer::Writer<K>) {
121 $function_body
122 }
123 }
124 }
125 }
126
127 /// Trait for deserializing Noir types from arrays of Fields.
128 ///
129 /// An implementation of the Deserialize trait has to follow Noir's intrinsic serialization (each member of a struct
130 /// converted directly into one or more Fields without any packing or compression). This trait is typically used when
131 /// deserializing return values from function calls in Noir. Since the same function could be called from TypeScript
132 /// (TS), in which case the TS deserialization would get used, we need to have a match between the 2.
133 ///
134 /// # Associated Constants
135 /// * `N` - The length of the input Field array, known at compile time
136 ///
137 /// # Example
138 /// ```
139 /// impl<let M: u32> Deserialize for str<M> {
140 /// let N: u32 = M;
141 ///
142 /// fn deserialize(fields: [Field; Self::N]) -> Self {
143 /// let mut reader = Reader::new(fields);
144 /// let result = Self::stream_deserialize(&mut reader);
145 /// reader.finish();
146 /// result
147 /// }
148 ///
149 /// fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
150 /// let mut bytes = [0 as u8; M];
151 /// for i in 0..M {
152 /// bytes[i] = reader.read() as u8;
153 /// }
154 /// str::<M>::from(bytes)
155 /// }
156 /// }
157 /// ```
158 #[derive_via(derive_deserialize)]
159 pub trait Deserialize {
160 let N: u32;
161
162 fn deserialize(fields: [Field; Self::N]) -> Self;
163
164 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self;
165 }
166
167 /// Generates a `Deserialize` trait implementation for a given struct `s`.
168 ///
169 /// # Arguments
170 /// * `s` - The struct type definition to generate the implementation for
171 ///
172 /// # Returns
173 /// A `Quoted` block containing the generated trait implementation
174 ///
175 /// # Requirements
176 /// Each struct member type must implement the `Deserialize` trait (it gets used in the generated code).
177 ///
178 /// # Example
179 /// For a struct like:
180 /// ```
181 /// struct MyStruct {
182 /// x: AztecAddress,
183 /// y: Field,
184 /// }
185 /// ```
186 ///
187 /// This generates:
188 /// ```
189 /// impl Deserialize for MyStruct {
190 /// let N: u32 = <AztecAddress as Deserialize>::N + <Field as Deserialize>::N;
191 ///
192 /// fn deserialize(fields: [Field; Self::N]) -> Self {
193 /// let mut reader = Reader::new(fields);
194 /// let result = Self::stream_deserialize(&mut reader);
195 /// reader.finish();
196 /// result
197 /// }
198 ///
199 /// #[inline_always]
200 /// fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
201 /// let x = <AztecAddress as Deserialize>::stream_deserialize(reader);
202 /// let y = <Field as Deserialize>::stream_deserialize(reader);
203 /// Self { x, y }
204 /// }
205 /// }
206 /// ```
207 pub comptime fn derive_deserialize(s: TypeDefinition) -> Quoted {
208 let typ = s.as_type();
209 let nested_struct = typ.as_data_type().unwrap();
210 let params = nested_struct.0.fields(nested_struct.1);
211
212 // Generates the generic parameter declarations (to be placed after the `impl` keyword) and the `where` clause
213 // for the `Deserialize` trait.
214 let generics_declarations = get_generics_declarations(s);
215 let where_deserialize_clause = get_where_trait_clause(s, quote { Deserialize });
216
217 // The following will give us:
218 // <type_of_struct_member_1 as Deserialize>::N + <type_of_struct_member_2 as Deserialize>::N + ...
219 // (or 0 if the struct has no members)
220 let right_hand_side_of_definition_of_n = if params.len() > 0 {
221 params
222 .map(|(_, param_type, _): (Quoted, Type, Quoted)| {
223 quote {
224 <$param_type as $crate::serialization::Deserialize>::N
225 }
226 })
227 .join(quote {+})
228 } else {
229 quote { 0 }
230 };
231
232 // For structs containing a single member, we can enhance performance by directly deserializing the input array,
233 // bypassing the need for loop-based array construction. While this optimization yields significant benefits in
234 // Brillig where the loops are expected to not be optimized, it is not relevant in ACIR where the loops are
235 // expected to be optimized away.
236 let function_body = if params.len() > 1 {
237 // This generates deserialization code for each struct member and concatenates them together.
238 let deserialization_of_struct_members = params
239 .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| {
240 quote {
241 let $param_name = <$param_type as Deserialize>::stream_deserialize(reader);
242 }
243 })
244 .join(quote {});
245
246 // We join the struct member names with a comma to be used in the `Self { ... }` syntax
247 // This will give us e.g. `a, b, c` for a struct with three fields named `a`, `b`, and `c`.
248 let struct_members = params
249 .map(|(param_name, _, _): (Quoted, Type, Quoted)| quote { $param_name })
250 .join(quote {,});
251
252 quote {
253 $deserialization_of_struct_members
254
255 Self { $struct_members }
256 }
257 } else if params.len() == 1 {
258 let param_name = params[0].0;
259 quote {
260 Self { $param_name: $crate::serialization::Deserialize::stream_deserialize(reader) }
261 }
262 } else {
263 quote {
264 Self {}
265 }
266 };
267
268 quote {
269 impl$generics_declarations $crate::serialization::Deserialize for $typ
270 $where_deserialize_clause
271 {
272 let N: u32 = $right_hand_side_of_definition_of_n;
273
274 fn deserialize(fields: [Field; Self::N]) -> Self {
275 let mut reader = $crate::reader::Reader::new(fields);
276 let result = Self::stream_deserialize(&mut reader);
277 reader.finish();
278 result
279 }
280
281 #[inline_always]
282 fn stream_deserialize<let K: u32>(reader: &mut $crate::reader::Reader<K>) -> Self {
283 $function_body
284 }
285 }
286 }
287 }
288
289 /// Generates a quoted expression that computes the total serialized length of function parameters.
290 ///
291 /// # Parameters
292 /// * `params` - An array of tuples where each tuple contains a quoted parameter name and its Type. The type needs
293 /// to implement the Serialize trait.
294 ///
295 /// # Returns
296 /// A quoted expression that evaluates to:
297 /// * `0` if there are no parameters
298 /// * `(<type1 as Serialize>::N + <type2 as Serialize>::N + ...)` for one or more parameters
299 comptime fn get_params_len_quote(params: [(Quoted, Type)]) -> Quoted {
300 if params.len() == 0 {
301 quote { 0 }
302 } else {
303 let params_quote_without_parentheses = params
304 .map(|(_, param_type): (Quoted, Type)| {
305 quote {
306 <$param_type as $crate::serialization::Serialize>::N
307 }
308 })
309 .join(quote {+});
310 quote { ($params_quote_without_parentheses) }
311 }
312 }
313
314 comptime fn get_generics_declarations(s: TypeDefinition) -> Quoted {
315 let generics = s.generics();
316
317 if generics.len() > 0 {
318 let generics_declarations_items = generics
319 .map(|(name, maybe_integer_typ)| {
320 // The second item in the generics tuple is an Option of an integer type that is Some only if
321 // the generic is numeric.
322 if maybe_integer_typ.is_some() {
323 // The generic is numeric, so we return a quote defined as e.g. "let N: u32"
324 let integer_type = maybe_integer_typ.unwrap();
325 quote {let $name: $integer_type}
326 } else {
327 // The generic is not numeric, so we return a quote containing the name of the generic (e.g. "T")
328 quote { $name }
329 }
330 })
331 .join(quote {,});
332 quote {<$generics_declarations_items>}
333 } else {
334 // The struct doesn't have any generics defined, so we just return an empty quote.
335 quote {}
336 }
337 }
338
339 comptime fn get_where_trait_clause(s: TypeDefinition, trait_name: Quoted) -> Quoted {
340 let generics = s.generics();
341
342 // The second item in the generics tuple is an Option of an integer type that is Some only if the generic is
343 // numeric.
344 let non_numeric_generics =
345 generics.filter(|(_, maybe_integer_typ)| maybe_integer_typ.is_none());
346
347 if non_numeric_generics.len() > 0 {
348 let non_numeric_generics_declarations =
349 non_numeric_generics.map(|(name, _)| quote {$name: $trait_name}).join(quote {,});
350 quote {where $non_numeric_generics_declarations}
351 } else {
352 // There are no non-numeric generics, so we return an empty quote.
353 quote {}
354 }
355 }
1 use crate::{reader::Reader, serialization::{Deserialize, Serialize}, writer::Writer};
2 use std::embedded_curve_ops::EmbeddedCurvePoint;
3 use std::embedded_curve_ops::EmbeddedCurveScalar;
4
5 global BOOL_SERIALIZED_LEN: u32 = 1;
6 global U8_SERIALIZED_LEN: u32 = 1;
7 global U16_SERIALIZED_LEN: u32 = 1;
8 global U32_SERIALIZED_LEN: u32 = 1;
9 global U64_SERIALIZED_LEN: u32 = 1;
10 global U128_SERIALIZED_LEN: u32 = 1;
11 global FIELD_SERIALIZED_LEN: u32 = 1;
12 global I8_SERIALIZED_LEN: u32 = 1;
13 global I16_SERIALIZED_LEN: u32 = 1;
14 global I32_SERIALIZED_LEN: u32 = 1;
15 global I64_SERIALIZED_LEN: u32 = 1;
16
17 impl Serialize for bool {
18 let N: u32 = BOOL_SERIALIZED_LEN;
19
20 fn serialize(self) -> [Field; Self::N] {
21 let mut writer: Writer<Self::N> = Writer::new();
22 self.stream_serialize(&mut writer);
23 writer.finish()
24 }
25
26 #[inline_always]
27 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
28 writer.write(self as Field);
29 }
30 }
31
32 impl Deserialize for bool {
33 let N: u32 = BOOL_SERIALIZED_LEN;
34
35 fn deserialize(fields: [Field; Self::N]) -> Self {
36 let mut reader = Reader::new(fields);
37 let result = Self::stream_deserialize(&mut reader);
38 reader.finish();
39 result
40 }
41
42 #[inline_always]
43 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> bool {
44 reader.read() != 0
45 }
46 }
47
48 impl Serialize for u8 {
49 let N: u32 = U8_SERIALIZED_LEN;
50
51 fn serialize(self) -> [Field; Self::N] {
52 let mut writer: Writer<Self::N> = Writer::new();
53 self.stream_serialize(&mut writer);
54 writer.finish()
55 }
56
57 #[inline_always]
58 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
59 writer.write(self as Field);
60 }
61 }
62
63 impl Deserialize for u8 {
64 let N: u32 = U8_SERIALIZED_LEN;
65
66 fn deserialize(fields: [Field; Self::N]) -> Self {
67 let mut reader = Reader::new(fields);
68 let result = Self::stream_deserialize(&mut reader);
69 reader.finish();
70 result
71 }
72
73 #[inline_always]
74 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
75 reader.read() as u8
76 }
77 }
78
79 impl Serialize for u16 {
80 let N: u32 = U16_SERIALIZED_LEN;
81
82 fn serialize(self) -> [Field; Self::N] {
83 let mut writer: Writer<Self::N> = Writer::new();
84 self.stream_serialize(&mut writer);
85 writer.finish()
86 }
87
88 #[inline_always]
89 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
90 writer.write(self as Field);
91 }
92 }
93
94 impl Deserialize for u16 {
95 let N: u32 = U16_SERIALIZED_LEN;
96
97 fn deserialize(fields: [Field; Self::N]) -> Self {
98 let mut reader = Reader::new(fields);
99 let result = Self::stream_deserialize(&mut reader);
100 reader.finish();
101 result
102 }
103
104 #[inline_always]
105 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
106 reader.read() as u16
107 }
108 }
109
110 impl Serialize for u32 {
111 let N: u32 = U32_SERIALIZED_LEN;
112
113 fn serialize(self) -> [Field; Self::N] {
114 let mut writer: Writer<Self::N> = Writer::new();
115 self.stream_serialize(&mut writer);
116 writer.finish()
117 }
118
119 #[inline_always]
120 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
121 writer.write(self as Field);
122 }
123 }
124
125 impl Deserialize for u32 {
126 let N: u32 = U32_SERIALIZED_LEN;
127
128 fn deserialize(fields: [Field; Self::N]) -> Self {
129 let mut reader = Reader::new(fields);
130 let result = Self::stream_deserialize(&mut reader);
131 reader.finish();
132 result
133 }
134
135 #[inline_always]
136 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
137 reader.read() as u32
138 }
139 }
140
141 impl Serialize for u64 {
142 let N: u32 = U64_SERIALIZED_LEN;
143
144 fn serialize(self) -> [Field; Self::N] {
145 let mut writer: Writer<Self::N> = Writer::new();
146 self.stream_serialize(&mut writer);
147 writer.finish()
148 }
149
150 #[inline_always]
151 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
152 writer.write(self as Field);
153 }
154 }
155
156 impl Deserialize for u64 {
157 let N: u32 = U64_SERIALIZED_LEN;
158
159 fn deserialize(fields: [Field; Self::N]) -> Self {
160 let mut reader = Reader::new(fields);
161 let result = Self::stream_deserialize(&mut reader);
162 reader.finish();
163 result
164 }
165
166 #[inline_always]
167 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
168 reader.read() as u64
169 }
170 }
171
172 impl Serialize for u128 {
173 let N: u32 = U128_SERIALIZED_LEN;
174
175 fn serialize(self) -> [Field; Self::N] {
176 let mut writer: Writer<Self::N> = Writer::new();
177 self.stream_serialize(&mut writer);
178 writer.finish()
179 }
180
181 #[inline_always]
182 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
183 writer.write(self as Field);
184 }
185 }
186
187 impl Deserialize for u128 {
188 let N: u32 = U128_SERIALIZED_LEN;
189
190 fn deserialize(fields: [Field; Self::N]) -> Self {
191 let mut reader = Reader::new(fields);
192 let result = Self::stream_deserialize(&mut reader);
193 reader.finish();
194 result
195 }
196
197 #[inline_always]
198 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
199· reader.read() as u128
200 }
201 }
202
203 impl Serialize for Field {
204 let N: u32 = FIELD_SERIALIZED_LEN;
205
206 fn serialize(self) -> [Field; Self::N] {
207 let mut writer: Writer<Self::N> = Writer::new();
208 self.stream_serialize(&mut writer);
209 writer.finish()
210 }
211
212 #[inline_always]
213 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
214 writer.write(self);
215 }
216 }
217
218 impl Deserialize for Field {
219 let N: u32 = FIELD_SERIALIZED_LEN;
220
221 fn deserialize(fields: [Field; Self::N]) -> Self {
222 let mut reader = Reader::new(fields);
223 let result = Self::stream_deserialize(&mut reader);
224 reader.finish();
225 result
226 }
227
228 #[inline_always]
229 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
230 reader.read()
231 }
232 }
233
234 impl Serialize for i8 {
235 let N: u32 = I8_SERIALIZED_LEN;
236
237 fn serialize(self) -> [Field; Self::N] {
238 let mut writer: Writer<Self::N> = Writer::new();
239 self.stream_serialize(&mut writer);
240 writer.finish()
241 }
242
243 #[inline_always]
244 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
245 writer.write(self as u8 as Field);
246 }
247 }
248
249 impl Deserialize for i8 {
250 let N: u32 = I8_SERIALIZED_LEN;
251
252 fn deserialize(fields: [Field; Self::N]) -> Self {
253 let mut reader = Reader::new(fields);
254 let result = Self::stream_deserialize(&mut reader);
255 reader.finish();
256 result
257 }
258
259 #[inline_always]
260 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
261 reader.read() as u8 as i8
262 }
263 }
264
265 impl Serialize for i16 {
266 let N: u32 = I16_SERIALIZED_LEN;
267
268 fn serialize(self) -> [Field; Self::N] {
269 let mut writer: Writer<Self::N> = Writer::new();
270 self.stream_serialize(&mut writer);
271 writer.finish()
272 }
273
274 #[inline_always]
275 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
276 writer.write(self as u16 as Field);
277 }
278 }
279
280 impl Deserialize for i16 {
281 let N: u32 = I16_SERIALIZED_LEN;
282
283 fn deserialize(fields: [Field; Self::N]) -> Self {
284 let mut reader = Reader::new(fields);
285 let result = Self::stream_deserialize(&mut reader);
286 reader.finish();
287 result
288 }
289
290 #[inline_always]
291 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
292 reader.read() as u16 as i16
293 }
294 }
295
296 impl Serialize for i32 {
297 let N: u32 = I32_SERIALIZED_LEN;
298
299 fn serialize(self) -> [Field; Self::N] {
300 let mut writer: Writer<Self::N> = Writer::new();
301 self.stream_serialize(&mut writer);
302 writer.finish()
303 }
304
305 #[inline_always]
306 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
307 writer.write(self as u32 as Field);
308 }
309 }
310
311 impl Deserialize for i32 {
312 let N: u32 = I32_SERIALIZED_LEN;
313
314 fn deserialize(fields: [Field; Self::N]) -> Self {
315 let mut reader = Reader::new(fields);
316 let result = Self::stream_deserialize(&mut reader);
317 reader.finish();
318 result
319 }
320
321 #[inline_always]
322 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
323 reader.read() as u32 as i32
324 }
325 }
326
327 impl Serialize for i64 {
328 let N: u32 = I64_SERIALIZED_LEN;
329
330 fn serialize(self) -> [Field; Self::N] {
331 let mut writer: Writer<Self::N> = Writer::new();
332 self.stream_serialize(&mut writer);
333 writer.finish()
334 }
335
336 #[inline_always]
337 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
338 writer.write(self as u64 as Field);
339 }
340 }
341
342 impl Deserialize for i64 {
343 let N: u32 = I64_SERIALIZED_LEN;
344
345 fn deserialize(fields: [Field; Self::N]) -> Self {
346 let mut reader = Reader::new(fields);
347 let result = Self::stream_deserialize(&mut reader);
348 reader.finish();
349 result
350 }
351
352 #[inline_always]
353 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
354 reader.read() as u64 as i64
355 }
356 }
357
358 impl<T, let M: u32> Serialize for [T; M]
359 where
360 T: Serialize,
361 {
362 let N: u32 = <T as Serialize>::N * M;
363
364 fn serialize(self) -> [Field; Self::N] {
365 let mut writer: Writer<Self::N> = Writer::new();
366 self.stream_serialize(&mut writer);
367 writer.finish()
368 }
369
370 #[inline_always]
371 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
372 for i in 0..M {
373 self[i].stream_serialize(writer);
374 }
375 }
376 }
377
378 impl<T, let M: u32> Deserialize for [T; M]
379 where
380 T: Deserialize,
381 {
382 let N: u32 = <T as Deserialize>::N * M;
383
384 fn deserialize(fields: [Field; Self::N]) -> Self {
385 let mut reader = Reader::new(fields);
386 let result = Self::stream_deserialize(&mut reader);
387 reader.finish();
388 result
389 }
390
391 #[inline_always]
392 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
393 let mut result: [T; M] = std::mem::zeroed();
394 for i in 0..M {
395 result[i] = T::stream_deserialize(reader);
396 }
397 result
398 }
399 }
400
401 impl<T> Serialize for Option<T>
402 where
403 T: Serialize,
404 {
405 let N: u32 = <T as Serialize>::N + 1;
406
407 fn serialize(self) -> [Field; Self::N] {
408 let mut writer: Writer<Self::N> = Writer::new();
409 self.stream_serialize(&mut writer);
410 writer.finish()
411 }
412
413 #[inline_always]
414 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
415 writer.write_bool(self.is_some());
416 if self.is_some() {
417 self.unwrap_unchecked().stream_serialize(writer);
418 } else {
419 writer.advance_offset(<T as Serialize>::N);
420 }
421 }
422 }
423
424 impl<T> Deserialize for Option<T>
425 where
426 T: Deserialize,
427 {
428 let N: u32 = <T as Deserialize>::N + 1;
429
430 fn deserialize(fields: [Field; Self::N]) -> Self {
431 let mut reader = Reader::new(fields);
432 let result = Self::stream_deserialize(&mut reader);
433 reader.finish();
434 result
435 }
436
437 #[inline_always]
438 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
439 if reader.read_bool() {
440 Option::some(<T as Deserialize>::stream_deserialize(reader))
441 } else {
442 reader.advance_offset(<T as Deserialize>::N);
443 Option::none()
444 }
445 }
446 }
447
448 global SCALAR_SIZE: u32 = 2;
449
450 impl Serialize for EmbeddedCurveScalar {
451
452 let N: u32 = SCALAR_SIZE;
453
454 fn serialize(self) -> [Field; SCALAR_SIZE] {
455 [self.lo, self.hi]
456 }
457
458 #[inline_always]
459 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
460 writer.write(self.lo);
461 writer.write(self.hi);
462 }
463 }
464
465 impl Deserialize for EmbeddedCurveScalar {
466 let N: u32 = SCALAR_SIZE;
467
468 fn deserialize(fields: [Field; Self::N]) -> Self {
469 Self { lo: fields[0], hi: fields[1] }
470 }
471
472 #[inline_always]
473 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
474 Self { lo: reader.read(), hi: reader.read() }
475 }
476 }
477
478 global POINT_SIZE: u32 = 2;
479
480 impl Serialize for EmbeddedCurvePoint {
481 let N: u32 = POINT_SIZE;
482
483 fn serialize(self) -> [Field; Self::N] {
484 [self.x, self.y]
485 }
486
487 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
488 writer.write(self.x);
489 writer.write(self.y);
490 }
491 }
492
493 impl Deserialize for EmbeddedCurvePoint {
494 let N: u32 = POINT_SIZE;
495
496 fn deserialize(fields: [Field; Self::N]) -> Self {
497 Self { x: fields[0], y: fields[1] }
498 }
499
500 #[inline_always]
501 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
502 Self { x: reader.read(), y: reader.read() }
503 }
504 }
505
506 impl<let M: u32> Deserialize for str<M> {
507 let N: u32 = M;
508
509 fn deserialize(fields: [Field; Self::N]) -> Self {
510 let mut reader = Reader::new(fields);
511 let result = Self::stream_deserialize(&mut reader);
512 reader.finish();
513 result
514 }
515
516 #[inline_always]
517 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
518 let u8_arr = <[u8; Self::N] as Deserialize>::stream_deserialize(reader);
519 str::<Self::N>::from(u8_arr)
520 }
521 }
522
523 impl<let M: u32> Serialize for str<M> {
524 let N: u32 = M;
525
526 fn serialize(self) -> [Field; Self::N] {
527 let mut writer: Writer<Self::N> = Writer::new();
528 self.stream_serialize(&mut writer);
529 writer.finish()
530 }
531
532 #[inline_always]
533 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
534 self.as_bytes().stream_serialize(writer);
535 }
536 }
537
538 // Note: Not deriving this because it's not supported to call derive_serialize on a "remote" struct (and it will never
539 // be supported).
540 impl<T, let M: u32> Deserialize for BoundedVec<T, M>
541 where
542 T: Deserialize,
543 {
544 let N: u32 = <T as Deserialize>::N * M + 1;
545
546 fn deserialize(fields: [Field; Self::N]) -> Self {
547 let mut reader = Reader::new(fields);
548 let result = Self::stream_deserialize(&mut reader);
549 reader.finish();
550 result
551 }
552
553 #[inline_always]
554 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
555 let mut new_bounded_vec: BoundedVec<T, M> = BoundedVec::new();
556 let payload_len = Self::N - 1;
557
558 // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct
559 // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)
560 let len = reader.peek_offset(payload_len) as u32;
561
562 for i in 0..M {
563 if i < len {
564 new_bounded_vec.push(<T as Deserialize>::stream_deserialize(reader));
565 }
566 }
567
568 // +1 for the length of the BoundedVec
569 reader.advance_offset((M - len) * <T as Deserialize>::N + 1);
570
571 new_bounded_vec
572 }
573 }
574
575 // This may cause issues if used as program input, because noir disallows empty arrays for program input.
576 // I think this is okay because I don't foresee a unit type being used as input. But leaving this comment as a hint
577 // if someone does run into this in the future.
578 impl Deserialize for () {
579 let N: u32 = 0;
580
581 fn deserialize(fields: [Field; Self::N]) -> Self {
582 let mut reader = Reader::new(fields);
583 let result = Self::stream_deserialize(&mut reader);
584 reader.finish();
585 result
586 }
587
588 #[inline_always]
589 fn stream_deserialize<let K: u32>(_reader: &mut Reader<K>) -> Self {
590 ()
591 }
592 }
593
594 // Note: Not deriving this because it's not supported to call derive_serialize on a "remote" struct (and it will never
595 // be supported).
596 impl<T, let M: u32> Serialize for BoundedVec<T, M>
597 where
598 T: Serialize,
599 {
600 let N: u32 = <T as Serialize>::N * M + 1; // +1 for the length of the BoundedVec
601
602 fn serialize(self) -> [Field; Self::N] {
603 let mut writer: Writer<Self::N> = Writer::new();
604 self.stream_serialize(&mut writer);
605 writer.finish()
606 }
607
608 #[inline_always]
609 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
610 self.storage().stream_serialize(writer);
611 // Length is stored in the last field as we need to match intrinsic Noir serialization and the `len` struct
612 // field is after `storage` struct field (see `bounded_vec.nr` in noir-stdlib)
613 writer.write_u32(self.len() as u32);
614 }
615 }
616
617 // Create a slice of the given length with each element made from `f(i)` where `i` is the current index
618 comptime fn make_slice<Env, T>(length: u32, f: fn[Env](u32) -> T) -> [T] {
619 let mut slice = @[];
620 for i in 0..length {
621 slice = slice.push_back(f(i));
622 }
623 slice
624 }
625
626 // Implements Serialize and Deserialize for an arbitrary tuple type
627 comptime fn impl_serialize_for_tuple(_m: Module, length: u32) -> Quoted {
628 // `T0`, `T1`, `T2`
629 let type_names = make_slice(length, |i| f"T{i}".quoted_contents());
630
631 // `result0`, `result1`, `result2`
632 let result_names = make_slice(length, |i| f"result{i}".quoted_contents());
633
634 // `T0, T1, T2`
635 let field_generics = type_names.join(quote [,]);
636
637 // `<T0 as Serialize>::N + <T1 as Serialize>::N + <T2 as Serialize>::N`
638 let full_size_serialize = type_names
639 .map(|type_name| quote {
640 <$type_name as Serialize>::N
641 })
642 .join(quote [+]);
643
644 // `<T0 as Deserialize>::N + <T1 as Deserialize>::N + <T2 as Deserialize>::N`
645 let full_size_deserialize = type_names
646 .map(|type_name| quote {
647 <$type_name as Deserialize>::N
648 })
649 .join(quote [+]);
650
651 // `T0: Serialize, T1: Serialize, T2: Serialize,`
652 let serialize_constraints = type_names
653 .map(|field_name| quote {
654 $field_name: Serialize,
655 })
656 .join(quote []);
657
658 // `T0: Deserialize, T1: Deserialize, T2: Deserialize,`
659 let deserialize_constraints = type_names
660 .map(|field_name| quote {
661 $field_name: Deserialize,
662 })
663 .join(quote []);
664
665 // Statements to serialize each field
666 let serialized_fields = type_names
667 .mapi(|i, _type_name| quote {
668 $crate::serialization::Serialize::stream_serialize(self.$i, writer);
669 })
670 .join(quote []);
671
672 // Statements to deserialize each field
673 let deserialized_fields = type_names
674 .mapi(|i, type_name| {
675 let result_name = result_names[i];
676 quote {
677 let $result_name = <$type_name as $crate::serialization::Deserialize>::stream_deserialize(reader);
678 }
679 })
680 .join(quote []);
681 let deserialize_results = result_names.join(quote [,]);
682
683 quote {
684 impl<$field_generics> Serialize for ($field_generics) where $serialize_constraints {
685 let N: u32 = $full_size_serialize;
686
687 fn serialize(self) -> [Field; Self::N] {
688 let mut writer: $crate::writer::Writer<Self::N> = $crate::writer::Writer::new();
689 self.stream_serialize(&mut writer);
690 writer.finish()
691 }
692
693 #[inline_always]
694 fn stream_serialize<let K: u32>(self, writer: &mut $crate::writer::Writer<K>) {
695
696 $serialized_fields
697 }
698 }
699
700 impl<$field_generics> Deserialize for ($field_generics) where $deserialize_constraints {
701 let N: u32 = $full_size_deserialize;
702
703 fn deserialize(fields: [Field; Self::N]) -> Self {
704 let mut reader = $crate::reader::Reader::new(fields);
705 let result = Self::stream_deserialize(&mut reader);
706 reader.finish();
707 result
708 }
709
710 #[inline_always]
711 fn stream_deserialize<let K: u32>(reader: &mut $crate::reader::Reader<K>) -> Self {
712 $deserialized_fields
713 ($deserialize_results)
714 }
715 }
716 }
717 }
718
719 // Keeping these manual impls. They are more efficient since they do not
720 // require copying sub-arrays from any serialized arrays.
721 impl<T1> Serialize for (T1,)
722 where
723 T1: Serialize,
724 {
725 let N: u32 = <T1 as Serialize>::N;
726
727 fn serialize(self) -> [Field; Self::N] {
728 let mut writer: crate::writer::Writer<Self::N> = crate::writer::Writer::new();
729 self.stream_serialize(&mut writer);
730 writer.finish()
731 }
732
733 #[inline_always]
734 fn stream_serialize<let K: u32>(self, writer: &mut Writer<K>) {
735 self.0.stream_serialize(writer);
736 }
737 }
738
739 impl<T1> Deserialize for (T1,)
740 where
741 T1: Deserialize,
742 {
743 let N: u32 = <T1 as Deserialize>::N;
744
745 fn deserialize(fields: [Field; Self::N]) -> Self {
746 let mut reader = crate::reader::Reader::new(fields);
747 let result = Self::stream_deserialize(&mut reader);
748 reader.finish();
749 result
750 }
751
752 #[inline_always]
753 fn stream_deserialize<let K: u32>(reader: &mut Reader<K>) -> Self {
754 (<T1 as Deserialize>::stream_deserialize(reader),)
755 }
756 }
757
758 #[impl_serialize_for_tuple(2)]
759 #[impl_serialize_for_tuple(3)]
760 #[impl_serialize_for_tuple(4)]
761 #[impl_serialize_for_tuple(5)]
762 #[impl_serialize_for_tuple(6)]
763 mod impls {
764 use crate::serialization::{Deserialize, Serialize};
765 }
766
767 #[test]
768 unconstrained fn bounded_vec_serialization() {
769 // Test empty BoundedVec
770 let empty_vec: BoundedVec<Field, 3> = BoundedVec::from_array([]);
771 let serialized = empty_vec.serialize();
772 let deserialized = BoundedVec::<Field, 3>::deserialize(serialized);
773 assert_eq(empty_vec, deserialized);
774 assert_eq(deserialized.len(), 0);
775
776 // Test partially filled BoundedVec
777 let partial_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2]]);
778 let serialized = partial_vec.serialize();
779 let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);
780 assert_eq(partial_vec, deserialized);
781 assert_eq(deserialized.len(), 1);
782 assert_eq(deserialized.get(0), [1, 2]);
783
784 // Test full BoundedVec
785 let full_vec: BoundedVec<[u32; 2], 3> = BoundedVec::from_array([[1, 2], [3, 4], [5, 6]]);
786 let serialized = full_vec.serialize();
787 let deserialized = BoundedVec::<[u32; 2], 3>::deserialize(serialized);
788 assert_eq(full_vec, deserialized);
789 assert_eq(deserialized.len(), 3);
790 assert_eq(deserialized.get(0), [1, 2]);
791 assert_eq(deserialized.get(1), [3, 4]);
792 assert_eq(deserialized.get(2), [5, 6]);
793 }
1 mod poseidon2_chunks;
2
3 use crate::{
4 abis::{
5 contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage,
6 function_selector::FunctionSelector, nullifier::Nullifier, private_log::PrivateLog,
7 transaction::tx_request::TxRequest,
8 },
9 address::{AztecAddress, EthAddress},
10 constants::{
11 CONTRACT_CLASS_LOG_SIZE_IN_FIELDS, DOM_SEP__NOTE_HASH_NONCE,
12 DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER,
13 DOM_SEP__UNIQUE_NOTE_HASH, FUNCTION_TREE_HEIGHT, NULL_MSG_SENDER_CONTRACT_ADDRESS,
14 TWO_POW_64,
15 },
16 merkle_tree::root_from_sibling_path,
17 messaging::l2_to_l1_message::L2ToL1Message,
18 poseidon2::Poseidon2Sponge,
19 side_effect::{Counted, Scoped},
20 traits::{FromField, Hash, ToField},
21 utils::field::{field_from_bytes, field_from_bytes_32_trunc},
22 };
23
24 pub use poseidon2_chunks::poseidon2_absorb_in_chunks_existing_sponge;
25 use poseidon2_chunks::poseidon2_absorb_in_chunks;
26 use std::embedded_curve_ops::EmbeddedCurveScalar;
27
28 // TODO: refactor these into their own files: sha256, poseidon2, some protocol-specific hash computations, some merkle computations.
29
30 pub fn sha256_to_field<let N: u32>(bytes_to_hash: [u8; N]) -> Field {
31 let sha256_hashed = sha256::digest(bytes_to_hash);
32 let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed);
33
34 hash_in_a_field
35 }
36
37 pub fn private_functions_root_from_siblings(
38 selector: FunctionSelector,
39 vk_hash: Field,
40 function_leaf_index: Field,
41 function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT],
42 ) -> Field {
43 let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };
44 let function_leaf = function_leaf_preimage.hash();
45 root_from_sibling_path(
46 function_leaf,
47 function_leaf_index,
48 function_leaf_sibling_path,
49 )
50 }
51
52 /// Siloing in the context of Aztec refers to the process of hashing a note hash with a contract address (this way
53 /// the note hash is scoped to a specific contract). This is used to prevent intermingling of notes between contracts.
54 pub fn compute_siloed_note_hash(contract_address: AztecAddress, note_hash: Field) -> Field {
55 poseidon2_hash_with_separator(
56 [contract_address.to_field(), note_hash],
57 DOM_SEP__SILOED_NOTE_HASH,
58 )
59 }
60
61 /// Computes unique, siloed note hashes from siloed note hashes.
62 ///
63 /// The protocol injects uniqueness into every note_hash, so that every single note_hash in the
64 /// tree is unique. This prevents faerie gold attacks, where a malicious sender could create
65 /// two identical note_hashes for a recipient (meaning only one would be nullifiable in future).
66 ///
67 /// Most privacy protocols will inject the note's leaf_index (its position in the Note Hashes Tree)
68 /// into the note, but this requires the creator of a note to wait until their tx is included in
69 /// a block to know the note's final note hash (the unique, siloed note hash), because inserting
70 /// leaves into trees is the job of a block producer.
71 ///
72 /// We took a different approach so that the creator of a note will know each note's unique, siloed
73 /// note hash before broadcasting their tx to the network.
74 /// (There was also a historical requirement relating to "chained transactions" -- a feature that
75 /// Aztec Connect had to enable notes to be spent from distinct txs earlier in the same block,
76 /// and hence before an archive block root had been established for that block -- but that feature
77 /// was abandoned for the Aztec Network for having too many bad tradeoffs).
78 ///
79 /// (
80 /// Edit: it is no longer true that all final note_hashes will be known by the creator of a tx
81 /// before they send it to the network. If a tx makes public function calls, then _revertible_
82 /// note_hashes that are created in private will not be made unique in private by the Reset circuit,
83 /// but will instead be made unique by the AVM, because the `note_index_in_tx` will not be known
84 /// until the AVM has executed the public functions of the tx. (See an explanation in
85 /// reset_output_composer.nr for why).
86 /// For some such txs, the `note_index_in_tx` might still be predictable through simulation, but
87 /// for txs whose public functions create a varying number of non-revertible notes (determined at
88 /// runtime), the `note_index_in_tx` will not be deterministically derivable before submitting the
89 /// tx to the network.
90 /// )
91 ///
92 /// We use the `first_nullifier` of a tx as a seed of uniqueness. We have a guarantee that there will
93 /// always be at least one nullifier per tx, because the init circuit will create one if one isn't
94 /// created naturally by any functions of the tx. (Search "protocol_nullifier").
95 /// We combine the `first_nullifier` with the note's index (its position within this tx's new
96 /// note_hashes array) (`note_index_in_tx`) to get a truly unique value to inject into a note, which
97 /// we call a `note_nonce`.
98 pub fn compute_unique_note_hash(note_nonce: Field, siloed_note_hash: Field) -> Field {
99 let inputs = [note_nonce, siloed_note_hash];
100 poseidon2_hash_with_separator(inputs, DOM_SEP__UNIQUE_NOTE_HASH)
101 }
102
103 pub fn compute_note_hash_nonce(first_nullifier_in_tx: Field, note_index_in_tx: u32) -> Field {
104 // Hashing the first nullifier with note index in tx is guaranteed to be unique (because all nullifiers are also
105 // unique).
106 poseidon2_hash_with_separator(
107 [first_nullifier_in_tx, note_index_in_tx as Field],
108 DOM_SEP__NOTE_HASH_NONCE,
109 )
110 }
111
112 pub fn compute_note_nonce_and_unique_note_hash(
113 siloed_note_hash: Field,
114 first_nullifier: Field,
115 note_index_in_tx: u32,
116 ) -> Field {
117 let note_nonce = compute_note_hash_nonce(first_nullifier, note_index_in_tx);
118 compute_unique_note_hash(note_nonce, siloed_note_hash)
119 }
120
121 pub fn compute_siloed_nullifier(contract_address: AztecAddress, nullifier: Field) -> Field {
122 poseidon2_hash_with_separator(
123 [contract_address.to_field(), nullifier],
124 DOM_SEP__SILOED_NULLIFIER,
125 )
126 }
127
128 pub fn create_protocol_nullifier(tx_request: TxRequest) -> Scoped<Counted<Nullifier>> {
129 // The protocol nullifier is ascribed a special side-effect counter of 1. No other side-effect
130 // can have counter 1 (see `validate_as_first_call` for that assertion).
131 Nullifier { value: tx_request.hash(), note_hash: 0 }.count(1).scope(
132 NULL_MSG_SENDER_CONTRACT_ADDRESS,
133 )
134 }
135
136 pub fn compute_log_tag(raw_tag: Field, dom_sep: u32) -> Field {
137 poseidon2_hash_with_separator([raw_tag], dom_sep)
138 }
139
140 pub fn compute_siloed_private_log_first_field(
141 contract_address: AztecAddress,
142 field: Field,
143 ) -> Field {
144 poseidon2_hash_with_separator(
145 [contract_address.to_field(), field],
146 DOM_SEP__PRIVATE_LOG_FIRST_FIELD,
147 )
148 }
149
150 pub fn compute_siloed_private_log(contract_address: AztecAddress, log: PrivateLog) -> PrivateLog {
151 let mut fields = log.fields;
152 fields[0] = compute_siloed_private_log_first_field(contract_address, fields[0]);
153 PrivateLog::new(fields, log.length)
154 }
155
156 pub fn compute_contract_class_log_hash(log: [Field; CONTRACT_CLASS_LOG_SIZE_IN_FIELDS]) -> Field {
157 poseidon2_hash(log)
158 }
159
160 pub fn compute_app_siloed_secret_key(
161 master_secret_key: EmbeddedCurveScalar,
162 app_address: AztecAddress,
163 key_type_domain_separator: Field,
164 ) -> Field {
165 poseidon2_hash_with_separator(
166 [master_secret_key.hi, master_secret_key.lo, app_address.to_field()],
167 key_type_domain_separator,
168 )
169 }
170
171 pub fn compute_l2_to_l1_message_hash(
172 message: Scoped<L2ToL1Message>,
173 rollup_version_id: Field,
174 chain_id: Field,
175 ) -> Field {
176 let contract_address_bytes: [u8; 32] = message.contract_address.to_field().to_be_bytes();
177 let recipient_bytes: [u8; 20] = message.inner.recipient.to_be_bytes();
178 let content_bytes: [u8; 32] = message.inner.content.to_be_bytes();
179 let rollup_version_id_bytes: [u8; 32] = rollup_version_id.to_be_bytes();
180 let chain_id_bytes: [u8; 32] = chain_id.to_be_bytes();
181
182 let mut bytes: [u8; 148] = std::mem::zeroed();
183 for i in 0..32 {
184 bytes[i] = contract_address_bytes[i];
185 bytes[i + 32] = rollup_version_id_bytes[i];
186 // 64 - 84 are for recipient.
187 bytes[i + 84] = chain_id_bytes[i];
188 bytes[i + 116] = content_bytes[i];
189 }
190
191 for i in 0..20 {
192 bytes[64 + i] = recipient_bytes[i];
193 }
194
195 sha256_to_field(bytes)
196 }
197
198 // TODO: consider a variant that enables domain separation with a u32 (we seem to have standardised u32s for domain separators)
199 /// Computes sha256 hash of 2 input fields.
200 ///
201 /// @returns A truncated field (i.e., the first byte is always 0).
202 pub fn accumulate_sha256(v0: Field, v1: Field) -> Field {
203 // Concatenate two fields into 32 x 2 = 64 bytes
204 let v0_as_bytes: [u8; 32] = v0.to_be_bytes();
205 let v1_as_bytes: [u8; 32] = v1.to_be_bytes();
206 let hash_input_flattened = v0_as_bytes.concat(v1_as_bytes);
207
208 sha256_to_field(hash_input_flattened)
209 }
210
211 pub fn poseidon2_hash<let N: u32>(inputs: [Field; N]) -> Field {
212 poseidon::poseidon2::Poseidon2::hash(inputs, N)
213 }
214
215 #[no_predicates]
216 pub fn poseidon2_hash_with_separator<let N: u32, T>(inputs: [Field; N], separator: T) -> Field
217 where
218 T: ToField,
219 {
220 let inputs_with_separator = [separator.to_field()].concat(inputs);
221 poseidon2_hash(inputs_with_separator)
222 }
223
224 /// Computes a Poseidon2 hash over a dynamic-length subarray of the given input.
225 /// Only the first `in_len` fields of `input` are absorbed; any remaining fields are ignored.
226 /// The caller is responsible for ensuring that the input is padded with zeros if required.
227 #[no_predicates]
228 pub fn poseidon2_hash_subarray<let N: u32>(input: [Field; N], in_len: u32) -> Field {
229 let mut sponge = poseidon2_absorb_in_chunks(input, in_len);
230 sponge.squeeze()
231 }
232
233 // This function is unconstrained because it is intended to be used in unconstrained context only as
234 // in constrained contexts it would be too inefficient.
235 pub unconstrained fn poseidon2_hash_with_separator_bounded_vec<let N: u32, T>(
236 inputs: BoundedVec<Field, N>,
237 separator: T,
238 ) -> Field
239 where
240 T: ToField,
241 {
242 let in_len = inputs.len() + 1;
243 let iv: Field = (in_len as Field) * TWO_POW_64;
244 let mut sponge = Poseidon2Sponge::new(iv);
245 sponge.absorb(separator.to_field());
246
247 for i in 0..inputs.len() {
248 sponge.absorb(inputs.get(i));
249 }
250
251 sponge.squeeze()
252 }
253
254 #[no_predicates]
255 pub fn poseidon2_hash_bytes<let N: u32>(inputs: [u8; N]) -> Field {
256 let mut fields = [0; (N + 30) / 31];
257 let mut field_index = 0;
258 let mut current_field = [0; 31];
259 for i in 0..inputs.len() {
260 let index = i % 31;
261 current_field[index] = inputs[i];
262 if index == 30 {
263 fields[field_index] = field_from_bytes(current_field, false);
264 current_field = [0; 31];
265 field_index += 1;
266 }
267 }
268 if field_index != fields.len() {
269 fields[field_index] = field_from_bytes(current_field, false);
270 }
271 poseidon2_hash(fields)
272 }
273
274 #[test]
275 fn subarray_hash_matches_fixed() {
276 let values_to_hash = [3; 17];
277 let padded = values_to_hash.concat([0; 11]);
278 let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());
279
280 // Hash the entire values_to_hash.
281 let fixed_len_hash = poseidon::poseidon2::Poseidon2::hash(values_to_hash, values_to_hash.len());
282
283 assert_eq(subarray_hash, fixed_len_hash);
284 }
285
286 #[test]
287 fn subarray_hash_matches_variable() {
288 let values_to_hash = [3; 17];
289 let padded = values_to_hash.concat([0; 11]);
290 let subarray_hash = poseidon2_hash_subarray(padded, values_to_hash.len());
291
292 // Hash up to values_to_hash.len() fields of the padded array.
293 let variable_len_hash = poseidon::poseidon2::Poseidon2::hash(padded, values_to_hash.len());
294
295 assert_eq(subarray_hash, variable_len_hash);
296 }
297
298 #[test]
299 fn smoke_sha256_to_field() {
300 let full_buffer = [
301 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
302 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
303 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
304 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
305 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
306 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
307 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
308 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
309 ];
310 let result = sha256_to_field(full_buffer);
311
312 assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7);
313
314 // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes):
315 let result_bytes = sha256::digest(full_buffer);
316 let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes);
317 assert(truncated_field == result);
318 let mod_res = result + (result_bytes[31] as Field);
319 assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0);
320 }
321
322 #[test]
323 fn unique_siloed_note_hash_matches_typescript() {
324 let inner_note_hash = 1;
325 let contract_address = AztecAddress::from_field(2);
326 let first_nullifier = 3;
327 let note_index_in_tx = 4;
328
329 let siloed_note_hash = compute_siloed_note_hash(contract_address, inner_note_hash);
330 let siloed_note_hash_from_ts =
331 0x1986a4bea3eddb1fff917d629a13e10f63f514f401bdd61838c6b475db949169;
332 assert_eq(siloed_note_hash, siloed_note_hash_from_ts);
333
334 let nonce: Field = compute_note_hash_nonce(first_nullifier, note_index_in_tx);
335 let note_hash_nonce_from_ts =
336 0x28e7799791bf066a57bb51fdd0fbcaf3f0926414314c7db515ea343f44f5d58b;
337 assert_eq(nonce, note_hash_nonce_from_ts);
338
339 let unique_siloed_note_hash_from_nonce = compute_unique_note_hash(nonce, siloed_note_hash);
340 let unique_siloed_note_hash = compute_note_nonce_and_unique_note_hash(
341 siloed_note_hash,
342 first_nullifier,
343 note_index_in_tx,
344 );
345 assert_eq(unique_siloed_note_hash_from_nonce, unique_siloed_note_hash);
346
347 let unique_siloed_note_hash_from_ts =
348 0x29949aef207b715303b24639737c17fbfeb375c1d965ecfa85c7e4f0febb7d16;
349 assert_eq(unique_siloed_note_hash, unique_siloed_note_hash_from_ts);
350 }
351
352 #[test]
353 fn siloed_nullifier_matches_typescript() {
354 let contract_address = AztecAddress::from_field(123);
355 let nullifier = 456;
356
357 let res = compute_siloed_nullifier(contract_address, nullifier);
358
359 let siloed_nullifier_from_ts =
360 0x169b50336c1f29afdb8a03d955a81e485f5ac7d5f0b8065673d1e407e5877813;
361
362 assert_eq(res, siloed_nullifier_from_ts);
363 }
364
365 #[test]
366 fn siloed_private_log_first_field_matches_typescript() {
367 let contract_address = AztecAddress::from_field(123);
368 let field = 456;
369 let res = compute_siloed_private_log_first_field(contract_address, field);
370
371 let siloed_private_log_first_field_from_ts =
372 0x29480984f7b9257fded523d50addbcfc8d1d33adcf2db73ef3390a8fd5cdffaa;
373
374 assert_eq(res, siloed_private_log_first_field_from_ts);
375 }
376
377 #[test]
378 fn empty_l2_to_l1_message_hash_matches_typescript() {
379 // All zeroes
380 let res = compute_l2_to_l1_message_hash(
381 L2ToL1Message { recipient: EthAddress::zero(), content: 0 }.scope(AztecAddress::from_field(
382 0,
383 )),
384 0,
385 0,
386 );
387
388 let empty_l2_to_l1_msg_hash_from_ts =
389 0x003b18c58c739716e76429634a61375c45b3b5cd470c22ab6d3e14cee23dd992;
390
391 assert_eq(res, empty_l2_to_l1_msg_hash_from_ts);
392 }
393
394 #[test]
395 fn l2_to_l1_message_hash_matches_typescript() {
396 let message = L2ToL1Message { recipient: EthAddress::from_field(1), content: 2 }.scope(
397 AztecAddress::from_field(3),
398 );
399 let version = 4;
400 let chainId = 5;
401
402 let hash = compute_l2_to_l1_message_hash(message, version, chainId);
403
404 // The following value was generated by `yarn-project/stdlib/src/hash/hash.test.ts`
405 let l2_to_l1_message_hash_from_ts =
406 0x0081edf209e087ad31b3fd24263698723d57190bd1d6e9fe056fc0c0a68ee661;
407
408 assert_eq(hash, l2_to_l1_message_hash_from_ts);
409 }
410
411 #[test]
412 unconstrained fn poseidon2_hash_with_separator_bounded_vec_matches_non_bounded_vec_version() {
413 let inputs = BoundedVec::<Field, 4>::from_array([1, 2, 3]);
414 let separator = 42;
415
416 // Hash using bounded vec version
417 let bounded_result = poseidon2_hash_with_separator_bounded_vec(inputs, separator);
418
419 // Hash using regular version
420 let regular_result = poseidon2_hash_with_separator([1, 2, 3], separator);
421
422 // Results should match
423 assert_eq(bounded_result, regular_result);
424 }
1 use crate::{
2 constants::{
3 DOM_SEP__MERKLE_HASH, DOM_SEP__NULLIFIER_MERKLE, DOM_SEP__PUBLIC_DATA_MERKLE,
4 DOM_SEP__RETRIEVED_BYTECODES_MERKLE, DOM_SEP__WRITTEN_SLOTS_MERKLE,
5 },
6 hash::{accumulate_sha256, poseidon2_hash_with_separator},
7 traits::Empty,
8 utils::math::is_power_of_2_u32,
9 };
10
11 /// Merkle-node hash used by append-only trees.
12 pub fn merkle_hash(left: Field, right: Field) -> Field {
13 poseidon2_hash_with_separator([left, right], DOM_SEP__MERKLE_HASH)
14 }
15
16 /// Merkle-node hash for the nullifier tree's sibling paths.
17 pub fn nullifier_merkle_hash(left: Field, right: Field) -> Field {
18 poseidon2_hash_with_separator([left, right], DOM_SEP__NULLIFIER_MERKLE)
19 }
20
21 /// Merkle-node hash for the public-data tree's sibling paths.
22 pub fn public_data_merkle_hash(left: Field, right: Field) -> Field {
23 poseidon2_hash_with_separator([left, right], DOM_SEP__PUBLIC_DATA_MERKLE)
24 }
25
26 /// Merkle-node hash for the AVM-internal written-public-data-slots tree's sibling paths.
27 pub fn written_slots_merkle_hash(left: Field, right: Field) -> Field {
28 poseidon2_hash_with_separator([left, right], DOM_SEP__WRITTEN_SLOTS_MERKLE)
29 }
30
31 /// Merkle-node hash for the AVM-internal retrieved-bytecodes (class-id) tree's sibling paths.
32 pub fn retrieved_bytecodes_merkle_hash(left: Field, right: Field) -> Field {
33 poseidon2_hash_with_separator([left, right], DOM_SEP__RETRIEVED_BYTECODES_MERKLE)
34 }
35
36 pub fn sha_merkle_hash(left: Field, right: Field) -> Field {
37 accumulate_sha256(left, right)
38 }
39
40 #[derive(Eq)]
41 pub struct MerkleTree<let N: u32> {
42 pub leaves: [Field; N],
43 pub nodes: [Field; N - 1],
44 }
45
46 impl<let N: u32> Empty for MerkleTree<N> {
47 fn empty() -> Self {
48 MerkleTree { leaves: [0; N], nodes: [0; N - 1] }
49 }
50 }
51
52 impl<let N: u32> MerkleTree<N> {
53 pub fn new(leaves: [Field; N]) -> Self {
54 let nodes = compute_merkle_tree_nodes(leaves, merkle_hash);
55 MerkleTree { leaves, nodes }
56 }
57
58 pub fn new_with_hasher(leaves: [Field; N], hasher: fn(Field, Field) -> Field) -> Self {
59 let nodes = compute_merkle_tree_nodes(leaves, hasher);
60 MerkleTree { leaves, nodes }
61 }
62
63 pub fn new_sha(leaves: [Field; N]) -> Self {
64 let nodes = compute_merkle_tree_nodes(leaves, sha_merkle_hash);
65 MerkleTree { leaves, nodes }
66 }
67
68 pub fn get_root(self) -> Field {
69 self.nodes[N - 2]
70 }
71
72 pub fn get_sibling_path<let K: u32>(self, leaf_index: u32) -> [Field; K] {
73 assert_eq(2.pow_32(K as Field), N as Field, "Invalid path length");
74
75 let mut path = [0; K];
76 let mut current_index = leaf_index;
77 let mut subtree_width = N;
78
79 let mut current_sibling_index = sibling_index(current_index);
80
81 path[0] = self.leaves[current_sibling_index];
82
83 let mut subtree_offset: u32 = 0;
84
85 for i in 1..K {
86 current_index = current_index / 2;
87 subtree_width = subtree_width / 2;
88
89 current_sibling_index = sibling_index(current_index);
90
91 path[i] = self.nodes[subtree_offset + current_sibling_index];
92
93 subtree_offset += subtree_width;
94 }
95
96 path
97 }
98 }
99
100 pub fn sibling_index(index: u32) -> u32 {
101 if index % 2 == 0 {
102 index + 1
103 } else {
104 index - 1
105 }
106 }
107
108 pub fn compute_merkle_tree_nodes<let N: u32>(
109 leaves: [Field; N],
110 hasher: fn(Field, Field) -> Field,
111 ) -> [Field; N - 1] {
112 // Note: `N` must be a power of 2.
113 std::static_assert(is_power_of_2_u32(N), "N must be a power of 2");
114 std::static_assert(N != 1, "2 must divide N");
115
116 let mut nodes = [0; N - 1];
117
118 let total_nodes = N - 1;
119 let half_size = N / 2;
120
121 // Hash base layer.
122 for i in 0..half_size {
123 nodes[i] = hasher(leaves[2 * i], leaves[2 * i + 1]);
124 }
125
126 // Hash the other layers.
127 for i in 0..(total_nodes - half_size) {
128 nodes[half_size + i] = hasher(nodes[2 * i], nodes[2 * i + 1]);
129 }
130
131 nodes
132 }
1 use crate::merkle_tree::merkle_tree::{compute_merkle_tree_nodes, merkle_hash, sha_merkle_hash};
2
3 /// Calculate the Merkle tree root from the sibling path and leaf, using the default merkle hash.
4 pub fn root_from_sibling_path<let N: u32>(
5 leaf: Field,
6 leaf_index: Field,
7 sibling_path: [Field; N],
8 ) -> Field {
9 root_from_sibling_path_with_hasher(leaf, leaf_index, sibling_path, merkle_hash)
10 }
11
12 /// Calculate the Merkle tree root from the sibling path and leaf, using a custom hasher.
13 ///
14 /// The leaf is hashed with its sibling, the result is then hashed with the next sibling in the path. and so on.
15 /// The last hash is the root.
16 pub fn root_from_sibling_path_with_hasher<let N: u32>(
17 leaf: Field,
18 leaf_index: Field,
19 sibling_path: [Field; N],
20 hasher: fn(Field, Field) -> Field,
21 ) -> Field {
22 let mut node = leaf;
23 let indices: [bool; N] = leaf_index.to_le_bits();
24
25 for i in 0..N {
26 let (hash_left, hash_right) = if indices[i] {
27 (sibling_path[i], node)
28 } else {
29 (node, sibling_path[i])
30 };
31 node = hasher(hash_left, hash_right);
32 }
33 node
34 }
35
36 pub fn compute_tree_root<let N: u32>(leaves: [Field; N]) -> Field {
37 compute_tree_root_with_hasher(leaves, merkle_hash)
38 }
39
40 pub fn compute_sha_tree_root<let N: u32>(leaves: [Field; N]) -> Field {
41 compute_tree_root_with_hasher(leaves, sha_merkle_hash)
42 }
43
44 pub fn compute_tree_root_with_hasher<let N: u32>(
45 leaves: [Field; N],
46 hasher: fn(Field, Field) -> Field,
47 ) -> Field {
48 compute_merkle_tree_nodes(leaves, hasher)[N - 2]
49 }
50
51 pub fn compute_empty_tree_root<let TreeHeight: u32>() -> Field {
52 compute_empty_tree_root_with_hasher::<TreeHeight>(merkle_hash)
53 }
54
55 pub fn compute_empty_sha_tree_root<let TreeHeight: u32>() -> Field {
56 compute_empty_tree_root_with_hasher::<TreeHeight>(sha_merkle_hash)
57 }
58
59 pub fn compute_empty_tree_root_with_hasher<let TreeHeight: u32>(
60 hasher: fn(Field, Field) -> Field,
61 ) -> Field {
62 let mut hashes = [0; TreeHeight + 1];
63 for i in 1..TreeHeight + 1 {
64 hashes[i] = hasher(hashes[i - 1], hashes[i - 1]);
65 }
66 hashes[TreeHeight]
67 }
68
69 #[test]
70 fn test_merkle_roots_match_typescript() {
71 // The following hardcoded values are generated from yarn-project/foundation/src/trees/balanced_merkle_tree_root.test.ts
72
73 let root = compute_tree_root([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
74 let expected_tree_root_from_ts =
75 0x2bc86dba04dfdd6352c3b1c66b2300445964e2888aa52fdb023d2e645a3d3399;
76 assert_eq(root, expected_tree_root_from_ts);
77
78 let empty_root = compute_tree_root([0; 16]);
79 let expected_empty_root_from_ts =
80 0x1e20ad4181460cbfdc74ca773502c59b890f184efe300ebad895956d318422da;
81 assert_eq(empty_root, expected_empty_root_from_ts);
82
83 let sha_root = compute_sha_tree_root([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
84 let expected_sha_root_from_ts =
85 0x00b007869b8a5e2a9b3b580a318e702cea04b2f5438f2e26743f545e4d1ecbdb;
86 assert_eq(sha_root, expected_sha_root_from_ts);
87 }
88
89 #[test]
90 fn test_empty_tree_root() {
91 assert_eq(compute_empty_tree_root::<0>(), 0);
92
93 assert_eq(
94 compute_empty_tree_root::<1>(),
95 0x19f1a0c09db4cd026f686e9c8fb45501a9fefb4eb1b4c6c328a51343a0094eeb,
96 );
97
98 assert_eq(
99 compute_empty_tree_root::<2>(),
100 0x14e4b977b2203b70e6ee1c2456eb7114d090fe4b907f631eecd0919fed432e7d,
101 );
102
103 assert_eq(
104 compute_empty_tree_root::<6>(),
105 0x119f56a2e8423a7feaab49b9b5dcbadec0648dfa4096b61b6774ea33ae29dc7f,
106 );
107
108 assert_eq(
109 compute_empty_tree_root::<10>(),
110 0x0d04c63f36bd168215c9b09a227c7e8d3ad48e2f11b8202fd07c524bd30ee88f,
111 );
112 }
1 use crate::{
2 constants::DOM_SEP__PUBLIC_STORAGE_MAP_SLOT, hash::poseidon2_hash_with_separator,
3 traits::ToField,
4 };
5
6 // TODO: Move this to src/public_data/storage/map.nr
7 pub fn derive_storage_slot_in_map<K>(storage_slot: Field, key: K) -> Field
8 where
9 K: ToField,
10 {
11 poseidon2_hash_with_separator(
12 [storage_slot, key.to_field()],
13 DOM_SEP__PUBLIC_STORAGE_MAP_SLOT,
14 )
15 }
16
17 mod test {
18 use crate::{address::AztecAddress, storage::map::derive_storage_slot_in_map, traits::FromField};
19
20 #[test]
21 fn test_derive_storage_slot_in_map_matches_typescript() {
22 let map_slot = 0x132258fb6962c4387ba659d9556521102d227549a386d39f0b22d1890d59c2b5;
23 let key = AztecAddress::from_field(
24 0x302dbc2f9b50a73283d5fb2f35bc01eae8935615817a0b4219a057b2ba8a5a3f,
25 );
26
27 let slot = derive_storage_slot_in_map(map_slot, key);
28
29 // The following value was generated by `map_slot.test.ts`
30 let slot_from_typescript =
31 0x2d225f361108379adc2da91378b9702675c5546b57e78bafc1e74ec7fec55967;
32
33 assert_eq(slot, slot_from_typescript);
34 }
35 }
1 use crate::traits::{Deserialize, Packable, Serialize};
2
3 global BOOL_PACKED_LEN: u32 = 1;
4 global U8_PACKED_LEN: u32 = 1;
5 global U16_PACKED_LEN: u32 = 1;
6 global U32_PACKED_LEN: u32 = 1;
7 global U64_PACKED_LEN: u32 = 1;
8 global U128_PACKED_LEN: u32 = 1;
9 global FIELD_PACKED_LEN: u32 = 1;
10 global I8_PACKED_LEN: u32 = 1;
11 global I16_PACKED_LEN: u32 = 1;
12 global I32_PACKED_LEN: u32 = 1;
13 global I64_PACKED_LEN: u32 = 1;
14 global POINT_PACKED_LEN: u32 = 2;
15
16 impl Packable for bool {
17 let N: u32 = BOOL_PACKED_LEN;
18
19 #[inline_always]
20 fn pack(self) -> [Field; Self::N] {
21 [self as Field]
22 }
23
24 /// Unpacks a `bool`, constraining the field to be a canonical boolean. A field outside `{0, 1}` is
25 /// rejected (rather than silently reinterpreted), so an arbitrary-origin field cannot be misread.
26 /// `pack` always emits `0` or `1`, so round-tripping is unaffected.
27 #[inline_always]
28 fn unpack(fields: [Field; Self::N]) -> bool {
29 let v = fields[0];
30 // v * v == v holds iff v is 0 or 1: a single degree-2 constraint that both validates the field
31 // is a canonical bool and avoids the byte-range decomposition that a cast to u8 would require.
32 assert(v * v == v, "Packable::unpack: bool field must be 0 or 1");
33 v == 1
34 }
35 }
36
37 impl Packable for u8 {
38 let N: u32 = U8_PACKED_LEN;
39
40 #[inline_always]
41 fn pack(self) -> [Field; Self::N] {
42 [self as Field]
43 }
44
45 #[inline_always]
46 fn unpack(fields: [Field; Self::N]) -> Self {
47 fields[0] as u8
48 }
49 }
50
51 impl Packable for u16 {
52 let N: u32 = U16_PACKED_LEN;
53
54 #[inline_always]
55 fn pack(self) -> [Field; Self::N] {
56 [self as Field]
57 }
58
59 #[inline_always]
60 fn unpack(fields: [Field; Self::N]) -> Self {
61 fields[0] as u16
62 }
63 }
64
65 impl Packable for u32 {
66 let N: u32 = U32_PACKED_LEN;
67
68 #[inline_always]
69 fn pack(self) -> [Field; Self::N] {
70 [self as Field]
71 }
72
73 #[inline_always]
74 fn unpack(fields: [Field; Self::N]) -> Self {
75 fields[0] as u32
76 }
77 }
78
79 impl Packable for u64 {
80 let N: u32 = U64_PACKED_LEN;
81
82 #[inline_always]
83 fn pack(self) -> [Field; Self::N] {
84 [self as Field]
85 }
86
87 #[inline_always]
88 fn unpack(fields: [Field; Self::N]) -> Self {
89 fields[0] as u64
90 }
91 }
92
93 impl Packable for u128 {
94 let N: u32 = U128_PACKED_LEN;
95
96 #[inline_always]
97 fn pack(self) -> [Field; Self::N] {
98· [self as Field]
99 }
100
101 #[inline_always]
102 fn unpack(fields: [Field; Self::N]) -> Self {
103· fields[0] as u128
104 }
105 }
106
107 impl Packable for Field {
108 let N: u32 = FIELD_PACKED_LEN;
109
110 #[inline_always]
111 fn pack(self) -> [Field; Self::N] {
112 [self]
113 }
114
115 #[inline_always]
116 fn unpack(fields: [Field; Self::N]) -> Self {
117 fields[0]
118 }
119 }
120
121 impl Packable for i8 {
122 let N: u32 = I8_PACKED_LEN;
123
124 #[inline_always]
125 fn pack(self) -> [Field; Self::N] {
126 [self as u8 as Field]
127 }
128
129 #[inline_always]
130 fn unpack(fields: [Field; Self::N]) -> Self {
131 fields[0] as u8 as i8
132 }
133 }
134
135 impl Packable for i16 {
136 let N: u32 = I16_PACKED_LEN;
137
138 #[inline_always]
139 fn pack(self) -> [Field; Self::N] {
140 [self as u16 as Field]
141 }
142
143 #[inline_always]
144 fn unpack(fields: [Field; Self::N]) -> Self {
145 fields[0] as u16 as i16
146 }
147 }
148
149 impl Packable for i32 {
150 let N: u32 = I32_PACKED_LEN;
151
152 #[inline_always]
153 fn pack(self) -> [Field; Self::N] {
154 [self as u32 as Field]
155 }
156
157 #[inline_always]
158 fn unpack(fields: [Field; Self::N]) -> Self {
159 fields[0] as u32 as i32
160 }
161 }
162
163 impl Packable for i64 {
164 let N: u32 = I64_PACKED_LEN;
165
166 #[inline_always]
167 fn pack(self) -> [Field; Self::N] {
168 [self as u64 as Field]
169 }
170
171 #[inline_always]
172 fn unpack(fields: [Field; Self::N]) -> Self {
173 fields[0] as u64 as i64
174 }
175 }
176
177 impl Packable for super::point::EmbeddedCurvePoint {
178 let N: u32 = POINT_PACKED_LEN;
179 fn pack(self) -> [Field; Self::N] {
180 self.serialize()
181 }
182
183 fn unpack(packed: [Field; Self::N]) -> Self {
184 Self::deserialize(packed)
185 }
186 }
187
188 impl<T, let M: u32> Packable for [T; M]
189 where
190 T: Packable,
191 {
192 let N: u32 = M * <T as Packable>::N;
193
194 #[inline_always]
195 fn pack(self) -> [Field; Self::N] {
196 let mut result: [Field; Self::N] = std::mem::zeroed();
197 for i in 0..M {
198 let serialized = self[i].pack();
199 for j in 0..<T as Packable>::N {
200 result[i * <T as Packable>::N + j] = serialized[j];
201 }
202 }
203 result
204 }
205
206 #[inline_always]
207 fn unpack(fields: [Field; Self::N]) -> Self {
208 let mut reader = crate::utils::reader::Reader::new(fields);
209 let result: [T; M] = std::mem::zeroed();
210 reader.read_struct_array::<T, <T as Packable>::N, M>(Packable::unpack, result)
211 }
212 }
213
214 #[test]
215 fn test_u16_packing() {
216 let a: u16 = 10;
217 assert_eq(a, u16::unpack(a.pack()));
218 }
219
220 #[test]
221 fn test_i8_packing() {
222 let a: i8 = -10;
223 assert_eq(a, i8::unpack(a.pack()));
224 }
225
226 #[test]
227 fn test_i16_packing() {
228 let a: i16 = -10;
229 assert_eq(a, i16::unpack(a.pack()));
230 }
231
232 #[test]
233 fn test_i32_packing() {
234 let a: i32 = -10;
235 assert_eq(a, i32::unpack(a.pack()));
236 }
237
238 #[test]
239 fn test_i64_packing() {
240 let a: i64 = -10;
241 assert_eq(a, i64::unpack(a.pack()));
242 }
243
244 #[test]
245 fn test_bool_unpack_accepts_canonical_values() {
246 assert_eq(bool::unpack([0]), false);
247 assert_eq(bool::unpack([1]), true);
248 }
249
250 #[test(should_fail_with = "bool field must be 0 or 1")]
251 fn test_bool_unpack_rejects_even_non_bool() {
252 // 2 has LSB 0, so the previous LSB-based unpack silently returned false; now it is rejected.
253 let _ = bool::unpack([2]);
254 }
255
256 #[test(should_fail_with = "bool field must be 0 or 1")]
257 fn test_bool_unpack_rejects_odd_non_bool() {
258 // 3 has LSB 1, so the previous LSB-based unpack silently returned true; now it is rejected.
259 let _ = bool::unpack([3]);
260 }
261
262 #[test(should_fail_with = "bool field must be 0 or 1")]
263 fn test_bool_unpack_rejects_large_field() {
264 let _ = bool::unpack([1000000]);
265 }
266
267 #[test]
268 fn test_bool_pack_unpack_roundtrip() {
269 // `pack` always emits 0 or 1, so it round-trips through the canonical-bool check in `unpack`.
270 assert_eq(true.pack(), [1]);
271 assert_eq(false.pack(), [0]);
272 assert_eq(bool::unpack(true.pack()), true);
273 assert_eq(bool::unpack(false.pack()), false);
274 }
1 use std::default::Default;
2 use std::hash::Hasher;
3
4 global RATE: u32 = 3;
5
6 pub struct Poseidon2 {
7 cache: [Field; 3],
8 state: [Field; 4],
9 cache_size: u32,
10 squeeze_mode: bool, // 0 => absorb, 1 => squeeze
11 }
12
13 impl Poseidon2 {
14 #[no_predicates]
15 pub fn hash<let N: u32>(input: [Field; N], message_size: u32) -> Field {
16 Poseidon2::hash_internal(input, message_size)
17 }
18
19 pub(crate) fn new(iv: Field) -> Poseidon2 {
20 let mut result =
21 Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false };
22 result.state[RATE] = iv;
23 result
24 }
25
26 fn perform_duplex(&mut self) {
27 // add the cache into sponge state
28 self.state[0] += self.cache[0];
29 self.state[1] += self.cache[1];
30 self.state[2] += self.cache[2];
31 self.state = crate::poseidon2_permutation(self.state);
32 }
33
34 fn absorb(&mut self, input: Field) {
35 assert(!self.squeeze_mode);
36 if self.cache_size == RATE {
37 // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache
38 self.perform_duplex();
39 self.cache[0] = input;
40 self.cache_size = 1;
41 } else {
42 // If we're absorbing, and the cache is not full, add the input into the cache
43 self.cache[self.cache_size] = input;
44 self.cache_size += 1;
45 }
46 }
47
48 fn squeeze(&mut self) -> Field {
49 assert(!self.squeeze_mode);
50 // If we're in absorb mode, apply sponge permutation to compress the cache.
51 self.perform_duplex();
52 self.squeeze_mode = true;
53
54 // Pop one item off the top of the permutation and return it.
55 self.state[0]
56 }
57
58 fn hash_internal<let N: u32>(input: [Field; N], in_len: u32) -> Field {
59 let two_pow_64 = 18446744073709551616;
60 let iv: Field = (in_len as Field) * two_pow_64;
61 let mut state = [0; 4];
62 state[RATE] = iv;
63
64 if std::runtime::is_unconstrained() {
65 for i in 0..(in_len / RATE) {
66 state[0] += input[i * RATE];
67 state[1] += input[i * RATE + 1];
68· state[2] += input[i * RATE + 2];
69 state = crate::poseidon2_permutation(state);
70 }
71
72 // handle remaining elements after last full RATE-sized chunk
73 let num_extra_fields = in_len % RATE;
74 if num_extra_fields != 0 {
75 let remainder_start = in_len - num_extra_fields;
76 state[0] += input[remainder_start];
77 if num_extra_fields > 1 {
78 state[1] += input[remainder_start + 1];
79 }
80 }
81 } else {
82 let mut states: [[Field; 4]; N / RATE + 1] = [[0; 4]; N / RATE + 1];
83 states[0] = state;
84
85 // process all full RATE-sized chunks, storing state after each permutation
86 for chunk_idx in 0..(N / RATE) {
87 for i in 0..RATE {
88 state[i] += input[chunk_idx * RATE + i];
89 }
90 state = crate::poseidon2_permutation(state);
91 states[chunk_idx + 1] = state;
92 }
93
94 // get state at the last full block before in_len
95 let first_partially_filled_chunk = in_len / RATE;
96 state = states[first_partially_filled_chunk];
97
98 // handle remaining elements after last full RATE-sized chunk
99 let remainder_start = (in_len / RATE) * RATE;
100 for j in 0..RATE {
101 let idx = remainder_start + j;
102 if idx < in_len {
103 state[j] += input[idx];
104 }
105 }
106 }
107
108 // always run final permutation unless we just completed a full chunk
109 // still need to permute once if in_len is 0
110 if (in_len == 0) | (in_len % RATE != 0) {
111 state = crate::poseidon2_permutation(state);
112 };
113
114· state[0]
115 }
116 }
117
118 pub struct Poseidon2Hasher {
119 _state: [Field],
120 }
121
122 impl Hasher for Poseidon2Hasher {
123 fn finish(self) -> Field {
124 let iv: Field = (self._state.len() as Field) * 18446744073709551616; // iv = (self._state.len() << 64)
125 let mut sponge = Poseidon2::new(iv);
126 for i in 0..self._state.len() {
127 sponge.absorb(self._state[i]);
128 }
129 sponge.squeeze()
130 }
131
132 fn write(&mut self, input: Field) {
133 self._state = self._state.push_back(input);
134 }
135 }
136
137 impl Default for Poseidon2Hasher {
138 fn default() -> Self {
139 Poseidon2Hasher { _state: @[] }
140 }
141 }
1 use std::hash::sha256_compression;
2 use std::runtime::is_unconstrained;
3
4 use constants::{
5 BLOCK_BYTE_PTR, BLOCK_SIZE, HASH, INITIAL_STATE, INT_BLOCK_SIZE, INT_SIZE, INT_SIZE_PTR,
6 MSG_BLOCK, MSG_SIZE_PTR, STATE, TWO_POW_16, TWO_POW_24, TWO_POW_32, TWO_POW_8,
7 };
8
9 pub(crate) mod constants;
10 mod tests;
11 mod oracle_tests;
12
13 // Implementation of SHA-256 mapping a byte array of variable length to
14 // 32 bytes.
15
16 // Deprecated in favour of `sha256_var`
17 // docs:start:sha256
18 pub fn sha256<let N: u32>(input: [u8; N]) -> HASH
19 // docs:end:sha256
20 {
21 digest(input)
22 }
23
24 // SHA-256 hash function
25 #[no_predicates]
26 pub fn digest<let N: u32>(msg: [u8; N]) -> HASH {
27 sha256_var(msg, N)
28 }
29
30 // Variable size SHA-256 hash
31 pub fn sha256_var<let N: u32>(msg: [u8; N], message_size: u32) -> HASH {
32 assert(message_size <= N);
33
34 let (h, msg_block) = process_full_blocks(msg, message_size, INITIAL_STATE);
35
36 finalize_sha256_blocks(message_size, h, msg_block)
37 }
38
39 /// Returns the first partially filled message block along with the internal state prior to its compression.
40 pub(crate) fn process_full_blocks<let N: u32>(
41 msg: [u8; N],
42 message_size: u32,
43 initial_state: STATE,
44 ) -> (STATE, MSG_BLOCK) {
45 if std::runtime::is_unconstrained() {
46 let num_full_blocks = message_size / BLOCK_SIZE;
47 // Intermediate hash, starting with the canonical initial value
48 let mut h: STATE = initial_state;
49 // Pointer into msg_block on a 64 byte scale
50 for i in 0..num_full_blocks {
51 let msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * i);
52 h = sha256_compression(msg_block, h);
53 }
54
55 // We now build the final un-filled block.
56 let msg_byte_ptr = message_size % BLOCK_SIZE;
57 let msg_block: MSG_BLOCK = if msg_byte_ptr != 0 {
58 let num_full_blocks = message_size / BLOCK_SIZE;
59 let msg_start = BLOCK_SIZE * num_full_blocks;
60 build_msg_block(msg, message_size, msg_start)
61 } else {
62 // If the message size is a multiple of the block size (i.e. `msg_byte_ptr == 0`) then this block will be empty,
63 // so we short-circuit in this case.
64 [0; 16]
65 };
66
67 (h, msg_block)
68 } else {
69 let num_blocks = N / BLOCK_SIZE;
70
71 // We store the intermediate hash states and message blocks in these two arrays which allows us to select the correct state
72 // for the given message size with a lookup.
73 //
74 // These can be reasoned about as followed:
75 // Consider a message with an unknown number of bytes, `msg_size. It can be seen that this will have `msg_size / BLOCK_SIZE` full blocks.
76 // - `states[i]` should then be the state after processing the first `i` blocks.
77 // - `blocks[i]` should then be the next message block after processing the first `i` blocks.
78 // blocks[first_partially_filled_block_index] is the last block that is partially filled or all 0 if the message is a multiple of the block size.
79 //
80 // In other words:
81 //
82 // blocks = [block 1, block 2, ..., block N / BLOCK_SIZE, block N / BLOCK_SIZE + 1]
83 // states = [INITIAL_STATE, state after block 1, state after block 2, ..., state after block N / BLOCK_SIZE]
84 //
85 // We place the initial state in `states[0]` as in the case where the `message_size < BLOCK_SIZE` then there are no full blocks to process and no compressions should occur.
86 let mut blocks: [MSG_BLOCK; N / BLOCK_SIZE + 1] = std::mem::zeroed();
87 let mut states: [STATE; N / BLOCK_SIZE + 1] = [initial_state; N / BLOCK_SIZE + 1];
88
89 // Optimization for small messages. If the largest possible message is smaller than a block then we know that the first block is partially filled
90 // no matter the value of `message_size`.
91 //
92 // Note that the condition `N >= BLOCK_SIZE` is known during monomorphization so this has no runtime cost.
93 let first_partially_filled_block_index = if N >= BLOCK_SIZE {
94 message_size / BLOCK_SIZE
95 } else {
96 0
97 };
98
99 for i in 0..num_blocks {
100 let msg_start = BLOCK_SIZE * i;
101 let new_msg_block = build_msg_block(msg, message_size, msg_start);
102
103 blocks[i] = new_msg_block;
104 states[i + 1] = sha256_compression(new_msg_block, states[i]);
105 }
106 // If message_size/BLOCK_SIZE == N/BLOCK_SIZE, and there is a remainder, we need to process the last block.
107 if N % BLOCK_SIZE != 0 {
108 let new_msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * num_blocks);
109
110 blocks[num_blocks] = new_msg_block;
111 }
112
113 (states[first_partially_filled_block_index], blocks[first_partially_filled_block_index])
114 }
115 }
116
117 // Take `BLOCK_SIZE` number of bytes from `msg` starting at `msg_start` and pack them into a `MSG_BLOCK`.
118 pub(crate) unconstrained fn build_msg_block_helper<let N: u32>(
119 msg: [u8; N],
120 message_size: u32,
121 msg_start: u32,
122 ) -> MSG_BLOCK {
123 let mut msg_block: MSG_BLOCK = [0; INT_BLOCK_SIZE];
124
125 // We insert `BLOCK_SIZE` bytes (or up to the end of the message)
126 let block_input = if message_size < msg_start {
127 // This function is sometimes called with `msg_start` past the end of the message.
128 // In this case we return an empty block and zero pointer to signal that the result should be ignored.
129 0
130 } else if message_size < msg_start + BLOCK_SIZE {
131 message_size - msg_start
132 } else {
133 BLOCK_SIZE
134 };
135
136 // Figure out the number of items in the int array that we have to pack.
137 // e.g. if the input is [0,1,2,3,4,5] then we need to pack it as 2 items: [0123, 4500]
138 let int_input = (block_input + INT_SIZE - 1) / INT_SIZE;
139
140 for i in 0..int_input {
141 let mut msg_item: u32 = 0;
142 // Always construct the integer as 4 bytes, even if it means going beyond the input.
143 for j in 0..INT_SIZE {
144 let k = i * INT_SIZE + j;
145 let msg_byte = if k < block_input {
146 msg[msg_start + k]
147 } else {
148 0
149 };
150 msg_item = (msg_item << 8) + msg_byte as u32;
151 }
152 msg_block[i] = msg_item;
153 }
154
155 // Returning the index as if it was a 64 byte array.
156 // We have to project it down to 16 items and bit shifting to get a byte back if we need it.
157 msg_block
158 }
159
160 // Build a message block from the input message starting at `msg_start`.
161 //
162 // If `message_size` is less than `msg_start` then this is called with the old non-empty block;
163 // in that case we can skip verification, ie. no need to check that everything is zero.
164 fn build_msg_block<let N: u32>(msg: [u8; N], message_size: u32, msg_start: u32) -> MSG_BLOCK {
165 let msg_block =
166 // Safety: We constrain the block below by reconstructing each `u32` word from the input bytes.
167 unsafe { build_msg_block_helper(msg, message_size, msg_start) };
168
169 if !is_unconstrained() {
170 let mut msg_end = msg_start + BLOCK_SIZE;
171
172 let max_read_index = std::cmp::min(message_size, msg_end);
173
174 // Reconstructed packed item
175 let mut msg_item: Field = 0;
176
177 // Inclusive at the end so that we can compare the last item.
178 for k in msg_start..=msg_end {
179 if (k != msg_start) & (k % INT_SIZE == 0) {
180 // If we consumed some input we can compare against the block.
181 let msg_block_index = (k - msg_start) / INT_SIZE - 1;
182 assert_eq(msg_block[msg_block_index] as Field, msg_item);
183
184 msg_item = 0;
185 }
186
187 // If we have input to consume, add it at the rightmost position.
188 let msg_byte = if k < max_read_index { msg[k] } else { 0 };
189 msg_item = msg_item * (TWO_POW_8 as Field) + msg_byte as Field;
190 }
191 }
192 msg_block
193 }
194
195 // Encode `8 * message_size` into two `u32` limbs.
196 unconstrained fn encode_len(message_size: u32) -> (u32, u32) {
197 let len = 8 * message_size as u64;
198 let lo = len & 0xFFFFFFFF;
199 let hi = (len >> 32) & 0xFFFFFFFF;
200 (lo as u32, hi as u32)
201 }
202
203 // Write the length into the last 8 bytes of the block.
204 fn attach_len_to_msg_block(mut msg_block: MSG_BLOCK, message_size: u32) -> MSG_BLOCK {
205 // Safety: We assert the correctness of the decomposition below.
206 // 2 `u32` limbs cannot overflow the field modulus so performing the check as `Field`s is safe.
207 let (lo, hi) = unsafe { encode_len(message_size) };
208 assert_eq(8 * (message_size as Field), lo as Field + hi as Field * TWO_POW_32);
209
210 msg_block[INT_SIZE_PTR] = hi;
211 msg_block[INT_SIZE_PTR + 1] = lo;
212 msg_block
213 }
214
215 // Perform the final compression, then transform the `STATE` into `HASH`.
216 fn hash_final_block(msg_block: MSG_BLOCK, mut state: STATE) -> HASH {
217 // Hash final padded block
218 state = sha256_compression(msg_block, state);
219
220 // Return final hash as byte array
221 let mut out_h: HASH = [0; 32]; // Digest as sequence of bytes
222 for j in 0..8 {
223 let h_bytes: [u8; 4] = (state[j] as Field).to_be_bytes();
224 for k in 0..4 {
225 out_h[4 * j + k] = h_bytes[k];
226 }
227 }
228
229 out_h
230 }
231
232 /// Lookup table for the position of the padding bit within one of the `u32` words in the final message block.
233 global PADDING_BIT_TABLE: [u32; 4] =
234 [(1 << 7) * TWO_POW_24, (1 << 7) * TWO_POW_16, (1 << 7) * TWO_POW_8, (1 << 7)];
235
236 /// Add 1 bit padding to end of message and compress the block if there's not enough room for the 8-byte length.
237 /// Returns the updated hash state and message block that will be used to write the message size.
238 ///
239 /// # Assumptions:
240 ///
241 /// - `msg_block[i] == 0` for all `i > msg_byte_ptr / INT_SIZE`
242 /// - `msg_block[msg_byte_ptr / INT_SIZE] & ((1 << 7) * (msg_byte_ptr % INT_SIZE)) == 0`
243 fn add_padding_byte_and_compress_if_needed(
244 mut msg_block: MSG_BLOCK,
245 msg_byte_ptr: BLOCK_BYTE_PTR,
246 h: STATE,
247 ) -> (STATE, MSG_BLOCK) {
248 // Pad the rest such that we have a [u32; 2] block at the end representing the length
249 // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]).
250 // Here we rely on the fact that everything beyond the available input is set to 0.
251 let index = msg_byte_ptr / INT_SIZE;
252
253 // Lookup the position of the padding bit and insert it into the message block.
254 msg_block[index] += PADDING_BIT_TABLE[msg_byte_ptr % INT_SIZE];
255
256 // If we don't have room to write the size, compress the block and reset it.
257 if msg_byte_ptr >= MSG_SIZE_PTR {
258 let h = sha256_compression(msg_block, h);
259
260 // In this case, the final block consists of all zeros with the last 8 bytes containing the length.
261 // We set msg_block to all zeros and attach_len_to_msg_block will add the length to the last 8 bytes.
262 let msg_block = [0; INT_BLOCK_SIZE];
263 (h, msg_block)
264 } else {
265 (h, msg_block)
266 }
267 }
268
269 pub(crate) fn finalize_sha256_blocks(
270 message_size: u32,
271 mut h: STATE,
272 mut msg_block: MSG_BLOCK,
273 ) -> HASH {
274 let msg_byte_ptr = message_size % BLOCK_SIZE;
275
276 let (h, mut msg_block) = add_padding_byte_and_compress_if_needed(msg_block, msg_byte_ptr, h);
277
278 msg_block = attach_len_to_msg_block(msg_block, message_size);
279
280 hash_final_block(msg_block, h)
281 }
282
283 /**
284 * Given some state of a partially computed sha256 hash and part of the preimage, continue hashing
285 * @notice used for complex/ recursive offloading of post-partial hashing
286 *
287 * @param N - the maximum length of the message to hash
288 * @param h - the intermediate hash state
289 * @param msg - the preimage to hash
290 * @param message_size - the actual length of the preimage to hash
291 * @return the intermediate hash state after compressing in msg to h
292 */
293 pub fn partial_sha256_var_interstitial<let N: u32>(
294 mut h: [u32; 8],
295 msg: [u8; N],
296 message_size: u32,
297 ) -> [u32; 8] {
298 assert(message_size % BLOCK_SIZE == 0, "Message size must be a multiple of the block size");
299 if std::runtime::is_unconstrained() {
300 // Safety: running as an unconstrained function
301 unsafe {
302 __sha_partial_var_interstitial(h, msg, message_size)
303 }
304 } else {
305 let (h, _) = process_full_blocks(msg, message_size, h);
306
307 h
308 }
309 }
310
311 /**
312 * Given some state of a partially computed sha256 hash and remaining preimage, complete the hash
313 * @notice used for traditional partial hashing
314 *
315 * @param N - the maximum length of the message to hash
316 * @param h - the intermediate hash state
317 * @param msg - the remaining preimage to hash
318 * @param message_size - the size of the current chunk
319 * @param real_message_size - the total size of the original preimage
320 * @return finalized sha256 hash
321 */
322 pub fn partial_sha256_var_end<let N: u32>(
323 mut h: [u32; 8],
324 msg: [u8; N],
325 message_size: u32,
326 real_message_size: u32,
327 ) -> [u8; 32] {
328 assert(message_size % BLOCK_SIZE == 0, "Message size must be a multiple of the block size");
329 if std::runtime::is_unconstrained() {
330 // Safety: running as an unconstrained function
331 unsafe {
332 h = __sha_partial_var_interstitial(h, msg, message_size);
333
334 // Handle setup of the final msg block.
335 // This case is only hit if the msg is less than the block size,
336 // or our message cannot be evenly split into blocks.
337
338 finalize_last_sha256_block(h, real_message_size, msg)
339 }
340 } else {
341 let (h, msg_block) = process_full_blocks(msg, message_size, h);
342 finalize_sha256_blocks(real_message_size, h, msg_block)
343 }
344 }
345
346 unconstrained fn __sha_partial_var_interstitial<let N: u32>(
347 mut h: [u32; 8],
348 msg: [u8; N],
349 message_size: u32,
350 ) -> [u32; 8] {
351 let num_full_blocks = message_size / BLOCK_SIZE;
352 // Intermediate hash, starting with the canonical initial value
353 // Pointer into msg_block on a 64 byte scale
354 for i in 0..num_full_blocks {
355 let msg_block = build_msg_block(msg, message_size, BLOCK_SIZE * i);
356 h = sha256_compression(msg_block, h);
357 }
358 h
359 }
360
361 // Helper function to finalize the message block with padding and length
362 unconstrained fn finalize_last_sha256_block<let N: u32>(
363 mut h: STATE,
364 message_size: u32,
365 msg: [u8; N],
366 ) -> HASH {
367 let msg_byte_ptr = message_size % BLOCK_SIZE;
368
369 // We now build the final un-filled block.
370 let msg_block: MSG_BLOCK = if msg_byte_ptr != 0 {
371 let num_full_blocks = message_size / BLOCK_SIZE;
372 let msg_start = BLOCK_SIZE * num_full_blocks;
373 build_msg_block(msg, message_size, msg_start)
374 } else {
375 // If the message size is a multiple of the block size (i.e. `msg_byte_ptr == 0`) then this block will be empty,
376 // so we short-circuit in this case.
377 [0; 16]
378 };
379
380 // Once built, we need to add the necessary padding bytes and encoded length
381 let (h, mut msg_block) = add_padding_byte_and_compress_if_needed(msg_block, msg_byte_ptr, h);
382 msg_block = attach_len_to_msg_block(msg_block, message_size);
383
384 hash_final_block(msg_block, h)
385 }
386
387 mod test_process_full_blocks {
388
389 /// Wrapper to force an unconstrained runtime on process_full_blocks.
390 unconstrained fn unconstrained_process_full_blocks<let N: u32>(
391 msg: [u8; N],
392 message_size: u32,
393 h: super::STATE,
394 ) -> (super::STATE, super::MSG_BLOCK) {
395 super::process_full_blocks(msg, message_size, h)
396 }
397
398 #[test]
399 fn test_implementations_agree(msg: [u8; 100], message_size: u32) {
400 let message_size = message_size % 100;
401 // Safety: test function
402 let unconstrained_state =
403 unsafe { unconstrained_process_full_blocks(msg, message_size, super::INITIAL_STATE) };
404 let state = super::process_full_blocks(msg, message_size, super::INITIAL_STATE);
405 assert_eq(state, unconstrained_state);
406 }
407 }
408
409 mod test_sha256_var {
410
411 /// Wrapper to force an unconstrained runtime on sha256.
412 unconstrained fn unconstrained_sha256<let N: u32>(
413 msg: [u8; N],
414 message_size: u32,
415 ) -> super::HASH {
416 super::sha256_var(msg, message_size)
417 }
418
419 #[test]
420 fn test_implementations_agree(msg: [u8; 100], message_size: u32) {
421 let message_size = message_size % 100;
422 // Safety: test function
423 let unconstrained_sha = unsafe { unconstrained_sha256(msg, message_size) };
424 let sha = super::sha256_var(msg, message_size);
425 assert_eq(sha, unconstrained_sha);
426 }
427
428 }
1 // docs:start:aes128
2 /// Given a plaintext as an array of bytes, returns the corresponding aes128 ciphertext (CBC mode). Input padding is performed using PKCS#7, so that the output length is `input.len() + (16 - input.len() % 16)`.
3 pub fn aes128_encrypt<let N: u32>(
4 input: [u8; N],
5 iv: [u8; 16],
6 key: [u8; 16],
7 ) -> [u8; N + 16 - N % 16] {
8 let padding_length = (16 - N % 16) as u8;
9 let mut padded_input: [u8; N + 16 - N % 16] = [0; N + 16 - N % 16];
10 for i in 0..N {
11 padded_input[i] = input[i];
12 }
13 for i in N..N + 16 - N % 16 {
14 padded_input[i] = padding_length;
15 }
16 let output = aes128_encrypt_padded_input(padded_input, iv, key);
17 output
18 }
19
20 #[foreign(aes128_encrypt)]
21 fn aes128_encrypt_padded_input<let N: u32>(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; N] {}
22
23 // docs:end:aes128
24
25 mod tests {
26 use super::aes128_encrypt;
27
28 #[test]
29 fn encrypt() {
30 let input = "kevlovesrust".as_bytes();
31 let iv = "0000000000000000".as_bytes();
32 let key = "0000000000000000".as_bytes();
33 let output = [244, 14, 126, 172, 171, 40, 208, 186, 173, 184, 226, 105, 238, 122, 205, 191];
34 assert_eq(aes128_encrypt(input, iv, key), output);
35 }
36 }
1 use crate::meta::ctstring::AsCtString;
2 use crate::meta::derive_via;
3
4 /// Compare two values for equality
5 #[derive_via(derive_eq)]
6 // docs:start:eq-trait
7 pub trait Eq {
8 fn eq(self, other: Self) -> bool;
9 }
10 // docs:end:eq-trait
11
12 // docs:start:derive_eq
13 comptime fn derive_eq(s: TypeDefinition) -> Quoted {
14 let signature = quote { fn eq(_self: Self, _other: Self) -> bool };
15· let for_each_field = |name| quote { (_self.$name == _other.$name) };
16 let body = |fields| {
17 if s.fields_as_written().len() == 0 {
18 quote { true }
19 } else {
20 fields
21 }
22 };
23 crate::meta::make_trait_impl(
24 s,
25 quote { $crate::cmp::Eq },
26 signature,
27 for_each_field,
28 quote { & },
29 body,
30 )
31 }
32 // docs:end:derive_eq
33
34 impl Eq for Field {
35 fn eq(self, other: Field) -> bool {
36 self == other
37 }
38 }
39
40 impl Eq for u128 {
41 fn eq(self, other: u128) -> bool {
42 self == other
43 }
44 }
45 impl Eq for u64 {
46 fn eq(self, other: u64) -> bool {
47 self == other
48 }
49 }
50 impl Eq for u32 {
51 fn eq(self, other: u32) -> bool {
52 self == other
53 }
54 }
55 impl Eq for u16 {
56 fn eq(self, other: u16) -> bool {
57 self == other
58 }
59 }
60 impl Eq for u8 {
61 fn eq(self, other: u8) -> bool {
62 self == other
63 }
64 }
65 impl Eq for i8 {
66 fn eq(self, other: i8) -> bool {
67 self == other
68 }
69 }
70 impl Eq for i16 {
71 fn eq(self, other: i16) -> bool {
72 self == other
73 }
74 }
75 impl Eq for i32 {
76 fn eq(self, other: i32) -> bool {
77 self == other
78 }
79 }
80 impl Eq for i64 {
81 fn eq(self, other: i64) -> bool {
82 self == other
83 }
84 }
85
86 impl Eq for () {
87 fn eq(_self: Self, _other: ()) -> bool {
88 true
89 }
90 }
91 impl Eq for bool {
92 fn eq(self, other: bool) -> bool {
93 self == other
94 }
95 }
96
97 impl<T, let N: u32> Eq for [T; N]
98 where
99 T: Eq,
100 {
101 fn eq(self, other: [T; N]) -> bool {
102 let mut result = true;
103 for i in 0..self.len() {
104 result &= self[i].eq(other[i]);
105 }
106 result
107 }
108 }
109
110 impl<T> Eq for [T]
111 where
112 T: Eq,
113 {
114 fn eq(self, other: [T]) -> bool {
115 let mut result = self.len() == other.len();
116 if result {
117 for i in 0..self.len() {
118 result &= self[i].eq(other[i]);
119 }
120 }
121 result
122 }
123 }
124
125 impl<let N: u32> Eq for str<N> {
126 fn eq(self, other: str<N>) -> bool {
127 let self_bytes = self.as_bytes();
128 let other_bytes = other.as_bytes();
129 self_bytes == other_bytes
130 }
131 }
132
133 comptime fn make_tuple_eq_body(n: u32) -> Quoted {
134 let mut body = f"self.0.eq(other.0)".as_ctstring();
135 for i in 1u32..n {
136 body = body.append_fmtstr(f" & self.{i}.eq(other.{i})");
137 }
138 f"{body}".quoted_contents()
139 }
140
141 impl<A: Eq> Eq for (A,) {
142 fn eq(self, other: (A,)) -> bool {
143 self.0 == other.0
144 }
145 }
146
147 impl<A: Eq, B: Eq> Eq for (A, B) {
148 fn eq(self, other: (A, B)) -> bool {
149 make_tuple_eq_body!(2u32)
150 }
151 }
152
153 impl<A: Eq, B: Eq, C: Eq> Eq for (A, B, C) {
154 fn eq(self, other: (A, B, C)) -> bool {
155 make_tuple_eq_body!(3u32)
156 }
157 }
158
159 impl<A: Eq, B: Eq, C: Eq, D: Eq> Eq for (A, B, C, D) {
160 fn eq(self, other: (A, B, C, D)) -> bool {
161 make_tuple_eq_body!(4u32)
162 }
163 }
164
165 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq> Eq for (A, B, C, D, E) {
166 fn eq(self, other: (A, B, C, D, E)) -> bool {
167 make_tuple_eq_body!(5u32)
168 }
169 }
170
171 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq> Eq for (A, B, C, D, E, F) {
172 fn eq(self, other: (A, B, C, D, E, F)) -> bool {
173 make_tuple_eq_body!(6u32)
174 }
175 }
176
177 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq> Eq for (A, B, C, D, E, F, G) {
178 fn eq(self, other: (A, B, C, D, E, F, G)) -> bool {
179 make_tuple_eq_body!(7u32)
180 }
181 }
182
183 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq> Eq for (A, B, C, D, E, F, G, H) {
184 fn eq(self, other: (A, B, C, D, E, F, G, H)) -> bool {
185 make_tuple_eq_body!(8u32)
186 }
187 }
188
189 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq> Eq for (A, B, C, D, E, F, G, H, I) {
190 fn eq(self, other: (A, B, C, D, E, F, G, H, I)) -> bool {
191 make_tuple_eq_body!(9u32)
192 }
193 }
194
195 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq> Eq for (A, B, C, D, E, F, G, H, I, J) {
196 fn eq(self, other: (A, B, C, D, E, F, G, H, I, J)) -> bool {
197 make_tuple_eq_body!(10u32)
198 }
199 }
200
201 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K) {
202 fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> bool {
203 make_tuple_eq_body!(11u32)
204 }
205 }
206
207 impl<A: Eq, B: Eq, C: Eq, D: Eq, E: Eq, F: Eq, G: Eq, H: Eq, I: Eq, J: Eq, K: Eq, L: Eq> Eq for (A, B, C, D, E, F, G, H, I, J, K, L) {
208 fn eq(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> bool {
209 make_tuple_eq_body!(12u32)
210 }
211 }
212
213 impl Eq for Ordering {
214 fn eq(self, other: Ordering) -> bool {
215 self.result == other.result
216 }
217 }
218
219 // Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct
220 // that has 3 public functions for constructing the struct.
221 /// A value with three states: `Ordering::less()`, `Ordering::equal()` or `Ordering::greater()`.
222 /// Most often used to encode the result of a comparison operation.
223 pub struct Ordering {
224 result: Field,
225 }
226
227 impl Ordering {
228 // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built
229 // into the compiler, do not change these without also updating
230 // the compiler itself!
231 pub fn less() -> Ordering {
232 Ordering { result: 0 }
233 }
234
235 pub fn equal() -> Ordering {
236 Ordering { result: 1 }
237 }
238
239 pub fn greater() -> Ordering {
240 Ordering { result: 2 }
241 }
242 }
243
244 /// Compare one object to another, returning whether it is less-than, equal-to,
245 /// or greater-than the other object.
246 #[derive_via(derive_ord)]
247 // docs:start:ord-trait
248 pub trait Ord {
249 fn cmp(self, other: Self) -> Ordering;
250 }
251 // docs:end:ord-trait
252
253 // docs:start:derive_ord
254 comptime fn derive_ord(s: TypeDefinition) -> Quoted {
255 let name = quote { $crate::cmp::Ord };
256 let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };
257 let for_each_field = |name| quote {
258 if result == $crate::cmp::Ordering::equal() {
259 result = _self.$name.cmp(_other.$name);
260 }
261 };
262 let body = |fields| quote {
263 let mut result = $crate::cmp::Ordering::equal();
264 $fields
265 result
266 };
267 crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)
268 }
269 // docs:end:derive_ord
270
271 // Note: Field deliberately does not implement Ord
272
273 impl Ord for u128 {
274 fn cmp(self, other: u128) -> Ordering {
275 if self < other {
276 Ordering::less()
277 } else if self > other {
278 Ordering::greater()
279 } else {
280 Ordering::equal()
281 }
282 }
283 }
284 impl Ord for u64 {
285 fn cmp(self, other: u64) -> Ordering {
286 if self < other {
287 Ordering::less()
288 } else if self > other {
289 Ordering::greater()
290 } else {
291 Ordering::equal()
292 }
293 }
294 }
295
296 impl Ord for u32 {
297 fn cmp(self, other: u32) -> Ordering {
298 if self < other {
299 Ordering::less()
300 } else if self > other {
301 Ordering::greater()
302 } else {
303 Ordering::equal()
304 }
305 }
306 }
307
308 impl Ord for u16 {
309 fn cmp(self, other: u16) -> Ordering {
310 if self < other {
311 Ordering::less()
312 } else if self > other {
313 Ordering::greater()
314 } else {
315 Ordering::equal()
316 }
317 }
318 }
319
320 impl Ord for u8 {
321 fn cmp(self, other: u8) -> Ordering {
322 if self < other {
323 Ordering::less()
324 } else if self > other {
325 Ordering::greater()
326 } else {
327 Ordering::equal()
328 }
329 }
330 }
331
332 impl Ord for i8 {
333 fn cmp(self, other: i8) -> Ordering {
334 if self < other {
335 Ordering::less()
336 } else if self > other {
337 Ordering::greater()
338 } else {
339 Ordering::equal()
340 }
341 }
342 }
343
344 impl Ord for i16 {
345 fn cmp(self, other: i16) -> Ordering {
346 if self < other {
347 Ordering::less()
348 } else if self > other {
349 Ordering::greater()
350 } else {
351 Ordering::equal()
352 }
353 }
354 }
355
356 impl Ord for i32 {
357 fn cmp(self, other: i32) -> Ordering {
358 if self < other {
359 Ordering::less()
360 } else if self > other {
361 Ordering::greater()
362 } else {
363 Ordering::equal()
364 }
365 }
366 }
367
368 impl Ord for i64 {
369 fn cmp(self, other: i64) -> Ordering {
370 if self < other {
371 Ordering::less()
372 } else if self > other {
373 Ordering::greater()
374 } else {
375 Ordering::equal()
376 }
377 }
378 }
379
380 impl Ord for () {
381 fn cmp(_self: Self, _other: ()) -> Ordering {
382 Ordering::equal()
383 }
384 }
385
386 impl Ord for bool {
387 fn cmp(self, other: bool) -> Ordering {
388 if self {
389 if other {
390 Ordering::equal()
391 } else {
392 Ordering::greater()
393 }
394 } else if other {
395 Ordering::less()
396 } else {
397 Ordering::equal()
398 }
399 }
400 }
401
402 impl<T, let N: u32> Ord for [T; N]
403 where
404 T: Ord,
405 {
406 // The first non-equal element of both arrays determines
407 // the ordering for the whole array.
408 fn cmp(self, other: [T; N]) -> Ordering {
409 let mut result = Ordering::equal();
410 for i in 0..self.len() {
411 if result == Ordering::equal() {
412 result = self[i].cmp(other[i]);
413 }
414 }
415 result
416 }
417 }
418
419 impl<T> Ord for [T]
420 where
421 T: Ord,
422 {
423 // The first non-equal element of both arrays determines
424 // the ordering for the whole array.
425 fn cmp(self, other: [T]) -> Ordering {
426 let self_len = self.len();
427 let other_len = other.len();
428 let min_len = if self_len < other_len {
429 self_len
430 } else {
431 other_len
432 };
433
434 let mut result = Ordering::equal();
435 for i in 0..min_len {
436 if result == Ordering::equal() {
437 result = self[i].cmp(other[i]);
438 }
439 }
440
441 if result != Ordering::equal() {
442 result
443 } else {
444 self_len.cmp(other_len)
445 }
446 }
447 }
448
449 comptime fn make_tuple_ord_body(n: u32) -> Quoted {
450 let last = n - 1u32;
451 let mut body = if last == 1 {
452 f"let result = self.0.cmp(other.0);".as_ctstring()
453 } else {
454 f"let mut result = self.0.cmp(other.0);".as_ctstring()
455 };
456 for i in 1u32..last {
457 body = body.append_fmtstr(
458 f" if result == Ordering::equal() {{ result = self.{i}.cmp(other.{i}); }}",
459 );
460 }
461 body = body.append_fmtstr(
462 f" if result != Ordering::equal() {{ result }} else {{ self.{last}.cmp(other.{last}) }}",
463 );
464 f"{body}".quoted_contents()
465 }
466
467 impl<A: Ord> Ord for (A,) {
468 fn cmp(self, other: (A,)) -> Ordering {
469 self.0.cmp(other.0)
470 }
471 }
472
473 impl<A: Ord, B: Ord> Ord for (A, B) {
474 fn cmp(self, other: (A, B)) -> Ordering {
475 make_tuple_ord_body!(2u32)
476 }
477 }
478
479 impl<A: Ord, B: Ord, C: Ord> Ord for (A, B, C) {
480 fn cmp(self, other: (A, B, C)) -> Ordering {
481 make_tuple_ord_body!(3u32)
482 }
483 }
484
485 impl<A: Ord, B: Ord, C: Ord, D: Ord> Ord for (A, B, C, D) {
486 fn cmp(self, other: (A, B, C, D)) -> Ordering {
487 make_tuple_ord_body!(4u32)
488 }
489 }
490
491 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord> Ord for (A, B, C, D, E) {
492 fn cmp(self, other: (A, B, C, D, E)) -> Ordering {
493 make_tuple_ord_body!(5u32)
494 }
495 }
496
497 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord> Ord for (A, B, C, D, E, F) {
498 fn cmp(self, other: (A, B, C, D, E, F)) -> Ordering {
499 make_tuple_ord_body!(6u32)
500 }
501 }
502
503 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord> Ord for (A, B, C, D, E, F, G) {
504 fn cmp(self, other: (A, B, C, D, E, F, G)) -> Ordering {
505 make_tuple_ord_body!(7u32)
506 }
507 }
508
509 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord> Ord for (A, B, C, D, E, F, G, H) {
510 fn cmp(self, other: (A, B, C, D, E, F, G, H)) -> Ordering {
511 make_tuple_ord_body!(8u32)
512 }
513 }
514
515 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord> Ord for (A, B, C, D, E, F, G, H, I) {
516 fn cmp(self, other: (A, B, C, D, E, F, G, H, I)) -> Ordering {
517 make_tuple_ord_body!(9u32)
518 }
519 }
520
521 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord> Ord for (A, B, C, D, E, F, G, H, I, J) {
522 fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J)) -> Ordering {
523 make_tuple_ord_body!(10u32)
524 }
525 }
526
527 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K) {
528 fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K)) -> Ordering {
529 make_tuple_ord_body!(11u32)
530 }
531 }
532
533 impl<A: Ord, B: Ord, C: Ord, D: Ord, E: Ord, F: Ord, G: Ord, H: Ord, I: Ord, J: Ord, K: Ord, L: Ord> Ord for (A, B, C, D, E, F, G, H, I, J, K, L) {
534 fn cmp(self, other: (A, B, C, D, E, F, G, H, I, J, K, L)) -> Ordering {
535 make_tuple_ord_body!(12u32)
536 }
537 }
538
539 /// Compares and returns the maximum of two values.
540 ///
541 /// Returns the second argument if the comparison determines them to be equal.
542 ///
543 /// # Examples
544 ///
545 /// ```
546 /// use std::cmp;
547 ///
548 /// assert_eq(cmp::max(1, 2), 2);
549 /// assert_eq(cmp::max(2, 2), 2);
550 /// ```
551 pub fn max<T>(v1: T, v2: T) -> T
552 where
553 T: Ord,
554 {
555 if v1 > v2 {
556 v1
557 } else {
558 v2
559 }
560 }
561
562 /// Compares and returns the minimum of two values.
563 ///
564 /// Returns the first argument if the comparison determines them to be equal.
565 ///
566 /// # Examples
567 ///
568 /// ```
569 /// use std::cmp;
570 ///
571 /// assert_eq(cmp::min(1, 2), 1);
572 /// assert_eq(cmp::min(2, 2), 2);
573 /// ```
574 pub fn min<T>(v1: T, v2: T) -> T
575 where
576 T: Ord,
577 {
578 if v1 > v2 {
579 v2
580 } else {
581 v1
582 }
583 }
584
585 mod cmp_tests {
586 use crate::meta::unquote;
587 use super::{Eq, max, min, Ord, Ordering};
588
589 #[test]
590 fn sanity_check_min() {
591 assert_eq(min(0_u64, 1), 0);
592 assert_eq(min(0_u64, 0), 0);
593 assert_eq(min(1_u64, 1), 1);
594 assert_eq(min(255_u8, 0), 0);
595 }
596
597 #[test]
598 fn sanity_check_max() {
599 assert_eq(max(0_u64, 1), 1);
600 assert_eq(max(0_u64, 0), 0);
601 assert_eq(max(1_u64, 1), 1);
602 assert_eq(max(255_u8, 0), 255);
603 }
604
605 #[test]
606 fn correctly_handles_unequal_length_vectors() {
607 let vector_1 = [0, 1, 2, 3].as_vector();
608 let vector_2 = [0, 1, 2].as_vector();
609 assert(!vector_1.eq(vector_2));
610 }
611
612 #[test]
613 fn lexicographic_ordering_for_vectors() {
614 assert(
615 [2_u32].as_vector().cmp([1_u32, 1_u32, 1_u32].as_vector())
616 == super::Ordering::greater(),
617 );
618 assert(
619 [1_u32, 2_u32].as_vector().cmp([1_u32, 2_u32, 3_u32].as_vector())
620 == super::Ordering::less(),
621 );
622 }
623
624 #[test]
625 fn eq_unit() {
626 assert(().eq(()));
627 }
628
629 #[test]
630 fn eq_bool() {
631 assert(false.eq(false));
632 assert(!(false.eq(true)));
633 assert(!(true.eq(false)));
634 assert(true.eq(true));
635 }
636
637 #[test]
638 fn eq_integers() {
639 comptime {
640 for typ in @[
641 quote { u8 },
642 quote { i8 },
643 quote { u16 },
644 quote { i16 },
645 quote { u32 },
646 quote { i32 },
647 quote { u64 },
648 quote { i64 },
649 quote { u128 },
650 quote { Field },
651 ] {
652 let one = f"1_{typ}".quoted_contents();
653 let two = f"2_{typ}".quoted_contents();
654 unquote!(
655 quote {
656 assert($one.eq($one));
657 assert(!($one.eq($two)));
658 },
659 );
660 }
661 }
662 }
663
664 #[test]
665 fn eq_tuples() {
666 comptime {
667 for i in 1..=12 {
668 let mut tuple1 = @[];
669 let mut tuple2 = @[];
670 for _ in 0..i - 1 {
671 tuple1 = tuple1.push_back(quote { 0 });
672 tuple2 = tuple2.push_back(quote { 0 });
673 }
674 tuple1 = tuple1.push_back(quote { 0 });
675 tuple2 = tuple2.push_back(quote { 1 });
676 let tuple1 = tuple1.join(quote { , });
677 let tuple2 = tuple2.join(quote { , });
678 let tuple1 = quote { ($tuple1,) };
679 let tuple2 = quote { ($tuple2,) };
680 unquote!(
681 quote {
682 assert($tuple1.eq($tuple1));
683 assert(!($tuple1.eq($tuple2)));
684 },
685 )
686 }
687 }
688 }
689
690 #[test]
691 fn cmp_unit() {
692 assert_eq(().cmp(()), Ordering::equal());
693 }
694
695 #[test]
696 fn cmp_bool() {
697 assert_eq(false.cmp(true), Ordering::less());
698 assert_eq(false.cmp(false), Ordering::equal());
699 assert_eq(true.cmp(true), Ordering::equal());
700 assert_eq(true.cmp(false), Ordering::greater());
701 }
702
703 #[test]
704 fn cmp_integers() {
705 comptime {
706 for typ in @[
707 quote { u8 },
708 quote { i8 },
709 quote { u16 },
710 quote { i16 },
711 quote { u32 },
712 quote { i32 },
713 quote { u64 },
714 quote { i64 },
715 quote { u128 },
716 ] {
717 let one = f"1_{typ}".quoted_contents();
718 let two = f"2_{typ}".quoted_contents();
719 unquote!(
720 quote {
721 assert_eq($one.cmp($two), Ordering::less());
722 assert_eq($one.cmp($one), Ordering::equal());
723 assert_eq($two.cmp($one), Ordering::greater());
724 },
725 );
726 }
727 }
728 }
729
730 #[test]
731 fn cmp_tuples() {
732 comptime {
733 for i in 1..=12 {
734 let mut tuple1 = @[];
735 let mut tuple2 = @[];
736 for _ in 0..i - 1 {
737 tuple1 = tuple1.push_back(quote { 0_u8 });
738 tuple2 = tuple2.push_back(quote { 0_u8 });
739 }
740 tuple1 = tuple1.push_back(quote { 0_u8 });
741 tuple2 = tuple2.push_back(quote { 1_u8 });
742 let tuple1 = tuple1.join(quote { , });
743 let tuple2 = tuple2.join(quote { , });
744 let tuple1 = quote { ($tuple1,) };
745 let tuple2 = quote { ($tuple2,) };
746 unquote!(
747 quote {
748 assert_eq($tuple1.cmp($tuple1), Ordering::equal());
749 assert_eq($tuple1.cmp($tuple2), Ordering::less());
750 assert_eq($tuple2.cmp($tuple1), Ordering::greater());
751 },
752 )
753 }
754 }
755 }
756
757 #[test]
758 fn cmp_array() {
759 assert_eq([1_u8, 2, 3].cmp([1, 2, 3]), Ordering::equal());
760 assert_eq([1_u8, 2, 3].cmp([1, 3, 2]), Ordering::less());
761 assert_eq([1_u8, 3, 3].cmp([1, 2, 3]), Ordering::greater());
762 }
763
764 #[test]
765 fn cmp_vectors() {
766 // Equal lengths
767 assert_eq(@[1_u8, 2, 3].cmp(@[1, 2, 3]), Ordering::equal());
768 assert_eq(@[1_u8, 3, 3].cmp(@[1, 2, 3]), Ordering::greater());
769 assert_eq(@[1_u8, 2, 3].cmp(@[1, 3, 3]), Ordering::less());
770
771 // Different lengths
772 assert_eq(@[1_u8, 2].cmp(@[1, 2, 3]), Ordering::less());
773 assert_eq(@[1_u8, 2, 3].cmp(@[1, 2]), Ordering::greater());
774 assert_eq(@[10_u8, 0].cmp(@[9]), Ordering::greater());
775 assert_eq(@[9_u8, 0].cmp(@[10]), Ordering::less());
776 assert_eq(@[9_u8].cmp(@[10, 0]), Ordering::less());
777 assert_eq(@[10_u8].cmp(@[9, 0]), Ordering::greater());
778 }
779 }
1 pub mod bn254;
2 use crate::{runtime::is_unconstrained, static_assert};
3 use bn254::lt as bn254_lt;
4
5 impl Field {
6 /// Asserts that `self` can be represented in `bit_size` bits.
7 ///
8 /// # Failures
9 /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.
10 // docs:start:assert_max_bit_size
11 pub fn assert_max_bit_size<let BIT_SIZE: u32>(self) {
12 // docs:end:assert_max_bit_size
13 static_assert(
14 BIT_SIZE < modulus_num_bits() as u32,
15 "BIT_SIZE must be less than modulus_num_bits",
16 );
17 __assert_max_bit_size(self, BIT_SIZE);
18 }
19
20 /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.
21 /// This array will be zero padded should not all bits be necessary to represent `self`.
22 ///
23 /// # Failures
24 /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not
25 /// be able to represent the original `Field`.
26 ///
27 /// # Safety
28 /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.
29 // docs:start:to_le_bits
30 pub fn to_le_bits<let N: u32>(self: Self) -> [bool; N] {
31 // docs:end:to_le_bits
32 let bits = __to_le_bits(self);
33
34 if !is_unconstrained() {
35 // Ensure that the byte decomposition does not overflow the modulus
36 let p = modulus_le_bits();
37 assert(bits.len() <= p.len());
38 let mut ok = bits.len() != p.len();
39 for i in 0..N {
40 if !ok {
41 if (bits[N - 1 - i] != p[N - 1 - i]) {
42 assert(p[N - 1 - i]);
43 ok = true;
44 }
45 }
46 }
47 assert(ok);
48 }
49 bits
50 }
51
52 /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.
53 /// This array will be zero padded should not all bits be necessary to represent `self`.
54 ///
55 /// # Failures
56 /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not
57 /// be able to represent the original `Field`.
58 ///
59 /// # Safety
60 /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.
61 // docs:start:to_be_bits
62 pub fn to_be_bits<let N: u32>(self: Self) -> [bool; N] {
63 // docs:end:to_be_bits
64 let bits = __to_be_bits(self);
65
66 if !is_unconstrained() {
67 // Ensure that the decomposition does not overflow the modulus
68 let p = modulus_be_bits();
69 assert(bits.len() <= p.len());
70 let mut ok = bits.len() != p.len();
71 for i in 0..N {
72 if !ok {
73 if (bits[i] != p[i]) {
74 assert(p[i]);
75 ok = true;
76 }
77 }
78 }
79 assert(ok);
80 }
81 bits
82 }
83
84 /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array
85 /// This array will be zero padded should not all bytes be necessary to represent `self`.
86 ///
87 /// # Failures
88 /// The length N of the array must be big enough to contain all the bytes of the 'self',
89 /// and no more than the number of bytes required to represent the field modulus
90 ///
91 /// # Safety
92 /// The result is ensured to be the canonical decomposition of the field element
93 // docs:start:to_le_bytes
94 pub fn to_le_bytes<let N: u32>(self: Self) -> [u8; N] {
95 // docs:end:to_le_bytes
96 static_assert(
97 N <= modulus_le_bytes().len(),
98 "N must be less than or equal to modulus_le_bytes().len()",
99 );
100 // Compute the byte decomposition
101 let bytes = self.to_le_radix(256);
102
103 if !is_unconstrained() {
104 // Ensure that the byte decomposition does not overflow the modulus
105 let p = modulus_le_bytes();
106 assert(bytes.len() <= p.len());
107 let mut ok = bytes.len() != p.len();
108 for i in 0..N {
109 if !ok {
110 if (bytes[N - 1 - i] != p[N - 1 - i]) {
111 assert(bytes[N - 1 - i] < p[N - 1 - i]);
112 ok = true;
113 }
114 }
115 }
116 assert(ok);
117 }
118 bytes
119 }
120
121 /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus
122 /// This array will be zero padded should not all bytes be necessary to represent `self`.
123 ///
124 /// # Failures
125 /// The length N of the array must be big enough to contain all the bytes of the 'self',
126 /// and no more than the number of bytes required to represent the field modulus
127 ///
128 /// # Safety
129 /// The result is ensured to be the canonical decomposition of the field element
130 // docs:start:to_be_bytes
131 pub fn to_be_bytes<let N: u32>(self: Self) -> [u8; N] {
132 // docs:end:to_be_bytes
133 static_assert(
134 N <= modulus_le_bytes().len(),
135 "N must be less than or equal to modulus_le_bytes().len()",
136 );
137 // Compute the byte decomposition
138 let bytes = self.to_be_radix(256);
139
140 if !is_unconstrained() {
141 // Ensure that the byte decomposition does not overflow the modulus
142 let p = modulus_be_bytes();
143 assert(bytes.len() <= p.len());
144 let mut ok = bytes.len() != p.len();
145 for i in 0..N {
146 if !ok {
147 if (bytes[i] != p[i]) {
148 assert(bytes[i] < p[i]);
149 ok = true;
150 }
151 }
152 }
153 assert(ok);
154 }
155 bytes
156 }
157
158 fn to_le_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {
159 // Brillig does not need an immediate radix
160 if !crate::runtime::is_unconstrained() {
161 static_assert(1 < radix, "radix must be greater than 1");
162 static_assert(radix <= 256, "radix must be less than or equal to 256");
163 static_assert(radix & (radix - 1) == 0, "radix must be a power of 2");
164 }
165 __to_le_radix(self, radix)
166 }
167
168 fn to_be_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {
169 // Brillig does not need an immediate radix
170 if !crate::runtime::is_unconstrained() {
171 static_assert(1 < radix, "radix must be greater than 1");
172 static_assert(radix <= 256, "radix must be less than or equal to 256");
173 static_assert(radix & (radix - 1) == 0, "radix must be a power of 2");
174 }
175 __to_be_radix(self, radix)
176 }
177
178 // Returns self to the power of the given exponent value.
179 // Caution: we assume the exponent fits into 32 bits
180 // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits
181 pub fn pow_32(self, exponent: Field) -> Field {
182 let mut r: Field = 1;
183 let b: [bool; 32] = exponent.to_le_bits();
184
185 for i in 1..33 {
186 r *= r;
187 r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;
188 }
189 r
190 }
191
192 // Parity of (prime) Field element, i.e. sgn0(x mod p) = false if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = true.
193 pub fn sgn0(self) -> bool {
194 (self as u8) % 2 == 1
195 }
196
197 pub fn lt(self, another: Field) -> bool {
198 if crate::compat::is_bn254() {
199 bn254_lt(self, another)
200 } else {
201 lt_fallback(self, another)
202 }
203 }
204
205 /// Convert a little endian byte array to a field element.
206 /// If the provided byte array overflows the field modulus then the Field will silently wrap around.
207 ///
208 /// # Failures
209 /// `N` must be no greater than the number of bytes required to represent the field modulus
210 // docs:start:from_le_bytes
211 pub fn from_le_bytes<let N: u32>(bytes: [u8; N]) -> Field {
212 // docs:end:from_le_bytes
213 static_assert(
214 N <= modulus_le_bytes().len(),
215 "N must be less than or equal to modulus_le_bytes().len()",
216 );
217 let mut v = 1;
218 let mut result = 0;
219
220 for i in 0..N {
221 result += (bytes[i] as Field) * v;
222 v = v * 256;
223 }
224 result
225 }
226
227 /// Convert a big endian byte array to a field element.
228 /// If the provided byte array overflows the field modulus then the Field will silently wrap around.
229 ///
230 /// # Failures
231 /// `N` must be no greater than the number of bytes required to represent the field modulus
232 // docs:start:from_be_bytes
233 pub fn from_be_bytes<let N: u32>(bytes: [u8; N]) -> Field {
234 // docs:end:from_be_bytes
235 static_assert(
236 N <= modulus_be_bytes().len(),
237 "N must be less than or equal to modulus_be_bytes().len()",
238 );
239 let mut v = 1;
240 let mut result = 0;
241
242 for i in 0..N {
243 result += (bytes[N - 1 - i] as Field) * v;
244 v = v * 256;
245 }
246 result
247 }
248
249 /// Convert a little endian byte array to a field element, asserting that the input is a
250 /// canonical representation (strictly less than the field modulus).
251 ///
252 /// # Failures
253 /// Causes a constraint failure if `bytes` encodes a value greater than or equal to the
254 /// field modulus.
255 // docs:start:from_le_bytes_checked
256 pub fn from_le_bytes_checked<let N: u32>(bytes: [u8; N]) -> Field {
257 // docs:end:from_le_bytes_checked
258 let p = modulus_le_bytes();
259 let mut ok = N != p.len();
260 for i in 0..N {
261 if !ok {
262 if bytes[N - 1 - i] != p[N - 1 - i] {
263 assert(
264 bytes[N - 1 - i] < p[N - 1 - i],
265 "input bytes are not a canonical field representation",
266 );
267 ok = true;
268 }
269 }
270 }
271 assert(ok, "input bytes are not a canonical field representation");
272 Field::from_le_bytes(bytes)
273 }
274
275 /// Convert a big endian byte array to a field element, asserting that the input is a
276 /// canonical representation (strictly less than the field modulus).
277 ///
278 /// # Failures
279 /// Causes a constraint failure if `bytes` encodes a value greater than or equal to the
280 /// field modulus.
281 // docs:start:from_be_bytes_checked
282 pub fn from_be_bytes_checked<let N: u32>(bytes: [u8; N]) -> Field {
283 // docs:end:from_be_bytes_checked
284 let p = modulus_be_bytes();
285 let mut ok = N != p.len();
286 for i in 0..N {
287 if !ok {
288 if bytes[i] != p[i] {
289 assert(bytes[i] < p[i], "input bytes are not a canonical field representation");
290 ok = true;
291 }
292 }
293 }
294 assert(ok, "input bytes are not a canonical field representation");
295 Field::from_be_bytes(bytes)
296 }
297 }
298
299 #[builtin(apply_range_constraint)]
300 fn __assert_max_bit_size(value: Field, bit_size: u32) {}
301
302 // `_radix` must be less than 256
303 #[builtin(to_le_radix)]
304 fn __to_le_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}
305
306 // `_radix` must be less than 256
307 #[builtin(to_be_radix)]
308 fn __to_be_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}
309
310 /// Decomposes `self` into its little endian bit decomposition as a `[bool; N]` array.
311 /// This array will be zero padded should not all bits be necessary to represent `self`.
312 ///
313 /// # Failures
314 /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not
315 /// be able to represent the original `Field`.
316 ///
317 /// # Safety
318 /// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus
319 /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will
320 /// wrap around due to overflow when verifying the decomposition.
321 #[builtin(to_le_bits)]
322 fn __to_le_bits<let N: u32>(value: Field) -> [bool; N] {}
323
324 /// Decomposes `self` into its big endian bit decomposition as a `[bool; N]` array.
325 /// This array will be zero padded should not all bits be necessary to represent `self`.
326 ///
327 /// # Failures
328 /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting array will not
329 /// be able to represent the original `Field`.
330 ///
331 /// # Safety
332 /// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus
333 /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will
334 /// wrap around due to overflow when verifying the decomposition.
335 #[builtin(to_be_bits)]
336 fn __to_be_bits<let N: u32>(value: Field) -> [bool; N] {}
337
338 #[builtin(modulus_num_bits)]
339 pub comptime fn modulus_num_bits() -> u64 {}
340
341 #[builtin(modulus_be_bits)]
342 pub comptime fn modulus_be_bits() -> [bool] {}
343
344 #[builtin(modulus_le_bits)]
345 pub comptime fn modulus_le_bits() -> [bool] {}
346
347 #[builtin(modulus_be_bytes)]
348 pub comptime fn modulus_be_bytes() -> [u8] {}
349
350 #[builtin(modulus_le_bytes)]
351 pub comptime fn modulus_le_bytes() -> [u8] {}
352
353 /// An unconstrained only built in to efficiently compare fields.
354 #[builtin(field_less_than)]
355 unconstrained fn __field_less_than(x: Field, y: Field) -> bool {}
356
357 pub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {
358 __field_less_than(x, y)
359 }
360
361 fn lt_fallback(x: Field, y: Field) -> bool {
362 if is_unconstrained() {
363 // Safety: unconstrained context
364 unsafe {
365 field_less_than(x, y)
366 }
367 } else {
368 let x_bytes: [u8; 32] = x.to_le_bytes();
369 let y_bytes: [u8; 32] = y.to_le_bytes();
370 let mut x_is_lt = false;
371 let mut done = false;
372 for i in 0..32 {
373 if (!done) {
374 let x_byte = x_bytes[32 - 1 - i] as u8;
375 let y_byte = y_bytes[32 - 1 - i] as u8;
376 let bytes_match = x_byte == y_byte;
377 if !bytes_match {
378 x_is_lt = x_byte < y_byte;
379 done = true;
380 }
381 }
382 }
383 x_is_lt
384 }
385 }
386
387 mod tests {
388 use crate::{panic::panic, runtime, static_assert};
389 use super::{
390 field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,
391 };
392
393 #[test]
394 // docs:start:to_be_bits_example
395 fn test_to_be_bits() {
396 let field = 2;
397 let bits: [bool; 8] = field.to_be_bits();
398 assert_eq(bits, [false, false, false, false, false, false, true, false]);
399 }
400 // docs:end:to_be_bits_example
401
402 #[test]
403 // docs:start:to_le_bits_example
404 fn test_to_le_bits() {
405 let field = 2;
406 let bits: [bool; 8] = field.to_le_bits();
407 assert_eq(bits, [false, true, false, false, false, false, false, false]);
408 }
409 // docs:end:to_le_bits_example
410
411 #[test]
412 // docs:start:to_be_bytes_example
413 fn test_to_be_bytes() {
414 let field = 2;
415 let bytes: [u8; 8] = field.to_be_bytes();
416 assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);
417 assert_eq(Field::from_be_bytes::<8>(bytes), field);
418 }
419 // docs:end:to_be_bytes_example
420
421 #[test]
422 // docs:start:to_le_bytes_example
423 fn test_to_le_bytes() {
424 let field = 2;
425 let bytes: [u8; 8] = field.to_le_bytes();
426 assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);
427 assert_eq(Field::from_le_bytes::<8>(bytes), field);
428 }
429 // docs:end:to_le_bytes_example
430
431 #[test]
432 // docs:start:to_be_radix_example
433 fn test_to_be_radix() {
434 // 259, in base 256, big endian, is [1, 3].
435 // i.e. 3 * 256^0 + 1 * 256^1
436 let field = 259;
437
438 // The radix (in this example, 256) must be a power of 2.
439 // The length of the returned byte array can be specified to be
440 // >= the amount of space needed.
441 let bytes: [u8; 8] = field.to_be_radix(256);
442 assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);
443 assert_eq(Field::from_be_bytes::<8>(bytes), field);
444 }
445 // docs:end:to_be_radix_example
446
447 #[test]
448 // docs:start:to_le_radix_example
449 fn test_to_le_radix() {
450 // 259, in base 256, little endian, is [3, 1].
451 // i.e. 3 * 256^0 + 1 * 256^1
452 let field = 259;
453
454 // The radix (in this example, 256) must be a power of 2.
455 // The length of the returned byte array can be specified to be
456 // >= the amount of space needed.
457 let bytes: [u8; 8] = field.to_le_radix(256);
458 assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);
459 assert_eq(Field::from_le_bytes::<8>(bytes), field);
460 }
461 // docs:end:to_le_radix_example
462
463 #[test(should_fail_with = "radix must be greater than 1")]
464 fn test_to_le_radix_1() {
465 // this test should only fail in constrained mode
466 if !runtime::is_unconstrained() {
467 let field = 2;
468 let _: [u8; 8] = field.to_le_radix(1);
469 } else {
470 panic("radix must be greater than 1");
471 }
472 }
473
474 // Updated test to account for Brillig restriction that radix must be greater than 2
475 #[test(should_fail_with = "radix must be greater than 1")]
476 fn test_to_le_radix_brillig_1() {
477 // this test should only fail in constrained mode
478 if !runtime::is_unconstrained() {
479 let field = 1;
480 let _: [u8; 8] = field.to_le_radix(1);
481 } else {
482 panic("radix must be greater than 1");
483 }
484 }
485
486 #[test(should_fail_with = "radix must be a power of 2")]
487 fn test_to_le_radix_3() {
488 // this test should only fail in constrained mode
489 if !runtime::is_unconstrained() {
490 let field = 2;
491 let _: [u8; 8] = field.to_le_radix(3);
492 } else {
493 panic("radix must be a power of 2");
494 }
495 }
496
497 #[test]
498 fn test_to_le_radix_brillig_3() {
499 // this test should only fail in constrained mode
500 if runtime::is_unconstrained() {
501 let field = 1;
502 let out: [u8; 8] = field.to_le_radix(3);
503 let mut expected = [0; 8];
504 expected[0] = 1;
505 assert(out == expected, "unexpected result");
506 }
507 }
508
509 #[test(should_fail_with = "radix must be less than or equal to 256")]
510 fn test_to_le_radix_512() {
511 // this test should only fail in constrained mode
512 if !runtime::is_unconstrained() {
513 let field = 2;
514 let _: [u8; 8] = field.to_le_radix(512);
515 } else {
516 panic("radix must be less than or equal to 256")
517 }
518 }
519
520 #[test(should_fail_with = "Field failed to decompose into specified 16 limbs")]
521 unconstrained fn not_enough_limbs_brillig() {
522 let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();
523 }
524
525 #[test(should_fail_with = "Field failed to decompose into specified 16 limbs")]
526 fn not_enough_limbs() {
527 let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();
528 }
529
530 #[test(should_fail_with = "Field failed to decompose into specified 0 limbs")]
531 unconstrained fn non_zero_field_to_le_bytes_zero_limbs() {
532 let _: [u8; 0] = 5.to_le_bytes();
533 }
534
535 #[test(should_fail_with = "Field failed to decompose into specified 0 limbs")]
536 unconstrained fn non_zero_field_to_be_bytes_zero_limbs() {
537 let _: [u8; 0] = 5.to_be_bytes();
538 }
539
540 #[test]
541 unconstrained fn test_field_less_than() {
542 assert(field_less_than(0, 1));
543 assert(field_less_than(0, 0x100));
544 assert(field_less_than(0x100, 0 - 1));
545 assert(!field_less_than(0 - 1, 0));
546 }
547
548 #[test]
549 unconstrained fn test_large_field_values_unconstrained() {
550 let large_field = 0xffffffffffffffff;
551
552 let bits: [bool; 64] = large_field.to_le_bits();
553 assert_eq(bits[0], true);
554
555 let bytes: [u8; 8] = large_field.to_le_bytes();
556 assert_eq(Field::from_le_bytes::<8>(bytes), large_field);
557
558 let radix_bytes: [u8; 8] = large_field.to_le_radix(256);
559 assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);
560 }
561
562 #[test]
563 fn test_large_field_values() {
564 let large_val = 0xffffffffffffffff;
565
566 let bits: [bool; 64] = large_val.to_le_bits();
567 assert_eq(bits[0], true);
568
569 let bytes: [u8; 8] = large_val.to_le_bytes();
570 assert_eq(Field::from_le_bytes::<8>(bytes), large_val);
571
572 let radix_bytes: [u8; 8] = large_val.to_le_radix(256);
573 assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);
574 }
575
576 #[test]
577 fn test_decomposition_edge_cases() {
578 let zero_bits: [bool; 8] = 0.to_le_bits();
579 assert_eq(zero_bits, [false; 8]);
580
581 let zero_bytes: [u8; 8] = 0.to_le_bytes();
582 assert_eq(zero_bytes, [0; 8]);
583
584 let one_bits: [bool; 8] = 1.to_le_bits();
585 let expected: [bool; 8] = [true, false, false, false, false, false, false, false];
586 assert_eq(one_bits, expected);
587
588 let pow2_bits: [bool; 8] = 4.to_le_bits();
589 let expected: [bool; 8] = [false, false, true, false, false, false, false, false];
590 assert_eq(pow2_bits, expected);
591 }
592
593 #[test]
594 fn test_pow_32() {
595 assert_eq(2.pow_32(3), 8);
596 assert_eq(3.pow_32(2), 9);
597 assert_eq(5.pow_32(0), 1);
598 assert_eq(7.pow_32(1), 7);
599
600 assert_eq(2.pow_32(10), 1024);
601
602 assert_eq(0.pow_32(5), 0);
603 assert_eq(0.pow_32(0), 1);
604
605 assert_eq(1.pow_32(100), 1);
606 }
607
608 #[test]
609 fn test_sgn0() {
610 assert_eq(0.sgn0(), false);
611 assert_eq(2.sgn0(), false);
612 assert_eq(4.sgn0(), false);
613 assert_eq(100.sgn0(), false);
614
615 assert_eq(1.sgn0(), true);
616 assert_eq(3.sgn0(), true);
617 assert_eq(5.sgn0(), true);
618 assert_eq(101.sgn0(), true);
619 }
620
621 #[test(should_fail_with = "Field failed to decompose into specified 8 limbs")]
622 fn test_bit_decomposition_overflow() {
623 // 8 bits can't represent large field values
624 let large_val = 0x1000000000000000;
625 let _: [bool; 8] = large_val.to_le_bits();
626 }
627
628 #[test(should_fail_with = "Field failed to decompose into specified 4 limbs")]
629 fn test_byte_decomposition_overflow() {
630 // 4 bytes can't represent large field values
631 let large_val = 0x1000000000000000;
632 let _: [u8; 4] = large_val.to_le_bytes();
633 }
634
635 #[test]
636 fn test_to_from_be_bytes_bn254_edge_cases() {
637 if crate::compat::is_bn254() {
638 // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)
639 let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();
640 assert(p_minus_1_bytes[32 - 1] > 0);
641 p_minus_1_bytes[32 - 1] -= 1;
642
643 let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);
644 assert_eq(p_minus_1 + 1, 0);
645
646 // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes
647 let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();
648 assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);
649
650 // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)
651 let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();
652 assert(p_plus_1_bytes[32 - 1] < 255);
653 p_plus_1_bytes[32 - 1] += 1;
654
655 let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);
656 assert_eq(p_plus_1, 1);
657
658 // checking that converting p_plus_1 to 32 BE bytes produces the same
659 // byte set to 1 as p_plus_1_bytes and otherwise zeroes
660 let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();
661 assert_eq(p_plus_1_converted_bytes[32 - 1], 1);
662 p_plus_1_converted_bytes[32 - 1] = 0;
663 assert_eq(p_plus_1_converted_bytes, [0; 32]);
664
665 // checking that Field::from_be_bytes::<32> on the Field modulus produces 0
666 assert_eq(modulus_be_bytes().len(), 32);
667 let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());
668 assert_eq(p, 0);
669
670 // checking that converting 0 to 32 BE bytes produces 32 zeroes
671 let p_bytes: [u8; 32] = 0.to_be_bytes();
672 assert_eq(p_bytes, [0; 32]);
673 }
674 }
675
676 #[test]
677 fn test_to_from_le_bytes_bn254_edge_cases() {
678 if crate::compat::is_bn254() {
679 // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)
680 let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();
681 assert(p_minus_1_bytes[0] > 0);
682 p_minus_1_bytes[0] -= 1;
683
684 let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);
685 assert_eq(p_minus_1 + 1, 0);
686
687 // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes
688 let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();
689 assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);
690
691 // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)
692 let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();
693 assert(p_plus_1_bytes[0] < 255);
694 p_plus_1_bytes[0] += 1;
695
696 let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);
697 assert_eq(p_plus_1, 1);
698
699 // checking that converting p_plus_1 to 32 LE bytes produces the same
700 // byte set to 1 as p_plus_1_bytes and otherwise zeroes
701 let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();
702 assert_eq(p_plus_1_converted_bytes[0], 1);
703 p_plus_1_converted_bytes[0] = 0;
704 assert_eq(p_plus_1_converted_bytes, [0; 32]);
705
706 // checking that Field::from_le_bytes::<32> on the Field modulus produces 0
707 assert_eq(modulus_le_bytes().len(), 32);
708 let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());
709 assert_eq(p, 0);
710
711 // checking that converting 0 to 32 LE bytes produces 32 zeroes
712 let p_bytes: [u8; 32] = 0.to_le_bytes();
713 assert_eq(p_bytes, [0; 32]);
714 }
715 }
716
717 #[test]
718 fn test_from_le_bytes_checked_accepts_modulus_minus_one() {
719 if crate::compat::is_bn254() {
720 let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();
721 assert(p_minus_1_bytes[0] > 0);
722 p_minus_1_bytes[0] -= 1;
723 let p_minus_1 = Field::from_le_bytes_checked::<32>(p_minus_1_bytes);
724 assert_eq(p_minus_1 + 1, 0);
725 }
726 }
727
728 #[test(should_fail_with = "input bytes are not a canonical field representation")]
729 fn test_from_le_bytes_checked_rejects_modulus() {
730 if crate::compat::is_bn254() {
731 let _ = Field::from_le_bytes_checked::<32>(modulus_le_bytes().as_array());
732 } else {
733 panic("input bytes are not a canonical field representation");
734 }
735 }
736
737 #[test(should_fail_with = "input bytes are not a canonical field representation")]
738 fn test_from_le_bytes_checked_rejects_modulus_plus_one() {
739 if crate::compat::is_bn254() {
740 let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();
741 assert(p_plus_1_bytes[0] < 255);
742 p_plus_1_bytes[0] += 1;
743 let _ = Field::from_le_bytes_checked::<32>(p_plus_1_bytes);
744 } else {
745 panic("input bytes are not a canonical field representation");
746 }
747 }
748
749 #[test]
750 fn test_from_be_bytes_checked_accepts_modulus_minus_one() {
751 if crate::compat::is_bn254() {
752 let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();
753 assert(p_minus_1_bytes[32 - 1] > 0);
754 p_minus_1_bytes[32 - 1] -= 1;
755 let p_minus_1 = Field::from_be_bytes_checked::<32>(p_minus_1_bytes);
756 assert_eq(p_minus_1 + 1, 0);
757 }
758 }
759
760 #[test(should_fail_with = "input bytes are not a canonical field representation")]
761 fn test_from_be_bytes_checked_rejects_modulus() {
762 if crate::compat::is_bn254() {
763 let _ = Field::from_be_bytes_checked::<32>(modulus_be_bytes().as_array());
764 } else {
765 panic("input bytes are not a canonical field representation");
766 }
767 }
768
769 #[test(should_fail_with = "input bytes are not a canonical field representation")]
770 fn test_from_be_bytes_checked_rejects_modulus_plus_one() {
771 if crate::compat::is_bn254() {
772 let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();
773 assert(p_plus_1_bytes[32 - 1] < 255);
774 p_plus_1_bytes[32 - 1] += 1;
775 let _ = Field::from_be_bytes_checked::<32>(p_plus_1_bytes);
776 } else {
777 panic("input bytes are not a canonical field representation");
778 }
779 }
780
781 #[test]
782 fn test_from_bytes_checked_small_n() {
783 // For N < modulus_bytes().len(), the input cannot overflow the modulus, so the checked
784 // variants behave identically to the unchecked ones.
785 let le_bytes: [u8; 8] = [3, 1, 0, 0, 0, 0, 0, 0];
786 assert_eq(Field::from_le_bytes_checked::<8>(le_bytes), 259);
787 let be_bytes: [u8; 8] = [0, 0, 0, 0, 0, 0, 1, 3];
788 assert_eq(Field::from_be_bytes_checked::<8>(be_bytes), 259);
789 }
790
791 /// Convert a little endian bit array to a field element.
792 /// If the provided bit array overflows the field modulus then the Field will silently wrap around.
793 fn from_le_bits<let N: u32>(bits: [bool; N]) -> Field {
794 static_assert(
795 N <= modulus_le_bits().len(),
796 "N must be less than or equal to modulus_le_bits().len()",
797 );
798 let mut v = 1;
799 let mut result = 0;
800
801 for i in 0..N {
802 result += (bits[i] as Field) * v;
803 v = v * 2;
804 }
805 result
806 }
807
808 /// Convert a big endian bit array to a field element.
809 /// If the provided bit array overflows the field modulus then the Field will silently wrap around.
810 fn from_be_bits<let N: u32>(bits: [bool; N]) -> Field {
811 let mut v = 1;
812 let mut result = 0;
813
814 for i in 0..N {
815 result += (bits[N - 1 - i] as Field) * v;
816 v = v * 2;
817 }
818 result
819 }
820
821 #[test]
822 fn test_to_from_be_bits_bn254_edge_cases() {
823 if crate::compat::is_bn254() {
824 // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)
825 let mut p_minus_1_bits: [bool; 254] = modulus_be_bits().as_array();
826 assert(p_minus_1_bits[254 - 1]);
827 p_minus_1_bits[254 - 1] = false;
828
829 let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);
830 assert_eq(p_minus_1 + 1, 0);
831
832 // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits
833 let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_be_bits();
834 assert_eq(p_minus_1_converted_bits, p_minus_1_bits);
835
836 // checking that incrementing this bit produces 254 BE bits for (modulus + 4)
837 let mut p_plus_4_bits: [bool; 254] = modulus_be_bits().as_array();
838 assert(!p_plus_4_bits[254 - 3]);
839 p_plus_4_bits[254 - 3] = true;
840
841 let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);
842 assert_eq(p_plus_4, 4);
843
844 // checking that converting p_plus_4 to 254 BE bits produces the same
845 // bit set to 1 as p_plus_4_bits and otherwise zeroes
846 let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_be_bits();
847 assert(p_plus_4_converted_bits[254 - 3]);
848 p_plus_4_converted_bits[254 - 3] = false;
849 assert_eq(p_plus_4_converted_bits, [false; 254]);
850
851 // checking that Field::from_be_bits::<254> on the Field modulus produces 0
852 assert_eq(modulus_be_bits().len(), 254);
853 let p = from_be_bits::<254>(modulus_be_bits().as_array());
854 assert_eq(p, 0);
855
856 // checking that converting 0 to 254 BE bits produces 254 false values
857 let p_bits: [bool; 254] = 0.to_be_bits();
858 assert_eq(p_bits, [false; 254]);
859 }
860 }
861
862 #[test]
863 fn test_to_from_le_bits_bn254_edge_cases() {
864 if crate::compat::is_bn254() {
865 // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)
866 let mut p_minus_1_bits: [bool; 254] = modulus_le_bits().as_array();
867 assert(p_minus_1_bits[0]);
868 p_minus_1_bits[0] = false;
869
870 let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);
871 assert_eq(p_minus_1 + 1, 0);
872
873 // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits
874 let p_minus_1_converted_bits: [bool; 254] = p_minus_1.to_le_bits();
875 assert_eq(p_minus_1_converted_bits, p_minus_1_bits);
876
877 // checking that incrementing this bit produces 254 LE bits for (modulus + 4)
878 let mut p_plus_4_bits: [bool; 254] = modulus_le_bits().as_array();
879 assert(!p_plus_4_bits[2]);
880 p_plus_4_bits[2] = true;
881
882 let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);
883 assert_eq(p_plus_4, 4);
884
885 // checking that converting p_plus_4 to 254 LE bits produces the same
886 // bit set to 1 as p_plus_4_bits and otherwise zeroes
887 let mut p_plus_4_converted_bits: [bool; 254] = p_plus_4.to_le_bits();
888 assert(p_plus_4_converted_bits[2]);
889 p_plus_4_converted_bits[2] = false;
890 assert_eq(p_plus_4_converted_bits, [false; 254]);
891
892 // checking that Field::from_le_bits::<254> on the Field modulus produces 0
893 assert_eq(modulus_le_bits().len(), 254);
894 let p = from_le_bits::<254>(modulus_le_bits().as_array());
895 assert_eq(p, 0);
896
897 // checking that converting 0 to 254 LE bits produces 254 false values
898 let p_bits: [bool; 254] = 0.to_le_bits();
899 assert_eq(p_bits, [false; 254]);
900 }
901 }
902
903 #[test(should_fail_with = "call to assert_max_bit_size")]
904 fn max_bit_size_too_large() {
905 let x: Field = 0x010000;
906 x.assert_max_bit_size::<16>();
907 }
908
909 }
1 // Exposed only for usage in `std::meta`
2 pub(crate) mod poseidon2;
3
4 use crate::default::Default;
5 use crate::embedded_curve_ops::{
6 EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,
7 };
8 use crate::meta::derive_via;
9 use crate::static_assert;
10
11 /// The size of the state accepted by the backend in `poseidon2_permutation`.
12 global POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();
13
14 #[foreign(sha256_compression)]
15 // docs:start:sha256_compression
16 pub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}
17 // docs:end:sha256_compression
18
19 #[foreign(keccakf1600)]
20 // docs:start:keccakf1600
21 pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}
22 // docs:end:keccakf1600
23
24 pub mod keccak {
25 #[deprecated("This function has been moved to std::hash::keccakf1600")]
26 pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {
27 super::keccakf1600(input)
28 }
29 }
30
31 #[foreign(blake2s)]
32 // docs:start:blake2s
33 pub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]
34 // docs:end:blake2s
35 {}
36
37 // docs:start:blake3
38 pub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]
39 // docs:end:blake3
40 {
41 if crate::runtime::is_unconstrained() {
42 // Temporary measure while Barretenberg is main proving system.
43 // Please open an issue if you're working on another proving system and running into problems due to this.
44 crate::static_assert(
45 N <= 1024,
46 "Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes",
47 );
48 }
49 __blake3(input)
50 }
51
52 #[foreign(blake3)]
53 fn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}
54
55 // docs:start:pedersen_commitment
56 pub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {
57 // docs:end:pedersen_commitment
58 pedersen_commitment_with_separator(input, 0)
59 }
60
61 #[inline_always]
62 pub fn pedersen_commitment_with_separator<let N: u32>(
63 input: [Field; N],
64 separator: u32,
65 ) -> EmbeddedCurvePoint {
66 let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];
67 for i in 0..N {
68 points[i] = EmbeddedCurveScalar::from_field(input[i]);
69 }
70 let generators = derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);
71 multi_scalar_mul(generators, points)
72 }
73
74 // docs:start:pedersen_hash
75 pub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field
76 // docs:end:pedersen_hash
77 {
78 pedersen_hash_with_separator(input, 0)
79 }
80
81 #[no_predicates]
82 pub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {
83 let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];
84 let mut generators: [EmbeddedCurvePoint; N + 1] =
85 [EmbeddedCurvePoint::point_at_infinity(); N + 1];
86 crate::assert_constant(separator);
87 let domain_generators: [EmbeddedCurvePoint; N] =
88 derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);
89
90 for i in 0..N {
91 scalars[i] = EmbeddedCurveScalar::from_field(input[i]);
92 generators[i] = domain_generators[i];
93 }
94 scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };
95
96 let length_generator: [EmbeddedCurvePoint; 1] =
97 derive_generators("pedersen_hash_length".as_bytes(), 0);
98 generators[N] = length_generator[0];
99 multi_scalar_mul_array_return(generators, scalars, true)[0].x
100 }
101
102 #[field(bn254)]
103 #[inline_always]
104 pub fn derive_generators<let N: u32, let M: u32>(
105 domain_separator_bytes: [u8; M],
106 starting_index: u32,
107 ) -> [EmbeddedCurvePoint; N] {
108 crate::assert_constant(domain_separator_bytes);
109 crate::assert_constant(starting_index);
110 __derive_generators(domain_separator_bytes, starting_index)
111 }
112
113 #[builtin(derive_pedersen_generators)]
114 #[field(bn254)]
115 fn __derive_generators<let N: u32, let M: u32>(
116 domain_separator_bytes: [u8; M],
117 starting_index: u32,
118 ) -> [EmbeddedCurvePoint; N] {}
119
120 pub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {
121 static_assert(
122 N == POSEIDON2_CONFIG_STATE_SIZE,
123 f"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}",
124 );
125· poseidon2_permutation_internal(input)
126 }
127
128 #[foreign(poseidon2_permutation)]
129 fn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}
130
131 #[foreign(poseidon2_config_state_size)]
132 comptime fn poseidon2_config_state_size() -> u32 {}
133
134 // Generic hashing support.
135 // Partially ported and impacted by rust.
136
137 // Hash trait shall be implemented per type.
138 #[derive_via(derive_hash)]
139 pub trait Hash {
140 fn hash<H>(self, state: &mut H)
141 where
142 H: Hasher;
143 }
144
145 // docs:start:derive_hash
146 comptime fn derive_hash(s: TypeDefinition) -> Quoted {
147 let name = quote { $crate::hash::Hash };
148 let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };
149 let for_each_field = |name| quote { _self.$name.hash(_state); };
150 crate::meta::make_trait_impl(
151 s,
152 name,
153 signature,
154 for_each_field,
155 quote {},
156 |fields| fields,
157 )
158 }
159 // docs:end:derive_hash
160
161 // Hasher trait shall be implemented by algorithms to provide hash-agnostic means.
162 // TODO: consider making the types generic here ([u8], [Field], etc.)
163 pub trait Hasher {
164 fn finish(self) -> Field;
165
166 /// Returns the hash value without consuming the hasher.
167 /// Override this for more efficient implementations that avoid copying.
168 /// TODO: deprecate finish() and replace it
169 fn finish_ref(&self) -> Field {
170 (*self).finish()
171 }
172
173 fn write(&mut self, input: Field);
174 }
175
176 // BuildHasher is a factory trait, responsible for production of specific Hasher.
177 pub trait BuildHasher {
178 type H: Hasher;
179
180 fn build_hasher(self) -> H;
181 }
182
183 pub struct BuildHasherDefault<H>;
184
185 impl<H> BuildHasher for BuildHasherDefault<H>
186 where
187 H: Hasher + Default,
188 {
189 type H = H;
190
191 fn build_hasher(_self: Self) -> H {
192 H::default()
193 }
194 }
195
196 impl<H> Default for BuildHasherDefault<H>
197 where
198 H: Hasher + Default,
199 {
200 fn default() -> Self {
201 BuildHasherDefault {}
202 }
203 }
204
205 impl Hash for Field {
206 fn hash<H>(self, state: &mut H)
207 where
208 H: Hasher,
209 {
210 H::write(state, self);
211 }
212 }
213
214 impl Hash for u8 {
215 fn hash<H>(self, state: &mut H)
216 where
217 H: Hasher,
218 {
219 H::write(state, self as Field);
220 }
221 }
222
223 impl Hash for u16 {
224 fn hash<H>(self, state: &mut H)
225 where
226 H: Hasher,
227 {
228 H::write(state, self as Field);
229 }
230 }
231
232 impl Hash for u32 {
233 fn hash<H>(self, state: &mut H)
234 where
235 H: Hasher,
236 {
237 H::write(state, self as Field);
238 }
239 }
240
241 impl Hash for u64 {
242 fn hash<H>(self, state: &mut H)
243 where
244 H: Hasher,
245 {
246 H::write(state, self as Field);
247 }
248 }
249
250 impl Hash for u128 {
251 fn hash<H>(self, state: &mut H)
252 where
253 H: Hasher,
254 {
255 H::write(state, self as Field);
256 }
257 }
258
259 impl Hash for i8 {
260 fn hash<H>(self, state: &mut H)
261 where
262 H: Hasher,
263 {
264 H::write(state, self as u8 as Field);
265 }
266 }
267
268 impl Hash for i16 {
269 fn hash<H>(self, state: &mut H)
270 where
271 H: Hasher,
272 {
273 H::write(state, self as u16 as Field);
274 }
275 }
276
277 impl Hash for i32 {
278 fn hash<H>(self, state: &mut H)
279 where
280 H: Hasher,
281 {
282 H::write(state, self as u32 as Field);
283 }
284 }
285
286 impl Hash for i64 {
287 fn hash<H>(self, state: &mut H)
288 where
289 H: Hasher,
290 {
291 H::write(state, self as u64 as Field);
292 }
293 }
294
295 impl Hash for bool {
296 fn hash<H>(self, state: &mut H)
297 where
298 H: Hasher,
299 {
300 H::write(state, self as Field);
301 }
302 }
303
304 impl Hash for () {
305 fn hash<H>(_self: Self, _state: &mut H)
306 where
307 H: Hasher,
308 {}
309 }
310
311 impl<T, let N: u32> Hash for [T; N]
312 where
313 T: Hash,
314 {
315 fn hash<H>(self, state: &mut H)
316 where
317 H: Hasher,
318 {
319 for elem in self {
320 elem.hash(state);
321 }
322 }
323 }
324
325 impl<T> Hash for [T]
326 where
327 T: Hash,
328 {
329 fn hash<H>(self, state: &mut H)
330 where
331 H: Hasher,
332 {
333 self.len().hash(state);
334 for elem in self {
335 elem.hash(state);
336 }
337 }
338 }
339
340 impl<A> Hash for (A,)
341 where
342 A: Hash,
343 {
344 fn hash<H>(self, state: &mut H)
345 where
346 H: Hasher,
347 {
348 self.0.hash(state);
349 }
350 }
351
352 impl<A, B> Hash for (A, B)
353 where
354 A: Hash,
355 B: Hash,
356 {
357 fn hash<H>(self, state: &mut H)
358 where
359 H: Hasher,
360 {
361 self.0.hash(state);
362 self.1.hash(state);
363 }
364 }
365
366 impl<A, B, C> Hash for (A, B, C)
367 where
368 A: Hash,
369 B: Hash,
370 C: Hash,
371 {
372 fn hash<H>(self, state: &mut H)
373 where
374 H: Hasher,
375 {
376 self.0.hash(state);
377 self.1.hash(state);
378 self.2.hash(state);
379 }
380 }
381
382 impl<A, B, C, D> Hash for (A, B, C, D)
383 where
384 A: Hash,
385 B: Hash,
386 C: Hash,
387 D: Hash,
388 {
389 fn hash<H>(self, state: &mut H)
390 where
391 H: Hasher,
392 {
393 self.0.hash(state);
394 self.1.hash(state);
395 self.2.hash(state);
396 self.3.hash(state);
397 }
398 }
399
400 impl<A, B, C, D, E> Hash for (A, B, C, D, E)
401 where
402 A: Hash,
403 B: Hash,
404 C: Hash,
405 D: Hash,
406 E: Hash,
407 {
408 fn hash<H>(self, state: &mut H)
409 where
410 H: Hasher,
411 {
412 self.0.hash(state);
413 self.1.hash(state);
414 self.2.hash(state);
415 self.3.hash(state);
416 self.4.hash(state);
417 }
418 }
419
420 impl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)
421 where
422 A: Hash,
423 B: Hash,
424 C: Hash,
425 D: Hash,
426 E: Hash,
427 F: Hash,
428 {
429 fn hash<H>(self, state: &mut H)
430 where
431 H: Hasher,
432 {
433 self.0.hash(state);
434 self.1.hash(state);
435 self.2.hash(state);
436 self.3.hash(state);
437 self.4.hash(state);
438 self.5.hash(state);
439 }
440 }
441
442 impl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)
443 where
444 A: Hash,
445 B: Hash,
446 C: Hash,
447 D: Hash,
448 E: Hash,
449 F: Hash,
450 G: Hash,
451 {
452 fn hash<H>(self, state: &mut H)
453 where
454 H: Hasher,
455 {
456 self.0.hash(state);
457 self.1.hash(state);
458 self.2.hash(state);
459 self.3.hash(state);
460 self.4.hash(state);
461 self.5.hash(state);
462 self.6.hash(state);
463 }
464 }
465
466 impl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)
467 where
468 A: Hash,
469 B: Hash,
470 C: Hash,
471 D: Hash,
472 E: Hash,
473 F: Hash,
474 G: Hash,
475 H_: Hash,
476 {
477 fn hash<H>(self, state: &mut H)
478 where
479 H: Hasher,
480 {
481 self.0.hash(state);
482 self.1.hash(state);
483 self.2.hash(state);
484 self.3.hash(state);
485 self.4.hash(state);
486 self.5.hash(state);
487 self.6.hash(state);
488 self.7.hash(state);
489 }
490 }
491
492 impl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)
493 where
494 A: Hash,
495 B: Hash,
496 C: Hash,
497 D: Hash,
498 E: Hash,
499 F: Hash,
500 G: Hash,
501 H_: Hash,
502 I: Hash,
503 {
504 fn hash<H>(self, state: &mut H)
505 where
506 H: Hasher,
507 {
508 self.0.hash(state);
509 self.1.hash(state);
510 self.2.hash(state);
511 self.3.hash(state);
512 self.4.hash(state);
513 self.5.hash(state);
514 self.6.hash(state);
515 self.7.hash(state);
516 self.8.hash(state);
517 }
518 }
519
520 impl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)
521 where
522 A: Hash,
523 B: Hash,
524 C: Hash,
525 D: Hash,
526 E: Hash,
527 F: Hash,
528 G: Hash,
529 H_: Hash,
530 I: Hash,
531 J: Hash,
532 {
533 fn hash<H>(self, state: &mut H)
534 where
535 H: Hasher,
536 {
537 self.0.hash(state);
538 self.1.hash(state);
539 self.2.hash(state);
540 self.3.hash(state);
541 self.4.hash(state);
542 self.5.hash(state);
543 self.6.hash(state);
544 self.7.hash(state);
545 self.8.hash(state);
546 self.9.hash(state);
547 }
548 }
549
550 impl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)
551 where
552 A: Hash,
553 B: Hash,
554 C: Hash,
555 D: Hash,
556 E: Hash,
557 F: Hash,
558 G: Hash,
559 H_: Hash,
560 I: Hash,
561 J: Hash,
562 K: Hash,
563 {
564 fn hash<H>(self, state: &mut H)
565 where
566 H: Hasher,
567 {
568 self.0.hash(state);
569 self.1.hash(state);
570 self.2.hash(state);
571 self.3.hash(state);
572 self.4.hash(state);
573 self.5.hash(state);
574 self.6.hash(state);
575 self.7.hash(state);
576 self.8.hash(state);
577 self.9.hash(state);
578 self.10.hash(state);
579 }
580 }
581
582 impl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)
583 where
584 A: Hash,
585 B: Hash,
586 C: Hash,
587 D: Hash,
588 E: Hash,
589 F: Hash,
590 G: Hash,
591 H_: Hash,
592 I: Hash,
593 J: Hash,
594 K: Hash,
595 L: Hash,
596 {
597 fn hash<H>(self, state: &mut H)
598 where
599 H: Hasher,
600 {
601 self.0.hash(state);
602 self.1.hash(state);
603 self.2.hash(state);
604 self.3.hash(state);
605 self.4.hash(state);
606 self.5.hash(state);
607 self.6.hash(state);
608 self.7.hash(state);
609 self.8.hash(state);
610 self.9.hash(state);
611 self.10.hash(state);
612 self.11.hash(state);
613 }
614 }
615
616 // Some test vectors for Pedersen hash and Pedersen Commitment.
617 // They have been generated using the same functions so the tests are for now useless
618 // but they will be useful when we switch to Noir implementation.
619 #[test]
620 fn assert_pedersen() {
621 assert_eq(
622 pedersen_hash_with_separator([1], 1),
623 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,
624 );
625 assert_eq(
626 pedersen_commitment_with_separator([1], 1),
627 EmbeddedCurvePoint {
628 x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,
629 y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,
630 },
631 );
632
633 assert_eq(
634 pedersen_hash_with_separator([1, 2], 2),
635 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,
636 );
637 assert_eq(
638 pedersen_commitment_with_separator([1, 2], 2),
639 EmbeddedCurvePoint {
640 x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,
641 y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,
642 },
643 );
644 assert_eq(
645 pedersen_hash_with_separator([1, 2, 3], 3),
646 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,
647 );
648 assert_eq(
649 pedersen_commitment_with_separator([1, 2, 3], 3),
650 EmbeddedCurvePoint {
651 x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,
652 y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,
653 },
654 );
655 assert_eq(
656 pedersen_hash_with_separator([1, 2, 3, 4], 4),
657 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,
658 );
659 assert_eq(
660 pedersen_commitment_with_separator([1, 2, 3, 4], 4),
661 EmbeddedCurvePoint {
662 x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,
663 y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,
664 },
665 );
666 assert_eq(
667 pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),
668 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,
669 );
670 assert_eq(
671 pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),
672 EmbeddedCurvePoint {
673 x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,
674 y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,
675 },
676 );
677 assert_eq(
678 pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),
679 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,
680 );
681 assert_eq(
682 pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),
683 EmbeddedCurvePoint {
684 x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,
685 y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,
686 },
687 );
688 assert_eq(
689 pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),
690 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,
691 );
692 assert_eq(
693 pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),
694 EmbeddedCurvePoint {
695 x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,
696 y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,
697 },
698 );
699 assert_eq(
700 pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),
701 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,
702 );
703 assert_eq(
704 pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),
705 EmbeddedCurvePoint {
706 x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,
707 y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,
708 },
709 );
710 assert_eq(
711 pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),
712 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,
713 );
714 assert_eq(
715 pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),
716 EmbeddedCurvePoint {
717 x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,
718 y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,
719 },
720 );
721 assert_eq(
722 pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),
723 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,
724 );
725 assert_eq(
726 pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),
727 EmbeddedCurvePoint {
728 x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,
729 y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,
730 },
731 );
732 }
1 use crate::convert::AsPrimitive;
2
3 // docs:start:add-trait
4 pub trait Add {
5 fn add(self, other: Self) -> Self;
6 }
7 // docs:end:add-trait
8
9 impl Add for Field {
10 fn add(self, other: Field) -> Field {
11 self + other
12 }
13 }
14
15 impl Add for u128 {
16 fn add(self, other: u128) -> u128 {
17· self + other
18 }
19 }
20 impl Add for u64 {
21 fn add(self, other: u64) -> u64 {
22 self + other
23 }
24 }
25 impl Add for u32 {
26 fn add(self, other: u32) -> u32 {
27 self + other
28 }
29 }
30 impl Add for u16 {
31 fn add(self, other: u16) -> u16 {
32 self + other
33 }
34 }
35 impl Add for u8 {
36 fn add(self, other: u8) -> u8 {
37 self + other
38 }
39 }
40 impl Add for i8 {
41 fn add(self, other: i8) -> i8 {
42 self + other
43 }
44 }
45 impl Add for i16 {
46 fn add(self, other: i16) -> i16 {
47 self + other
48 }
49 }
50 impl Add for i32 {
51 fn add(self, other: i32) -> i32 {
52 self + other
53 }
54 }
55 impl Add for i64 {
56 fn add(self, other: i64) -> i64 {
57 self + other
58 }
59 }
60
61 // docs:start:sub-trait
62 pub trait Sub {
63 fn sub(self, other: Self) -> Self;
64 }
65 // docs:end:sub-trait
66
67 impl Sub for Field {
68 fn sub(self, other: Field) -> Field {
69 self - other
70 }
71 }
72
73 impl Sub for u128 {
74 fn sub(self, other: u128) -> u128 {
75 self - other
76 }
77 }
78 impl Sub for u64 {
79 fn sub(self, other: u64) -> u64 {
80 self - other
81 }
82 }
83 impl Sub for u32 {
84 fn sub(self, other: u32) -> u32 {
85 self - other
86 }
87 }
88 impl Sub for u16 {
89 fn sub(self, other: u16) -> u16 {
90 self - other
91 }
92 }
93 impl Sub for u8 {
94 fn sub(self, other: u8) -> u8 {
95 self - other
96 }
97 }
98 impl Sub for i8 {
99 fn sub(self, other: i8) -> i8 {
100 self - other
101 }
102 }
103 impl Sub for i16 {
104 fn sub(self, other: i16) -> i16 {
105 self - other
106 }
107 }
108 impl Sub for i32 {
109 fn sub(self, other: i32) -> i32 {
110 self - other
111 }
112 }
113 impl Sub for i64 {
114 fn sub(self, other: i64) -> i64 {
115 self - other
116 }
117 }
118
119 // docs:start:mul-trait
120 pub trait Mul {
121 fn mul(self, other: Self) -> Self;
122 }
123 // docs:end:mul-trait
124
125 impl Mul for Field {
126 fn mul(self, other: Field) -> Field {
127 self * other
128 }
129 }
130
131 impl Mul for u128 {
132 fn mul(self, other: u128) -> u128 {
133 self * other
134 }
135 }
136 impl Mul for u64 {
137 fn mul(self, other: u64) -> u64 {
138 self * other
139 }
140 }
141 impl Mul for u32 {
142 fn mul(self, other: u32) -> u32 {
143 self * other
144 }
145 }
146 impl Mul for u16 {
147 fn mul(self, other: u16) -> u16 {
148 self * other
149 }
150 }
151 impl Mul for u8 {
152 fn mul(self, other: u8) -> u8 {
153 self * other
154 }
155 }
156 impl Mul for i8 {
157 fn mul(self, other: i8) -> i8 {
158 self * other
159 }
160 }
161 impl Mul for i16 {
162 fn mul(self, other: i16) -> i16 {
163 self * other
164 }
165 }
166 impl Mul for i32 {
167 fn mul(self, other: i32) -> i32 {
168 self * other
169 }
170 }
171 impl Mul for i64 {
172 fn mul(self, other: i64) -> i64 {
173 self * other
174 }
175 }
176
177 // docs:start:div-trait
178 pub trait Div {
179 fn div(self, other: Self) -> Self;
180 }
181 // docs:end:div-trait
182
183 impl Div for Field {
184 fn div(self, other: Field) -> Field {
185 self / other
186 }
187 }
188
189 impl Div for u128 {
190 fn div(self, other: u128) -> u128 {
191 self / other
192 }
193 }
194 impl Div for u64 {
195 fn div(self, other: u64) -> u64 {
196 self / other
197 }
198 }
199 impl Div for u32 {
200 fn div(self, other: u32) -> u32 {
201 self / other
202 }
203 }
204 impl Div for u16 {
205 fn div(self, other: u16) -> u16 {
206 self / other
207 }
208 }
209 impl Div for u8 {
210 fn div(self, other: u8) -> u8 {
211 self / other
212 }
213 }
214 impl Div for i8 {
215 fn div(self, other: i8) -> i8 {
216 self / other
217 }
218 }
219 impl Div for i16 {
220 fn div(self, other: i16) -> i16 {
221 self / other
222 }
223 }
224 impl Div for i32 {
225 fn div(self, other: i32) -> i32 {
226 self / other
227 }
228 }
229 impl Div for i64 {
230 fn div(self, other: i64) -> i64 {
231 self / other
232 }
233 }
234
235 // docs:start:rem-trait
236 pub trait Rem {
237 fn rem(self, other: Self) -> Self;
238 }
239 // docs:end:rem-trait
240
241 impl Rem for u128 {
242 fn rem(self, other: u128) -> u128 {
243 self % other
244 }
245 }
246 impl Rem for u64 {
247 fn rem(self, other: u64) -> u64 {
248 self % other
249 }
250 }
251 impl Rem for u32 {
252 fn rem(self, other: u32) -> u32 {
253 self % other
254 }
255 }
256 impl Rem for u16 {
257 fn rem(self, other: u16) -> u16 {
258 self % other
259 }
260 }
261 impl Rem for u8 {
262 fn rem(self, other: u8) -> u8 {
263 self % other
264 }
265 }
266 impl Rem for i8 {
267 fn rem(self, other: i8) -> i8 {
268 self % other
269 }
270 }
271 impl Rem for i16 {
272 fn rem(self, other: i16) -> i16 {
273 self % other
274 }
275 }
276 impl Rem for i32 {
277 fn rem(self, other: i32) -> i32 {
278 self % other
279 }
280 }
281 impl Rem for i64 {
282 fn rem(self, other: i64) -> i64 {
283 self % other
284 }
285 }
286
287 // docs:start:neg-trait
288 pub trait Neg {
289 fn neg(self) -> Self;
290 }
291 // docs:end:neg-trait
292
293 // docs:start:neg-trait-impls
294 impl Neg for Field {
295 fn neg(self) -> Field {
296 -self
297 }
298 }
299
300 impl Neg for i8 {
301 fn neg(self) -> i8 {
302 -self
303 }
304 }
305 impl Neg for i16 {
306 fn neg(self) -> i16 {
307 -self
308 }
309 }
310 impl Neg for i32 {
311 fn neg(self) -> i32 {
312 -self
313 }
314 }
315 impl Neg for i64 {
316 fn neg(self) -> i64 {
317 -self
318 }
319 }
320 // docs:end:neg-trait-impls
321
322 // docs:start:wrapping-add-trait
323 pub trait WrappingAdd {
324 fn wrapping_add(self, y: Self) -> Self;
325 }
326 // docs:end:wrapping-add-trait
327
328 impl WrappingAdd for u8 {
329 fn wrapping_add(self: u8, y: u8) -> u8 {
330 wrapping_add_hlp(self, y)
331 }
332 }
333
334 impl WrappingAdd for u16 {
335 fn wrapping_add(self: u16, y: u16) -> u16 {
336 wrapping_add_hlp(self, y)
337 }
338 }
339
340 impl WrappingAdd for u32 {
341 fn wrapping_add(self: u32, y: u32) -> u32 {
342 wrapping_add_hlp(self, y)
343 }
344 }
345
346 impl WrappingAdd for u64 {
347 fn wrapping_add(self: u64, y: u64) -> u64 {
348 wrapping_add_hlp(self, y)
349 }
350 }
351
352 impl WrappingAdd for u128 {
353 fn wrapping_add(self: u128, y: u128) -> u128 {
354 wrapping_add_hlp(self, y)
355 }
356 }
357
358 impl WrappingAdd for i8 {
359 fn wrapping_add(self: i8, y: i8) -> i8 {
360 let x = self as u8;
361 x.wrapping_add(y as u8) as i8
362 }
363 }
364
365 impl WrappingAdd for i16 {
366 fn wrapping_add(self: i16, y: i16) -> i16 {
367 let x = self as u16;
368 x.wrapping_add(y as u16) as i16
369 }
370 }
371
372 impl WrappingAdd for i32 {
373 fn wrapping_add(self: i32, y: i32) -> i32 {
374 let x = self as u32;
375 x.wrapping_add(y as u32) as i32
376 }
377 }
378
379 impl WrappingAdd for i64 {
380 fn wrapping_add(self: i64, y: i64) -> i64 {
381 let x = self as u64;
382 x.wrapping_add(y as u64) as i64
383 }
384 }
385 impl WrappingAdd for Field {
386 fn wrapping_add(self: Field, y: Field) -> Field {
387 self + y
388 }
389 }
390
391 // docs:start:wrapping-sub-trait
392 pub trait WrappingSub {
393 fn wrapping_sub(self, y: Self) -> Self;
394 }
395 // docs:start:wrapping-sub-trait
396
397 impl WrappingSub for u8 {
398 fn wrapping_sub(self: u8, y: u8) -> u8 {
399 wrapping_sub_hlp(self, y) as u8
400 }
401 }
402
403 impl WrappingSub for u16 {
404 fn wrapping_sub(self: u16, y: u16) -> u16 {
405 wrapping_sub_hlp(self, y) as u16
406 }
407 }
408
409 impl WrappingSub for u32 {
410 fn wrapping_sub(self: u32, y: u32) -> u32 {
411 wrapping_sub_hlp(self, y) as u32
412 }
413 }
414 impl WrappingSub for u64 {
415 fn wrapping_sub(self: u64, y: u64) -> u64 {
416 wrapping_sub_hlp(self, y) as u64
417 }
418 }
419 impl WrappingSub for u128 {
420 fn wrapping_sub(self: u128, y: u128) -> u128 {
421 wrapping_sub_hlp(self, y) as u128
422 }
423 }
424
425 impl WrappingSub for i8 {
426 fn wrapping_sub(self: i8, y: i8) -> i8 {
427 let x = self as u8;
428 x.wrapping_sub(y as u8) as i8
429 }
430 }
431
432 impl WrappingSub for i16 {
433 fn wrapping_sub(self: i16, y: i16) -> i16 {
434 let x = self as u16;
435 x.wrapping_sub(y as u16) as i16
436 }
437 }
438
439 impl WrappingSub for i32 {
440 fn wrapping_sub(self: i32, y: i32) -> i32 {
441 let x = self as u32;
442 x.wrapping_sub(y as u32) as i32
443 }
444 }
445 impl WrappingSub for i64 {
446 fn wrapping_sub(self: i64, y: i64) -> i64 {
447 let x = self as u64;
448 x.wrapping_sub(y as u64) as i64
449 }
450 }
451 impl WrappingSub for Field {
452 fn wrapping_sub(self: Field, y: Field) -> Field {
453 self - y
454 }
455 }
456
457 // docs:start:wrapping-mul-trait
458 pub trait WrappingMul {
459 fn wrapping_mul(self, y: Self) -> Self;
460 }
461 // docs:start:wrapping-mul-trait
462
463 impl WrappingMul for u8 {
464 fn wrapping_mul(self: u8, y: u8) -> u8 {
465 wrapping_mul_hlp(self, y)
466 }
467 }
468
469 impl WrappingMul for u16 {
470 fn wrapping_mul(self: u16, y: u16) -> u16 {
471 wrapping_mul_hlp(self, y)
472 }
473 }
474
475 impl WrappingMul for u32 {
476 fn wrapping_mul(self: u32, y: u32) -> u32 {
477 wrapping_mul_hlp(self, y)
478 }
479 }
480 impl WrappingMul for u64 {
481 fn wrapping_mul(self: u64, y: u64) -> u64 {
482 wrapping_mul_hlp(self, y)
483 }
484 }
485
486 impl WrappingMul for i8 {
487 fn wrapping_mul(self: i8, y: i8) -> i8 {
488 let x = self as u8;
489 x.wrapping_mul(y as u8) as i8
490 }
491 }
492
493 impl WrappingMul for i16 {
494 fn wrapping_mul(self: i16, y: i16) -> i16 {
495 let x = self as u16;
496 x.wrapping_mul(y as u16) as i16
497 }
498 }
499
500 impl WrappingMul for i32 {
501 fn wrapping_mul(self: i32, y: i32) -> i32 {
502 let x = self as u32;
503 x.wrapping_mul(y as u32) as i32
504 }
505 }
506
507 impl WrappingMul for i64 {
508 fn wrapping_mul(self: i64, y: i64) -> i64 {
509 let x = self as u64;
510 x.wrapping_mul(y as u64) as i64
511 }
512 }
513
514 impl WrappingMul for u128 {
515 fn wrapping_mul(self: u128, y: u128) -> u128 {
516 wrapping_mul128_hlp(self, y)
517 }
518 }
519 impl WrappingMul for Field {
520 fn wrapping_mul(self: Field, y: Field) -> Field {
521 self * y
522 }
523 }
524
525 fn wrapping_add_hlp<T>(x: T, y: T) -> T
526 where
527 T: AsPrimitive<Field>,
528 Field: AsPrimitive<T>,
529 {
530 AsPrimitive::as_(x.as_() + y.as_())
531 }
532
533 fn wrapping_sub_hlp<T>(x: T, y: T) -> Field
534 where
535 T: AsPrimitive<Field>,
536 {
537 //340282366920938463463374607431768211456 is 2^128, it is used to avoid underflow
538 x.as_() + 340282366920938463463374607431768211456 - y.as_()
539 }
540
541 fn wrapping_mul_hlp<T>(x: T, y: T) -> T
542 where
543 T: AsPrimitive<Field>,
544 Field: AsPrimitive<T>,
545 {
546 AsPrimitive::as_(x.as_() * y.as_())
547 }
548
549 global two_pow_64: u128 = 0x10000000000000000;
550 /// Splits a 128 bits number into two 64 bits limbs
551 unconstrained fn split64(x: u128) -> (u64, u64) {
552 let lo = x as u64;
553 let hi = (x / two_pow_64) as u64;
554 (lo, hi)
555 }
556
557 /// Split a 128 bits number into two 64 bits limbs
558 /// It will fail if the number is more than 128 bits
559 fn split_into_64_bit_limbs(x: u128) -> (u64, u64) {
560 // Safety: the limbs are constrained below
561 let (x_lo, x_hi) = unsafe { split64(x) };
562 assert(x as Field == x_lo as Field + x_hi as Field * two_pow_64 as Field);
563 (x_lo, x_hi)
564 }
565
566 #[field(bn254)]
567 fn wrapping_mul128_hlp(x: u128, y: u128) -> u128 {
568 let (x_lo, x_hi) = split_into_64_bit_limbs(x);
569 let (y_lo, y_hi) = split_into_64_bit_limbs(y);
570 // Multiplication using the limbs:(x_lo + 2**64*x_hi)*(y_lo + 2**64*y_hi)=x_lo*y_lo+...
571 // and skipping the terms over 2**128
572 // Working with u64 limbs ensures that we cannot overflow the field modulus.
573 let low = x_lo as Field * y_lo as Field;
574 let lo = low as u64 as Field;
575 let carry = (low - lo) / two_pow_64 as Field;
576 let high = x_lo as Field * y_hi as Field + x_hi as Field * y_lo as Field + carry;
577 let hi = high as u64 as Field;
578 (lo + two_pow_64 as Field * hi) as u128
579 }
580
581 mod tests {
582 #[test(should_fail_with = "custom message")]
583 fn test_static_assert_custom_message() {
584 crate::static_assert(1 == 2, "custom message");
585 }
586
587 mod arithmetic {
588 use crate::ops::arith::{Add, Div, Mul, Neg, Rem, Sub};
589 #[test]
590 fn test_basic_arithmetic_traits() {
591 // add
592 assert_eq(5.add(3), 8);
593 assert_eq(0u8.add(255u8), 255u8);
594 assert_eq(42.add(58), 100);
595
596 // sub
597 assert_eq(10.sub(3), 7);
598 assert_eq(100.sub(42), 58);
599
600 // mul
601 assert_eq(6.mul(7), 42);
602
603 // div
604 assert_eq(15.div(3), 5);
605 assert_eq(10u8.div(3u8), 3u8);
606 assert_eq(15.div(3), 5);
607
608 // rem (Field doesn't implement Rem)
609 assert_eq(17u64.rem(5u64), 2u64);
610 assert_eq(10u8.rem(3u8), 1u8);
611
612 // neg
613 assert_eq(42.neg(), -42);
614 assert_eq((-10).neg(), 10);
615 assert_eq(42.neg(), -42);
616 }
617
618 #[test]
619 fn test_division() {
620 // test division by one
621 assert_eq(42.div(1), 42);
622 assert_eq(0.div(1), 0);
623 assert_eq(255u8.div(1u8), 255u8);
624
625 // test division by self
626 assert_eq(42.div(42), 1);
627 assert_eq(1.div(1), 1);
628
629 // test remainder (Field doesn't implement Rem)
630 assert_eq(42u32.rem(42u32), 0u32);
631 assert_eq(0u16.rem(42u16), 0u16);
632 assert_eq(1u64.rem(42u64), 1u64);
633 }
634
635 #[test(should_fail)]
636 fn test_u8_sub_overflow_failure() {
637 let _ = 0u8.sub(1u8);
638 }
639
640 #[test(should_fail)]
641 fn test_u8_add_overflow_failure() {
642 let _ = 255u8.add(1u8);
643 }
644
645 #[test(should_fail)]
646 fn test_u8_mul_overflow_failure() {
647 let _ = 255u8.mul(2u8);
648 }
649
650 #[test(should_fail)]
651 fn test_u16_sub_overflow_failure() {
652 let _ = 0u16.sub(1u16);
653 }
654
655 #[test(should_fail)]
656 fn test_u16_add_overflow_failure() {
657 let _ = 65535u16.add(1u16);
658 }
659
660 #[test(should_fail)]
661 fn test_u16_mul_overflow_failure() {
662 let _ = 65535u16.mul(2u16);
663 }
664
665 #[test(should_fail)]
666 fn test_signed_sub_overflow_failure() {
667 let val: i8 = -128;
668 let _ = val.sub(1i8);
669 }
670
671 #[test(should_fail)]
672 fn test_signed_overflow_failure() {
673 let _ = 127i8.add(1i8);
674 }
675
676 #[test]
677 fn test_field() {
678 let zero: Field = 0;
679 let one: Field = 1;
680
681 // test Field basic operations
682 assert_eq(zero.add(one), one);
683 assert_eq(one.add(zero), one);
684 assert_eq(one.sub(one), zero);
685 assert_eq(one.mul(one), one);
686 assert_eq(one.div(one), one);
687 assert_eq(zero.neg(), zero);
688 assert_eq(one.neg(), -one);
689 }
690
691 }
692
693 mod wrapping_arithmetic {
694 use crate::ops::arith::{Add, Div, Mul, Neg, Sub, WrappingAdd, WrappingMul, WrappingSub};
695 #[test]
696 fn test_wrapping_add() {
697 assert_eq(255u8.wrapping_add(1u8), 0u8);
698 assert_eq(255u8.wrapping_add(255u8), 254u8);
699 assert_eq(0u8.wrapping_add(0u8), 0u8);
700 assert_eq(128u8.wrapping_add(128u8), 0u8);
701
702 // test u16 wrapping add
703 assert_eq(65535u16.wrapping_add(1u16), 0u16);
704 assert_eq(65535u16.wrapping_add(65535u16), 65534u16);
705
706 // test u32 wrapping add
707 assert_eq(0xffffffffu32.wrapping_add(1u32), 0u32);
708 assert_eq(0xffffffffu32.wrapping_add(0xffffffffu32), 0xfffffffeu32);
709
710 // test u64 wrapping add
711 assert_eq(0xffffffffffffffffu64.wrapping_add(1u64), 0u64);
712 assert_eq(
713 0xffffffffffffffffu64.wrapping_add(0xffffffffffffffffu64),
714 0xfffffffffffffffeu64,
715 );
716
717 // test u128 wrapping add
718 assert_eq(0xffffffffffffffffffffffffffffffffu128.wrapping_add(1u128), 0u128);
719
720 // test signed types
721 assert_eq(127i8.wrapping_add(1i8), -128i8);
722 let val: i8 = -128;
723 assert_eq(val.wrapping_add(-1i8), 127i8);
724
725 // test Field wrapping add
726 let forty_two: Field = 42;
727 let fifty_eight: Field = 58;
728 let hundred: Field = 100;
729 let neg_two: Field = -2;
730 let two: Field = 2;
731 let zero: Field = 0;
732 let neg_two_hundred: Field = -200;
733 let neg_one_ninety_eight: Field = -198;
734 assert_eq(forty_two.wrapping_add(fifty_eight), hundred);
735 assert_eq(neg_two.wrapping_add(two), zero);
736 assert_eq(neg_two_hundred.wrapping_add(two), neg_one_ninety_eight);
737 }
738
739 #[test]
740 fn test_wrapping_sub() {
741 assert_eq(0u8.wrapping_sub(1u8), 255u8);
742 assert_eq(255u8.wrapping_sub(255u8), 0u8);
743 assert_eq(0u8.wrapping_sub(0u8), 0u8);
744 assert_eq(1u8.wrapping_sub(2u8), 255u8);
745
746 // test u16 wrapping sub
747 assert_eq(0u16.wrapping_sub(1u16), 65535u16);
748 assert_eq(65535u16.wrapping_sub(65535u16), 0u16);
749
750 // test u32 wrapping sub
751 assert_eq(0u32.wrapping_sub(1u32), 0xffffffffu32);
752 assert_eq(0xffffffffu32.wrapping_sub(0xffffffffu32), 0u32);
753
754 // test u64 wrapping sub
755 assert_eq(0u64.wrapping_sub(1u64), 0xffffffffffffffffu64);
756 assert_eq(0xffffffffffffffffu64.wrapping_sub(0xffffffffffffffffu64), 0u64);
757
758 // test u128 wrapping sub
759 assert_eq(0u128.wrapping_sub(1u128), 0xffffffffffffffffffffffffffffffffu128);
760
761 // test signed types
762 let val: i8 = -128;
763 assert_eq(val.wrapping_sub(1i8), 127i8);
764 assert_eq(127i8.wrapping_sub(-1i8), -128i8);
765
766 // test Field wrapping sub
767 let forty_two: Field = 42;
768 let fifty_eight: Field = 58;
769 let neg_sixteen: Field = -16;
770 assert_eq(forty_two.wrapping_sub(fifty_eight), neg_sixteen);
771 }
772
773 #[test]
774 fn test_wrapping_mul() {
775 let zero: u128 = 0;
776 let one: u128 = 1;
777 let two_pow_64: u128 = 0x10000000000000000;
778 let u128_max: u128 = 0xffffffffffffffffffffffffffffffff;
779
780 assert_eq(zero, zero.wrapping_mul(one));
781 assert_eq(zero, one.wrapping_mul(zero));
782 assert_eq(one, one.wrapping_mul(one));
783 assert_eq(zero, zero.wrapping_mul(two_pow_64));
784 assert_eq(zero, two_pow_64.wrapping_mul(zero));
785 assert_eq(two_pow_64, two_pow_64.wrapping_mul(one));
786 assert_eq(two_pow_64, one.wrapping_mul(two_pow_64));
787 assert_eq(zero, two_pow_64.wrapping_mul(two_pow_64));
788 assert_eq(one, u128_max.wrapping_mul(u128_max));
789
790 // test u8 wrapping mul
791 assert_eq(255u8.wrapping_mul(2u8), 254u8);
792 assert_eq(255u8.wrapping_mul(255u8), 1u8);
793 assert_eq(128u8.wrapping_mul(2u8), 0u8);
794
795 // test u16 wrapping mul
796 assert_eq(65535u16.wrapping_mul(2u16), 65534u16);
797 assert_eq(65535u16.wrapping_mul(65535u16), 1u16);
798
799 // test u32 wrapping mul
800 assert_eq(0xffffffffu32.wrapping_mul(2u32), 0xfffffffeu32);
801 assert_eq(0xffffffffu32.wrapping_mul(0xffffffffu32), 1u32);
802
803 // test u64 wrapping mul
804 // 0xffffffffffffffffu64 is 2^64 - 1
805 assert_eq(0xffffffffffffffffu64.wrapping_mul(2u64), 0xfffffffffffffffeu64);
806 assert_eq(0xffffffffffffffffu64.wrapping_mul(0xffffffffffffffffu64), 1u64);
807
808 // test signed types
809 assert_eq(127i8.wrapping_mul(2i8), -2i8);
810 let val: i8 = -128;
811 assert_eq(val.wrapping_mul(-1i8), -128i8);
812
813 // test Field wrapping mul
814 let six: Field = 6;
815 let seven: Field = 7;
816 let forty_two: Field = 42;
817 let neg_two: Field = -2;
818 let two: Field = 2;
819 let neg_four: Field = -4;
820 assert_eq(six.wrapping_mul(seven), forty_two);
821 assert_eq(neg_two.wrapping_mul(two), neg_four);
822 }
823
824 // test wrapping operations is the same as the regular operations
825 #[test]
826 fn test_wrapping_vs_regular() {
827 let u64_large = 0x123456789abcdef0u64;
828 let u128_large = 0x123456789abcdef0123456789abcdef0u128;
829
830 assert_eq(u64_large.wrapping_add(1u64), u64_large + 1u64);
831 assert_eq(u64_large.wrapping_sub(1u64), u64_large - 1u64);
832 assert_eq(u64_large.wrapping_mul(2u64), u64_large * 2u64);
833
834 assert_eq(u128_large.wrapping_add(1u128), u128_large + 1u128);
835 assert_eq(u128_large.wrapping_sub(1u128), u128_large - 1u128);
836 assert_eq(u128_large.wrapping_mul(2u128), u128_large * 2u128);
837 }
838
839 #[test]
840 fn test_field_wrapping_operations() {
841 let zero: Field = 0;
842 let one: Field = 1;
843 let large_val = 0xffffffffffffffff;
844
845 // test Field wrapping operations
846 assert_eq(zero.wrapping_add(one), one);
847 assert_eq(one.wrapping_add(large_val), one + large_val);
848 assert_eq(zero.wrapping_sub(one), -one);
849 assert_eq(one.wrapping_sub(large_val), one - large_val);
850 assert_eq(zero.wrapping_mul(one), zero);
851 assert_eq(one.wrapping_mul(large_val), large_val);
852
853 // test Field basic operations
854 assert_eq(zero.add(one), one);
855 assert_eq(one.add(zero), one);
856 assert_eq(one.sub(one), zero);
857 assert_eq(one.mul(one), one);
858 assert_eq(one.div(one), one);
859 assert_eq(zero.neg(), zero);
860 assert_eq(one.neg(), -one);
861 }
862
863 }
864
865 mod split_functions {
866
867 use crate::ops::arith::{split64, split_into_64_bit_limbs};
868
869 // test split64 and split_into_64_bit_limbs functions
870 #[test]
871 fn test_split_functions() {
872 let small_val = 0x123456789abcdefu128;
873 let large_val = 0x123456789abcdef0123456789abcdef0u128;
874 let max_val = 0xffffffffffffffffffffffffffffffffu128;
875
876 // test split64 (unconstrained)
877 // Safety: testing
878 unsafe {
879 let (lo, hi) = split64(small_val);
880 assert_eq(lo, 0x123456789abcdefu64);
881 assert_eq(hi, 0u64);
882
883 let (lo2, hi2) = split64(large_val);
884 assert_eq(lo2, 0x123456789abcdef0u64);
885 assert_eq(hi2, 0x123456789abcdef0u64);
886 }
887
888 // test split_into_64_bit_limbs (constrained)
889 let (lo3, hi3) = split_into_64_bit_limbs(small_val);
890 assert_eq(lo3, 0x123456789abcdefu64);
891 assert_eq(hi3, 0u64);
892
893 let (lo4, hi4) = split_into_64_bit_limbs(large_val);
894 assert_eq(lo4, 0x123456789abcdef0u64);
895 assert_eq(hi4, 0x123456789abcdef0u64);
896
897 let (lo5, hi5) = split_into_64_bit_limbs(max_val);
898 assert_eq(lo5, 0xffffffffffffffffu64);
899 assert_eq(hi5, 0xffffffffffffffffu64);
900 }
901 }
902
903 mod traits {
904 use crate::ops::arith::{
905 Add, Div, Mul, Neg, Rem, Sub, WrappingAdd, WrappingMul, WrappingSub,
906 };
907
908 #[test]
909 fn add() {
910 assert_eq(1_u8.add(2), 3);
911 assert_eq(1_u16.add(2), 3);
912 assert_eq(1_u32.add(2), 3);
913 assert_eq(1_u64.add(2), 3);
914 assert_eq(1_u128.add(2), 3);
915 assert_eq(1_i8.add(2), 3);
916 assert_eq(1_i16.add(2), 3);
917 assert_eq(1_i32.add(2), 3);
918 assert_eq(1_i64.add(2), 3);
919 assert_eq(1_Field.add(2), 3);
920 }
921
922 #[test]
923 fn sub() {
924 assert_eq(3_u8.sub(2), 1);
925 assert_eq(3_u16.sub(2), 1);
926 assert_eq(3_u32.sub(2), 1);
927 assert_eq(3_u64.sub(2), 1);
928 assert_eq(3_u128.sub(2), 1);
929 assert_eq(3_i8.sub(2), 1);
930 assert_eq(3_i16.sub(2), 1);
931 assert_eq(3_i32.sub(2), 1);
932 assert_eq(3_i64.sub(2), 1);
933 assert_eq(3_Field.sub(2), 1);
934 }
935
936 #[test]
937 fn mul() {
938 assert_eq(3_u8.mul(2), 6);
939 assert_eq(3_u16.mul(2), 6);
940 assert_eq(3_u32.mul(2), 6);
941 assert_eq(3_u64.mul(2), 6);
942 assert_eq(3_u128.mul(2), 6);
943 assert_eq(3_i8.mul(2), 6);
944 assert_eq(3_i16.mul(2), 6);
945 assert_eq(3_i32.mul(2), 6);
946 assert_eq(3_i64.mul(2), 6);
947 assert_eq(3_Field.mul(2), 6);
948 }
949
950 #[test]
951 fn div() {
952 assert_eq(6_u8.div(2), 3);
953 assert_eq(6_u16.div(2), 3);
954 assert_eq(6_u32.div(2), 3);
955 assert_eq(6_u64.div(2), 3);
956 assert_eq(6_u128.div(2), 3);
957 assert_eq(6_i8.div(2), 3);
958 assert_eq(6_i16.div(2), 3);
959 assert_eq(6_i32.div(2), 3);
960 assert_eq(6_i64.div(2), 3);
961 assert_eq(6_Field.div(2), 3);
962 }
963
964 #[test]
965 fn rem() {
966 assert_eq(3_u8.rem(2), 1);
967 assert_eq(3_u16.rem(2), 1);
968 assert_eq(3_u32.rem(2), 1);
969 assert_eq(3_u64.rem(2), 1);
970 assert_eq(3_u128.rem(2), 1);
971 assert_eq(3_i8.rem(2), 1);
972 assert_eq(3_i16.rem(2), 1);
973 assert_eq(3_i32.rem(2), 1);
974 assert_eq(3_i64.rem(2), 1);
975 }
976
977 #[test]
978 fn neg() {
979 assert_eq(3_i8.neg(), -3);
980 assert_eq(3_i16.neg(), -3);
981 assert_eq(3_i32.neg(), -3);
982 assert_eq(3_i64.neg(), -3);
983 }
984
985 #[test]
986 fn wrapping_add() {
987 assert_eq(255_u8.wrapping_add(2), 1);
988 assert_eq(65535_u16.wrapping_add(2), 1);
989 assert_eq(4294967295_u32.wrapping_add(2), 1);
990 assert_eq(18446744073709551615_u64.wrapping_add(2), 1);
991 assert_eq(340282366920938463463374607431768211455_u128.wrapping_add(2), 1);
992 assert_eq(127_i8.wrapping_add(2), -127);
993 assert_eq(32767_i16.wrapping_add(2), -32767);
994 assert_eq(2147483647_i32.wrapping_add(2), -2147483647);
995 assert_eq(9223372036854775807_i64.wrapping_add(2), -9223372036854775807);
996 assert_eq(1_Field.wrapping_add(2), 3);
997 }
998
999 #[test]
1000 fn wrapping_sub() {
1001 assert_eq(0_u8.wrapping_sub(1), 255);
1002 assert_eq(0_u16.wrapping_sub(1), 65535);
1003 assert_eq(0_u32.wrapping_sub(1), 4294967295);
1004 assert_eq(0_u64.wrapping_sub(1), 18446744073709551615);
1005 assert_eq(0_u128.wrapping_sub(1), 340282366920938463463374607431768211455);
1006 assert_eq((-128_i8).wrapping_sub(1), 127);
1007 assert_eq((-32768_i16).wrapping_sub(1), 32767);
1008 assert_eq((-2147483648_i32).wrapping_sub(1), 2147483647);
1009 assert_eq((-9223372036854775808_i64).wrapping_sub(1), 9223372036854775807);
1010 assert_eq(3_Field.wrapping_sub(1), 2);
1011 }
1012
1013 #[test]
1014 fn wrapping_mul() {
1015 assert_eq(255_u8.wrapping_mul(2), 254);
1016 assert_eq(65535_u16.wrapping_mul(2), 65534);
1017 assert_eq(4294967295_u32.wrapping_mul(2), 4294967294);
1018 assert_eq(18446744073709551615_u64.wrapping_mul(2), 18446744073709551614);
1019 assert_eq(
1020 340282366920938463463374607431768211455_u128.wrapping_mul(2),
1021 340282366920938463463374607431768211454,
1022 );
1023 assert_eq(127_i8.wrapping_mul(2), -2);
1024 assert_eq(32767_i16.wrapping_mul(2), -2);
1025 assert_eq(2147483647_i32.wrapping_mul(2), -2);
1026 assert_eq(9223372036854775807_i64.wrapping_mul(2), -2);
1027 assert_eq(2_Field.wrapping_mul(3), 6);
1028 }
1029 }
1030 }
1 use crate::cmp::{Eq, Ord, Ordering};
2 use crate::default::Default;
3 use crate::hash::{Hash, Hasher};
4
5 /// Represents a value of type T or its absence.
6 /// Use `Option::some(value)` to construct a value or `Option::none()` to record the absence of one.
7 pub struct Option<T> {
8 _is_some: bool,
9 _value: T,
10 }
11
12 impl<T> Option<T> {
13 /// Constructs a None value
14 pub fn none() -> Self {
15 Self { _is_some: false, _value: crate::mem::zeroed() }
16 }
17
18 /// Constructs a Some wrapper around the given value
19 pub fn some(_value: T) -> Self {
20 Self { _is_some: true, _value }
21 }
22
23 /// True if this Option is None
24 pub fn is_none(&self) -> bool {
25 !self._is_some
26 }
27
28 /// True if this Option is Some
29 pub fn is_some(&self) -> bool {
30 self._is_some
31 }
32
33 /// Asserts `self.is_some()` and returns the wrapped value.
34 pub fn unwrap(self) -> T {
35· assert(self._is_some);
36 self._value
37 }
38
39 /// Returns the inner value without asserting `self.is_some()`
40 /// Note that if `self` is `None`, there is no guarantee what value will be returned,
41 /// only that it will be of type `T`.
42 pub fn unwrap_unchecked(self) -> T {
43 self._value
44 }
45
46 /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.
47 pub fn unwrap_or(self, default: T) -> T {
48 if self._is_some {
49 self._value
50 } else {
51 default
52 }
53 }
54
55 /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return
56 /// a default value.
57 pub fn unwrap_or_else<Env>(self, default: fn[Env]() -> T) -> T {
58 if self._is_some {
59 self._value
60 } else {
61 default()
62 }
63 }
64
65 /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value
66 pub fn expect<let N: u32, MessageTypes>(self, message: fmtstr<N, MessageTypes>) -> T {
67 assert(self.is_some(), message);
68 self._value
69 }
70
71 /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.
72 pub fn map<U, Env>(self, f: fn[Env](T) -> U) -> Option<U> {
73 if self._is_some {
74 Option::some(f(self._value))
75 } else {
76 Option::none()
77 }
78 }
79
80 /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.
81 pub fn map_or<U, Env>(self, default: U, f: fn[Env](T) -> U) -> U {
82 if self._is_some {
83 f(self._value)
84 } else {
85 default
86 }
87 }
88
89 /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.
90 pub fn map_or_else<U, Env1, Env2>(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {
91 if self._is_some {
92 f(self._value)
93 } else {
94 default()
95 }
96 }
97
98 /// Returns None if self is None. Otherwise, this returns `other`.
99 pub fn and(self, other: Self) -> Self {
100 if self.is_none() {
101 Option::none()
102 } else {
103 other
104 }
105 }
106
107 /// If self is None, this returns None. Otherwise, this calls the given function
108 /// with the Some value contained within self, and returns the result of that call.
109 ///
110 /// In some languages this function is called `flat_map` or `bind`.
111 pub fn and_then<U, Env>(self, f: fn[Env](T) -> Option<U>) -> Option<U> {
112 if self._is_some {
113 f(self._value)
114 } else {
115 Option::none()
116 }
117 }
118
119 /// If self is Some, return self. Otherwise, return `other`.
120 pub fn or(self, other: Self) -> Self {
121 if self._is_some {
122 self
123 } else {
124 other
125 }
126 }
127
128 /// If self is Some, return self. Otherwise, return `default()`.
129 pub fn or_else<Env>(self, default: fn[Env]() -> Self) -> Self {
130 if self._is_some {
131 self
132 } else {
133 default()
134 }
135 }
136
137 // If only one of the two Options is Some, return that option.
138 // Otherwise, if both options are Some or both are None, None is returned.
139 pub fn xor(self, other: Self) -> Self {
140 if self._is_some {
141 if other._is_some {
142 Option::none()
143 } else {
144 self
145 }
146 } else if other._is_some {
147 other
148 } else {
149 Option::none()
150 }
151 }
152
153 /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.
154 /// Otherwise, this returns `None`
155 pub fn filter<Env>(self, predicate: fn[Env](T) -> bool) -> Self {
156 if self._is_some {
157 if predicate(self._value) {
158 self
159 } else {
160 Option::none()
161 }
162 } else {
163 Option::none()
164 }
165 }
166
167 /// Flattens an Option<Option<T>> into a Option<T>.
168 /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.
169 pub fn flatten(option: Option<Option<T>>) -> Option<T> {
170 if option._is_some {
171 option._value
172 } else {
173 Option::none()
174 }
175 }
176 }
177
178 impl<T> Default for Option<T> {
179 fn default() -> Self {
180 Option::none()
181 }
182 }
183
184 impl<T> Eq for Option<T>
185 where
186 T: Eq,
187 {
188 fn eq(self, other: Self) -> bool {
189 if self._is_some == other._is_some {
190 if self._is_some {
191 self._value == other._value
192 } else {
193 true
194 }
195 } else {
196 false
197 }
198 }
199 }
200
201 impl<T> Hash for Option<T>
202 where
203 T: Hash,
204 {
205 fn hash<H>(self, state: &mut H)
206 where
207 H: Hasher,
208 {
209 self._is_some.hash(state);
210 if self._is_some {
211 self._value.hash(state);
212 }
213 }
214 }
215
216 // For this impl we're declaring Option::none < Option::some
217 impl<T> Ord for Option<T>
218 where
219 T: Ord,
220 {
221 fn cmp(self, other: Self) -> Ordering {
222 if self._is_some {
223 if other._is_some {
224 self._value.cmp(other._value)
225 } else {
226 Ordering::greater()
227 }
228 } else if other._is_some {
229 Ordering::less()
230 } else {
231 Ordering::equal()
232 }
233 }
234 }
235
236 mod tests {
237 use crate::cmp::Ord;
238 use crate::cmp::Ordering;
239 use crate::default::Default as _;
240 use super::Option;
241
242 #[test]
243 fn some_and_none() {
244 assert(Option::<u8>::none().is_none());
245 assert(!Option::<u8>::none().is_some());
246 assert(Option::some(1).is_some());
247 assert(!Option::some(1).is_none());
248 }
249
250 #[test]
251 fn unwrap_succeeds() {
252 assert_eq(Option::some(1).unwrap(), 1);
253 }
254
255 #[test(should_fail)]
256 fn unwrap_fails() {
257 let _ = Option::<u8>::none().unwrap();
258 }
259
260 #[test]
261 fn unwrap_or() {
262 assert_eq(Option::some(1).unwrap_or(2), 1);
263 assert_eq(Option::none().unwrap_or(2), 2);
264 }
265
266 #[test]
267 fn unwrap_or_else() {
268 assert_eq(Option::some(1).unwrap_or_else(|| 2), 1);
269 assert_eq(Option::none().unwrap_or_else(|| 2), 2);
270 }
271
272 #[test]
273 fn expect_succeeds() {
274 assert_eq(Option::some(1).expect(f"Should be there"), 1);
275 }
276
277 #[test(should_fail_with = "Should be there")]
278 fn expect_fails() {
279 let _ = Option::<u8>::none().expect(f"Should be there");
280 }
281
282 #[test]
283 fn map() {
284 assert(Option::<u8>::none().map(|x| x + 1).is_none());
285 assert_eq(Option::some(1).map(|x| x + 1), Option::some(2));
286 }
287
288 #[test]
289 fn map_or() {
290 assert_eq(Option::<u8>::none().map_or(0, |x| x + 1), 0);
291 assert_eq(Option::some(1).map_or(0, |x| x + 1), 2);
292 }
293
294 #[test]
295 fn map_or_else() {
296 assert_eq(Option::<u8>::none().map_or_else(|| 0, |x| x + 1), 0);
297 assert_eq(Option::some(1).map_or_else(|| 0, |x| x + 1), 2);
298 }
299
300 #[test]
301 fn and() {
302 assert_eq(Option::<u8>::none().and(Option::none()), Option::none());
303 assert_eq(Option::<u8>::none().and(Option::some(1)), Option::none());
304 assert_eq(Option::some(1).and(Option::some(2)), Option::some(2));
305 assert_eq(Option::some(1).and(Option::none()), Option::none());
306 }
307
308 #[test]
309 fn and_then() {
310 assert_eq(Option::<u8>::none().and_then(|_| Option::<u8>::none()), Option::none());
311 assert_eq(Option::<u8>::none().and_then(|_| Option::some(1)), Option::none());
312 assert_eq(Option::some(1).and_then(|x| Option::some(x + 1)), Option::some(2));
313 assert_eq(Option::some(1).and_then(|_| Option::<u8>::none()), Option::none());
314 }
315
316 #[test]
317 fn or() {
318 assert_eq(Option::<u8>::none().or(Option::none()), Option::none());
319 assert_eq(Option::<u8>::none().or(Option::some(1)), Option::some(1));
320 assert_eq(Option::some(1).or(Option::some(2)), Option::some(1));
321 assert_eq(Option::some(1).or(Option::none()), Option::some(1));
322 }
323
324 #[test]
325 fn or_else() {
326 assert_eq(Option::<u8>::none().or_else(|| Option::none()), Option::none());
327 assert_eq(Option::<u8>::none().or_else(|| Option::some(1)), Option::some(1));
328 assert_eq(Option::some(1).or_else(|| Option::some(2)), Option::some(1));
329 assert_eq(Option::some(1).or_else(|| Option::none()), Option::some(1));
330 }
331
332 #[test]
333 fn xor() {
334 assert_eq(Option::<u8>::none().xor(Option::none()), Option::none());
335 assert_eq(Option::<u8>::none().xor(Option::some(1)), Option::some(1));
336 assert_eq(Option::some(1).xor(Option::some(2)), Option::none());
337 assert_eq(Option::some(1).xor(Option::none()), Option::some(1));
338 }
339
340 #[test]
341 fn filter() {
342 assert_eq(Option::<u8>::none().filter(|_| true), Option::none());
343 assert_eq(Option::some(1).filter(|x| x == 1), Option::some(1));
344 assert_eq(Option::some(1).filter(|x| x == 2), Option::none());
345 assert_eq(Option::some(1).filter(|x| x == 2), Option::none());
346 }
347
348 #[test]
349 fn flatten() {
350 assert_eq(Option::<Option<u8>>::none().flatten(), Option::none());
351 assert_eq(Option::some(Option::<u8>::none()).flatten(), Option::none());
352 assert_eq(Option::some(Option::some(1)).flatten(), Option::some(1));
353 }
354
355 #[test]
356 fn default() {
357 assert_eq(Option::<u8>::default(), Option::none());
358 }
359
360 #[test]
361 fn eq() {
362 assert(Option::<u8>::none() == Option::none());
363 assert(Option::<u8>::some(1) != Option::none());
364 assert(Option::<u8>::none() != Option::some(1));
365 assert(Option::<u8>::some(1) == Option::some(1));
366 assert(Option::<u8>::some(1) != Option::some(2));
367 }
368
369 #[test]
370 fn cmp() {
371 let none = Option::<u8>::none();
372 let one = Option::<u8>::some(1);
373 let two = Option::<u8>::some(2);
374 assert_eq(none.cmp(none), Ordering::equal());
375 assert_eq(none.cmp(one), Ordering::less());
376 assert_eq(one.cmp(none), Ordering::greater());
377 assert_eq(one.cmp(one), Ordering::equal());
378 assert_eq(one.cmp(two), Ordering::less());
379 assert_eq(two.cmp(one), Ordering::greater());
380 }
381 }
1 /// Halt the program at runtime with the given error message.
2 ///
3 /// The provided error message must be either a `str` or a `fmtstr`.
4 pub fn panic<T, U>(message: T) -> U
5 where
6 T: StringLike,
7 {
8 assert(false, message);
9 crate::mem::zeroed()
10 }
11
12 trait StringLike {}
13
14 impl<let N: u32> StringLike for str<N> {}
15 impl<let N: u32, T> StringLike for fmtstr<N, T> {}
16
17 mod tests {
18 use crate::prelude::panic;
19
20 #[test(should_fail_with = "OH NO")]
21 fn panics() {
22 panic("OH NO");
23 }
24 }
1 //! AVM oracles.
2 //!
3 //! There are only available during public execution. Calling any of them from a private or utility function will
4 //! result in runtime errors.
5
6 use crate::protocol::address::{AztecAddress, EthAddress};
7
8 pub unconstrained fn address() -> AztecAddress {
9· address_opcode()
10 }
11 pub unconstrained fn sender() -> AztecAddress {
12· sender_opcode()
13 }
14 pub unconstrained fn transaction_fee() -> Field {
15 transaction_fee_opcode()
16 }
17 pub unconstrained fn chain_id() -> Field {
18 chain_id_opcode()
19 }
20 pub unconstrained fn version() -> Field {
21 version_opcode()
22 }
23 pub unconstrained fn block_number() -> u32 {
24 block_number_opcode()
25 }
26 pub unconstrained fn timestamp() -> u64 {
27 timestamp_opcode()
28 }
29 pub unconstrained fn min_fee_per_l2_gas() -> u128 {
30 min_fee_per_l2_gas_opcode()
31 }
32 pub unconstrained fn min_fee_per_da_gas() -> u128 {
33 min_fee_per_da_gas_opcode()
34 }
35 pub unconstrained fn l2_gas_left() -> u32 {
36 l2_gas_left_opcode()
37 }
38 pub unconstrained fn da_gas_left() -> u32 {
39 da_gas_left_opcode()
40 }
41 pub unconstrained fn is_static_call() -> bool {
42 is_static_call_opcode()
43 }
44 pub unconstrained fn note_hash_exists(note_hash: Field, leaf_index: u64) -> bool {
45 note_hash_exists_opcode(note_hash, leaf_index)
46 }
47 pub unconstrained fn emit_note_hash(note_hash: Field) {
48 emit_note_hash_opcode(note_hash)
49 }
50 pub unconstrained fn nullifier_exists(siloed_nullifier: Field) -> bool {
51 nullifier_exists_opcode(siloed_nullifier)
52 }
53 pub unconstrained fn emit_nullifier(nullifier: Field) {
54 emit_nullifier_opcode(nullifier)
55 }
56 pub unconstrained fn emit_public_log(message: [Field]) {
57 emit_public_log_opcode(message)
58 }
59 pub unconstrained fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: u64) -> bool {
60 l1_to_l2_msg_exists_opcode(msg_hash, msg_leaf_index)
61 }
62 pub unconstrained fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {
63 send_l2_to_l1_msg_opcode(recipient, content)
64 }
65
66 pub unconstrained fn call<let N: u32>(
67 l2_gas_allocation: u32,
68 da_gas_allocation: u32,
69 address: AztecAddress,
70 args: [Field; N],
71 ) {
72 call_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)
73 }
74
75 pub unconstrained fn call_static<let N: u32>(
76 l2_gas_allocation: u32,
77 da_gas_allocation: u32,
78 address: AztecAddress,
79 args: [Field; N],
80 ) {
81 call_static_opcode(l2_gas_allocation, da_gas_allocation, address, N, args)
82 }
83
84 pub unconstrained fn calldata_copy<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {
85· calldata_copy_opcode(cdoffset, copy_size)
86 }
87
88 /// `success_copy` is placed immediately after the CALL opcode to get the success value
89 pub unconstrained fn success_copy() -> bool {
90 success_copy_opcode()
91 }
92
93 pub unconstrained fn returndata_size() -> u32 {
94 returndata_size_opcode()
95 }
96
97 pub unconstrained fn returndata_copy(rdoffset: u32, copy_size: u32) -> [Field] {
98 returndata_copy_opcode(rdoffset, copy_size)
99 }
100
101 /// The additional prefix is to avoid clashing with the `return` Noir keyword.
102 pub unconstrained fn avm_return(returndata: [Field]) {
103· return_opcode(returndata)
104 }
105
106 /// This opcode reverts using the exact data given. In general it should only be used to do rethrows, where the revert
107 /// data is the same as the original revert data. For normal reverts, use Noir's `assert` which, on top of reverting,
108 /// will also add an error selector to the revert data.
109 pub unconstrained fn revert(revertdata: [Field]) {
110 revert_opcode(revertdata)
111 }
112
113 pub unconstrained fn storage_read(storage_slot: Field, contract_address: Field) -> Field {
114· storage_read_opcode(storage_slot, contract_address)
115 }
116
117 pub unconstrained fn storage_write(storage_slot: Field, value: Field) {
118· storage_write_opcode(storage_slot, value);
119 }
120
121 #[oracle(aztec_avm_address)]
122 unconstrained fn address_opcode() -> AztecAddress {}
123
124 #[oracle(aztec_avm_sender)]
125 unconstrained fn sender_opcode() -> AztecAddress {}
126
127 #[oracle(aztec_avm_transactionFee)]
128 unconstrained fn transaction_fee_opcode() -> Field {}
129
130 #[oracle(aztec_avm_chainId)]
131 unconstrained fn chain_id_opcode() -> Field {}
132
133 #[oracle(aztec_avm_version)]
134 unconstrained fn version_opcode() -> Field {}
135
136 #[oracle(aztec_avm_blockNumber)]
137 unconstrained fn block_number_opcode() -> u32 {}
138
139 #[oracle(aztec_avm_timestamp)]
140 unconstrained fn timestamp_opcode() -> u64 {}
141
142 #[oracle(aztec_avm_minFeePerL2Gas)]
143 unconstrained fn min_fee_per_l2_gas_opcode() -> u128 {}
144
145 #[oracle(aztec_avm_minFeePerDaGas)]
146 unconstrained fn min_fee_per_da_gas_opcode() -> u128 {}
147
148 #[oracle(aztec_avm_l2GasLeft)]
149 unconstrained fn l2_gas_left_opcode() -> u32 {}
150
151 #[oracle(aztec_avm_daGasLeft)]
152 unconstrained fn da_gas_left_opcode() -> u32 {}
153
154 #[oracle(aztec_avm_isStaticCall)]
155 unconstrained fn is_static_call_opcode() -> bool {}
156
157 #[oracle(aztec_avm_noteHashExists)]
158 unconstrained fn note_hash_exists_opcode(note_hash: Field, leaf_index: u64) -> bool {}
159
160 #[oracle(aztec_avm_emitNoteHash)]
161 unconstrained fn emit_note_hash_opcode(note_hash: Field) {}
162
163 #[oracle(aztec_avm_nullifierExists)]
164 unconstrained fn nullifier_exists_opcode(siloed_nullifier: Field) -> bool {}
165
166 #[oracle(aztec_avm_emitNullifier)]
167 unconstrained fn emit_nullifier_opcode(nullifier: Field) {}
168
169 #[oracle(aztec_avm_emitPublicLog)]
170 unconstrained fn emit_public_log_opcode(message: [Field]) {}
171
172 #[oracle(aztec_avm_l1ToL2MsgExists)]
173 unconstrained fn l1_to_l2_msg_exists_opcode(msg_hash: Field, msg_leaf_index: u64) -> bool {}
174
175 #[oracle(aztec_avm_sendL2ToL1Msg)]
176 unconstrained fn send_l2_to_l1_msg_opcode(recipient: EthAddress, content: Field) {}
177
178 #[oracle(aztec_avm_calldataCopy)]
179 unconstrained fn calldata_copy_opcode<let N: u32>(cdoffset: u32, copy_size: u32) -> [Field; N] {}
180
181 #[oracle(aztec_avm_returndataSize)]
182 unconstrained fn returndata_size_opcode() -> u32 {}
183
184 #[oracle(aztec_avm_returndataCopy)]
185 unconstrained fn returndata_copy_opcode(rdoffset: u32, copy_size: u32) -> [Field] {}
186
187 #[oracle(aztec_avm_return)]
188 unconstrained fn return_opcode(returndata: [Field]) {}
189
190 #[oracle(aztec_avm_revert)]
191 unconstrained fn revert_opcode(revertdata: [Field]) {}
192
193 // While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode
194 // level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take
195 // that route.
196 #[oracle(aztec_avm_call)]
197 unconstrained fn call_opcode<let N: u32>(
198 l2_gas_allocation: u32,
199 da_gas_allocation: u32,
200 address: AztecAddress,
201 length: u32,
202 args: [Field; N],
203 ) {}
204
205 // While the length parameter might seem unnecessary given that we have N we keep it around because at the AVM bytecode
206 // level, we want to support non-comptime-known lengths for such opcodes, even if Noir code will not generally take
207 // that route.
208 #[oracle(aztec_avm_staticCall)]
209 unconstrained fn call_static_opcode<let N: u32>(
210 l2_gas_allocation: u32,
211 da_gas_allocation: u32,
212 address: AztecAddress,
213 length: u32,
214 args: [Field; N],
215 ) {}
216
217 #[oracle(aztec_avm_successCopy)]
218 unconstrained fn success_copy_opcode() -> bool {}
219
220 #[oracle(aztec_avm_storageRead)]
221 unconstrained fn storage_read_opcode(storage_slot: Field, contract_address: Field) -> Field {}
222
223 #[oracle(aztec_avm_storageWrite)]
224 unconstrained fn storage_write_opcode(storage_slot: Field, value: Field) {}
Event Log

Calls and storage writes are recorded against the step they happened on. 86 of this recording's 459 steps carry a source position; the rest are compiler-generated code the artifact maps no line for.

Call Trace
FunctionCallsSelf
<toplevel>10
enqueued-call-010
FeeJuice::public_dispatch10
calldata_copy10
derive_deserialize10
<impl Deserialize for Field>::stream_deserialize10
Reader<N>::read20
<impl Deserialize for u128>::stream_deserialize10
FeeJuice::_increase_public_balance10
PublicContext::maybe_msg_sender10
sender20
derive_eq10
Option<T>::unwrap10
PublicContext::this_address20
address20
Map<K, V, Context>::at20
derive_storage_slot_in_map20
poseidon2_hash_with_separator20
poseidon2_hash20
Poseidon2::hash20
Poseidon2::hash_internal20
poseidon2_permutation20
<impl StateVariable<M, Context> for PublicMutable<T, Context>>::new10
PublicMutable<T, PublicContext>::read10
PublicContext::storage_read10
PublicContext::raw_storage_read10
storage_read10
<impl Packable for u128>::unpack10
<impl Add for u128>::add10
PublicMutable<T, PublicContext>::write10
PublicContext::storage_write10
<impl Packable for u128>::pack10
PublicContext::raw_storage_write10
storage_write10
avm_return10
context210
By function — self cost, callees excluded.Call order
Frame
<toplevel>
enqueued-call-0
FeeJuice::public_dispatch:203
calldata_copy:85
derive_deserialize:260
<impl Deserialize for Field>::stream_deserialize:230
Reader<N>::read:12
<impl Deserialize for u128>::stream_deserialize:199
Reader<N>::read:12
FeeJuice::_increase_public_balance:149
PublicContext::maybe_msg_sender:182
sender:12
derive_eq:15
sender:12
Option<T>::unwrap:35
PublicContext::this_address:175
address:9
Map<K, V, Context>::at:36
derive_storage_slot_in_map:11
poseidon2_hash_with_separator:221
poseidon2_hash:212
Poseidon2::hash:162 frames · 22 steps
Poseidon2::hash_internal:68
poseidon2_permutation:125
<impl StateVariable<M, Context> for PublicMutable<T, Context>>::new:19
PublicMutable<T, PublicContext>::read:34
PublicContext::storage_read:302
PublicContext::raw_storage_read:291
PublicContext::this_address:175
address:9
storage_read:114
<impl Packable for u128>::unpack:103
<impl Add for u128>::add:17
Map<K, V, Context>::at:36
derive_storage_slot_in_map:11
poseidon2_hash_with_separator:221
poseidon2_hash:212
Poseidon2::hash:162 frames · 6 steps
Poseidon2::hash_internal:68
poseidon2_permutation:125
PublicMutable<T, PublicContext>::write:42
PublicContext::storage_write:318
<impl Packable for u128>::pack:98
PublicContext::raw_storage_write:309
storage_write:118
avm_return:103
context2
By call order.Self cost
Values

This recording carries no variable names. The contract's artifact resolved and its debug symbols carry the source map, but their variable table is empty — Aztec publishes these contracts compiled without variable debug information, so there are no locals to name.