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