Skip to main content

ark_r1cs_std/fields/
mod.rs

1use ark_ff::{prelude::*, BitIteratorBE};
2use ark_relations::gr1cs::{ConstraintSystemRef, SynthesisError};
3use core::{
4    fmt::Debug,
5    iter::Sum,
6    ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
7};
8
9use crate::{
10    convert::{ToBitsGadget, ToBytesGadget, ToConstraintFieldGadget},
11    prelude::*,
12};
13
14/// This module contains a generic implementation of cubic extension field
15/// variables. That is, it implements the R1CS equivalent of
16/// `ark_ff::CubicExtField`.
17pub mod cubic_extension;
18/// This module contains a generic implementation of quadratic extension field
19/// variables. That is, it implements the R1CS equivalent of
20/// `ark_ff::QuadExtField`.
21pub mod quadratic_extension;
22
23/// This module contains a generic implementation of prime field variables.
24/// That is, it implements the R1CS equivalent of `ark_ff::Fp*`.
25pub mod fp;
26
27/// This module contains a generic implementation of "emulated" prime field
28/// variables. It emulates `Fp` arithmetic using `Fq` operations, where `p !=
29/// q`.
30pub mod emulated_fp;
31
32/// This module contains a generic implementation of the degree-12 tower
33/// extension field. That is, it implements the R1CS equivalent of
34/// `ark_ff::Fp12`
35pub mod fp12;
36/// This module contains a generic implementation of the degree-2 tower
37/// extension field. That is, it implements the R1CS equivalent of
38/// `ark_ff::Fp2`
39pub mod fp2;
40/// This module contains a generic implementation of the degree-3 tower
41/// extension field. That is, it implements the R1CS equivalent of
42/// `ark_ff::Fp3`
43pub mod fp3;
44/// This module contains a generic implementation of the degree-4 tower
45/// extension field. That is, it implements the R1CS equivalent of
46/// `ark_ff::Fp4`
47pub mod fp4;
48/// This module contains a generic implementation of the degree-6 tower
49/// extension field. That is, it implements the R1CS equivalent of
50/// `ark_ff::fp6_2over3::Fp6`
51pub mod fp6_2over3;
52/// This module contains a generic implementation of the degree-6 tower
53/// extension field. That is, it implements the R1CS equivalent of
54/// `ark_ff::fp6_3over2::Fp6`
55pub mod fp6_3over2;
56
57/// This trait is a hack used to work around the lack of implied bounds.
58pub trait FieldOpsBounds<'a, F, T: 'a>:
59    Sized
60    + Add<&'a T, Output = T>
61    + Sub<&'a T, Output = T>
62    + Mul<&'a T, Output = T>
63    + Add<T, Output = T>
64    + Sub<T, Output = T>
65    + Mul<T, Output = T>
66    + Add<F, Output = T>
67    + Sub<F, Output = T>
68    + Mul<F, Output = T>
69{
70}
71
72/// A variable representing a field. Corresponds to the native type `F`.
73pub trait FieldVar<F: Field, ConstraintF: PrimeField>:
74    'static
75    + Clone
76    + From<Boolean<ConstraintF>>
77    + GR1CSVar<ConstraintF, Value = F>
78    + EqGadget<ConstraintF>
79    + ToBitsGadget<ConstraintF>
80    + AllocVar<F, ConstraintF>
81    + ToBytesGadget<ConstraintF>
82    + CondSelectGadget<ConstraintF>
83    + ToConstraintFieldGadget<ConstraintF>
84    + for<'a> FieldOpsBounds<'a, F, Self>
85    + for<'a> AddAssign<&'a Self>
86    + for<'a> SubAssign<&'a Self>
87    + for<'a> MulAssign<&'a Self>
88    + AddAssign<Self>
89    + SubAssign<Self>
90    + MulAssign<Self>
91    + AddAssign<F>
92    + SubAssign<F>
93    + MulAssign<F>
94    + Sum<Self>
95    + for<'a> Sum<&'a Self>
96    + Debug
97{
98    /// Returns the constant `F::zero()`.
99    fn zero() -> Self;
100
101    /// Returns a `Boolean` representing whether `self == Self::zero()`.
102    fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
103        self.is_eq(&Self::zero())
104    }
105
106    /// Returns the constant `F::one()`.
107    fn one() -> Self;
108
109    /// Returns a `Boolean` representing whether `self == Self::one()`.
110    fn is_one(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
111        self.is_eq(&Self::one())
112    }
113
114    /// Returns a constant with value `v`.
115    ///
116    /// This *should not* allocate any variables.
117    fn constant(v: F) -> Self;
118
119    /// Computes `self + self`.
120    fn double(&self) -> Result<Self, SynthesisError> {
121        Ok(self.clone() + self)
122    }
123
124    /// Sets `self = self + self`.
125    fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
126        *self = self.double()?;
127        Ok(self)
128    }
129
130    /// Coputes `-self`.
131    fn negate(&self) -> Result<Self, SynthesisError>;
132
133    /// Sets `self = -self`.
134    #[inline]
135    fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
136        *self = self.negate()?;
137        Ok(self)
138    }
139
140    /// Computes `self * self`.
141    ///
142    /// A default implementation is provided which just invokes the underlying
143    /// multiplication routine. However, this method should be specialized
144    /// for extension fields, where faster algorithms exist for squaring.
145    fn square(&self) -> Result<Self, SynthesisError> {
146        Ok(self.clone() * self)
147    }
148
149    /// Sets `self = self.square()`.
150    fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
151        *self = self.square()?;
152        Ok(self)
153    }
154
155    /// Enforces that `self * other == result`.
156    fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
157        let actual_result = self.clone() * other;
158        result.enforce_equal(&actual_result)
159    }
160
161    /// Enforces that `self * self == result`.
162    fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
163        let actual_result = self.square()?;
164        result.enforce_equal(&actual_result)
165    }
166
167    /// Computes `result` such that `self * result == Self::one()`.
168    fn inverse(&self) -> Result<Self, SynthesisError>;
169
170    /// Returns `(self / d)`.
171    /// The constraint system will be unsatisfiable when `d = 0`.
172    fn mul_by_inverse(&self, d: &Self) -> Result<Self, SynthesisError> {
173        // Enforce that `d` is not zero.
174        d.enforce_not_equal(&Self::zero())?;
175        self.mul_by_inverse_unchecked(d)
176    }
177
178    /// Returns `(self / d)`.
179    ///
180    /// The precondition for this method is that `d != 0`. If `d == 0`, this
181    /// method offers no guarantees about the soundness of the resulting
182    /// constraint system. For example, if `self == d == 0`, the current
183    /// implementation allows the constraint system to be trivially satisfiable.
184    fn mul_by_inverse_unchecked(&self, d: &Self) -> Result<Self, SynthesisError> {
185        let cs = self.cs().or(d.cs());
186        match cs {
187            // If we're in the constant case, we just allocate a new constant having value equalling
188            // `self * d.inverse()`.
189            ConstraintSystemRef::None => Self::new_constant(
190                cs,
191                self.value()? * d.value()?.inverse().expect("division by zero"),
192            ),
193            // If not, we allocate `result` as a new witness having value `self * d.inverse()`,
194            // and check that `result * d = self`.
195            _ => {
196                let result = Self::new_witness(ark_relations::ns!(cs, "self  * d_inv"), || {
197                    Ok(self.value()? * &d.value()?.inverse().unwrap_or(F::ZERO))
198                })?;
199                result.mul_equals(d, self)?;
200                Ok(result)
201            },
202        }
203    }
204
205    /// Computes the inner product of `this` and `other`.
206    fn inner_product(this: &[Self], other: &[Self]) -> Result<Self, SynthesisError> {
207        if this.len() != other.len() {
208            return Err(SynthesisError::Unsatisfiable);
209        }
210        Ok(this.iter().zip(other).map(|(a, b)| a.clone() * b).sum())
211    }
212
213    /// Computes the frobenius map over `self`.
214    fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError>;
215
216    /// Sets `self = self.frobenius_map()`.
217    fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
218        *self = self.frobenius_map(power)?;
219        Ok(self)
220    }
221
222    /// Comptues `self^bits`, where `bits` is a *little-endian* bit-wise
223    /// decomposition of the exponent.
224    fn pow_le(&self, bits: &[Boolean<ConstraintF>]) -> Result<Self, SynthesisError> {
225        let mut res = Self::one();
226        let mut power = self.clone();
227        for bit in bits {
228            let tmp = res.clone() * &power;
229            res = bit.select(&tmp, &res)?;
230            power.square_in_place()?;
231        }
232        Ok(res)
233    }
234
235    /// Computes `self^S`, where S is interpreted as an little-endian
236    /// u64-decomposition of an integer.
237    fn pow_by_constant<S: AsRef<[u64]>>(&self, exp: S) -> Result<Self, SynthesisError> {
238        let mut res = Self::one();
239        for i in BitIteratorBE::without_leading_zeros(exp) {
240            res.square_in_place()?;
241            if i {
242                res *= self;
243            }
244        }
245        Ok(res)
246    }
247}