1#[cfg(test)]
16#[cfg(feature = "num-bigint-dig")]
17extern crate num_bigint_dig as num_bigint;
18
19pub mod ec;
20pub mod ffi;
21pub mod field;
22pub mod rsa;
23
24pub(crate) const WORD_SIZE: usize = 4;
25
26pub trait ToBigInt2Buffer<const WIDTH: usize> {
28 fn to_u32_array(&self) -> [u32; WIDTH];
30
31 fn from_u32_array(array: [u32; WIDTH]) -> Self;
33}
34
35#[inline]
36fn is_less<const N: usize>(lhs: &[u32; N], rhs: &[u32; N]) -> bool {
38 for i in (0..N).rev() {
39 if lhs[i] < rhs[i] {
40 return true;
41 }
42 if lhs[i] > rhs[i] {
43 return false;
44 }
45 }
46 false
47}
48
49#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))]
50const _: () = {
51 assert!(
52 core::option_env!("RISC0_FEATURE_bigint2").is_some(),
53 r#"
54RISC Zero zkVM feature bigint2 is not available, and is required by this crate.
55
56If you'd like to use bigint2, please upgrade to risc0-zkvm and risc0-build and ensure the required
57feature flags are enabled. See the RISC Zero dev docs for more information.
58https://dev.risczero.com/api/zkvm/acceleration
59"#
60 );
61};
62
63#[cfg(feature = "num-bigint")]
64impl<const WIDTH: usize> ToBigInt2Buffer<WIDTH> for num_bigint::BigUint {
65 fn to_u32_array(&self) -> [u32; WIDTH] {
66 let digits = self.to_u32_digits();
67 assert!(
68 digits.len() <= WIDTH,
69 "Input too large: {} words exceeds width of {} words",
70 digits.len(),
71 WIDTH,
72 );
73
74 let mut result = [0u32; WIDTH];
75 result[..digits.len()].copy_from_slice(&digits);
76 result
77 }
78
79 fn from_u32_array(array: [u32; WIDTH]) -> Self {
80 Self::from_slice(&array)
81 }
82}
83
84#[cfg(feature = "num-bigint-dig")]
85impl<const WIDTH: usize> ToBigInt2Buffer<WIDTH> for num_bigint_dig::BigUint {
86 fn to_u32_array(&self) -> [u32; WIDTH] {
87 let mut result = [0u32; WIDTH];
88 let bytes = self.to_bytes_le();
89 let max_width = WIDTH * 4;
90 assert!(
91 bytes.len() <= max_width,
92 "Input too large: {} bytes exceeds width of {} bytes",
93 bytes.len(),
94 max_width,
95 );
96
97 let mut chunks = bytes.chunks_exact(WORD_SIZE);
98 for (i, chunk) in chunks.by_ref().enumerate() {
99 result[i] = u32::from_le_bytes(chunk.try_into().unwrap());
100 }
101
102 let remainder = chunks.remainder();
103 if !remainder.is_empty() {
104 let idx = bytes.len() / WORD_SIZE;
105 let mut word = 0u32;
106 for (i, &byte) in remainder.iter().enumerate() {
107 word |= (byte as u32) << (i * 8);
108 }
109 result[idx] = word;
110 }
111
112 result
113 }
114
115 fn from_u32_array(array: [u32; WIDTH]) -> Self {
116 Self::from_slice(&array)
117 }
118}
119
120#[cfg(test)]
121struct BigUintWrap(num_bigint::BigUint);
122
123#[cfg(test)]
124impl std::str::FromStr for BigUintWrap {
125 type Err = num_bigint::ParseBigIntError;
126
127 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
128 use num_traits::Num as _;
129 Ok(BigUintWrap(num_bigint::BigUint::from_str_radix(s, 16)?))
130 }
131}