arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/groups/mod.rs
src/groups/mod.rsRaw
  1use crate::prelude::*;
  2use ark_ec::ProjectiveCurve;
  3use ark_ff::Field;
  4use ark_relations::r1cs::{Namespace, SynthesisError};
  5use core::ops::{Add, AddAssign, Sub, SubAssign};
  6
  7use core::{borrow::Borrow, fmt::Debug};
  8
  9/// This module contains implementations of arithmetic for various curve models.
 10pub mod curves;
 11
 12pub use self::curves::short_weierstrass::{bls12, mnt4, mnt6};
 13
 14/// A hack used to work around the lack of implied bounds.
 15pub trait GroupOpsBounds<'a, F, T: 'a>:
 16    Sized
 17    + Add<&'a T, Output = T>
 18    + Sub<&'a T, Output = T>
 19    + Add<T, Output = T>
 20    + Sub<T, Output = T>
 21    + Add<F, Output = T>
 22    + Sub<F, Output = T>
 23{
 24}
 25
 26/// A variable that represents a curve point for
 27/// the curve `C`.
 28pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
 29    'static
 30    + Sized
 31    + Clone
 32    + Debug
 33    + R1CSVar<ConstraintF, Value = C>
 34    + ToBitsGadget<ConstraintF>
 35    + ToBytesGadget<ConstraintF>
 36    + EqGadget<ConstraintF>
 37    + CondSelectGadget<ConstraintF>
 38    + AllocVar<C, ConstraintF>
 39    + AllocVar<C::Affine, ConstraintF>
 40    + for<'a> GroupOpsBounds<'a, C, Self>
 41    + for<'a> AddAssign<&'a Self>
 42    + for<'a> SubAssign<&'a Self>
 43    + AddAssign<C>
 44    + SubAssign<C>
 45    + AddAssign<Self>
 46    + SubAssign<Self>
 47{
 48    /// Returns the constant `F::zero()`. This is the identity
 49    /// of the group.
 50    fn zero() -> Self;
 51
 52    /// Returns a `Boolean` representing whether `self == Self::zero()`.
 53    #[tracing::instrument(target = "r1cs")]
 54    fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
 55        self.is_eq(&Self::zero())
 56    }
 57
 58    /// Returns a constant with value `v`.
 59    ///
 60    /// This *should not* allocate any variables.
 61    fn constant(other: C) -> Self;
 62
 63    /// Allocates a variable in the subgroup without checking if it's in the
 64    /// prime-order subgroup.
 65    fn new_variable_omit_prime_order_check(
 66        cs: impl Into<Namespace<ConstraintF>>,
 67        f: impl FnOnce() -> Result<C, SynthesisError>,
 68        mode: AllocationMode,
 69    ) -> Result<Self, SynthesisError>;
 70
 71    /// Enforce that `self` is in the prime-order subgroup.
 72    fn enforce_prime_order(&self) -> Result<(), SynthesisError>;
 73
 74    /// Computes `self + self`.
 75    #[tracing::instrument(target = "r1cs")]
 76    fn double(&self) -> Result<Self, SynthesisError> {
 77        let mut result = self.clone();
 78        result.double_in_place()?;
 79        Ok(result)
 80    }
 81
 82    /// Sets `self = self + self`.
 83    fn double_in_place(&mut self) -> Result<(), SynthesisError>;
 84
 85    /// Coputes `-self`.
 86    fn negate(&self) -> Result<Self, SynthesisError>;
 87
 88    /// Computes `bits * self`, where `bits` is a little-endian
 89    /// `Boolean` representation of a scalar.
 90    #[tracing::instrument(target = "r1cs", skip(bits))]
 91    fn scalar_mul_le<'a>(
 92        &self,
 93        bits: impl Iterator<Item = &'a Boolean<ConstraintF>>,
 94    ) -> Result<Self, SynthesisError> {
 95        let mut res = Self::zero();
 96        let mut multiple = self.clone();
 97        for bit in bits {
 98            let tmp = res.clone() + &multiple;
 99            res = bit.select(&tmp, &res)?;
100            multiple.double_in_place()?;
101        }
102        Ok(res)
103    }
104
105    /// Computes a `I * self` in place, where `I` is a `Boolean` *little-endian*
106    /// representation of the scalar.
107    ///
108    /// The base powers are precomputed power-of-two multiples of a single
109    /// base.
110    #[tracing::instrument(target = "r1cs", skip(scalar_bits_with_base_powers))]
111    fn precomputed_base_scalar_mul_le<'a, I, B>(
112        &mut self,
113        scalar_bits_with_base_powers: I,
114    ) -> Result<(), SynthesisError>
115    where
116        I: Iterator<Item = (B, &'a C)>,
117        B: Borrow<Boolean<ConstraintF>>,
118        C: 'a,
119    {
120        for (bit, base_power) in scalar_bits_with_base_powers {
121            let new_encoded = self.clone() + *base_power;
122            *self = bit.borrow().select(&new_encoded, self)?;
123        }
124        Ok(())
125    }
126
127    /// Computes a `\sum_j I_j * B_j`, where `I_j` is a `Boolean`
128    /// representation of the j-th scalar.
129    #[tracing::instrument(target = "r1cs", skip(bases, scalars))]
130    fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
131        bases: &[B],
132        scalars: I,
133    ) -> Result<Self, SynthesisError>
134    where
135        T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
136        I: Iterator<Item = &'a T>,
137        B: Borrow<[C]>,
138    {
139        let mut result = Self::zero();
140        // Compute ∏(h_i^{m_i}) for all i.
141        for (bits, base_powers) in scalars.zip(bases) {
142            let base_powers = base_powers.borrow();
143            let bits = bits.to_bits_le()?;
144            result.precomputed_base_scalar_mul_le(bits.iter().zip(base_powers))?;
145        }
146        Ok(result)
147    }
148}