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