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