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