o1_utils/
foreign_field.rs1use crate::field_helpers::FieldHelpers;
7use ark_ff::{Field, PrimeField};
8use num_bigint::BigUint;
9use std::{
10    fmt::{Debug, Formatter},
11    ops::{Index, IndexMut},
12};
13
14#[derive(Clone, PartialEq, Eq)]
16pub struct ForeignElement<F: Field, const B: usize, const N: usize> {
18    pub limbs: [F; N],
20    len: usize,
22}
23
24impl<F: Field, const B: usize, const N: usize> ForeignElement<F, B, N> {
25    pub fn new(limbs: [F; N]) -> Self {
27        Self { limbs, len: N }
28    }
29
30    pub fn zero() -> Self {
32        Self {
33            limbs: [F::zero(); N],
34            len: N,
35        }
36    }
37
38    pub fn from_biguint(big: BigUint) -> Self {
41        let vec = ForeignElement::<F, B, N>::big_to_vec(big);
42
43        if vec.len() > N {
47            panic!("BigUint element is too large for N limbs");
48        }
49
50        let mut limbs = [F::zero(); N];
51        for (i, term) in vec.iter().enumerate() {
52            limbs[i] = *term;
53        }
54
55        Self {
56            limbs,
57            len: limbs.len(),
58        }
59    }
60
61    pub fn neg(&self, modulus: &BigUint) -> Self {
66        let big = self.to_biguint();
67        let ok = big % modulus;
68        let neg = modulus - ok;
69        Self::from_biguint(neg)
70    }
71
72    pub fn from_be(bytes: &[u8]) -> Self {
74        Self::from_biguint(BigUint::from_bytes_be(bytes))
75    }
76
77    pub fn to_biguint(&self) -> BigUint {
79        let mut bytes = vec![];
80        if B % 8 == 0 {
81            for limb in self.limbs {
83                let crumb = &limb.to_bytes()[0..B / 8];
84                bytes.extend_from_slice(crumb);
85            }
86        } else {
87            let mut bits: Vec<bool> = vec![];
88            for limb in self.limbs {
89                let f_bits_lower: Vec<bool> = limb.to_bits().into_iter().take(B).collect();
91                bits.extend(&f_bits_lower);
92            }
93
94            let bytes_len = if (B * N) % 8 == 0 {
95                (B * N) / 8
96            } else {
97                ((B * N) / 8) + 1
98            };
99            bytes = vec![0u8; bytes_len];
100            for i in 0..bits.len() {
101                bytes[i / 8] |= u8::from(bits[i]) << (i % 8);
102            }
103        }
104        BigUint::from_bytes_le(&bytes)
105    }
106
107    fn big_to_vec(fe: BigUint) -> Vec<F> {
111        if B % 8 == 0 {
112            let bytes = fe.to_bytes_le();
113            let chunks: Vec<&[u8]> = bytes.chunks(B / 8).collect();
114            chunks
115                .iter()
116                .map(|chunk| F::from_random_bytes(chunk).expect("failed to deserialize"))
117                .collect()
118        } else {
119            let mut bits = vec![]; assert!(
122                fe.bits() <= (B * N) as u64,
123                "BigUint too big to be represented in B*N elements"
124            );
125            for i in 0..B * N {
126                bits.push(fe.bit(i as u64));
127            }
128            let chunks: Vec<_> = bits.chunks(B).collect();
129            chunks
130                .into_iter()
131                .map(|chunk| F::from_bits(chunk).expect("failed to deserialize"))
132                .collect()
133        }
134    }
135}
136
137impl<F: PrimeField, const B: usize, const N: usize> ForeignElement<F, B, N> {
138    pub fn from_field(field: F) -> Self {
140        Self::from_biguint(field.into())
141    }
142}
143
144impl<F: Field, const B: usize, const N: usize> Index<usize> for ForeignElement<F, B, N> {
145    type Output = F;
146    fn index(&self, idx: usize) -> &Self::Output {
147        &self.limbs[idx]
148    }
149}
150
151impl<F: Field, const B: usize, const N: usize> IndexMut<usize> for ForeignElement<F, B, N> {
152    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
153        &mut self.limbs[idx]
154    }
155}
156
157impl<F: Field, const B: usize, const N: usize> Debug for ForeignElement<F, B, N> {
158    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159        write!(f, "ForeignElement(")?;
160        for i in 0..self.len {
161            write!(f, "{:?}", self.limbs[i].to_hex())?;
162            if i != self.len - 1 {
163                write!(f, ", ")?;
164            }
165        }
166        write!(f, ")")
167    }
168}
169
170pub trait ForeignFieldHelpers<F, const B: usize> {
172    fn two_to_limb() -> F;
174
175    fn two_to_2limb() -> F;
177
178    fn two_to_3limb() -> F;
180}
181
182impl<F: Field, const B: usize, const N: usize> ForeignFieldHelpers<F, B>
183    for ForeignElement<F, B, N>
184{
185    fn two_to_limb() -> F {
186        F::from(2u64).pow([B as u64])
187    }
188
189    fn two_to_2limb() -> F {
190        F::from(2u64).pow([2 * B as u64])
191    }
192
193    fn two_to_3limb() -> F {
194        F::from(2u64).pow([3 * B as u64])
196    }
197}