arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/fields/fp/mod.rs
r1cs-std/src/fields/fp/mod.rsRaw
   1use algebra::{BigInteger, FpParameters, PrimeField};
   2use r1cs_core::{lc, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable};
   3
   4use core::borrow::Borrow;
   5
   6use crate::fields::{FieldOpsBounds, FieldVar};
   7use crate::{prelude::*, Assignment, ToConstraintFieldGadget, Vec};
   8
   9mod cmp;
  10
  11/// Represents a variable in the constraint system whose
  12/// value can be an arbitrary field element.
  13#[derive(Debug, Clone)]
  14#[must_use]
  15pub struct AllocatedFp<F: PrimeField> {
  16    pub(crate) value: Option<F>,
  17    /// The allocated variable corresponding to `self` in `self.cs`.
  18    pub variable: Variable,
  19    /// The constraint system that `self` was allocated in.
  20    pub cs: ConstraintSystemRef<F>,
  21}
  22
  23impl<F: PrimeField> AllocatedFp<F> {
  24    /// Constructs a new `AllocatedFp` from a (optional) value, a low-level Variable,
  25    /// and a `ConstraintSystemRef`.
  26    pub fn new(value: Option<F>, variable: Variable, cs: ConstraintSystemRef<F>) -> Self {
  27        Self {
  28            value,
  29            variable,
  30            cs,
  31        }
  32    }
  33}
  34
  35/// Represent variables corresponding to a field element in `F`.
  36#[derive(Clone, Debug)]
  37#[must_use]
  38pub enum FpVar<F: PrimeField> {
  39    /// Represents a constant in the constraint system, which means that
  40    /// it does not have a corresponding variable.
  41    Constant(F),
  42    /// Represents an allocated variable constant in the constraint system.
  43    Var(AllocatedFp<F>),
  44}
  45
  46impl<F: PrimeField> R1CSVar<F> for FpVar<F> {
  47    type Value = F;
  48
  49    fn cs(&self) -> Option<ConstraintSystemRef<F>> {
  50        match self {
  51            Self::Constant(_) => Some(ConstraintSystemRef::None),
  52            Self::Var(a) => Some(a.cs.clone()),
  53        }
  54    }
  55
  56    fn value(&self) -> Result<Self::Value, SynthesisError> {
  57        match self {
  58            Self::Constant(v) => Ok(*v),
  59            Self::Var(v) => v.value(),
  60        }
  61    }
  62}
  63
  64impl<F: PrimeField> From<Boolean<F>> for FpVar<F> {
  65    fn from(other: Boolean<F>) -> Self {
  66        if let Boolean::Constant(b) = other {
  67            Self::Constant(F::from(b as u8))
  68        } else {
  69            // `other` is a variable
  70            let cs = other.cs().unwrap();
  71            let variable = cs.new_lc(other.lc()).unwrap();
  72            Self::Var(AllocatedFp::new(
  73                other.value().ok().map(|b| F::from(b as u8)),
  74                variable,
  75                cs,
  76            ))
  77        }
  78    }
  79}
  80
  81impl<F: PrimeField> From<AllocatedFp<F>> for FpVar<F> {
  82    fn from(other: AllocatedFp<F>) -> Self {
  83        Self::Var(other)
  84    }
  85}
  86
  87impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar<F> {}
  88impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar<F>> for &'a FpVar<F> {}
  89
  90impl<F: PrimeField> AllocatedFp<F> {
  91    /// Constructs `Self` from a `Boolean`: if `other` is false, this outputs `zero`, else it outputs `one`.
  92    pub fn from(other: Boolean<F>) -> Self {
  93        if let Some(cs) = other.cs() {
  94            let variable = cs.new_lc(other.lc()).unwrap();
  95            Self::new(other.value().ok().map(|b| F::from(b as u8)), variable, cs)
  96        } else {
  97            unreachable!("Cannot create a constant value")
  98        }
  99    }
 100
 101    /// Returns the value assigned to `self` in the underlying constraint system
 102    /// (if a value was assigned).
 103    pub fn value(&self) -> Result<F, SynthesisError> {
 104        self.cs.assigned_value(self.variable).get()
 105    }
 106
 107    /// Outputs `self + other`.
 108    ///
 109    /// This does not create any constraints.
 110    #[tracing::instrument(target = "r1cs")]
 111    pub fn add(&self, other: &Self) -> Self {
 112        let value = match (self.value, other.value) {
 113            (Some(val1), Some(val2)) => Some(val1 + &val2),
 114            (..) => None,
 115        };
 116
 117        let variable = self
 118            .cs
 119            .new_lc(lc!() + self.variable + other.variable)
 120            .unwrap();
 121        AllocatedFp::new(value, variable, self.cs.clone())
 122    }
 123
 124    /// Outputs `self - other`.
 125    ///
 126    /// This does not create any constraints.
 127    #[tracing::instrument(target = "r1cs")]
 128    pub fn sub(&self, other: &Self) -> Self {
 129        let value = match (self.value, other.value) {
 130            (Some(val1), Some(val2)) => Some(val1 - &val2),
 131            (..) => None,
 132        };
 133
 134        let variable = self
 135            .cs
 136            .new_lc(lc!() + self.variable - other.variable)
 137            .unwrap();
 138        AllocatedFp::new(value, variable, self.cs.clone())
 139    }
 140
 141    /// Outputs `self * other`.
 142    ///
 143    /// This requires *one* constraint.
 144    #[tracing::instrument(target = "r1cs")]
 145    pub fn mul(&self, other: &Self) -> Self {
 146        let product = AllocatedFp::new_witness(self.cs.clone(), || {
 147            Ok(self.value.get()? * &other.value.get()?)
 148        })
 149        .unwrap();
 150        self.cs
 151            .enforce_constraint(
 152                lc!() + self.variable,
 153                lc!() + other.variable,
 154                lc!() + product.variable,
 155            )
 156            .unwrap();
 157        product
 158    }
 159
 160    /// Output `self + other`
 161    ///
 162    /// This does not create any constraints.
 163    #[tracing::instrument(target = "r1cs")]
 164    pub fn add_constant(&self, other: F) -> Self {
 165        if other.is_zero() {
 166            self.clone()
 167        } else {
 168            let value = self.value.map(|val| val + other);
 169            let variable = self
 170                .cs
 171                .new_lc(lc!() + self.variable + (other, Variable::One))
 172                .unwrap();
 173            AllocatedFp::new(value, variable, self.cs.clone())
 174        }
 175    }
 176
 177    /// Output `self - other`
 178    ///
 179    /// This does not create any constraints.
 180    #[tracing::instrument(target = "r1cs")]
 181    pub fn sub_constant(&self, other: F) -> Self {
 182        self.add_constant(-other)
 183    }
 184
 185    /// Output `self * other`
 186    ///
 187    /// This does not create any constraints.
 188    #[tracing::instrument(target = "r1cs")]
 189    pub fn mul_constant(&self, other: F) -> Self {
 190        if other.is_one() {
 191            self.clone()
 192        } else {
 193            let value = self.value.map(|val| val * other);
 194            let variable = self.cs.new_lc(lc!() + (other, self.variable)).unwrap();
 195            AllocatedFp::new(value, variable, self.cs.clone())
 196        }
 197    }
 198
 199    /// Output `self + self`
 200    ///
 201    /// This does not create any constraints.
 202    #[tracing::instrument(target = "r1cs")]
 203    pub fn double(&self) -> Result<Self, SynthesisError> {
 204        let value = self.value.map(|val| val.double());
 205        let variable = self.cs.new_lc(lc!() + self.variable + self.variable)?;
 206        Ok(Self::new(value, variable, self.cs.clone()))
 207    }
 208
 209    /// Output `-self`
 210    ///
 211    /// This does not create any constraints.
 212    #[tracing::instrument(target = "r1cs")]
 213    pub fn negate(&self) -> Self {
 214        let mut result = self.clone();
 215        result.negate_in_place();
 216        result
 217    }
 218
 219    /// Sets `self = -self`
 220    ///
 221    /// This does not create any constraints.
 222    #[tracing::instrument(target = "r1cs")]
 223    pub fn negate_in_place(&mut self) -> &mut Self {
 224        self.value.as_mut().map(|val| *val = -(*val));
 225        self.variable = self.cs.new_lc(lc!() - self.variable).unwrap();
 226        self
 227    }
 228
 229    /// Outputs `self * self`
 230    ///
 231    /// This requires *one* constraint.
 232    #[tracing::instrument(target = "r1cs")]
 233    pub fn square(&self) -> Result<Self, SynthesisError> {
 234        Ok(self.mul(self))
 235    }
 236
 237    /// Outputs `result` such that `result * self = 1`.
 238    ///
 239    /// This requires *one* constraint.
 240    #[tracing::instrument(target = "r1cs")]
 241    pub fn inverse(&self) -> Result<Self, SynthesisError> {
 242        let inverse = Self::new_witness(self.cs.clone(), || {
 243            Ok(self.value.get()?.inverse().unwrap_or(F::zero()))
 244        })?;
 245
 246        self.cs.enforce_constraint(
 247            lc!() + self.variable,
 248            lc!() + inverse.variable,
 249            lc!() + Variable::One,
 250        )?;
 251        Ok(inverse)
 252    }
 253
 254    /// This is a no-op for prime fields.
 255    #[tracing::instrument(target = "r1cs")]
 256    pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> {
 257        Ok(self.clone())
 258    }
 259
 260    /// Enforces that `self * other = result`.
 261    ///
 262    /// This requires *one* constraint.
 263    #[tracing::instrument(target = "r1cs")]
 264    pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
 265        self.cs.enforce_constraint(
 266            lc!() + self.variable,
 267            lc!() + other.variable,
 268            lc!() + result.variable,
 269        )
 270    }
 271
 272    /// Enforces that `self * self = result`.
 273    ///
 274    /// This requires *one* constraint.
 275    #[tracing::instrument(target = "r1cs")]
 276    pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
 277        self.cs.enforce_constraint(
 278            lc!() + self.variable,
 279            lc!() + self.variable,
 280            lc!() + result.variable,
 281        )
 282    }
 283
 284    /// Outputs the bit `self == other`.
 285    ///
 286    /// This requires three constraints.
 287    #[tracing::instrument(target = "r1cs")]
 288    pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 289        Ok(self.is_neq(other)?.not())
 290    }
 291
 292    /// Outputs the bit `self != other`.
 293    ///
 294    /// This requires three constraints.
 295    #[tracing::instrument(target = "r1cs")]
 296    pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 297        let is_not_equal = Boolean::new_witness(self.cs.clone(), || {
 298            Ok(self.value.get()? != other.value.get()?)
 299        })?;
 300        let multiplier = self.cs.new_witness_variable(|| {
 301            if is_not_equal.value()? {
 302                (self.value.get()? - other.value.get()?).inverse().get()
 303            } else {
 304                Ok(F::one())
 305            }
 306        })?;
 307
 308        // Completeness:
 309        // Case 1: self != other:
 310        // ----------------------
 311        //   constraint 1:
 312        //   (self - other) * multiplier = is_not_equal
 313        //   => (non_zero) * multiplier = 1 (satisfied, because multiplier = 1/(self - other)
 314        //
 315        //   constraint 2:
 316        //   (self - other) * not(is_not_equal) = 0
 317        //   => (non_zero) * not(1) = 0
 318        //   => (non_zero) * 0 = 0
 319        //
 320        // Case 2: self == other:
 321        // ----------------------
 322        //   constraint 1:
 323        //   (self - other) * multiplier = is_not_equal
 324        //   => 0 * multiplier = 0 (satisfied, because multiplier = 1
 325        //
 326        //   constraint 2:
 327        //   (self - other) * not(is_not_equal) = 0
 328        //   => 0 * not(0) = 0
 329        //   => 0 * 1 = 0
 330        //
 331        // --------------------------------------------------------------------
 332        //
 333        // Soundness:
 334        // Case 1: self != other, but is_not_equal = 0.
 335        // --------------------------------------------
 336        //   constraint 1:
 337        //   (self - other) * multiplier = is_not_equal
 338        //   => non_zero * multiplier = 0 (only satisfiable if multiplier == 0)
 339        //
 340        //   constraint 2:
 341        //   (self - other) * not(is_not_equal) = 0
 342        //   => (non_zero) * 1 = 0 (impossible)
 343        //
 344        // Case 2: self == other, but is_not_equal = 1.
 345        // --------------------------------------------
 346        //   constraint 1:
 347        //   (self - other) * multiplier = is_not_equal
 348        //   0 * multiplier = 1 (unsatisfiable)
 349        self.cs.enforce_constraint(
 350            lc!() + self.variable - other.variable,
 351            lc!() + multiplier,
 352            is_not_equal.lc(),
 353        )?;
 354        self.cs.enforce_constraint(
 355            lc!() + self.variable - other.variable,
 356            is_not_equal.not().lc(),
 357            lc!(),
 358        )?;
 359        Ok(is_not_equal)
 360    }
 361
 362    /// Enforces that self == other if `should_enforce.is_eq(&Boolean::TRUE)`.
 363    ///
 364    /// This requires one constraint.
 365    #[tracing::instrument(target = "r1cs")]
 366    pub fn conditional_enforce_equal(
 367        &self,
 368        other: &Self,
 369        should_enforce: &Boolean<F>,
 370    ) -> Result<(), SynthesisError> {
 371        self.cs.enforce_constraint(
 372            lc!() + self.variable - other.variable,
 373            lc!() + should_enforce.lc(),
 374            lc!(),
 375        )
 376    }
 377
 378    /// Enforces that self != other if `should_enforce.is_eq(&Boolean::TRUE)`.
 379    ///
 380    /// This requires one constraint.
 381    #[tracing::instrument(target = "r1cs")]
 382    pub fn conditional_enforce_not_equal(
 383        &self,
 384        other: &Self,
 385        should_enforce: &Boolean<F>,
 386    ) -> Result<(), SynthesisError> {
 387        let multiplier = Self::new_witness(self.cs.clone(), || {
 388            if should_enforce.value()? {
 389                (self.value.get()? - other.value.get()?).inverse().get()
 390            } else {
 391                Ok(F::zero())
 392            }
 393        })?;
 394
 395        self.cs.enforce_constraint(
 396            lc!() + self.variable - other.variable,
 397            lc!() + multiplier.variable,
 398            should_enforce.lc(),
 399        )?;
 400        Ok(())
 401    }
 402}
 403
 404/****************************************************************************/
 405/****************************************************************************/
 406
 407impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
 408    /// Outputs the unique bit-wise decomposition of `self` in *little-endian*
 409    /// form.
 410    ///
 411    /// This method enforces that the output is in the field, i.e.
 412    /// it invokes `Boolean::enforce_in_field_le` on the bit decomposition.
 413    #[tracing::instrument(target = "r1cs")]
 414    fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
 415        let bits = self.to_non_unique_bits_le()?;
 416        Boolean::enforce_in_field_le(&bits)?;
 417        Ok(bits)
 418    }
 419
 420    #[tracing::instrument(target = "r1cs")]
 421    fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
 422        let cs = self.cs.clone();
 423        use algebra::BitIteratorBE;
 424        let mut bits = if let Some(value) = self.value {
 425            let field_char = BitIteratorBE::new(F::characteristic());
 426            let bits: Vec<_> = BitIteratorBE::new(value.into_repr())
 427                .zip(field_char)
 428                .skip_while(|(_, c)| !c)
 429                .map(|(b, _)| Some(b))
 430                .collect();
 431            assert_eq!(bits.len(), F::Params::MODULUS_BITS as usize);
 432            bits
 433        } else {
 434            vec![None; F::Params::MODULUS_BITS as usize]
 435        };
 436
 437        // Convert to little-endian
 438        bits.reverse();
 439
 440        let bits: Vec<_> = bits
 441            .into_iter()
 442            .map(|b| Boolean::new_witness(cs.clone(), || b.get()))
 443            .collect::<Result<_, _>>()?;
 444
 445        let mut lc = LinearCombination::zero();
 446        let mut coeff = F::one();
 447
 448        for bit in bits.iter() {
 449            lc = &lc + bit.lc() * coeff;
 450
 451            coeff.double_in_place();
 452        }
 453
 454        lc = lc - &self.variable;
 455
 456        cs.enforce_constraint(lc!(), lc!(), lc)?;
 457
 458        Ok(bits)
 459    }
 460}
 461
 462impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
 463    /// Outputs the unique byte decomposition of `self` in *little-endian*
 464    /// form.
 465    ///
 466    /// This method enforces that the decomposition represents
 467    /// an integer that is less than `F::MODULUS`.
 468    #[tracing::instrument(target = "r1cs")]
 469    fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
 470        let num_bits = F::BigInt::NUM_LIMBS * 64;
 471        let mut bits = self.to_bits_le()?;
 472        let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len());
 473        bits.extend(remainder);
 474        let bytes = bits
 475            .chunks(8)
 476            .map(|chunk| UInt8::from_bits_le(chunk))
 477            .collect();
 478        Ok(bytes)
 479    }
 480
 481    #[tracing::instrument(target = "r1cs")]
 482    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
 483        let num_bits = F::BigInt::NUM_LIMBS * 64;
 484        let mut bits = self.to_non_unique_bits_le()?;
 485        let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len());
 486        bits.extend(remainder);
 487        let bytes = bits
 488            .chunks(8)
 489            .map(|chunk| UInt8::from_bits_le(chunk))
 490            .collect();
 491        Ok(bytes)
 492    }
 493}
 494
 495impl<F: PrimeField> ToConstraintFieldGadget<F> for AllocatedFp<F> {
 496    #[tracing::instrument(target = "r1cs")]
 497    fn to_constraint_field(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
 498        Ok(vec![self.clone().into()])
 499    }
 500}
 501
 502impl<F: PrimeField> CondSelectGadget<F> for AllocatedFp<F> {
 503    #[inline]
 504    #[tracing::instrument(target = "r1cs")]
 505    fn conditionally_select(
 506        cond: &Boolean<F>,
 507        true_val: &Self,
 508        false_val: &Self,
 509    ) -> Result<Self, SynthesisError> {
 510        match cond {
 511            Boolean::Constant(true) => Ok(true_val.clone()),
 512            Boolean::Constant(false) => Ok(false_val.clone()),
 513            _ => {
 514                let cs = cond.cs().unwrap();
 515                let result = Self::new_witness(cs.clone(), || {
 516                    cond.value()
 517                        .and_then(|c| if c { true_val } else { false_val }.value.get())
 518                })?;
 519                // a = self; b = other; c = cond;
 520                //
 521                // r = c * a + (1  - c) * b
 522                // r = b + c * (a - b)
 523                // c * (a - b) = r - b
 524                cs.enforce_constraint(
 525                    cond.lc(),
 526                    lc!() + true_val.variable - false_val.variable,
 527                    lc!() + result.variable - false_val.variable,
 528                )?;
 529
 530                Ok(result)
 531            }
 532        }
 533    }
 534}
 535
 536/// Uses two bits to perform a lookup into a table
 537/// `b` is little-endian: `b[0]` is LSB.
 538impl<F: PrimeField> TwoBitLookupGadget<F> for AllocatedFp<F> {
 539    type TableConstant = F;
 540    #[tracing::instrument(target = "r1cs")]
 541    fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
 542        debug_assert_eq!(b.len(), 2);
 543        debug_assert_eq!(c.len(), 4);
 544        if let Some(cs) = b.cs() {
 545            let result = Self::new_witness(cs.clone(), || {
 546                let lsb = usize::from(b[0].value()?);
 547                let msb = usize::from(b[1].value()?);
 548                let index = lsb + (msb << 1);
 549                Ok(c[index])
 550            })?;
 551            let one = Variable::One;
 552            cs.enforce_constraint(
 553                lc!() + b[1].lc() * (c[3] - &c[2] - &c[1] + &c[0]) + (c[1] - &c[0], one),
 554                lc!() + b[0].lc(),
 555                lc!() + result.variable - (c[0], one) + b[1].lc() * (c[0] - &c[2]),
 556            )?;
 557
 558            Ok(result)
 559        } else {
 560            unreachable!("must provide a way to obtain a ConstraintSystemRef")
 561        }
 562    }
 563}
 564
 565impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for AllocatedFp<F> {
 566    type TableConstant = F;
 567
 568    #[tracing::instrument(target = "r1cs")]
 569    fn three_bit_cond_neg_lookup(
 570        b: &[Boolean<F>],
 571        b0b1: &Boolean<F>,
 572        c: &[Self::TableConstant],
 573    ) -> Result<Self, SynthesisError> {
 574        debug_assert_eq!(b.len(), 3);
 575        debug_assert_eq!(c.len(), 4);
 576
 577        if let Some(cs) = b.cs() {
 578            let result = Self::new_witness(cs.clone(), || {
 579                let lsb = usize::from(b[0].value()?);
 580                let msb = usize::from(b[1].value()?);
 581                let index = lsb + (msb << 1);
 582                let intermediate = c[index];
 583
 584                let is_negative = b[2].value()?;
 585                let y = if is_negative {
 586                    -intermediate
 587                } else {
 588                    intermediate
 589                };
 590                Ok(y)
 591            })?;
 592
 593            let y_lc = b0b1.lc() * (c[3] - &c[2] - &c[1] + &c[0])
 594                + b[0].lc() * (c[1] - &c[0])
 595                + b[1].lc() * (c[2] - &c[0])
 596                + (c[0], Variable::One);
 597            cs.enforce_constraint(
 598                y_lc.clone() + y_lc.clone(),
 599                b[2].lc(),
 600                y_lc.clone() - result.variable,
 601            )?;
 602
 603            Ok(result)
 604        } else {
 605            unreachable!("must provide a way to obtain a ConstraintSystemRef")
 606        }
 607    }
 608}
 609
 610impl<F: PrimeField> AllocVar<F, F> for AllocatedFp<F> {
 611    fn new_variable<T: Borrow<F>>(
 612        cs: impl Into<Namespace<F>>,
 613        f: impl FnOnce() -> Result<T, SynthesisError>,
 614        mode: AllocationMode,
 615    ) -> Result<Self, SynthesisError> {
 616        let ns = cs.into();
 617        let cs = ns.cs();
 618        if mode == AllocationMode::Constant {
 619            let v = *f()?.borrow();
 620            let lc = cs.new_lc(lc!() + (v, Variable::One))?;
 621            Ok(Self::new(Some(v), lc, cs))
 622        } else {
 623            let mut value = None;
 624            let value_generator = || {
 625                value = Some(*f()?.borrow());
 626                value.ok_or(SynthesisError::AssignmentMissing)
 627            };
 628            let variable = if mode == AllocationMode::Input {
 629                cs.new_input_variable(value_generator)?
 630            } else {
 631                cs.new_witness_variable(value_generator)?
 632            };
 633            Ok(Self::new(value, variable, cs.clone()))
 634        }
 635    }
 636}
 637
 638impl<F: PrimeField> FieldVar<F, F> for FpVar<F> {
 639    fn constant(f: F) -> Self {
 640        Self::Constant(f)
 641    }
 642
 643    fn zero() -> Self {
 644        Self::Constant(F::zero())
 645    }
 646
 647    fn one() -> Self {
 648        Self::Constant(F::one())
 649    }
 650
 651    #[tracing::instrument(target = "r1cs")]
 652    fn double(&self) -> Result<Self, SynthesisError> {
 653        match self {
 654            Self::Constant(c) => Ok(Self::Constant(c.double())),
 655            Self::Var(v) => Ok(Self::Var(v.double()?)),
 656        }
 657    }
 658
 659    #[tracing::instrument(target = "r1cs")]
 660    fn negate(&self) -> Result<Self, SynthesisError> {
 661        match self {
 662            Self::Constant(c) => Ok(Self::Constant(-*c)),
 663            Self::Var(v) => Ok(Self::Var(v.negate())),
 664        }
 665    }
 666
 667    #[tracing::instrument(target = "r1cs")]
 668    fn square(&self) -> Result<Self, SynthesisError> {
 669        match self {
 670            Self::Constant(c) => Ok(Self::Constant(c.square())),
 671            Self::Var(v) => Ok(Self::Var(v.square()?)),
 672        }
 673    }
 674
 675    /// Enforce that `self * other == result`.
 676    #[tracing::instrument(target = "r1cs")]
 677    fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
 678        use FpVar::*;
 679        match (self, other, result) {
 680            (Constant(_), Constant(_), Constant(_)) => Ok(()),
 681            (Constant(_), Constant(_), _) | (Constant(_), Var(_), _) | (Var(_), Constant(_), _) => {
 682                result.enforce_equal(&(self * other))
 683            } // this multiplication should be free
 684            (Var(v1), Var(v2), Var(v3)) => v1.mul_equals(v2, v3),
 685            (Var(v1), Var(v2), Constant(f)) => {
 686                let cs = v1.cs.clone();
 687                let v3 = AllocatedFp::new_constant(cs.clone(), f).unwrap();
 688                v1.mul_equals(v2, &v3)
 689            }
 690        }
 691    }
 692
 693    /// Enforce that `self * self == result`.
 694    #[tracing::instrument(target = "r1cs")]
 695    fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
 696        use FpVar::*;
 697        match (self, result) {
 698            (Constant(_), Constant(_)) => Ok(()),
 699            (Constant(f), Var(r)) => {
 700                let cs = r.cs.clone();
 701                let v = AllocatedFp::new_witness(cs, || Ok(f))?;
 702                v.square_equals(&r)
 703            }
 704            (Var(v), Constant(f)) => {
 705                let cs = v.cs.clone();
 706                let r = AllocatedFp::new_witness(cs, || Ok(f))?;
 707                v.square_equals(&r)
 708            }
 709            (Var(v1), Var(v2)) => v1.square_equals(v2),
 710        }
 711    }
 712
 713    #[tracing::instrument(target = "r1cs")]
 714    fn inverse(&self) -> Result<Self, SynthesisError> {
 715        match self {
 716            FpVar::Var(v) => v.inverse().map(FpVar::Var),
 717            FpVar::Constant(f) => f.inverse().get().map(FpVar::Constant),
 718        }
 719    }
 720
 721    /// Returns (self / denominator), but requires fewer constraints than
 722    /// self * denominator.inverse()
 723    /// It is up to the caller to ensure that denominator is non-zero,
 724    /// since in that case the result is unconstrained.
 725    #[tracing::instrument(target = "r1cs")]
 726    fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
 727        use FpVar::*;
 728        match (self, denominator) {
 729            (Constant(s), Constant(d)) => Ok(Constant(*s / *d)),
 730            (Var(s), Constant(d)) => Ok(Var(s.mul_constant(d.inverse().get()?))),
 731            (Constant(s), Var(d)) => Ok(Var(d.inverse()?.mul_constant(*s))),
 732            (Var(s), Var(d)) => Ok(Var(d.inverse()?.mul(s))),
 733        }
 734    }
 735
 736    #[tracing::instrument(target = "r1cs")]
 737    fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
 738        match self {
 739            FpVar::Var(v) => v.frobenius_map(power).map(FpVar::Var),
 740            FpVar::Constant(f) => {
 741                let mut f = *f;
 742                f.frobenius_map(power);
 743                Ok(FpVar::Constant(f))
 744            }
 745        }
 746    }
 747
 748    #[tracing::instrument(target = "r1cs")]
 749    fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
 750        *self = self.frobenius_map(power)?;
 751        Ok(self)
 752    }
 753}
 754
 755/****************************************************************************/
 756/****************************************************************************/
 757
 758impl_ops!(
 759    FpVar<F>,
 760    F,
 761    Add,
 762    add,
 763    AddAssign,
 764    add_assign,
 765    |this: &'a FpVar<F>, other: &'a FpVar<F>| {
 766        use FpVar::*;
 767        match (this, other) {
 768            (Constant(c1), Constant(c2)) => Constant(*c1 + *c2),
 769            (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(*c)),
 770            (Var(v1), Var(v2)) => Var(v1.add(v2)),
 771        }
 772    },
 773    |this: &'a FpVar<F>, other: F| { this + &FpVar::Constant(other) },
 774    F: PrimeField,
 775);
 776
 777impl_ops!(
 778    FpVar<F>,
 779    F,
 780    Sub,
 781    sub,
 782    SubAssign,
 783    sub_assign,
 784    |this: &'a FpVar<F>, other: &'a FpVar<F>| {
 785        use FpVar::*;
 786        match (this, other) {
 787            (Constant(c1), Constant(c2)) => Constant(*c1 - *c2),
 788            (Var(v), Constant(c)) => Var(v.sub_constant(*c)),
 789            (Constant(c), Var(v)) => Var(v.sub_constant(*c).negate()),
 790            (Var(v1), Var(v2)) => Var(v1.sub(v2)),
 791        }
 792    },
 793    |this: &'a FpVar<F>, other: F| { this - &FpVar::Constant(other) },
 794    F: PrimeField
 795);
 796
 797impl_ops!(
 798    FpVar<F>,
 799    F,
 800    Mul,
 801    mul,
 802    MulAssign,
 803    mul_assign,
 804    |this: &'a FpVar<F>, other: &'a FpVar<F>| {
 805        use FpVar::*;
 806        match (this, other) {
 807            (Constant(c1), Constant(c2)) => Constant(*c1 * *c2),
 808            (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.mul_constant(*c)),
 809            (Var(v1), Var(v2)) => Var(v1.mul(v2)),
 810        }
 811    },
 812    |this: &'a FpVar<F>, other: F| {
 813        if other.is_zero() {
 814            FpVar::zero()
 815        } else {
 816            this * &FpVar::Constant(other)
 817        }
 818    },
 819    F: PrimeField
 820);
 821
 822/****************************************************************************/
 823/****************************************************************************/
 824
 825impl<F: PrimeField> EqGadget<F> for FpVar<F> {
 826    #[tracing::instrument(target = "r1cs")]
 827    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 828        match (self, other) {
 829            (Self::Constant(c1), Self::Constant(c2)) => Ok(Boolean::Constant(c1 == c2)),
 830            (Self::Constant(c), Self::Var(v)) | (Self::Var(v), Self::Constant(c)) => {
 831                let cs = v.cs.clone();
 832                let c = AllocatedFp::new_constant(cs, c)?;
 833                c.is_eq(v)
 834            }
 835            (Self::Var(v1), Self::Var(v2)) => v1.is_eq(v2),
 836        }
 837    }
 838
 839    #[tracing::instrument(target = "r1cs")]
 840    fn conditional_enforce_equal(
 841        &self,
 842        other: &Self,
 843        should_enforce: &Boolean<F>,
 844    ) -> Result<(), SynthesisError> {
 845        match (self, other) {
 846            (Self::Constant(_), Self::Constant(_)) => Ok(()),
 847            (Self::Constant(c), Self::Var(v)) | (Self::Var(v), Self::Constant(c)) => {
 848                let cs = v.cs.clone();
 849                let c = AllocatedFp::new_constant(cs, c)?;
 850                c.conditional_enforce_equal(v, should_enforce)
 851            }
 852            (Self::Var(v1), Self::Var(v2)) => v1.conditional_enforce_equal(v2, should_enforce),
 853        }
 854    }
 855
 856    #[tracing::instrument(target = "r1cs")]
 857    fn conditional_enforce_not_equal(
 858        &self,
 859        other: &Self,
 860        should_enforce: &Boolean<F>,
 861    ) -> Result<(), SynthesisError> {
 862        match (self, other) {
 863            (Self::Constant(_), Self::Constant(_)) => Ok(()),
 864            (Self::Constant(c), Self::Var(v)) | (Self::Var(v), Self::Constant(c)) => {
 865                let cs = v.cs.clone();
 866                let c = AllocatedFp::new_constant(cs, c)?;
 867                c.conditional_enforce_not_equal(v, should_enforce)
 868            }
 869            (Self::Var(v1), Self::Var(v2)) => v1.conditional_enforce_not_equal(v2, should_enforce),
 870        }
 871    }
 872}
 873
 874impl<F: PrimeField> ToBitsGadget<F> for FpVar<F> {
 875    #[tracing::instrument(target = "r1cs")]
 876    fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
 877        match self {
 878            Self::Constant(_) => self.to_non_unique_bits_le(),
 879            Self::Var(v) => v.to_bits_le(),
 880        }
 881    }
 882
 883    #[tracing::instrument(target = "r1cs")]
 884    fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
 885        use algebra::BitIteratorLE;
 886        match self {
 887            Self::Constant(c) => Ok(BitIteratorLE::without_trailing_zeros(&c.into_repr())
 888                .map(Boolean::constant)
 889                .collect::<Vec<_>>()),
 890            Self::Var(v) => v.to_non_unique_bits_le(),
 891        }
 892    }
 893}
 894
 895impl<F: PrimeField> ToBytesGadget<F> for FpVar<F> {
 896    /// Outputs the unique byte decomposition of `self` in *little-endian*
 897    /// form.
 898    #[tracing::instrument(target = "r1cs")]
 899    fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
 900        match self {
 901            Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
 902            Self::Var(v) => v.to_bytes(),
 903        }
 904    }
 905
 906    #[tracing::instrument(target = "r1cs")]
 907    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
 908        match self {
 909            Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
 910            Self::Var(v) => v.to_non_unique_bytes(),
 911        }
 912    }
 913}
 914
 915impl<F: PrimeField> ToConstraintFieldGadget<F> for FpVar<F> {
 916    #[tracing::instrument(target = "r1cs")]
 917    fn to_constraint_field(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
 918        Ok(vec![self.clone()])
 919    }
 920}
 921
 922impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> {
 923    #[tracing::instrument(target = "r1cs")]
 924    fn conditionally_select(
 925        cond: &Boolean<F>,
 926        true_value: &Self,
 927        false_value: &Self,
 928    ) -> Result<Self, SynthesisError> {
 929        match cond {
 930            Boolean::Constant(true) => Ok(true_value.clone()),
 931            Boolean::Constant(false) => Ok(false_value.clone()),
 932            _ => {
 933                match (true_value, false_value) {
 934                    (Self::Constant(t), Self::Constant(f)) => {
 935                        let is = AllocatedFp::from(cond.clone());
 936                        let not = AllocatedFp::from(cond.not());
 937                        // cond * t + (1 - cond) * f
 938                        Ok(is.mul_constant(*t).add(&not.mul_constant(*f)).into())
 939                    }
 940                    (_, _) => {
 941                        let cs = cond.cs().unwrap();
 942                        let true_value = match true_value {
 943                            Self::Constant(f) => AllocatedFp::new_constant(cs.clone(), f)?,
 944                            Self::Var(v) => v.clone(),
 945                        };
 946                        let false_value = match false_value {
 947                            Self::Constant(f) => AllocatedFp::new_constant(cs.clone(), f)?,
 948                            Self::Var(v) => v.clone(),
 949                        };
 950                        cond.select(&true_value, &false_value).map(Self::Var)
 951                    }
 952                }
 953            }
 954        }
 955    }
 956}
 957
 958/// Uses two bits to perform a lookup into a table
 959/// `b` is little-endian: `b[0]` is LSB.
 960impl<F: PrimeField> TwoBitLookupGadget<F> for FpVar<F> {
 961    type TableConstant = F;
 962
 963    #[tracing::instrument(target = "r1cs")]
 964    fn two_bit_lookup(b: &[Boolean<F>], c: &[Self::TableConstant]) -> Result<Self, SynthesisError> {
 965        debug_assert_eq!(b.len(), 2);
 966        debug_assert_eq!(c.len(), 4);
 967        if b.cs().is_some() {
 968            AllocatedFp::two_bit_lookup(b, c).map(Self::Var)
 969        } else {
 970            let lsb = usize::from(b[0].value()?);
 971            let msb = usize::from(b[1].value()?);
 972            let index = lsb + (msb << 1);
 973            Ok(Self::Constant(c[index]))
 974        }
 975    }
 976}
 977
 978impl<F: PrimeField> ThreeBitCondNegLookupGadget<F> for FpVar<F> {
 979    type TableConstant = F;
 980
 981    #[tracing::instrument(target = "r1cs")]
 982    fn three_bit_cond_neg_lookup(
 983        b: &[Boolean<F>],
 984        b0b1: &Boolean<F>,
 985        c: &[Self::TableConstant],
 986    ) -> Result<Self, SynthesisError> {
 987        debug_assert_eq!(b.len(), 3);
 988        debug_assert_eq!(c.len(), 4);
 989
 990        if b.cs().or(b0b1.cs()).is_some() {
 991            AllocatedFp::three_bit_cond_neg_lookup(b, b0b1, c).map(Self::Var)
 992        } else {
 993            let lsb = usize::from(b[0].value()?);
 994            let msb = usize::from(b[1].value()?);
 995            let index = lsb + (msb << 1);
 996            let intermediate = c[index];
 997
 998            let is_negative = b[2].value()?;
 999            let y = if is_negative {
1000                -intermediate
1001            } else {
1002                intermediate
1003            };
1004            Ok(Self::Constant(y))
1005        }
1006    }
1007}
1008
1009impl<F: PrimeField> AllocVar<F, F> for FpVar<F> {
1010    fn new_variable<T: Borrow<F>>(
1011        cs: impl Into<Namespace<F>>,
1012        f: impl FnOnce() -> Result<T, SynthesisError>,
1013        mode: AllocationMode,
1014    ) -> Result<Self, SynthesisError> {
1015        if mode == AllocationMode::Constant {
1016            Ok(Self::Constant(*f()?.borrow()))
1017        } else {
1018            AllocatedFp::new_variable(cs, f, mode).map(Self::Var)
1019        }
1020    }
1021}