1use alloc::vec::Vec;
2
3use paste::paste;
4
5use super::{
6 super::utils::{split_element, split_u32_into_u16},
7 ExecutionError, Felt, FieldElement, Operation, Process,
8};
9use crate::{ErrorContext, ZERO};
10
11const U32_MAX: u64 = u32::MAX as u64;
12
13macro_rules! require_u32_operands {
14 ($stack:expr, [$($idx:expr),*], $err_ctx:expr) => {
15 require_u32_operands!($stack, [$($idx),*], ZERO, $err_ctx)
16 };
17 ($stack:expr, [$($idx:expr),*], $errno:expr, $err_ctx:expr) => {{
18 paste!{
19 let mut invalid_values = Vec::new();
20
21 $(
22 let [<_operand_ $idx>] = $stack.get($idx);
23 if [<_operand_ $idx>].as_int() > U32_MAX {
24 invalid_values.push([<_operand_ $idx>]);
25 }
26 )*
27
28 if !invalid_values.is_empty() {
29 return Err(ExecutionError::not_u32_values(invalid_values, $errno, $err_ctx));
30 }
31 ($([<_operand_ $idx>].as_int()),*)
33 }
34 }};
35}
36
37impl Process {
38 pub(super) fn op_u32split(&mut self) -> Result<(), ExecutionError> {
44 let a = self.stack.get(0);
45 let (hi, lo) = split_element(a);
46
47 self.add_range_checks(Operation::U32split, lo, hi, true);
48
49 self.stack.set(0, hi);
50 self.stack.set(1, lo);
51 self.stack.shift_right(1);
52 Ok(())
53 }
54
55 pub(super) fn op_u32assert2(
59 &mut self,
60 err_code: Felt,
61 err_ctx: &impl ErrorContext,
62 ) -> Result<(), ExecutionError> {
63 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_code, err_ctx);
64
65 self.add_range_checks(Operation::U32assert2(err_code), Felt::new(a), Felt::new(b), false);
66
67 self.stack.copy_state(0);
68 Ok(())
69 }
70
71 pub(super) fn op_u32add(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
77 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
78
79 let result = Felt::new(a + b);
80 let (hi, lo) = split_element(result);
81 self.add_range_checks(Operation::U32add, lo, hi, false);
82
83 self.stack.set(0, hi);
84 self.stack.set(1, lo);
85 self.stack.copy_state(2);
86 Ok(())
87 }
88
89 pub(super) fn op_u32add3(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
92 let (c, b, a) = require_u32_operands!(self.stack, [0, 1, 2], err_ctx);
93 let result = Felt::new(a + b + c);
94 let (hi, lo) = split_element(result);
95
96 self.add_range_checks(Operation::U32add3, lo, hi, false);
97
98 self.stack.set(0, hi);
99 self.stack.set(1, lo);
100 self.stack.shift_left(3);
101 Ok(())
102 }
103
104 pub(super) fn op_u32sub(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
108 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
109 let result = a.wrapping_sub(b);
110 let d = Felt::new(result >> 63);
111 let c = Felt::new(result & U32_MAX);
112
113 self.add_range_checks(Operation::U32sub, c, ZERO, false);
117
118 self.stack.set(0, d);
119 self.stack.set(1, c);
120 self.stack.copy_state(2);
121 Ok(())
122 }
123
124 pub(super) fn op_u32mul(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
127 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
128 let result = Felt::new(a * b);
129 let (hi, lo) = split_element(result);
130
131 self.add_range_checks(Operation::U32mul, lo, hi, true);
132
133 self.stack.set(0, hi);
134 self.stack.set(1, lo);
135 self.stack.copy_state(2);
136 Ok(())
137 }
138
139 pub(super) fn op_u32madd(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
143 let (b, a, c) = require_u32_operands!(self.stack, [0, 1, 2], err_ctx);
144 let result = Felt::new(a * b + c);
145 let (hi, lo) = split_element(result);
146
147 self.add_range_checks(Operation::U32madd, lo, hi, true);
148
149 self.stack.set(0, hi);
150 self.stack.set(1, lo);
151 self.stack.shift_left(3);
152 Ok(())
153 }
154
155 pub(super) fn op_u32div(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
161 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
162
163 if b == 0 {
164 return Err(ExecutionError::divide_by_zero(self.system.clk(), err_ctx));
165 }
166
167 let q = a / b;
168 let r = a - q * b;
169
170 let lo = Felt::new(a - q);
172 let hi = Felt::new(b - r - 1);
174 self.add_range_checks(Operation::U32div, lo, hi, false);
175
176 self.stack.set(0, Felt::new(r));
177 self.stack.set(1, Felt::new(q));
178 self.stack.copy_state(2);
179 Ok(())
180 }
181
182 pub(super) fn op_u32and(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
188 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
189 let result = self.chiplets.bitwise.u32and(Felt::new(a), Felt::new(b), err_ctx)?;
190
191 self.stack.set(0, result);
192 self.stack.shift_left(2);
193
194 Ok(())
195 }
196
197 pub(super) fn op_u32xor(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
200 let (b, a) = require_u32_operands!(self.stack, [0, 1], err_ctx);
201 let result = self.chiplets.bitwise.u32xor(Felt::new(a), Felt::new(b), err_ctx)?;
202
203 self.stack.set(0, result);
204 self.stack.shift_left(2);
205
206 Ok(())
207 }
208
209 fn add_range_checks(
218 &mut self,
219 op: Operation,
220 lo: Felt,
221 hi: Felt,
222 check_element_validity: bool,
223 ) {
224 let (t1, t0) = split_u32_into_u16(lo.as_int());
225 let (t3, t2) = split_u32_into_u16(hi.as_int());
226
227 self.range.add_range_checks(self.system.clk(), &[t0, t1, t2, t3]);
229
230 let mut helper_values =
232 [Felt::from(t0), Felt::from(t1), Felt::from(t2), Felt::from(t3), ZERO];
233
234 if check_element_validity {
235 let m = (Felt::from(u32::MAX) - hi).inv();
236 helper_values[4] = m;
237 }
238
239 self.decoder.set_user_op_helpers(op, &helper_values);
240 }
241}
242
243#[cfg(test)]
247mod tests {
248 use miden_air::trace::decoder::NUM_USER_OP_HELPERS;
249 use miden_core::{mast::MastForest, stack::MIN_STACK_DEPTH};
250 use miden_utils_testing::rand::rand_value;
251
252 use super::{
253 super::{Felt, Operation},
254 Process, split_u32_into_u16,
255 };
256 use crate::{DefaultHost, ExecutionError, StackInputs, ZERO};
257
258 #[test]
262 fn op_u32split() {
263 let mut host = DefaultHost::default();
265 let program = &MastForest::default();
266
267 let a: u64 = rand_value();
268 let stack = StackInputs::try_from_ints([a]).unwrap();
269 let mut process = Process::new_dummy_with_decoder_helpers(stack);
270 let hi = a >> 32;
271 let lo = (a as u32) as u64;
272
273 process.execute_op(Operation::U32split, program, &mut host).unwrap();
274 let mut expected = [ZERO; 16];
275 expected[0] = Felt::new(hi);
276 expected[1] = Felt::new(lo);
277 assert_eq!(expected, process.stack.trace_state());
278
279 let b: u64 = rand_value();
281 let stack = StackInputs::try_from_ints([a, b]).unwrap();
282 let mut process = Process::new_dummy_with_decoder_helpers(stack);
283 let hi = b >> 32;
284 let lo = (b as u32) as u64;
285
286 process.execute_op(Operation::U32split, program, &mut host).unwrap();
287 let mut expected = [ZERO; 16];
288 expected[0] = Felt::new(hi);
289 expected[1] = Felt::new(lo);
290 expected[2] = Felt::new(a);
291 assert_eq!(expected, process.stack.trace_state());
292 }
293
294 #[test]
295 fn op_u32assert2() {
296 let mut host = DefaultHost::default();
298 let program = &MastForest::default();
299
300 let (a, b, c, d) = get_rand_values();
301 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
302 let mut process = Process::new_dummy_with_decoder_helpers(stack);
303
304 process.execute_op(Operation::U32assert2(ZERO), program, &mut host).unwrap();
305 let expected = build_expected(&[a, b, c, d]);
306 assert_eq!(expected, process.stack.trace_state());
307 }
308
309 #[test]
310 fn op_u32assert2_both_invalid() {
311 let mut host = DefaultHost::default();
312 let program = &MastForest::default();
313
314 let stack = StackInputs::try_from_ints([4294967297u64, 4294967296u64]).unwrap();
316 let mut process = Process::new_dummy_with_decoder_helpers(stack);
317
318 let result =
319 process.execute_op(Operation::U32assert2(Felt::from(123u32)), program, &mut host);
320 assert!(result.is_err());
321
322 if let Err(ExecutionError::NotU32Values { values, err_code, .. }) = result {
323 assert_eq!(err_code, Felt::from(123u32));
324 assert_eq!(values.len(), 2);
325 assert_eq!(values[0].as_int(), 4294967296u64); assert_eq!(values[1].as_int(), 4294967297u64); } else {
329 panic!("Expected NotU32Values error");
330 }
331 }
332
333 #[test]
334 fn op_u32assert2_second_invalid() {
335 let mut host = DefaultHost::default();
336 let program = &MastForest::default();
337
338 let stack = StackInputs::try_from_ints([4294967297u64, 1000u64]).unwrap();
340 let mut process = Process::new_dummy_with_decoder_helpers(stack);
341
342 let result =
343 process.execute_op(Operation::U32assert2(Felt::from(456u32)), program, &mut host);
344 assert!(result.is_err());
345
346 if let Err(ExecutionError::NotU32Values { values, err_code, .. }) = result {
347 assert_eq!(err_code, Felt::from(456u32));
348 assert_eq!(values.len(), 1);
349 assert_eq!(values[0].as_int(), 4294967297u64);
350 } else {
351 panic!("Expected NotU32Values error");
352 }
353 }
354
355 #[test]
356 fn op_u32assert2_first_invalid() {
357 let mut host = DefaultHost::default();
358 let program = &MastForest::default();
359
360 let stack = StackInputs::try_from_ints([2000u64, 4294967296u64]).unwrap();
362 let mut process = Process::new_dummy_with_decoder_helpers(stack);
363
364 let result =
365 process.execute_op(Operation::U32assert2(Felt::from(789u32)), program, &mut host);
366 assert!(result.is_err());
367
368 if let Err(ExecutionError::NotU32Values { values, err_code, .. }) = result {
369 assert_eq!(err_code, Felt::from(789u32));
370 assert_eq!(values.len(), 1);
371 assert_eq!(values[0].as_int(), 4294967296u64);
372 } else {
373 panic!("Expected NotU32Values error");
374 }
375 }
376
377 #[test]
381 fn op_u32add() {
382 let mut host = DefaultHost::default();
384 let (a, b, c, d) = get_rand_values();
385 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
386 let mut process = Process::new_dummy_with_decoder_helpers(stack);
387 let program = &MastForest::default();
388
389 let (result, over) = a.overflowing_add(b);
390
391 process.execute_op(Operation::U32add, program, &mut host).unwrap();
392 let expected = build_expected(&[over as u32, result, c, d]);
393 assert_eq!(expected, process.stack.trace_state());
394
395 let a = u32::MAX - 1;
397 let b = 2u32;
398
399 let stack = StackInputs::try_from_ints([a as u64, b as u64]).unwrap();
400 let mut process = Process::new_dummy_with_decoder_helpers(stack);
401 let (result, over) = a.overflowing_add(b);
402 let (b1, b0) = split_u32_into_u16(result.into());
403
404 process.execute_op(Operation::U32add, program, &mut host).unwrap();
405 let expected = build_expected(&[over as u32, result]);
406 assert_eq!(expected, process.stack.trace_state());
407
408 let expected_helper_registers =
409 build_expected_helper_registers(&[b0 as u32, b1 as u32, over as u32]);
410 assert_eq!(expected_helper_registers, process.decoder.get_user_op_helpers());
411 }
412
413 #[test]
414 fn op_u32add3() {
415 let mut host = DefaultHost::default();
416 let a = rand_value::<u32>() as u64;
417 let b = rand_value::<u32>() as u64;
418 let c = rand_value::<u32>() as u64;
419 let d = rand_value::<u32>() as u64;
420
421 let stack = StackInputs::try_from_ints([d, c, b, a]).unwrap();
422 let mut process = Process::new_dummy_with_decoder_helpers(stack);
423 let program = &MastForest::default();
424
425 let result = a + b + c;
426 let hi = (result >> 32) as u32;
427 let lo = result as u32;
428 assert!(hi <= 2);
429
430 process.execute_op(Operation::U32add3, program, &mut host).unwrap();
431 let expected = build_expected(&[hi, lo, d as u32]);
432 assert_eq!(expected, process.stack.trace_state());
433
434 let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack();
436 assert!(process.execute_op(Operation::U32add3, program, &mut host).is_ok());
437 }
438
439 #[test]
440 fn op_u32sub() {
441 let mut host = DefaultHost::default();
443 let program = &MastForest::default();
444
445 let (a, b, c, d) = get_rand_values();
446 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
447 let mut process = Process::new_dummy_with_decoder_helpers(stack);
448 let (result, under) = b.overflowing_sub(a);
449
450 process.execute_op(Operation::U32sub, program, &mut host).unwrap();
451 let expected = build_expected(&[under as u32, result, c, d]);
452 assert_eq!(expected, process.stack.trace_state());
453
454 let a = 10u32;
456 let b = 11u32;
457
458 let stack = StackInputs::try_from_ints([a as u64, b as u64]).unwrap();
459 let mut process = Process::new_dummy_with_decoder_helpers(stack);
460 let (result, under) = a.overflowing_sub(b);
461
462 process.execute_op(Operation::U32sub, program, &mut host).unwrap();
463 let expected = build_expected(&[under as u32, result]);
464 assert_eq!(expected, process.stack.trace_state());
465 }
466
467 #[test]
468 fn op_u32mul() {
469 let mut host = DefaultHost::default();
470 let program = &MastForest::default();
471
472 let (a, b, c, d) = get_rand_values();
473 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
474 let mut process = Process::new_dummy_with_decoder_helpers(stack);
475 let result = (a as u64) * (b as u64);
476 let hi = (result >> 32) as u32;
477 let lo = result as u32;
478
479 process.execute_op(Operation::U32mul, program, &mut host).unwrap();
480 let expected = build_expected(&[hi, lo, c, d]);
481 assert_eq!(expected, process.stack.trace_state());
482 }
483
484 #[test]
485 fn op_u32madd() {
486 let mut host = DefaultHost::default();
487 let program = &MastForest::default();
488
489 let (a, b, c, d) = get_rand_values();
490 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
491 let mut process = Process::new_dummy_with_decoder_helpers(stack);
492 let result = (a as u64) * (b as u64) + (c as u64);
493 let hi = (result >> 32) as u32;
494 let lo = result as u32;
495
496 process.execute_op(Operation::U32madd, program, &mut host).unwrap();
497 let expected = build_expected(&[hi, lo, d]);
498 assert_eq!(expected, process.stack.trace_state());
499
500 let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack();
502 assert!(process.execute_op(Operation::U32madd, program, &mut host).is_ok());
503 }
504
505 #[test]
506 fn op_u32div() {
507 let mut host = DefaultHost::default();
508 let program = &MastForest::default();
509
510 let (a, b, c, d) = get_rand_values();
511 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
512 let mut process = Process::new_dummy_with_decoder_helpers(stack);
513 let q = b / a;
514 let r = b % a;
515
516 process.execute_op(Operation::U32div, program, &mut host).unwrap();
517 let expected = build_expected(&[r, q, c, d]);
518 assert_eq!(expected, process.stack.trace_state());
519 }
520
521 #[test]
525 fn op_u32and() {
526 let mut host = DefaultHost::default();
527 let (a, b, c, d) = get_rand_values();
528 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
529 let mut process = Process::new_dummy_with_decoder_helpers(stack);
530 let program = &MastForest::default();
531
532 process.execute_op(Operation::U32and, program, &mut host).unwrap();
533 let expected = build_expected(&[a & b, c, d]);
534 assert_eq!(expected, process.stack.trace_state());
535
536 let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack();
538 assert!(process.execute_op(Operation::U32and, program, &mut host).is_ok());
539 }
540
541 #[test]
542 fn op_u32xor() {
543 let mut host = DefaultHost::default();
544 let (a, b, c, d) = get_rand_values();
545 let stack = StackInputs::try_from_ints([d as u64, c as u64, b as u64, a as u64]).unwrap();
546 let mut process = Process::new_dummy_with_decoder_helpers(stack);
547 let program = &MastForest::default();
548
549 process.execute_op(Operation::U32xor, program, &mut host).unwrap();
550 let expected = build_expected(&[a ^ b, c, d]);
551 assert_eq!(expected, process.stack.trace_state());
552
553 let mut process = Process::new_dummy_with_decoder_helpers_and_empty_stack();
555 assert!(process.execute_op(Operation::U32xor, program, &mut host).is_ok());
556 }
557
558 fn get_rand_values() -> (u32, u32, u32, u32) {
562 let a = rand_value::<u64>() as u32;
563 let b = rand_value::<u64>() as u32;
564 let c = rand_value::<u64>() as u32;
565 let d = rand_value::<u64>() as u32;
566 (d, c, b, a)
567 }
568
569 fn build_expected(values: &[u32]) -> [Felt; MIN_STACK_DEPTH] {
570 let mut expected = [ZERO; MIN_STACK_DEPTH];
571 for (&value, result) in values.iter().zip(expected.iter_mut()) {
572 *result = Felt::new(value as u64);
573 }
574 expected
575 }
576
577 fn build_expected_helper_registers(values: &[u32]) -> [Felt; NUM_USER_OP_HELPERS] {
578 let mut expected = [ZERO; NUM_USER_OP_HELPERS];
579 for (&value, result) in values.iter().zip(expected.iter_mut()) {
580 *result = Felt::new(value as u64);
581 }
582 expected
583 }
584}