openvm_bigint_guest/
utils.rs

1#[cfg(not(target_os = "zkvm"))]
2use num_bigint::BigInt;
3
4#[inline]
5#[cfg(not(target_os = "zkvm"))]
6#[allow(dead_code)]
7/// Convert a `BigInt` to a `[u8; NUM_LIMBS]` in two's complement little-endian format.
8pub(super) fn bigint_to_limbs<const NUM_LIMBS: usize>(x: &BigInt) -> [u8; NUM_LIMBS] {
9    let mut sm = x.to_signed_bytes_le();
10    let mut ext = 0;
11    if let Some(last) = sm.last() {
12        if (*last as i8) < 0 {
13            ext = u8::MAX;
14        }
15    }
16    sm.resize(NUM_LIMBS, ext);
17    sm.try_into().unwrap()
18}
19
20/// A macro that implements all the following for the given struct and operation:
21/// a op= b, a op= &b, a op b, a op &b, &a op b, &a op &b
22/// Description of the parameters (see [u256.rs] for an example):
23/// - $struct_name: The struct to implement the operation for.
24/// - $trait_name: The trait name of the operation to implement.
25/// - $trait_assign_name: The trait name of the assignment operation to implement.
26/// - $trait_fn: The trait function name to implement.
27/// - $trait_assign_fn: The assignment trait function name to implement.
28/// - $opcode: The custom opcode of the operation in openvm.
29/// - $func3: The func3 of the operation in openvm.
30/// - $func7: The func7 of the operation in openvm.
31/// - $op_sym: The symbol to use for the operation.
32/// - $rust_expr: A closure to get the result of the operation if target is non-zkvm.
33#[macro_export]
34macro_rules! impl_bin_op {
35    ($struct_name:ty, $trait_name:ident,
36        $trait_assign_name:ident, $trait_fn:ident,
37        $trait_assign_fn:ident, $opcode:expr,
38        $func3:expr, $func7:expr, $op_sym:tt,
39        $rust_expr:expr) => {
40        impl<'a> $trait_assign_name<&'a $struct_name> for $struct_name {
41            #[inline(always)]
42            fn $trait_assign_fn(&mut self, rhs: &'a $struct_name) {
43                #[cfg(target_os = "zkvm")]
44                custom_insn_r!(
45                    opcode = $opcode,
46                    funct3 = $func3,
47                    funct7 = $func7,
48                    rd = In self as *mut Self,
49                    rs1 = In self as *const Self,
50                    rs2 = In rhs as *const Self
51                );
52                #[cfg(not(target_os = "zkvm"))]
53                {
54                    *self = $rust_expr(self, rhs);
55                }
56            }
57        }
58
59        impl $trait_assign_name<$struct_name> for $struct_name {
60            #[inline(always)]
61            fn $trait_assign_fn(&mut self, rhs: $struct_name) {
62                *self $op_sym &rhs;
63            }
64        }
65
66        impl<'a> $trait_name<&'a $struct_name> for &$struct_name {
67            type Output = $struct_name;
68            #[inline(always)]
69            fn $trait_fn(self, rhs: &'a $struct_name) -> Self::Output {
70                #[cfg(target_os = "zkvm")]
71                {
72                    let mut uninit: MaybeUninit<$struct_name> = MaybeUninit::uninit();
73                    custom_insn_r!(
74                        opcode = $opcode,
75                        funct3 = $func3,
76                        funct7 = $func7,
77                        rd = In uninit.as_mut_ptr(),
78                        rs1 = In self as *const $struct_name,
79                        rs2 = In rhs as *const $struct_name
80                    );
81                    unsafe { uninit.assume_init() }
82                }
83                #[cfg(not(target_os = "zkvm"))]
84                return $rust_expr(self, rhs);
85            }
86        }
87
88        impl<'a> $trait_name<&'a $struct_name> for $struct_name {
89            type Output = $struct_name;
90            #[inline(always)]
91            fn $trait_fn(mut self, rhs: &'a $struct_name) -> Self::Output {
92                self $op_sym rhs;
93                self
94            }
95        }
96
97        impl $trait_name<$struct_name> for $struct_name {
98            type Output = $struct_name;
99            #[inline(always)]
100            fn $trait_fn(mut self, rhs: $struct_name) -> Self::Output {
101                self $op_sym &rhs;
102                self
103            }
104        }
105
106        impl $trait_name<$struct_name> for &$struct_name {
107            type Output = $struct_name;
108            #[inline(always)]
109            fn $trait_fn(self, mut rhs: $struct_name) -> Self::Output {
110                rhs $op_sym self;
111                rhs
112            }
113        }
114    };
115}