mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-10 16:01:28 +01:00
Document r1cs-std
This commit is contained in:
@@ -3,15 +3,26 @@ use algebra::Field;
|
|||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use r1cs_core::{Namespace, SynthesisError};
|
use r1cs_core::{Namespace, SynthesisError};
|
||||||
|
|
||||||
|
/// Describes the mode that a variable should be allocated in within
|
||||||
|
/// a `ConstraintSystem`.
|
||||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
|
||||||
pub enum AllocationMode {
|
pub enum AllocationMode {
|
||||||
|
/// Indicate to the `ConstraintSystem` that the high-level variable should
|
||||||
|
/// be allocated as a constant. That is, no `Variable`s should be
|
||||||
|
/// generated.
|
||||||
Constant = 0,
|
Constant = 0,
|
||||||
|
|
||||||
|
/// Indicate to the `ConstraintSystem` that the high-level variable should
|
||||||
|
/// be allocated as a public input to the `ConstraintSystem`.
|
||||||
Input = 1,
|
Input = 1,
|
||||||
|
|
||||||
|
/// Indicate to the `ConstraintSystem` that the high-level variable should
|
||||||
|
/// be allocated as a private witness to the `ConstraintSystem`.
|
||||||
Witness = 2,
|
Witness = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AllocationMode {
|
impl AllocationMode {
|
||||||
// Outputs the maximum according to the relation `Constant < Input < Witness`.
|
/// Outputs the maximum according to the relation `Constant < Input < Witness`.
|
||||||
pub fn max(&self, other: Self) -> Self {
|
pub fn max(&self, other: Self) -> Self {
|
||||||
use AllocationMode::*;
|
use AllocationMode::*;
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
@@ -23,17 +34,21 @@ impl AllocationMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies how variables of type `Self` should be allocated in a `ConstraintSystem`.
|
||||||
pub trait AllocVar<V, F: Field>
|
pub trait AllocVar<V, F: Field>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
V: ?Sized,
|
V: ?Sized,
|
||||||
{
|
{
|
||||||
|
/// Allocates a new variable of type `Self` in the `ConstraintSystem`.
|
||||||
|
/// The mode of allocation is decided by `mode`.
|
||||||
fn new_variable<T: Borrow<V>>(
|
fn new_variable<T: Borrow<V>>(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||||
mode: AllocationMode,
|
mode: AllocationMode,
|
||||||
) -> Result<Self, SynthesisError>;
|
) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
|
/// Allocates a new constant of type `Self` in the `ConstraintSystem`.
|
||||||
#[tracing::instrument(target = "r1cs", skip(cs, t))]
|
#[tracing::instrument(target = "r1cs", skip(cs, t))]
|
||||||
fn new_constant(
|
fn new_constant(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
@@ -42,6 +57,7 @@ where
|
|||||||
Self::new_variable(cs, || Ok(t), AllocationMode::Constant)
|
Self::new_variable(cs, || Ok(t), AllocationMode::Constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a new public input of type `Self` in the `ConstraintSystem`.
|
||||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||||
fn new_input<T: Borrow<V>>(
|
fn new_input<T: Borrow<V>>(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
@@ -50,6 +66,7 @@ where
|
|||||||
Self::new_variable(cs, f, AllocationMode::Input)
|
Self::new_variable(cs, f, AllocationMode::Input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a new private witness of type `Self` in the `ConstraintSystem`.
|
||||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||||
fn new_witness<T: Borrow<V>>(
|
fn new_witness<T: Borrow<V>>(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
|
|||||||
@@ -254,6 +254,10 @@ impl<F: Field> Boolean<F> {
|
|||||||
/// Returns the constrant `false`.
|
/// Returns the constrant `false`.
|
||||||
pub const FALSE: Self = Boolean::Constant(false);
|
pub const FALSE: Self = Boolean::Constant(false);
|
||||||
|
|
||||||
|
/// Constructs a `LinearCombination` from `Self`'s variables.
|
||||||
|
///
|
||||||
|
/// * `Boolean::Is(v) => lc!() + v.variable()`
|
||||||
|
/// * `Boolean::Not(v) => lc!() + Variable::One - v.variable()`
|
||||||
pub fn lc(&self) -> LinearCombination<F> {
|
pub fn lc(&self) -> LinearCombination<F> {
|
||||||
match self {
|
match self {
|
||||||
Boolean::Constant(false) => lc!(),
|
Boolean::Constant(false) => lc!(),
|
||||||
@@ -263,7 +267,9 @@ impl<F: Field> Boolean<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a boolean vector from a vector of u8
|
/// Constructs a `Boolean` vector from a slice of constant `u8`.
|
||||||
|
///
|
||||||
|
/// This *does not* create any new variables.
|
||||||
pub fn constant_vec_from_bytes(values: &[u8]) -> Vec<Self> {
|
pub fn constant_vec_from_bytes(values: &[u8]) -> Vec<Self> {
|
||||||
let mut input_bits = vec![];
|
let mut input_bits = vec![];
|
||||||
for input_byte in values {
|
for input_byte in values {
|
||||||
@@ -274,12 +280,12 @@ impl<F: Field> Boolean<F> {
|
|||||||
input_bits
|
input_bits
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a boolean from a known constant
|
/// Constructs a constant `Boolean` with value `b`.
|
||||||
pub fn constant(b: bool) -> Self {
|
pub fn constant(b: bool) -> Self {
|
||||||
Boolean::Constant(b)
|
Boolean::Constant(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a negated interpretation of this boolean.
|
/// Negates `self`.
|
||||||
pub fn not(&self) -> Self {
|
pub fn not(&self) -> Self {
|
||||||
match *self {
|
match *self {
|
||||||
Boolean::Constant(c) => Boolean::Constant(!c),
|
Boolean::Constant(c) => Boolean::Constant(!c),
|
||||||
@@ -290,11 +296,14 @@ impl<F: Field> Boolean<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Boolean<F> {
|
impl<F: Field> Boolean<F> {
|
||||||
/// Perform XOR over two boolean operands
|
/// Outputs `self ^ other`.
|
||||||
|
///
|
||||||
|
/// If at least one of `self` and `other` are constants, then this method
|
||||||
|
/// *does not* create any constraints or variables.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn xor<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
pub fn xor<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> {
|
||||||
use Boolean::*;
|
use Boolean::*;
|
||||||
match (self, b) {
|
match (self, other) {
|
||||||
(&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()),
|
(&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()),
|
||||||
(&Constant(true), x) | (x, &Constant(true)) => Ok(x.not()),
|
(&Constant(true), x) | (x, &Constant(true)) => Ok(x.not()),
|
||||||
// a XOR (NOT b) = NOT(a XOR b)
|
// a XOR (NOT b) = NOT(a XOR b)
|
||||||
@@ -306,11 +315,14 @@ impl<F: Field> Boolean<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform OR over two boolean operands
|
/// Outputs `self | other`.
|
||||||
|
///
|
||||||
|
/// If at least one of `self` and `other` are constants, then this method
|
||||||
|
/// *does not* create any constraints or variables.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn or<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
pub fn or<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> {
|
||||||
use Boolean::*;
|
use Boolean::*;
|
||||||
match (self, b) {
|
match (self, other) {
|
||||||
(&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()),
|
(&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()),
|
||||||
(&Constant(true), _) | (_, &Constant(true)) => Ok(Constant(true)),
|
(&Constant(true), _) | (_, &Constant(true)) => Ok(Constant(true)),
|
||||||
// a OR b = NOT ((NOT a) AND b)
|
// a OR b = NOT ((NOT a) AND b)
|
||||||
@@ -321,11 +333,14 @@ impl<F: Field> Boolean<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform AND over two boolean operands
|
/// Outputs `self & other`.
|
||||||
|
///
|
||||||
|
/// If at least one of `self` and `other` are constants, then this method
|
||||||
|
/// *does not* create any constraints or variables.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn and<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> {
|
pub fn and<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> {
|
||||||
use Boolean::*;
|
use Boolean::*;
|
||||||
match (self, b) {
|
match (self, other) {
|
||||||
// false AND x is always false
|
// false AND x is always false
|
||||||
(&Constant(false), _) | (_, &Constant(false)) => Ok(Constant(false)),
|
(&Constant(false), _) | (_, &Constant(false)) => Ok(Constant(false)),
|
||||||
// true AND x is always x
|
// true AND x is always x
|
||||||
@@ -339,6 +354,7 @@ impl<F: Field> Boolean<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `bits[0] & bits[1] & ... & bits.last().unwrap()`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> {
|
pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||||
assert!(!bits.is_empty());
|
assert!(!bits.is_empty());
|
||||||
@@ -354,6 +370,7 @@ impl<F: Field> Boolean<F> {
|
|||||||
Ok(cur.expect("should not be 0"))
|
Ok(cur.expect("should not be 0"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `bits[0] | bits[1] | ... | bits.last().unwrap()`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> {
|
pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||||
assert!(!bits.is_empty());
|
assert!(!bits.is_empty());
|
||||||
@@ -369,12 +386,15 @@ impl<F: Field> Boolean<F> {
|
|||||||
Ok(cur.expect("should not be 0"))
|
Ok(cur.expect("should not be 0"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `(bits[0] & bits[1] & ... & bits.last().unwrap()).not()`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> {
|
pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> {
|
||||||
Ok(Self::kary_and(bits)?.not())
|
Ok(Self::kary_and(bits)?.not())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert that at least one input is false.
|
/// Enforces that `Self::kary_nand(bits).is_eq(&Boolean::TRUE)`.
|
||||||
|
///
|
||||||
|
/// Informally, this means that at least one element in `bits` must be `false`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> {
|
fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> {
|
||||||
use Boolean::*;
|
use Boolean::*;
|
||||||
@@ -392,7 +412,7 @@ impl<F: Field> Boolean<F> {
|
|||||||
|
|
||||||
/// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`,
|
/// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`,
|
||||||
/// That is, interpret bits as a little-endian integer, and enforce that this integer
|
/// That is, interpret bits as a little-endian integer, and enforce that this integer
|
||||||
/// is "in the field F".
|
/// is "in the field Z_p", where `p = F::characteristic()` .
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
|
pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
|
||||||
// `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
|
// `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
|
||||||
@@ -466,6 +486,9 @@ impl<F: Field> Boolean<F> {
|
|||||||
Ok(current_run)
|
Ok(current_run)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Conditionally selects one of `first` and `second` based on the value of `self`:
|
||||||
|
///
|
||||||
|
/// If `self.is_eq(&Boolean::TRUE)`, this outputs `first`; else, it outputs `second`.
|
||||||
#[tracing::instrument(target = "r1cs", skip(first, second))]
|
#[tracing::instrument(target = "r1cs", skip(first, second))]
|
||||||
pub fn select<T: CondSelectGadget<F>>(
|
pub fn select<T: CondSelectGadget<F>>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -5,15 +5,20 @@ use crate::{
|
|||||||
use algebra::Field;
|
use algebra::Field;
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
|
/// This module contains `Boolean`, a R1CS equivalent of the `bool` type.
|
||||||
pub mod boolean;
|
pub mod boolean;
|
||||||
|
/// This module contains `UInt8`, a R1CS equivalent of the `u8` type.
|
||||||
pub mod uint8;
|
pub mod uint8;
|
||||||
|
/// This module contains a macro for generating `UIntN` types, which are R1CS equivalents of
|
||||||
|
/// `N`-bit unsigned integers.
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod uint;
|
pub mod uint;
|
||||||
|
|
||||||
make_uint!(UInt16, 16, u16, uint16);
|
make_uint!(UInt16, 16, u16, uint16, "16");
|
||||||
make_uint!(UInt32, 32, u32, uint32);
|
make_uint!(UInt32, 32, u32, uint32, "32");
|
||||||
make_uint!(UInt64, 64, u64, uint64);
|
make_uint!(UInt64, 64, u64, uint64, "64");
|
||||||
|
|
||||||
|
/// Specifies constraints for conversion to a little-endian bit representation of `self`.
|
||||||
pub trait ToBitsGadget<F: Field> {
|
pub trait ToBitsGadget<F: Field> {
|
||||||
/// Outputs the canonical little-endian bit-wise representation of `self`.
|
/// Outputs the canonical little-endian bit-wise representation of `self`.
|
||||||
///
|
///
|
||||||
@@ -70,6 +75,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies constraints for conversion to a little-endian byte representation of `self`.
|
||||||
pub trait ToBytesGadget<F: Field> {
|
pub trait ToBytesGadget<F: Field> {
|
||||||
/// Outputs a canonical, little-endian, byte decomposition of `self`.
|
/// Outputs a canonical, little-endian, byte decomposition of `self`.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
macro_rules! make_uint {
|
macro_rules! make_uint {
|
||||||
($name:ident, $size:expr, $native:ident, $mod_name:ident) => {
|
($name:ident, $size:expr, $native:ident, $mod_name:ident, $native_doc_name:expr) => {
|
||||||
|
#[doc = "This module contains a `UInt"]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "`, a R1CS equivalent of the `u"]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "`type."]
|
||||||
pub mod $mod_name {
|
pub mod $mod_name {
|
||||||
use algebra::{Field, FpParameters, PrimeField};
|
use algebra::{Field, FpParameters, PrimeField};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
@@ -15,8 +20,14 @@ macro_rules! make_uint {
|
|||||||
Assignment, Vec,
|
Assignment, Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents an interpretation of `Boolean` objects as an
|
#[doc = "This struct represent an unsigned"]
|
||||||
/// unsigned integer.
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "-bit integer as a sequence of "]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = " `Boolean`s\n"]
|
||||||
|
#[doc = "This is the R1CS equivalent of the native `u"]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "` unsigned integer type."]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct $name<F: Field> {
|
pub struct $name<F: Field> {
|
||||||
// Least significant bit first
|
// Least significant bit first
|
||||||
@@ -46,7 +57,11 @@ macro_rules! make_uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> $name<F> {
|
impl<F: Field> $name<F> {
|
||||||
/// Construct a constant `$name` from a `$native`
|
#[doc = "Construct a constant `UInt"]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "` from the native `u"]
|
||||||
|
#[doc = $native_doc_name]
|
||||||
|
#[doc = "` type."]
|
||||||
pub fn constant(value: $native) -> Self {
|
pub fn constant(value: $native) -> Self {
|
||||||
let mut bits = Vec::with_capacity($size);
|
let mut bits = Vec::with_capacity($size);
|
||||||
|
|
||||||
@@ -67,13 +82,18 @@ macro_rules! make_uint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turns this `$name` into its little-endian byte order representation.
|
/// Turns `self` into the underlying little-endian bits.
|
||||||
pub fn to_bits_le(&self) -> Vec<Boolean<F>> {
|
pub fn to_bits_le(&self) -> Vec<Boolean<F>> {
|
||||||
self.bits.clone()
|
self.bits.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a little-endian byte order representation of bits into a
|
/// Construct `Self` from a slice of `Boolean`s.
|
||||||
/// `$name`.
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This method panics if `bits.len() != u
|
||||||
|
#[doc($native_doc_name)]
|
||||||
|
#[doc("`.")]
|
||||||
pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
|
pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
|
||||||
assert_eq!(bits.len(), $size);
|
assert_eq!(bits.len(), $size);
|
||||||
|
|
||||||
@@ -105,6 +125,7 @@ macro_rules! make_uint {
|
|||||||
Self { value, bits }
|
Self { value, bits }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rotates `self` to the right by `by` steps, wrapping around.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
#[tracing::instrument(target = "r1cs", skip(self))]
|
||||||
pub fn rotr(&self, by: usize) -> Self {
|
pub fn rotr(&self, by: usize) -> Self {
|
||||||
let by = by % $size;
|
let by = by % $size;
|
||||||
@@ -126,8 +147,11 @@ macro_rules! make_uint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XOR this `$name` with another `$name`
|
/// Outputs `self ^ other`.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self))]
|
///
|
||||||
|
/// If at least one of `self` and `other` are constants, then this method
|
||||||
|
/// *does not* create any constraints or variables.
|
||||||
|
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||||
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
||||||
let new_value = match (self.value, other.value) {
|
let new_value = match (self.value, other.value) {
|
||||||
(Some(a), Some(b)) => Some(a ^ b),
|
(Some(a), Some(b)) => Some(a ^ b),
|
||||||
@@ -147,8 +171,10 @@ macro_rules! make_uint {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform modular addition of several `$name` objects.
|
/// Perform modular addition of `operands`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
///
|
||||||
|
/// The user must ensure that overflow does not occur.
|
||||||
|
#[tracing::instrument(target = "r1cs", skip(operands))]
|
||||||
pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError>
|
pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError>
|
||||||
where
|
where
|
||||||
F: PrimeField,
|
F: PrimeField,
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ impl<F: Field> UInt8<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a slice of `u8`'s as private witnesses.
|
||||||
pub fn new_witness_vec(
|
pub fn new_witness_vec(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
values: &[impl Into<Option<u8>> + Copy],
|
values: &[impl Into<Option<u8>> + Copy],
|
||||||
@@ -78,10 +79,13 @@ impl<F: Field> UInt8<F> {
|
|||||||
Ok(output_vec)
|
Ok(output_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a vector of `u8`'s by first converting (chunks of) them to
|
/// Allocates a slice of `u8`'s as public inputs by first packing them into
|
||||||
/// `ConstraintF` elements, (thus reducing the number of input allocations),
|
/// `F` elements, (thus reducing the number of input allocations),
|
||||||
/// and then converts this list of `ConstraintF` gadgets back into
|
/// and then converts this list of `AllocatedFp<F>` variables back into
|
||||||
/// bytes.
|
/// bytes.
|
||||||
|
///
|
||||||
|
/// From a user perspective, this trade-off adds constraints, but improves
|
||||||
|
/// verifier time and verification key size.
|
||||||
pub fn new_input_vec(
|
pub fn new_input_vec(
|
||||||
cs: impl Into<Namespace<F>>,
|
cs: impl Into<Namespace<F>>,
|
||||||
values: &[u8],
|
values: &[u8],
|
||||||
@@ -134,7 +138,10 @@ impl<F: Field> UInt8<F> {
|
|||||||
Self { value, bits }
|
Self { value, bits }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XOR this `UInt8` with another `UInt8`
|
/// Outputs `self ^ other`.
|
||||||
|
///
|
||||||
|
/// If at least one of `self` and `other` are constants, then this method
|
||||||
|
/// *does not* create any constraints or variables.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> {
|
||||||
let new_value = match (self.value, other.value) {
|
let new_value = match (self.value, other.value) {
|
||||||
|
|||||||
@@ -2,17 +2,26 @@ use crate::{prelude::*, Vec};
|
|||||||
use algebra::Field;
|
use algebra::Field;
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
|
/// Specifies how to generate constraints that check for equality for two variables of type `Self`.
|
||||||
pub trait EqGadget<F: Field> {
|
pub trait EqGadget<F: Field> {
|
||||||
/// Output a `Boolean` value representing whether `self.value() == other.value()`.
|
/// Output a `Boolean` value representing whether `self.value() == other.value()`.
|
||||||
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>;
|
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>;
|
||||||
|
|
||||||
/// Output a `Boolean` value representing whether `self.value() != other.value()`.
|
/// Output a `Boolean` value representing whether `self.value() != other.value()`.
|
||||||
|
///
|
||||||
|
/// By default, this is defined as `self.is_eq(other)?.not()`.
|
||||||
fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||||
Ok(self.is_eq(other)?.not())
|
Ok(self.is_eq(other)?.not())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
|
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
|
||||||
/// enforce a vacuously true statement.
|
/// enforce a vacuously true statement.
|
||||||
|
///
|
||||||
|
/// A safe default implementation is provided that generates the following constraints:
|
||||||
|
/// `self.is_eq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
|
||||||
|
///
|
||||||
|
/// More efficient specialized implementation may be possible; implementors
|
||||||
|
/// are encouraged to carefully analyze the efficiency and safety of these.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||||
fn conditional_enforce_equal(
|
fn conditional_enforce_equal(
|
||||||
&self,
|
&self,
|
||||||
@@ -24,13 +33,25 @@ pub trait EqGadget<F: Field> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce that `self` and `other` are equal.
|
/// Enforce that `self` and `other` are equal.
|
||||||
|
///
|
||||||
|
/// A safe default implementation is provided that generates the following constraints:
|
||||||
|
/// `self.conditional_enforce_equal(other, &Boolean::TRUE)`.
|
||||||
|
///
|
||||||
|
/// More efficient specialized implementation may be possible; implementors
|
||||||
|
/// are encouraged to carefully analyze the efficiency and safety of these.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||||
fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
self.conditional_enforce_equal(other, &Boolean::constant(true))
|
self.conditional_enforce_equal(other, &Boolean::constant(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
|
/// If `should_enforce == true`, enforce that `self` and `other` are *not* equal; else,
|
||||||
/// enforce a vacuously true statement.
|
/// enforce a vacuously true statement.
|
||||||
|
///
|
||||||
|
/// A safe default implementation is provided that generates the following constraints:
|
||||||
|
/// `self.is_neq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
|
||||||
|
///
|
||||||
|
/// More efficient specialized implementation may be possible; implementors
|
||||||
|
/// are encouraged to carefully analyze the efficiency and safety of these.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||||
fn conditional_enforce_not_equal(
|
fn conditional_enforce_not_equal(
|
||||||
&self,
|
&self,
|
||||||
@@ -41,7 +62,13 @@ pub trait EqGadget<F: Field> {
|
|||||||
.conditional_enforce_equal(&Boolean::constant(true), should_enforce)
|
.conditional_enforce_equal(&Boolean::constant(true), should_enforce)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce that `self` and `other` are not equal.
|
/// Enforce that `self` and `other` are *not* equal.
|
||||||
|
///
|
||||||
|
/// A safe default implementation is provided that generates the following constraints:
|
||||||
|
/// `self.conditional_enforce_not_equal(other, &Boolean::TRUE)`.
|
||||||
|
///
|
||||||
|
/// More efficient specialized implementation may be possible; implementors
|
||||||
|
/// are encouraged to carefully analyze the efficiency and safety of these.
|
||||||
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
#[tracing::instrument(target = "r1cs", skip(self, other))]
|
||||||
fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
self.conditional_enforce_not_equal(other, &Boolean::constant(true))
|
self.conditional_enforce_not_equal(other, &Boolean::constant(true))
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ use crate::{
|
|||||||
Assignment, ToConstraintFieldGadget, Vec,
|
Assignment, ToConstraintFieldGadget, Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This struct is the `R1CS` equivalent of the cubic extension field type
|
||||||
|
/// in `algebra-core`, i.e. `algebra_core::CubicExtField`.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
|
#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -19,18 +21,24 @@ pub struct CubicExtVar<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicEx
|
|||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// The zero-th coefficient of this field element.
|
||||||
pub c0: BF,
|
pub c0: BF,
|
||||||
|
/// The first coefficient of this field element.
|
||||||
pub c1: BF,
|
pub c1: BF,
|
||||||
|
/// The second coefficient of this field element.
|
||||||
pub c2: BF,
|
pub c2: BF,
|
||||||
#[derivative(Debug = "ignore")]
|
#[derivative(Debug = "ignore")]
|
||||||
_params: PhantomData<P>,
|
_params: PhantomData<P>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait describes parameters that are used to implement arithmetic for `CubicExtVar`.
|
||||||
pub trait CubicExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
|
pub trait CubicExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
|
||||||
CubicExtParameters
|
CubicExtParameters
|
||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// Multiply the base field of the `CubicExtVar` by the appropriate Frobenius coefficient.
|
||||||
|
/// This is equivalent to `Self::mul_base_field_by_frob_coeff(c1, c2, power)`.
|
||||||
fn mul_base_field_vars_by_frob_coeff(c1: &mut BF, c2: &mut BF, power: usize);
|
fn mul_base_field_vars_by_frob_coeff(c1: &mut BF, c2: &mut BF, power: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +46,7 @@ impl<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>> Cu
|
|||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// Constructs a `CubicExtVar` from the underlying coefficients.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(c0: BF, c1: BF, c2: BF) -> Self {
|
pub fn new(c0: BF, c1: BF, c2: BF) -> Self {
|
||||||
let _params = PhantomData;
|
let _params = PhantomData;
|
||||||
@@ -49,13 +58,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply a BF by cubic nonresidue P::NONRESIDUE.
|
/// Multiplies a variable of the base field by the cubic nonresidue `P::NONRESIDUE` that
|
||||||
|
/// is used to construct the extension field.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
|
pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
|
||||||
Ok(fe * P::NONRESIDUE)
|
Ok(fe * P::NONRESIDUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply a CubicExtVar by an element of `P::BaseField`.
|
/// Multiplies `self` by a constant from the base field.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self {
|
pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self {
|
||||||
let c0 = &self.c0 * fe;
|
let c0 = &self.c0 * fe;
|
||||||
@@ -64,6 +74,7 @@ where
|
|||||||
Self::new(c0, c1, c2)
|
Self::new(c0, c1, c2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = self.mul_by_base_field_constant(fe)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) {
|
pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) {
|
||||||
*self = (&*self).mul_by_base_field_constant(fe);
|
*self = (&*self).mul_by_base_field_constant(fe);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl<F: PrimeField> FpVar<F> {
|
|||||||
Ok((left.clone(), right_for_check))
|
Ok((left.clone(), right_for_check))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to enforce `self <= (p-1)/2`.
|
/// Helper function to enforce that `self <= (p-1)/2`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two(
|
pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -6,17 +6,23 @@ use core::borrow::Borrow;
|
|||||||
use crate::fields::{FieldOpsBounds, FieldVar};
|
use crate::fields::{FieldOpsBounds, FieldVar};
|
||||||
use crate::{prelude::*, Assignment, ToConstraintFieldGadget, Vec};
|
use crate::{prelude::*, Assignment, ToConstraintFieldGadget, Vec};
|
||||||
|
|
||||||
pub mod cmp;
|
mod cmp;
|
||||||
|
|
||||||
|
/// Represents a variable in the constraint system whose
|
||||||
|
/// value can be an arbitrary field element.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct AllocatedFp<F: PrimeField> {
|
pub struct AllocatedFp<F: PrimeField> {
|
||||||
pub(crate) value: Option<F>,
|
pub(crate) value: Option<F>,
|
||||||
|
/// The allocated variable corresponding to `self` in `self.cs`.
|
||||||
pub variable: Variable,
|
pub variable: Variable,
|
||||||
|
/// The constraint system that `self` was allocated in.
|
||||||
pub cs: ConstraintSystemRef<F>,
|
pub cs: ConstraintSystemRef<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> AllocatedFp<F> {
|
impl<F: PrimeField> AllocatedFp<F> {
|
||||||
|
/// Constructs a new `AllocatedFp` from a (optional) value, a low-level Variable,
|
||||||
|
/// and a `ConstraintSystemRef`.
|
||||||
pub fn new(value: Option<F>, variable: Variable, cs: ConstraintSystemRef<F>) -> Self {
|
pub fn new(value: Option<F>, variable: Variable, cs: ConstraintSystemRef<F>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
@@ -26,11 +32,14 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represent variables corresponding to the field `F`.
|
/// Represent variables corresponding to a field element in `F`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub enum FpVar<F: PrimeField> {
|
pub enum FpVar<F: PrimeField> {
|
||||||
|
/// Represents a constant in the constraint system, which means that
|
||||||
|
/// it does not have a corresponding variable.
|
||||||
Constant(F),
|
Constant(F),
|
||||||
|
/// Represents an allocated variable constant in the constraint system.
|
||||||
Var(AllocatedFp<F>),
|
Var(AllocatedFp<F>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +88,7 @@ impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar<F> {}
|
|||||||
impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar<F>> for &'a FpVar<F> {}
|
impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar<F>> for &'a FpVar<F> {}
|
||||||
|
|
||||||
impl<F: PrimeField> AllocatedFp<F> {
|
impl<F: PrimeField> AllocatedFp<F> {
|
||||||
|
/// Constructs `Self` from a `Boolean`: if `other` is false, this outputs `zero`, else it outputs `one`.
|
||||||
pub fn from(other: Boolean<F>) -> Self {
|
pub fn from(other: Boolean<F>) -> Self {
|
||||||
if let Some(cs) = other.cs() {
|
if let Some(cs) = other.cs() {
|
||||||
let variable = cs.new_lc(other.lc()).unwrap();
|
let variable = cs.new_lc(other.lc()).unwrap();
|
||||||
@@ -88,10 +98,15 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system
|
||||||
|
/// (if a value was assigned).
|
||||||
pub fn value(&self) -> Result<F, SynthesisError> {
|
pub fn value(&self) -> Result<F, SynthesisError> {
|
||||||
self.cs.assigned_value(self.variable).get()
|
self.cs.assigned_value(self.variable).get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `self + other`.
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn add(&self, other: &Self) -> Self {
|
pub fn add(&self, other: &Self) -> Self {
|
||||||
let value = match (self.value, other.value) {
|
let value = match (self.value, other.value) {
|
||||||
@@ -106,6 +121,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
AllocatedFp::new(value, variable, self.cs.clone())
|
AllocatedFp::new(value, variable, self.cs.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `self - other`.
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn sub(&self, other: &Self) -> Self {
|
pub fn sub(&self, other: &Self) -> Self {
|
||||||
let value = match (self.value, other.value) {
|
let value = match (self.value, other.value) {
|
||||||
@@ -120,6 +138,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
AllocatedFp::new(value, variable, self.cs.clone())
|
AllocatedFp::new(value, variable, self.cs.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `self * other`.
|
||||||
|
///
|
||||||
|
/// This requires *one* constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn mul(&self, other: &Self) -> Self {
|
pub fn mul(&self, other: &Self) -> Self {
|
||||||
let product = AllocatedFp::new_witness(self.cs.clone(), || {
|
let product = AllocatedFp::new_witness(self.cs.clone(), || {
|
||||||
@@ -136,6 +157,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
product
|
product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output `self + other`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn add_constant(&self, other: F) -> Self {
|
pub fn add_constant(&self, other: F) -> Self {
|
||||||
if other.is_zero() {
|
if other.is_zero() {
|
||||||
@@ -150,11 +174,17 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output `self - other`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn sub_constant(&self, other: F) -> Self {
|
pub fn sub_constant(&self, other: F) -> Self {
|
||||||
self.add_constant(-other)
|
self.add_constant(-other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output `self * other`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn mul_constant(&self, other: F) -> Self {
|
pub fn mul_constant(&self, other: F) -> Self {
|
||||||
if other.is_one() {
|
if other.is_one() {
|
||||||
@@ -166,6 +196,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output `self + self`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn double(&self) -> Result<Self, SynthesisError> {
|
pub fn double(&self) -> Result<Self, SynthesisError> {
|
||||||
let value = self.value.map(|val| val.double());
|
let value = self.value.map(|val| val.double());
|
||||||
@@ -173,6 +206,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
Ok(Self::new(value, variable, self.cs.clone()))
|
Ok(Self::new(value, variable, self.cs.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Output `-self`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn negate(&self) -> Self {
|
pub fn negate(&self) -> Self {
|
||||||
let mut result = self.clone();
|
let mut result = self.clone();
|
||||||
@@ -180,6 +216,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = -self`
|
||||||
|
///
|
||||||
|
/// This does not create any constraints.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn negate_in_place(&mut self) -> &mut Self {
|
pub fn negate_in_place(&mut self) -> &mut Self {
|
||||||
self.value.as_mut().map(|val| *val = -(*val));
|
self.value.as_mut().map(|val| *val = -(*val));
|
||||||
@@ -187,11 +226,17 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `self * self`
|
||||||
|
///
|
||||||
|
/// This requires *one* constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn square(&self) -> Result<Self, SynthesisError> {
|
pub fn square(&self) -> Result<Self, SynthesisError> {
|
||||||
Ok(self.mul(self))
|
Ok(self.mul(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outputs `result` such that `result * self = 1`.
|
||||||
|
///
|
||||||
|
/// This requires *one* constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn inverse(&self) -> Result<Self, SynthesisError> {
|
pub fn inverse(&self) -> Result<Self, SynthesisError> {
|
||||||
let inverse = Self::new_witness(self.cs.clone(), || {
|
let inverse = Self::new_witness(self.cs.clone(), || {
|
||||||
@@ -206,11 +251,15 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
Ok(inverse)
|
Ok(inverse)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is a no-op for prime fields.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> {
|
pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> {
|
||||||
Ok(self.clone())
|
Ok(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces that `self * other = result`.
|
||||||
|
///
|
||||||
|
/// This requires *one* constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||||
self.cs.enforce_constraint(
|
self.cs.enforce_constraint(
|
||||||
@@ -220,6 +269,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces that `self * self = result`.
|
||||||
|
///
|
||||||
|
/// This requires *one* constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
||||||
self.cs.enforce_constraint(
|
self.cs.enforce_constraint(
|
||||||
@@ -231,9 +283,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
|
|
||||||
/// Outputs the bit `self == other`.
|
/// Outputs the bit `self == other`.
|
||||||
///
|
///
|
||||||
/// # Constraint cost
|
/// This requires three constraints.
|
||||||
///
|
|
||||||
/// Consumes three constraints
|
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||||
Ok(self.is_neq(other)?.not())
|
Ok(self.is_neq(other)?.not())
|
||||||
@@ -241,9 +291,7 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
|
|
||||||
/// Outputs the bit `self != other`.
|
/// Outputs the bit `self != other`.
|
||||||
///
|
///
|
||||||
/// # Constraint cost
|
/// This requires three constraints.
|
||||||
///
|
|
||||||
/// Consumes three constraints
|
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
|
||||||
let is_not_equal = Boolean::new_witness(self.cs.clone(), || {
|
let is_not_equal = Boolean::new_witness(self.cs.clone(), || {
|
||||||
@@ -311,6 +359,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
Ok(is_not_equal)
|
Ok(is_not_equal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces that self == other if `should_enforce.is_eq(&Boolean::TRUE)`.
|
||||||
|
///
|
||||||
|
/// This requires one constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn conditional_enforce_equal(
|
pub fn conditional_enforce_equal(
|
||||||
&self,
|
&self,
|
||||||
@@ -324,6 +375,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces that self != other if `should_enforce.is_eq(&Boolean::TRUE)`.
|
||||||
|
///
|
||||||
|
/// This requires one constraint.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn conditional_enforce_not_equal(
|
pub fn conditional_enforce_not_equal(
|
||||||
&self,
|
&self,
|
||||||
@@ -353,6 +407,9 @@ impl<F: PrimeField> AllocatedFp<F> {
|
|||||||
impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
|
impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
|
||||||
/// Outputs the unique bit-wise decomposition of `self` in *little-endian*
|
/// Outputs the unique bit-wise decomposition of `self` in *little-endian*
|
||||||
/// form.
|
/// form.
|
||||||
|
///
|
||||||
|
/// This method enforces that the output is in the field, i.e.
|
||||||
|
/// it invokes `Boolean::enforce_in_field_le` on the bit decomposition.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
|
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
|
||||||
let bits = self.to_non_unique_bits_le()?;
|
let bits = self.to_non_unique_bits_le()?;
|
||||||
@@ -405,6 +462,9 @@ impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
|
|||||||
impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
|
impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> {
|
||||||
/// Outputs the unique byte decomposition of `self` in *little-endian*
|
/// Outputs the unique byte decomposition of `self` in *little-endian*
|
||||||
/// form.
|
/// form.
|
||||||
|
///
|
||||||
|
/// This method enforces that the decomposition represents
|
||||||
|
/// an integer that is less than `F::MODULUS`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
|
||||||
let num_bits = F::BigInt::NUM_LIMBS * 64;
|
let num_bits = F::BigInt::NUM_LIMBS * 64;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ use crate::fields::{fp2::Fp2Var, fp6_3over2::Fp6Var, quadratic_extension::*, Fie
|
|||||||
use algebra::fields::{fp12_2over3over2::*, fp6_3over2::Fp6Parameters, Field, QuadExtParameters};
|
use algebra::fields::{fp12_2over3over2::*, fp6_3over2::Fp6Parameters, Field, QuadExtParameters};
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
|
/// A degree-12 extension field constructed as the tower of a
|
||||||
|
/// quadratic extension over a cubic extension over a quadratic extension field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::fp12_2over3over2::Fp12<P>`.
|
||||||
pub type Fp12Var<P> = QuadExtVar<Fp6Var<<P as Fp12Parameters>::Fp6Params>, Fp12ParamsWrapper<P>>;
|
pub type Fp12Var<P> = QuadExtVar<Fp6Var<<P as Fp12Parameters>::Fp6Params>, Fp12ParamsWrapper<P>>;
|
||||||
|
|
||||||
type Fp2Params<P> = <<P as Fp12Parameters>::Fp6Params as Fp6Parameters>::Fp2Params;
|
type Fp2Params<P> = <<P as Fp12Parameters>::Fp6Params as Fp6Parameters>::Fp2Params;
|
||||||
@@ -15,7 +18,7 @@ impl<P: Fp12Parameters> QuadExtVarParams<Fp6Var<P::Fp6Params>> for Fp12ParamsWra
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Fp12Parameters> Fp12Var<P> {
|
impl<P: Fp12Parameters> Fp12Var<P> {
|
||||||
/// Multiplies by an element of the form (c0 = (c0, c1, 0), c1 = (0, d1, 0))
|
/// Multiplies by a sparse element of the form `(c0 = (c0, c1, 0), c1 = (0, d1, 0))`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_by_014(
|
pub fn mul_by_014(
|
||||||
&self,
|
&self,
|
||||||
@@ -31,7 +34,7 @@ impl<P: Fp12Parameters> Fp12Var<P> {
|
|||||||
Ok(Self::new(new_c0, new_c1))
|
Ok(Self::new(new_c0, new_c1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiplies by an element of the form (c0 = (c0, 0, 0), c1 = (d0, d1, 0))
|
/// Multiplies by a sparse element of the form `(c0 = (c0, 0, 0), c1 = (d0, d1, 0))`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_by_034(
|
pub fn mul_by_034(
|
||||||
&self,
|
&self,
|
||||||
@@ -54,6 +57,7 @@ impl<P: Fp12Parameters> Fp12Var<P> {
|
|||||||
Ok(Self::new(new_c0, new_c1))
|
Ok(Self::new(new_c0, new_c1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Squares `self` when `self` is in the cyclotomic subgroup.
|
||||||
pub fn cyclotomic_square(&self) -> Result<Self, SynthesisError> {
|
pub fn cyclotomic_square(&self) -> Result<Self, SynthesisError> {
|
||||||
if characteristic_square_mod_6_is_one(Fp12::<P>::characteristic()) {
|
if characteristic_square_mod_6_is_one(Fp12::<P>::characteristic()) {
|
||||||
let fp2_nr = <P::Fp6Params as Fp6Parameters>::NONRESIDUE;
|
let fp2_nr = <P::Fp6Params as Fp6Parameters>::NONRESIDUE;
|
||||||
@@ -132,7 +136,7 @@ impl<P: Fp12Parameters> Fp12Var<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `Self::cyclotomic_exp, but additionally uses cyclotomic squaring.
|
/// Like `Self::cyclotomic_exp`, but additionally uses cyclotomic squaring.
|
||||||
pub fn optimized_cyclotomic_exp(
|
pub fn optimized_cyclotomic_exp(
|
||||||
&self,
|
&self,
|
||||||
exponent: impl AsRef<[u64]>,
|
exponent: impl AsRef<[u64]>,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::fields::{fp::FpVar, quadratic_extension::*};
|
use crate::fields::{fp::FpVar, quadratic_extension::*};
|
||||||
use algebra::fields::{Fp2Parameters, Fp2ParamsWrapper, QuadExtParameters};
|
use algebra::fields::{Fp2Parameters, Fp2ParamsWrapper, QuadExtParameters};
|
||||||
|
|
||||||
|
/// A quadratic extension field constructed over a prime field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::Fp2<P>`.
|
||||||
pub type Fp2Var<P> = QuadExtVar<FpVar<<P as Fp2Parameters>::Fp>, Fp2ParamsWrapper<P>>;
|
pub type Fp2Var<P> = QuadExtVar<FpVar<<P as Fp2Parameters>::Fp>, Fp2ParamsWrapper<P>>;
|
||||||
|
|
||||||
impl<P: Fp2Parameters> QuadExtVarParams<FpVar<P::Fp>> for Fp2ParamsWrapper<P> {
|
impl<P: Fp2Parameters> QuadExtVarParams<FpVar<P::Fp>> for Fp2ParamsWrapper<P> {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::fields::{cubic_extension::*, fp::FpVar};
|
use crate::fields::{cubic_extension::*, fp::FpVar};
|
||||||
use algebra::fields::{CubicExtParameters, Fp3Parameters, Fp3ParamsWrapper};
|
use algebra::fields::{CubicExtParameters, Fp3Parameters, Fp3ParamsWrapper};
|
||||||
|
|
||||||
|
/// A cubic extension field constructed over a prime field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::Fp3<P>`.
|
||||||
pub type Fp3Var<P> = CubicExtVar<FpVar<<P as Fp3Parameters>::Fp>, Fp3ParamsWrapper<P>>;
|
pub type Fp3Var<P> = CubicExtVar<FpVar<<P as Fp3Parameters>::Fp>, Fp3ParamsWrapper<P>>;
|
||||||
|
|
||||||
impl<P: Fp3Parameters> CubicExtVarParams<FpVar<P::Fp>> for Fp3ParamsWrapper<P> {
|
impl<P: Fp3Parameters> CubicExtVarParams<FpVar<P::Fp>> for Fp3ParamsWrapper<P> {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use crate::fields::{fp2::Fp2Var, quadratic_extension::*};
|
use crate::fields::{fp2::Fp2Var, quadratic_extension::*};
|
||||||
use algebra::fields::{Fp4Parameters, Fp4ParamsWrapper, QuadExtParameters};
|
use algebra::fields::{Fp4Parameters, Fp4ParamsWrapper, QuadExtParameters};
|
||||||
|
|
||||||
|
/// A quartic extension field constructed as the tower of a
|
||||||
|
/// quadratic extension over a quadratic extension field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::Fp4<P>`.
|
||||||
pub type Fp4Var<P> = QuadExtVar<Fp2Var<<P as Fp4Parameters>::Fp2Params>, Fp4ParamsWrapper<P>>;
|
pub type Fp4Var<P> = QuadExtVar<Fp2Var<<P as Fp4Parameters>::Fp2Params>, Fp4ParamsWrapper<P>>;
|
||||||
|
|
||||||
impl<P: Fp4Parameters> QuadExtVarParams<Fp2Var<P::Fp2Params>> for Fp4ParamsWrapper<P> {
|
impl<P: Fp4Parameters> QuadExtVarParams<Fp2Var<P::Fp2Params>> for Fp4ParamsWrapper<P> {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use crate::fields::{fp3::Fp3Var, quadratic_extension::*};
|
use crate::fields::{fp3::Fp3Var, quadratic_extension::*};
|
||||||
use algebra::fields::{fp6_2over3::*, QuadExtParameters};
|
use algebra::fields::{fp6_2over3::*, QuadExtParameters};
|
||||||
|
|
||||||
|
/// A sextic extension field constructed as the tower of a
|
||||||
|
/// quadratic extension over a cubic extension field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::fp6_2over3::Fp6<P>`.
|
||||||
pub type Fp6Var<P> = QuadExtVar<Fp3Var<<P as Fp6Parameters>::Fp3Params>, Fp6ParamsWrapper<P>>;
|
pub type Fp6Var<P> = QuadExtVar<Fp3Var<<P as Fp6Parameters>::Fp3Params>, Fp6ParamsWrapper<P>>;
|
||||||
|
|
||||||
impl<P: Fp6Parameters> QuadExtVarParams<Fp3Var<P::Fp3Params>> for Fp6ParamsWrapper<P> {
|
impl<P: Fp6Parameters> QuadExtVarParams<Fp3Var<P::Fp3Params>> for Fp6ParamsWrapper<P> {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ use algebra::fields::{fp6_3over2::*, CubicExtParameters, Fp2};
|
|||||||
use core::ops::MulAssign;
|
use core::ops::MulAssign;
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
|
/// A sextic extension field constructed as the tower of a
|
||||||
|
/// cubic extension over a quadratic extension field.
|
||||||
|
/// This is the R1CS equivalent of `algebra_core::fp6_3over3::Fp6<P>`.
|
||||||
pub type Fp6Var<P> = CubicExtVar<Fp2Var<<P as Fp6Parameters>::Fp2Params>, Fp6ParamsWrapper<P>>;
|
pub type Fp6Var<P> = CubicExtVar<Fp2Var<<P as Fp6Parameters>::Fp2Params>, Fp6ParamsWrapper<P>>;
|
||||||
|
|
||||||
impl<P: Fp6Parameters> CubicExtVarParams<Fp2Var<P::Fp2Params>> for Fp6ParamsWrapper<P> {
|
impl<P: Fp6Parameters> CubicExtVarParams<Fp2Var<P::Fp2Params>> for Fp6ParamsWrapper<P> {
|
||||||
@@ -17,6 +20,7 @@ impl<P: Fp6Parameters> CubicExtVarParams<Fp2Var<P::Fp2Params>> for Fp6ParamsWrap
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Fp6Parameters> Fp6Var<P> {
|
impl<P: Fp6Parameters> Fp6Var<P> {
|
||||||
|
/// Multiplies `self` by a sparse element which has `c0 == c2 == zero`.
|
||||||
pub fn mul_by_0_c1_0(&self, c1: &Fp2Var<P::Fp2Params>) -> Result<Self, SynthesisError> {
|
pub fn mul_by_0_c1_0(&self, c1: &Fp2Var<P::Fp2Params>) -> Result<Self, SynthesisError> {
|
||||||
// Karatsuba multiplication
|
// Karatsuba multiplication
|
||||||
// v0 = a0 * b0 = 0
|
// v0 = a0 * b0 = 0
|
||||||
@@ -44,7 +48,7 @@ impl<P: Fp6Parameters> Fp6Var<P> {
|
|||||||
Ok(Self::new(c0, c1, c2))
|
Ok(Self::new(c0, c1, c2))
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[inline]
|
/// Multiplies `self` by a sparse element which has `c2 == zero`.
|
||||||
pub fn mul_by_c0_c1_0(
|
pub fn mul_by_c0_c1_0(
|
||||||
&self,
|
&self,
|
||||||
c0: &Fp2Var<P::Fp2Params>,
|
c0: &Fp2Var<P::Fp2Params>,
|
||||||
|
|||||||
@@ -7,18 +7,37 @@ use r1cs_core::SynthesisError;
|
|||||||
|
|
||||||
use crate::{prelude::*, Assignment};
|
use crate::{prelude::*, Assignment};
|
||||||
|
|
||||||
|
/// This module contains a generic implementation of cubic extension field variables.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::CubicExtField`.
|
||||||
pub mod cubic_extension;
|
pub mod cubic_extension;
|
||||||
|
/// This module contains a generic implementation of quadratic extension field variables.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::QuadExtField`.
|
||||||
pub mod quadratic_extension;
|
pub mod quadratic_extension;
|
||||||
|
|
||||||
|
/// This module contains a generic implementation of prime field variables.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::Fp*`.
|
||||||
pub mod fp;
|
pub mod fp;
|
||||||
|
|
||||||
|
/// This module contains a generic implementation of the degree-12 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::Fp12`
|
||||||
pub mod fp12;
|
pub mod fp12;
|
||||||
|
/// This module contains a generic implementation of the degree-2 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::Fp2`
|
||||||
pub mod fp2;
|
pub mod fp2;
|
||||||
|
/// This module contains a generic implementation of the degree-3 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::Fp3`
|
||||||
pub mod fp3;
|
pub mod fp3;
|
||||||
|
/// This module contains a generic implementation of the degree-4 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::Fp4`
|
||||||
pub mod fp4;
|
pub mod fp4;
|
||||||
|
/// This module contains a generic implementation of the degree-6 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::fp6_2over3::Fp6`
|
||||||
pub mod fp6_2over3;
|
pub mod fp6_2over3;
|
||||||
|
/// This module contains a generic implementation of the degree-6 tower extension field.
|
||||||
|
/// That is, it implements the R1CS equivalent of `algebra_core::fp6_3over2::Fp6`
|
||||||
pub mod fp6_3over2;
|
pub mod fp6_3over2;
|
||||||
|
|
||||||
/// A hack used to work around the lack of implied bounds.
|
/// This trait is a hack used to work around the lack of implied bounds.
|
||||||
pub trait FieldOpsBounds<'a, F, T: 'a>:
|
pub trait FieldOpsBounds<'a, F, T: 'a>:
|
||||||
Sized
|
Sized
|
||||||
+ Add<&'a T, Output = T>
|
+ Add<&'a T, Output = T>
|
||||||
@@ -56,62 +75,80 @@ pub trait FieldVar<F: Field, ConstraintF: Field>:
|
|||||||
+ MulAssign<F>
|
+ MulAssign<F>
|
||||||
+ Debug
|
+ Debug
|
||||||
{
|
{
|
||||||
|
/// Returns the constant `F::zero()`.
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// Returns a `Boolean` representing whether `self == Self::zero()`.
|
||||||
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||||
self.is_eq(&Self::zero())
|
self.is_eq(&Self::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the constant `F::one()`.
|
||||||
fn one() -> Self;
|
fn one() -> Self;
|
||||||
|
|
||||||
|
/// Returns a `Boolean` representing whether `self == Self::one()`.
|
||||||
fn is_one(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
fn is_one(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||||
self.is_eq(&Self::one())
|
self.is_eq(&Self::one())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a constant with value `v`.
|
||||||
|
///
|
||||||
|
/// This *should not* allocate any variables.
|
||||||
fn constant(v: F) -> Self;
|
fn constant(v: F) -> Self;
|
||||||
|
|
||||||
|
/// Computes `self + self`.
|
||||||
fn double(&self) -> Result<Self, SynthesisError> {
|
fn double(&self) -> Result<Self, SynthesisError> {
|
||||||
Ok(self.clone() + self)
|
Ok(self.clone() + self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = self + self`.
|
||||||
fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
||||||
*self += self.double()?;
|
*self += self.double()?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Coputes `-self`.
|
||||||
fn negate(&self) -> Result<Self, SynthesisError>;
|
fn negate(&self) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
|
/// Sets `self = -self`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
||||||
*self = self.negate()?;
|
*self = self.negate()?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes `self * self`.
|
||||||
|
///
|
||||||
|
/// A default implementation is provided which just invokes the underlying
|
||||||
|
/// multiplication routine. However, this method should be specialized
|
||||||
|
/// for extension fields, where faster algorithms exist for squaring.
|
||||||
fn square(&self) -> Result<Self, SynthesisError> {
|
fn square(&self) -> Result<Self, SynthesisError> {
|
||||||
Ok(self.clone() * self)
|
Ok(self.clone() * self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = self.square()`.
|
||||||
fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
|
||||||
*self = self.square()?;
|
*self = self.square()?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce that `self * other == result`.
|
/// Enforces that `self * other == result`.
|
||||||
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
|
||||||
let actual_result = self.clone() * other;
|
let actual_result = self.clone() * other;
|
||||||
result.enforce_equal(&actual_result)
|
result.enforce_equal(&actual_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce that `self * self == result`.
|
/// Enforces that `self * self == result`.
|
||||||
fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
|
||||||
let actual_result = self.square()?;
|
let actual_result = self.square()?;
|
||||||
result.enforce_equal(&actual_result)
|
result.enforce_equal(&actual_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes `result` such that `self * result == Self::one()`.
|
||||||
fn inverse(&self) -> Result<Self, SynthesisError>;
|
fn inverse(&self) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
/// Returns (self / denominator), but requires fewer constraints than
|
/// Returns `(self / denominator)`. but requires fewer constraints than
|
||||||
/// self * denominator.inverse()
|
/// `self * denominator.inverse()`.
|
||||||
/// It is up to the caller to ensure that denominator is non-zero,
|
/// It is up to the caller to ensure that denominator is non-zero,
|
||||||
/// since in that case the result is unconstrained.
|
/// since in that case the result is unconstrained.
|
||||||
fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
|
fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
|
||||||
@@ -125,8 +162,10 @@ pub trait FieldVar<F: Field, ConstraintF: Field>:
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the frobenius map over `self`.
|
||||||
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError>;
|
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
|
/// Sets `self = self.frobenius_map()`.
|
||||||
fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
|
fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
|
||||||
*self = self.frobenius_map(power)?;
|
*self = self.frobenius_map(power)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@@ -145,7 +184,8 @@ pub trait FieldVar<F: Field, ConstraintF: Field>:
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `self^S`, where S is interpreted as an integer.
|
/// Computes `self^S`, where S is interpreted as an little-endian u64-decomposition of
|
||||||
|
/// an integer.
|
||||||
fn pow_by_constant<S: AsRef<[u64]>>(&self, exp: S) -> Result<Self, SynthesisError> {
|
fn pow_by_constant<S: AsRef<[u64]>>(&self, exp: S) -> Result<Self, SynthesisError> {
|
||||||
let mut res = Self::one();
|
let mut res = Self::one();
|
||||||
for i in BitIteratorBE::without_leading_zeros(exp) {
|
for i in BitIteratorBE::without_leading_zeros(exp) {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ use crate::{
|
|||||||
Assignment, ToConstraintFieldGadget, Vec,
|
Assignment, ToConstraintFieldGadget, Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This struct is the `R1CS` equivalent of the quadratic extension field type
|
||||||
|
/// in `algebra-core`, i.e. `algebra_core::QuadExtField`.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
|
#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -19,17 +21,22 @@ pub struct QuadExtVar<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: QuadExtV
|
|||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// The zero-th coefficient of this field element.
|
||||||
pub c0: BF,
|
pub c0: BF,
|
||||||
|
/// The first coefficient of this field element.
|
||||||
pub c1: BF,
|
pub c1: BF,
|
||||||
#[derivative(Debug = "ignore")]
|
#[derivative(Debug = "ignore")]
|
||||||
_params: PhantomData<P>,
|
_params: PhantomData<P>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait describes parameters that are used to implement arithmetic for `QuadExtVar`.
|
||||||
pub trait QuadExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
|
pub trait QuadExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
|
||||||
QuadExtParameters
|
QuadExtParameters
|
||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// Multiply the base field of the `QuadExtVar` by the appropriate Frobenius coefficient.
|
||||||
|
/// This is equivalent to `Self::mul_base_field_by_frob_coeff(power)`.
|
||||||
fn mul_base_field_var_by_frob_coeff(fe: &mut BF, power: usize);
|
fn mul_base_field_var_by_frob_coeff(fe: &mut BF, power: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +44,7 @@ impl<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: QuadExtVarParams<BF>> Qua
|
|||||||
where
|
where
|
||||||
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
|
||||||
{
|
{
|
||||||
|
/// Constructs a `QuadExtVar` from the underlying coefficients.
|
||||||
pub fn new(c0: BF, c1: BF) -> Self {
|
pub fn new(c0: BF, c1: BF) -> Self {
|
||||||
Self {
|
Self {
|
||||||
c0,
|
c0,
|
||||||
@@ -45,12 +53,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply a BF by quadratic nonresidue P::NONRESIDUE.
|
/// Multiplies a variable of the base field by the quadratic nonresidue `P::NONRESIDUE` that
|
||||||
|
/// is used to construct the extension field.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
|
pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
|
||||||
Ok(fe * P::NONRESIDUE)
|
Ok(fe * P::NONRESIDUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Multiplies `self` by a constant from the base field.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self {
|
pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self {
|
||||||
let c0 = self.c0.clone() * fe;
|
let c0 = self.c0.clone() * fe;
|
||||||
@@ -58,6 +68,7 @@ where
|
|||||||
QuadExtVar::new(c0, c1)
|
QuadExtVar::new(c0, c1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = self.mul_by_base_field_constant(fe)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) {
|
pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) {
|
||||||
*self = (&*self).mul_by_base_field_constant(fe);
|
*self = (&*self).mul_by_base_field_constant(fe);
|
||||||
|
|||||||
@@ -1,2 +1,9 @@
|
|||||||
|
/// This module generically implements arithmetic for Short
|
||||||
|
/// Weierstrass elliptic curves by following the complete formulae of
|
||||||
|
/// [[Renes, Costello, Batina 2015]](https://eprint.iacr.org/2015/1060).
|
||||||
pub mod short_weierstrass;
|
pub mod short_weierstrass;
|
||||||
|
|
||||||
|
/// This module generically implements arithmetic for Twisted
|
||||||
|
/// Edwards elliptic curves by following the complete formulae described in the
|
||||||
|
/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html).
|
||||||
pub mod twisted_edwards;
|
pub mod twisted_edwards;
|
||||||
|
|||||||
@@ -16,19 +16,29 @@ use crate::{
|
|||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
/// Represents a projective point in G1.
|
||||||
pub type G1Var<P> =
|
pub type G1Var<P> =
|
||||||
ProjectiveVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
|
ProjectiveVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
|
||||||
|
|
||||||
|
/// Represents an affine point on G1. Should be used only for comparison and when
|
||||||
|
/// a canonical representation of a point is required, and not for arithmetic.
|
||||||
pub type G1AffineVar<P> =
|
pub type G1AffineVar<P> =
|
||||||
AffineVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
|
AffineVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
|
||||||
|
|
||||||
|
/// Represents a projective point in G2.
|
||||||
pub type G2Var<P> = ProjectiveVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
|
pub type G2Var<P> = ProjectiveVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
|
||||||
|
/// Represents an affine point on G2. Should be used only for comparison and when
|
||||||
|
/// a canonical representation of a point is required, and not for arithmetic.
|
||||||
pub type G2AffineVar<P> = AffineVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
|
pub type G2AffineVar<P> = AffineVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "G1Var<P>: Clone"), Debug(bound = "G1Var<P>: Debug"))]
|
#[derivative(Clone(bound = "G1Var<P>: Clone"), Debug(bound = "G1Var<P>: Debug"))]
|
||||||
pub struct G1PreparedVar<P: Bls12Parameters>(pub AffineVar<P::G1Parameters, FpVar<P::Fp>>);
|
pub struct G1PreparedVar<P: Bls12Parameters>(pub AffineVar<P::G1Parameters, FpVar<P::Fp>>);
|
||||||
|
|
||||||
impl<P: Bls12Parameters> G1PreparedVar<P> {
|
impl<P: Bls12Parameters> G1PreparedVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
||||||
let x = self.0.x.value()?;
|
let x = self.0.x.value()?;
|
||||||
let y = self.0.y.value()?;
|
let y = self.0.y.value()?;
|
||||||
@@ -37,6 +47,7 @@ impl<P: Bls12Parameters> G1PreparedVar<P> {
|
|||||||
Ok(g.into())
|
Ok(g.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Self` from a `G1Var`.
|
||||||
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let g = q.to_affine()?;
|
let g = q.to_affine()?;
|
||||||
Ok(Self(g))
|
Ok(Self(g))
|
||||||
@@ -90,12 +101,15 @@ impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
|||||||
|
|
||||||
type Fp2G<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
|
type Fp2G<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
|
||||||
type LCoeff<P> = (Fp2G<P>, Fp2G<P>);
|
type LCoeff<P> = (Fp2G<P>, Fp2G<P>);
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(
|
#[derivative(
|
||||||
Clone(bound = "Fp2Var<P::Fp2Params>: Clone"),
|
Clone(bound = "Fp2Var<P::Fp2Params>: Clone"),
|
||||||
Debug(bound = "Fp2Var<P::Fp2Params>: Debug")
|
Debug(bound = "Fp2Var<P::Fp2Params>: Debug")
|
||||||
)]
|
)]
|
||||||
pub struct G2PreparedVar<P: Bls12Parameters> {
|
pub struct G2PreparedVar<P: Bls12Parameters> {
|
||||||
|
#[doc(hidden)]
|
||||||
pub ell_coeffs: Vec<LCoeff<P>>,
|
pub ell_coeffs: Vec<LCoeff<P>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +179,7 @@ impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Bls12Parameters> G2PreparedVar<P> {
|
impl<P: Bls12Parameters> G2PreparedVar<P> {
|
||||||
|
/// Constructs `Self` from a `G2Var`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let q = q.to_affine()?;
|
let q = q.to_affine()?;
|
||||||
|
|||||||
@@ -16,17 +16,25 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
|
/// Represents a projective point in G1.
|
||||||
pub type G1Var<P> =
|
pub type G1Var<P> =
|
||||||
ProjectiveVar<<P as MNT4Parameters>::G1Parameters, FpVar<<P as MNT4Parameters>::Fp>>;
|
ProjectiveVar<<P as MNT4Parameters>::G1Parameters, FpVar<<P as MNT4Parameters>::Fp>>;
|
||||||
|
|
||||||
|
/// Represents a projective point in G2.
|
||||||
pub type G2Var<P> = ProjectiveVar<<P as MNT4Parameters>::G2Parameters, Fp2G<P>>;
|
pub type G2Var<P> = ProjectiveVar<<P as MNT4Parameters>::G2Parameters, Fp2G<P>>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
||||||
pub struct G1PreparedVar<P: MNT4Parameters> {
|
pub struct G1PreparedVar<P: MNT4Parameters> {
|
||||||
|
#[doc(hidden)]
|
||||||
pub x: FpVar<P::Fp>,
|
pub x: FpVar<P::Fp>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y: FpVar<P::Fp>,
|
pub y: FpVar<P::Fp>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub x_twist: Fp2Var<P::Fp2Params>,
|
pub x_twist: Fp2Var<P::Fp2Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y_twist: Fp2Var<P::Fp2Params>,
|
pub y_twist: Fp2Var<P::Fp2Params>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +72,7 @@ impl<P: MNT4Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT4Parameters> G1PreparedVar<P> {
|
impl<P: MNT4Parameters> G1PreparedVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
||||||
let (x, y, x_twist, y_twist) = (
|
let (x, y, x_twist, y_twist) = (
|
||||||
self.x.value()?,
|
self.x.value()?,
|
||||||
@@ -79,6 +88,7 @@ impl<P: MNT4Parameters> G1PreparedVar<P> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Self` from a `G1Var`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let q = q.to_affine()?;
|
let q = q.to_affine()?;
|
||||||
@@ -124,14 +134,22 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
|||||||
|
|
||||||
type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>;
|
type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
||||||
pub struct G2PreparedVar<P: MNT4Parameters> {
|
pub struct G2PreparedVar<P: MNT4Parameters> {
|
||||||
|
#[doc(hidden)]
|
||||||
pub x: Fp2Var<P::Fp2Params>,
|
pub x: Fp2Var<P::Fp2Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y: Fp2Var<P::Fp2Params>,
|
pub y: Fp2Var<P::Fp2Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub x_over_twist: Fp2Var<P::Fp2Params>,
|
pub x_over_twist: Fp2Var<P::Fp2Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y_over_twist: Fp2Var<P::Fp2Params>,
|
pub y_over_twist: Fp2Var<P::Fp2Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
|
pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
|
pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +243,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT4Parameters> G2PreparedVar<P> {
|
impl<P: MNT4Parameters> G2PreparedVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
|
pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
|
||||||
let x = self.x.value()?;
|
let x = self.x.value()?;
|
||||||
let y = self.y.value()?;
|
let y = self.y.value()?;
|
||||||
@@ -250,6 +269,7 @@ impl<P: MNT4Parameters> G2PreparedVar<P> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Self` from a `G2Var`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let twist_inv = P::TWIST.inverse().unwrap();
|
let twist_inv = P::TWIST.inverse().unwrap();
|
||||||
@@ -320,6 +340,7 @@ impl<P: MNT4Parameters> G2PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
||||||
pub struct AteDoubleCoefficientsVar<P: MNT4Parameters> {
|
pub struct AteDoubleCoefficientsVar<P: MNT4Parameters> {
|
||||||
@@ -385,6 +406,7 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT4Parameters> AteDoubleCoefficientsVar<P> {
|
impl<P: MNT4Parameters> AteDoubleCoefficientsVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
|
pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
|
||||||
let (c_h, c_4c, c_j, c_l) = (
|
let (c_h, c_4c, c_j, c_l) = (
|
||||||
self.c_l.value()?,
|
self.c_l.value()?,
|
||||||
@@ -401,6 +423,7 @@ impl<P: MNT4Parameters> AteDoubleCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))]
|
||||||
pub struct AteAdditionCoefficientsVar<P: MNT4Parameters> {
|
pub struct AteAdditionCoefficientsVar<P: MNT4Parameters> {
|
||||||
@@ -451,12 +474,14 @@ impl<P: MNT4Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT4Parameters> AteAdditionCoefficientsVar<P> {
|
impl<P: MNT4Parameters> AteAdditionCoefficientsVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
|
pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
|
||||||
let (c_l1, c_rz) = (self.c_l1.value()?, self.c_rz.value()?);
|
let (c_l1, c_rz) = (self.c_l1.value()?, self.c_rz.value()?);
|
||||||
Ok(AteAdditionCoefficients { c_l1, c_rz })
|
Ok(AteAdditionCoefficients { c_l1, c_rz })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
pub struct G2ProjectiveExtendedVar<P: MNT4Parameters> {
|
pub struct G2ProjectiveExtendedVar<P: MNT4Parameters> {
|
||||||
pub x: Fp2Var<P::Fp2Params>,
|
pub x: Fp2Var<P::Fp2Params>,
|
||||||
pub y: Fp2Var<P::Fp2Params>,
|
pub y: Fp2Var<P::Fp2Params>,
|
||||||
|
|||||||
@@ -16,21 +16,30 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
|
/// Represents a projective point in G1.
|
||||||
pub type G1Var<P> =
|
pub type G1Var<P> =
|
||||||
ProjectiveVar<<P as MNT6Parameters>::G1Parameters, FpVar<<P as MNT6Parameters>::Fp>>;
|
ProjectiveVar<<P as MNT6Parameters>::G1Parameters, FpVar<<P as MNT6Parameters>::Fp>>;
|
||||||
|
|
||||||
|
/// Represents a projective point in G2.
|
||||||
pub type G2Var<P> = ProjectiveVar<<P as MNT6Parameters>::G2Parameters, Fp3G<P>>;
|
pub type G2Var<P> = ProjectiveVar<<P as MNT6Parameters>::G2Parameters, Fp3G<P>>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
||||||
pub struct G1PreparedVar<P: MNT6Parameters> {
|
pub struct G1PreparedVar<P: MNT6Parameters> {
|
||||||
|
#[doc(hidden)]
|
||||||
pub x: FpVar<P::Fp>,
|
pub x: FpVar<P::Fp>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y: FpVar<P::Fp>,
|
pub y: FpVar<P::Fp>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub x_twist: Fp3Var<P::Fp3Params>,
|
pub x_twist: Fp3Var<P::Fp3Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y_twist: Fp3Var<P::Fp3Params>,
|
pub y_twist: Fp3Var<P::Fp3Params>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT6Parameters> G1PreparedVar<P> {
|
impl<P: MNT6Parameters> G1PreparedVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
|
||||||
let x = self.x.value()?;
|
let x = self.x.value()?;
|
||||||
let y = self.y.value()?;
|
let y = self.y.value()?;
|
||||||
@@ -44,6 +53,7 @@ impl<P: MNT6Parameters> G1PreparedVar<P> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Self` from a `G1Var`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let q = q.to_affine()?;
|
let q = q.to_affine()?;
|
||||||
@@ -123,14 +133,23 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>;
|
type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
||||||
pub struct G2PreparedVar<P: MNT6Parameters> {
|
pub struct G2PreparedVar<P: MNT6Parameters> {
|
||||||
|
#[doc(hidden)]
|
||||||
pub x: Fp3Var<P::Fp3Params>,
|
pub x: Fp3Var<P::Fp3Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y: Fp3Var<P::Fp3Params>,
|
pub y: Fp3Var<P::Fp3Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub x_over_twist: Fp3Var<P::Fp3Params>,
|
pub x_over_twist: Fp3Var<P::Fp3Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub y_over_twist: Fp3Var<P::Fp3Params>,
|
pub y_over_twist: Fp3Var<P::Fp3Params>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
|
pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
|
||||||
|
#[doc(hidden)]
|
||||||
pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
|
pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +243,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT6Parameters> G2PreparedVar<P> {
|
impl<P: MNT6Parameters> G2PreparedVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
|
pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
|
||||||
let x = self.x.value()?;
|
let x = self.x.value()?;
|
||||||
let y = self.y.value()?;
|
let y = self.y.value()?;
|
||||||
@@ -249,6 +269,7 @@ impl<P: MNT6Parameters> G2PreparedVar<P> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs `Self` from a `G2Var`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
|
||||||
let q = q.to_affine()?;
|
let q = q.to_affine()?;
|
||||||
@@ -319,6 +340,7 @@ impl<P: MNT6Parameters> G2PreparedVar<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
||||||
pub struct AteDoubleCoefficientsVar<P: MNT6Parameters> {
|
pub struct AteDoubleCoefficientsVar<P: MNT6Parameters> {
|
||||||
@@ -384,6 +406,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT6Parameters> AteDoubleCoefficientsVar<P> {
|
impl<P: MNT6Parameters> AteDoubleCoefficientsVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
|
pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
|
||||||
let c_h = self.c_h.value()?;
|
let c_h = self.c_h.value()?;
|
||||||
let c_4c = self.c_4c.value()?;
|
let c_4c = self.c_4c.value()?;
|
||||||
@@ -398,6 +421,7 @@ impl<P: MNT6Parameters> AteDoubleCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
|
||||||
pub struct AteAdditionCoefficientsVar<P: MNT6Parameters> {
|
pub struct AteAdditionCoefficientsVar<P: MNT6Parameters> {
|
||||||
@@ -448,6 +472,7 @@ impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: MNT6Parameters> AteAdditionCoefficientsVar<P> {
|
impl<P: MNT6Parameters> AteAdditionCoefficientsVar<P> {
|
||||||
|
/// Returns the value assigned to `self` in the underlying constraint system.
|
||||||
pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
|
pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
|
||||||
let c_l1 = self.c_l1.value()?;
|
let c_l1 = self.c_l1.value()?;
|
||||||
let c_rz = self.c_rz.value()?;
|
let c_rz = self.c_rz.value()?;
|
||||||
@@ -455,6 +480,7 @@ impl<P: MNT6Parameters> AteAdditionCoefficientsVar<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
pub struct G2ProjectiveExtendedVar<P: MNT6Parameters> {
|
pub struct G2ProjectiveExtendedVar<P: MNT6Parameters> {
|
||||||
pub x: Fp3Var<P::Fp3Params>,
|
pub x: Fp3Var<P::Fp3Params>,
|
||||||
pub y: Fp3Var<P::Fp3Params>,
|
pub y: Fp3Var<P::Fp3Params>,
|
||||||
|
|||||||
@@ -11,8 +11,17 @@ use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError};
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use crate::{prelude::*, ToConstraintFieldGadget, Vec};
|
use crate::{prelude::*, ToConstraintFieldGadget, Vec};
|
||||||
|
|
||||||
|
/// This module provides a generic implementation of G1 and G2 for
|
||||||
|
/// the [[BLS12]](https://eprint.iacr.org/2002/088.pdf) family of bilinear groups.
|
||||||
pub mod bls12;
|
pub mod bls12;
|
||||||
|
|
||||||
|
/// This module provides a generic implementation of G1 and G2 for
|
||||||
|
/// the [[MNT4]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf)
|
||||||
|
/// family of bilinear groups.
|
||||||
pub mod mnt4;
|
pub mod mnt4;
|
||||||
|
/// This module provides a generic implementation of G1 and G2 for
|
||||||
|
/// the [[MNT6]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf)
|
||||||
|
/// family of bilinear groups.
|
||||||
pub mod mnt6;
|
pub mod mnt6;
|
||||||
|
|
||||||
/// An implementation of arithmetic for Short Weierstrass curves that relies on
|
/// An implementation of arithmetic for Short Weierstrass curves that relies on
|
||||||
@@ -72,6 +81,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the value assigned to `self` in the underlying
|
||||||
|
/// constraint system.
|
||||||
pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
|
pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
|
||||||
Ok(SWAffine::new(
|
Ok(SWAffine::new(
|
||||||
self.x.value()?,
|
self.x.value()?,
|
||||||
@@ -128,6 +139,7 @@ impl<P: SWModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::Ba
|
|||||||
where
|
where
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
|
/// Constructs `Self` from an `(x, y, z)` coordinate triple.
|
||||||
pub fn new(x: F, y: F, z: F) -> Self {
|
pub fn new(x: F, y: F, z: F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x,
|
x,
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ use crate::{prelude::*, ToConstraintFieldGadget, Vec};
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use core::{borrow::Borrow, marker::PhantomData};
|
use core::{borrow::Borrow, marker::PhantomData};
|
||||||
|
|
||||||
|
/// An implementation of arithmetic for Montgomery curves that relies on
|
||||||
|
/// incomplete addition formulae for the affine model, as outlined in the
|
||||||
|
/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-montgom.html).
|
||||||
|
///
|
||||||
|
/// This is intended for use primarily for implementing efficient
|
||||||
|
/// multi-scalar-multiplication in the Bowe-Hopwood-Pedersen hash.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug, Clone)]
|
#[derivative(Debug, Clone)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -22,7 +28,9 @@ pub struct MontgomeryAffineVar<
|
|||||||
> where
|
> where
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
|
/// The x-coordinate.
|
||||||
pub x: F,
|
pub x: F,
|
||||||
|
/// The y-coordinate.
|
||||||
pub y: F,
|
pub y: F,
|
||||||
#[derivative(Debug = "ignore")]
|
#[derivative(Debug = "ignore")]
|
||||||
_params: PhantomData<P>,
|
_params: PhantomData<P>,
|
||||||
@@ -59,6 +67,7 @@ mod montgomery_affine_impl {
|
|||||||
where
|
where
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
|
/// Constructs `Self` from an `(x, y)` coordinate pair.
|
||||||
pub fn new(x: F, y: F) -> Self {
|
pub fn new(x: F, y: F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x,
|
x,
|
||||||
@@ -67,6 +76,8 @@ mod montgomery_affine_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a Twisted Edwards curve point to coordinates for the corresponding affine
|
||||||
|
/// Montgomery curve point.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn from_edwards_to_coords(
|
pub fn from_edwards_to_coords(
|
||||||
p: &TEAffine<P>,
|
p: &TEAffine<P>,
|
||||||
@@ -85,6 +96,8 @@ mod montgomery_affine_impl {
|
|||||||
Ok((montgomery_point.x, montgomery_point.y))
|
Ok((montgomery_point.x, montgomery_point.y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a Twisted Edwards curve point to coordinates for the corresponding affine
|
||||||
|
/// Montgomery curve point.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn new_witness_from_edwards(
|
pub fn new_witness_from_edwards(
|
||||||
cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>,
|
cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>,
|
||||||
@@ -96,6 +109,7 @@ mod montgomery_affine_impl {
|
|||||||
Ok(Self::new(u, v))
|
Ok(Self::new(u, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts `self` into a Twisted Edwards curve point variable.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> {
|
pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> {
|
||||||
let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
|
let cs = self.cs().unwrap_or(ConstraintSystemRef::None);
|
||||||
@@ -199,6 +213,9 @@ mod montgomery_affine_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An implementation of arithmetic for Twisted Edwards curves that relies on
|
||||||
|
/// the complete formulae for the affine model, as outlined in the
|
||||||
|
/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html).
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug, Clone)]
|
#[derivative(Debug, Clone)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -208,7 +225,9 @@ pub struct AffineVar<
|
|||||||
> where
|
> where
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
|
/// The x-coordinate.
|
||||||
pub x: F,
|
pub x: F,
|
||||||
|
/// The y-coordinate.
|
||||||
pub y: F,
|
pub y: F,
|
||||||
#[derivative(Debug = "ignore")]
|
#[derivative(Debug = "ignore")]
|
||||||
_params: PhantomData<P>,
|
_params: PhantomData<P>,
|
||||||
@@ -219,6 +238,7 @@ impl<P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::Ba
|
|||||||
where
|
where
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
|
/// Constructs `Self` from an `(x, y)` coordinate triple.
|
||||||
pub fn new(x: F, y: F) -> Self {
|
pub fn new(x: F, y: F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x,
|
x,
|
||||||
@@ -257,6 +277,99 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>>
|
||||||
|
AffineVar<P, F>
|
||||||
|
where
|
||||||
|
P: TEModelParameters,
|
||||||
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
||||||
|
+ ThreeBitCondNegLookupGadget<
|
||||||
|
<P::BaseField as Field>::BasePrimeField,
|
||||||
|
TableConstant = P::BaseField,
|
||||||
|
>,
|
||||||
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
|
{
|
||||||
|
/// Compute a scalar multiplication of `bases` with respect to `scalars`,
|
||||||
|
/// where the elements of `scalars` are length-three slices of bits, and which
|
||||||
|
/// such that the first two bits are use to select one of the bases,
|
||||||
|
/// while the third bit is used to conditionally negate the selection.
|
||||||
|
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
||||||
|
pub fn precomputed_base_3_bit_signed_digit_scalar_mul<J>(
|
||||||
|
bases: &[impl Borrow<[TEProjective<P>]>],
|
||||||
|
scalars: &[impl Borrow<[J]>],
|
||||||
|
) -> Result<Self, SynthesisError>
|
||||||
|
where
|
||||||
|
J: Borrow<[Boolean<<P::BaseField as Field>::BasePrimeField>]>,
|
||||||
|
{
|
||||||
|
const CHUNK_SIZE: usize = 3;
|
||||||
|
let mut ed_result: Option<AffineVar<P, F>> = None;
|
||||||
|
let mut result: Option<MontgomeryAffineVar<P, F>> = None;
|
||||||
|
|
||||||
|
let mut process_segment_result = |result: &MontgomeryAffineVar<P, F>| {
|
||||||
|
let sgmt_result = result.into_edwards()?;
|
||||||
|
ed_result = match ed_result.as_ref() {
|
||||||
|
None => Some(sgmt_result),
|
||||||
|
Some(r) => Some(sgmt_result + r),
|
||||||
|
};
|
||||||
|
Ok::<(), SynthesisError>(())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compute ∏(h_i^{m_i}) for all i.
|
||||||
|
for (segment_bits_chunks, segment_powers) in scalars.iter().zip(bases) {
|
||||||
|
for (bits, base_power) in segment_bits_chunks
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.zip(segment_powers.borrow())
|
||||||
|
{
|
||||||
|
let base_power = base_power.borrow();
|
||||||
|
let mut acc_power = *base_power;
|
||||||
|
let mut coords = vec![];
|
||||||
|
for _ in 0..4 {
|
||||||
|
coords.push(acc_power);
|
||||||
|
acc_power += base_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bits = bits.borrow().to_bits_le()?;
|
||||||
|
if bits.len() != CHUNK_SIZE {
|
||||||
|
return Err(SynthesisError::Unsatisfiable);
|
||||||
|
}
|
||||||
|
|
||||||
|
let coords = coords
|
||||||
|
.iter()
|
||||||
|
.map(|p| MontgomeryAffineVar::from_edwards_to_coords(&p.into_affine()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>();
|
||||||
|
let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let precomp = bits[0].and(&bits[1])?;
|
||||||
|
|
||||||
|
let x = F::zero()
|
||||||
|
+ x_coeffs[0]
|
||||||
|
+ F::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0])
|
||||||
|
+ F::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0])
|
||||||
|
+ F::from(precomp.clone())
|
||||||
|
* (x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0]);
|
||||||
|
|
||||||
|
let y = F::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?;
|
||||||
|
|
||||||
|
let tmp = MontgomeryAffineVar::new(x, y);
|
||||||
|
result = match result.as_ref() {
|
||||||
|
None => Some(tmp),
|
||||||
|
Some(r) => Some(tmp + r),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
process_segment_result(&result.unwrap())?;
|
||||||
|
result = None;
|
||||||
|
}
|
||||||
|
if result.is_some() {
|
||||||
|
process_segment_result(&result.unwrap())?;
|
||||||
|
}
|
||||||
|
Ok(ed_result.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
|
impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
|
||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
@@ -281,11 +394,7 @@ impl<P, F> CurveVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> fo
|
|||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<
|
|
||||||
<P::BaseField as Field>::BasePrimeField,
|
|
||||||
TableConstant = P::BaseField,
|
|
||||||
>,
|
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
fn constant(g: TEProjective<P>) -> Self {
|
fn constant(g: TEProjective<P>) -> Self {
|
||||||
@@ -441,95 +550,13 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
|
||||||
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
|
|
||||||
bases: &[B],
|
|
||||||
scalars: &[J],
|
|
||||||
) -> Result<Self, SynthesisError>
|
|
||||||
where
|
|
||||||
I: Borrow<[Boolean<<P::BaseField as Field>::BasePrimeField>]>,
|
|
||||||
J: Borrow<[I]>,
|
|
||||||
B: Borrow<[TEProjective<P>]>,
|
|
||||||
{
|
|
||||||
const CHUNK_SIZE: usize = 3;
|
|
||||||
let mut ed_result: Option<AffineVar<P, F>> = None;
|
|
||||||
let mut result: Option<MontgomeryAffineVar<P, F>> = None;
|
|
||||||
|
|
||||||
let mut process_segment_result = |result: &MontgomeryAffineVar<P, F>| {
|
|
||||||
let sgmt_result = result.into_edwards()?;
|
|
||||||
ed_result = match ed_result.as_ref() {
|
|
||||||
None => Some(sgmt_result),
|
|
||||||
Some(r) => Some(sgmt_result + r),
|
|
||||||
};
|
|
||||||
Ok::<(), SynthesisError>(())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compute ∏(h_i^{m_i}) for all i.
|
|
||||||
for (segment_bits_chunks, segment_powers) in scalars.iter().zip(bases) {
|
|
||||||
for (bits, base_power) in segment_bits_chunks
|
|
||||||
.borrow()
|
|
||||||
.iter()
|
|
||||||
.zip(segment_powers.borrow())
|
|
||||||
{
|
|
||||||
let base_power = base_power.borrow();
|
|
||||||
let mut acc_power = *base_power;
|
|
||||||
let mut coords = vec![];
|
|
||||||
for _ in 0..4 {
|
|
||||||
coords.push(acc_power);
|
|
||||||
acc_power += base_power;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bits = bits.borrow().to_bits_le()?;
|
|
||||||
if bits.len() != CHUNK_SIZE {
|
|
||||||
return Err(SynthesisError::Unsatisfiable);
|
|
||||||
}
|
|
||||||
|
|
||||||
let coords = coords
|
|
||||||
.iter()
|
|
||||||
.map(|p| MontgomeryAffineVar::from_edwards_to_coords(&p.into_affine()))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>();
|
|
||||||
let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let precomp = bits[0].and(&bits[1])?;
|
|
||||||
|
|
||||||
let x = F::zero()
|
|
||||||
+ x_coeffs[0]
|
|
||||||
+ F::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0])
|
|
||||||
+ F::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0])
|
|
||||||
+ F::from(precomp.clone())
|
|
||||||
* (x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0]);
|
|
||||||
|
|
||||||
let y = F::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?;
|
|
||||||
|
|
||||||
let tmp = MontgomeryAffineVar::new(x, y);
|
|
||||||
result = match result.as_ref() {
|
|
||||||
None => Some(tmp),
|
|
||||||
Some(r) => Some(tmp + r),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
process_segment_result(&result.unwrap())?;
|
|
||||||
result = None;
|
|
||||||
}
|
|
||||||
if result.is_some() {
|
|
||||||
process_segment_result(&result.unwrap())?;
|
|
||||||
}
|
|
||||||
Ok(ed_result.unwrap())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, F> AllocVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
|
impl<P, F> AllocVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
|
||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<
|
|
||||||
<P::BaseField as Field>::BasePrimeField,
|
|
||||||
TableConstant = P::BaseField,
|
|
||||||
>,
|
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||||
@@ -630,11 +657,7 @@ impl<P, F> AllocVar<TEAffine<P>, <P::BaseField as Field>::BasePrimeField> for Af
|
|||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<
|
|
||||||
<P::BaseField as Field>::BasePrimeField,
|
|
||||||
TableConstant = P::BaseField,
|
|
||||||
>,
|
|
||||||
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
#[tracing::instrument(target = "r1cs", skip(cs, f))]
|
||||||
@@ -737,8 +760,7 @@ impl_bounded_ops!(
|
|||||||
|this: &'a AffineVar<P, F>, other: TEProjective<P>| this + AffineVar::constant(other),
|
|this: &'a AffineVar<P, F>, other: TEProjective<P>| this + AffineVar::constant(other),
|
||||||
(
|
(
|
||||||
F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
),
|
),
|
||||||
for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||||
@@ -755,8 +777,7 @@ impl_bounded_ops!(
|
|||||||
|this: &'a AffineVar<P, F>, other: TEProjective<P>| this - AffineVar::constant(other),
|
|this: &'a AffineVar<P, F>, other: TEProjective<P>| this - AffineVar::constant(other),
|
||||||
(
|
(
|
||||||
F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
),
|
),
|
||||||
for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
|
for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
|
||||||
@@ -766,11 +787,7 @@ impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for AffineVa
|
|||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<
|
|
||||||
<P::BaseField as Field>::BasePrimeField,
|
|
||||||
TableConstant = P::BaseField,
|
|
||||||
>,
|
|
||||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -779,11 +796,7 @@ impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for &'a Affi
|
|||||||
where
|
where
|
||||||
P: TEModelParameters,
|
P: TEModelParameters,
|
||||||
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>
|
||||||
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>
|
+ TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>,
|
||||||
+ ThreeBitCondNegLookupGadget<
|
|
||||||
<P::BaseField as Field>::BasePrimeField,
|
|
||||||
TableConstant = P::BaseField,
|
|
||||||
>,
|
|
||||||
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use r1cs_core::{Namespace, SynthesisError};
|
|||||||
|
|
||||||
use core::{borrow::Borrow, fmt::Debug};
|
use core::{borrow::Borrow, fmt::Debug};
|
||||||
|
|
||||||
|
/// This module contains implementations of arithmetic for various curve models.
|
||||||
pub mod curves;
|
pub mod curves;
|
||||||
|
|
||||||
pub use self::curves::short_weierstrass::bls12;
|
pub use self::curves::short_weierstrass::bls12;
|
||||||
@@ -23,6 +24,8 @@ pub trait GroupOpsBounds<'a, F, T: 'a>:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A variable that represents a curve point for
|
||||||
|
/// the curve `C`.
|
||||||
pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
||||||
'static
|
'static
|
||||||
+ Sized
|
+ Sized
|
||||||
@@ -43,17 +46,23 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
|||||||
+ AddAssign<Self>
|
+ AddAssign<Self>
|
||||||
+ SubAssign<Self>
|
+ SubAssign<Self>
|
||||||
{
|
{
|
||||||
fn constant(other: C) -> Self;
|
/// Returns the constant `F::zero()`. This is the identity
|
||||||
|
/// of the group.
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// Returns a `Boolean` representing whether `self == Self::zero()`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
|
||||||
self.is_eq(&Self::zero())
|
self.is_eq(&Self::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a variable in the subgroup without checking if it's in the
|
/// Returns a constant with value `v`.
|
||||||
/// prime-order subgroup
|
///
|
||||||
|
/// This *should not* allocate any variables.
|
||||||
|
fn constant(other: C) -> Self;
|
||||||
|
|
||||||
|
/// Allocates a variable in the subgroup without checking if it's in the
|
||||||
|
/// prime-order subgroup.
|
||||||
fn new_variable_omit_prime_order_check(
|
fn new_variable_omit_prime_order_check(
|
||||||
cs: impl Into<Namespace<ConstraintF>>,
|
cs: impl Into<Namespace<ConstraintF>>,
|
||||||
f: impl FnOnce() -> Result<C, SynthesisError>,
|
f: impl FnOnce() -> Result<C, SynthesisError>,
|
||||||
@@ -63,6 +72,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
|||||||
/// Enforce that `self` is in the prime-order subgroup.
|
/// Enforce that `self` is in the prime-order subgroup.
|
||||||
fn enforce_prime_order(&self) -> Result<(), SynthesisError>;
|
fn enforce_prime_order(&self) -> Result<(), SynthesisError>;
|
||||||
|
|
||||||
|
/// Computes `self + self`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn double(&self) -> Result<Self, SynthesisError> {
|
fn double(&self) -> Result<Self, SynthesisError> {
|
||||||
let mut result = self.clone();
|
let mut result = self.clone();
|
||||||
@@ -70,8 +80,10 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `self = self + self`.
|
||||||
fn double_in_place(&mut self) -> Result<(), SynthesisError>;
|
fn double_in_place(&mut self) -> Result<(), SynthesisError>;
|
||||||
|
|
||||||
|
/// Coputes `-self`.
|
||||||
fn negate(&self) -> Result<Self, SynthesisError>;
|
fn negate(&self) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
/// Computes `bits * self`, where `bits` is a little-endian
|
/// Computes `bits * self`, where `bits` is a little-endian
|
||||||
@@ -113,20 +125,7 @@ pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>:
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs")]
|
/// Computes a `\sum_j I_j * B_j`, where `I_j` is a `Boolean`
|
||||||
fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>(
|
|
||||||
_: &[B],
|
|
||||||
_: &[J],
|
|
||||||
) -> Result<Self, SynthesisError>
|
|
||||||
where
|
|
||||||
I: Borrow<[Boolean<ConstraintF>]>,
|
|
||||||
J: Borrow<[I]>,
|
|
||||||
B: Borrow<[C]>,
|
|
||||||
{
|
|
||||||
Err(SynthesisError::AssignmentMissing)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean`
|
|
||||||
/// representation of the j-th scalar.
|
/// representation of the j-th scalar.
|
||||||
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
#[tracing::instrument(target = "r1cs", skip(bases, scalars))]
|
||||||
fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
|
fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::groups::bls12;
|
use crate::groups::bls12;
|
||||||
use algebra::bls12_377::Parameters;
|
use algebra::bls12_377::Parameters;
|
||||||
|
|
||||||
|
/// An element of G1 in the BLS12-377 bilinear group.
|
||||||
pub type G1Var = bls12::G1Var<Parameters>;
|
pub type G1Var = bls12::G1Var<Parameters>;
|
||||||
|
/// An element of G2 in the BLS12-377 bilinear group.
|
||||||
pub type G2Var = bls12::G2Var<Parameters>;
|
pub type G2Var = bls12::G2Var<Parameters>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G1PreparedVar = bls12::G1PreparedVar<Parameters>;
|
pub type G1PreparedVar = bls12::G1PreparedVar<Parameters>;
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G2PreparedVar = bls12::G2PreparedVar<Parameters>;
|
pub type G2PreparedVar = bls12::G2PreparedVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ use algebra::bls12_377::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters};
|
|||||||
|
|
||||||
use crate::fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, fp6_3over2::Fp6Var};
|
use crate::fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, fp6_3over2::Fp6Var};
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq2`.
|
||||||
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq6`.
|
||||||
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq12`.
|
||||||
pub type Fq12Var = Fp12Var<Fq12Parameters>;
|
pub type Fq12Var = Fp12Var<Fq12Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use algebra::bls12_377::Parameters;
|
use algebra::bls12_377::Parameters;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the BLS12-377 bilinear group.
|
||||||
pub type PairingVar = crate::pairing::bls12::PairingVar<Parameters>;
|
pub type PairingVar = crate::pairing::bls12::PairingVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_bls12_377::*;
|
|||||||
|
|
||||||
use crate::ed_on_bls12_377::FqVar;
|
use crate::ed_on_bls12_377::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use algebra::ed_on_bls12_377::fq::Fq;
|
use algebra::ed_on_bls12_377::fq::Fq;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_bls12_381::*;
|
|||||||
|
|
||||||
use crate::ed_on_bls12_381::FqVar;
|
use crate::ed_on_bls12_381::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::Fq`.
|
||||||
pub type FqVar = FpVar<algebra::ed_on_bls12_381::Fq>;
|
pub type FqVar = FpVar<algebra::ed_on_bls12_381::Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_bn254::*;
|
|||||||
|
|
||||||
use crate::ed_on_bn254::FqVar;
|
use crate::ed_on_bn254::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::Fq`.
|
||||||
pub type FqVar = FpVar<algebra::ed_on_bn254::Fq>;
|
pub type FqVar = FpVar<algebra::ed_on_bn254::Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
use crate::groups::curves::twisted_edwards::AffineGadget;
|
|
||||||
use algebra::ed_on_cp6_782::*;
|
|
||||||
|
|
||||||
use crate::ed_on_cp6_782::FqGadget;
|
|
||||||
|
|
||||||
pub type EdwardsGadget = AffineGadget<EdwardsParameters, Fq, FqGadget>;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
crate::groups::curves::twisted_edwards::test::<_, EdwardsParameters, EdwardsGadget>();
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
use crate::fields::fp::FpGadget;
|
|
||||||
use algebra::ed_on_cp6_782::fq::Fq;
|
|
||||||
|
|
||||||
pub type FqGadget = FpGadget<Fq>;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
crate::fields::tests::field_test::<_, _, Fq, FqGadget>();
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_cp6_782::*;
|
|||||||
|
|
||||||
use crate::instantiated::ed_on_cp6_782::FqVar;
|
use crate::instantiated::ed_on_cp6_782::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use algebra::ed_on_cp6_782::fq::Fq;
|
use algebra::ed_on_cp6_782::fq::Fq;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_mnt4_298::*;
|
|||||||
|
|
||||||
use crate::instantiated::ed_on_mnt4_298::fields::FqVar;
|
use crate::instantiated::ed_on_mnt4_298::fields::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use algebra::ed_on_mnt4_298::fq::Fq;
|
use algebra::ed_on_mnt4_298::fq::Fq;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use algebra::ed_on_mnt4_753::*;
|
|||||||
|
|
||||||
use crate::instantiated::ed_on_mnt4_753::fields::FqVar;
|
use crate::instantiated::ed_on_mnt4_753::fields::FqVar;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::EdwardsAffine`.
|
||||||
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::fields::fp::FpVar;
|
use crate::fields::fp::FpVar;
|
||||||
use algebra::ed_on_mnt4_753::fq::Fq;
|
use algebra::ed_on_mnt4_753::fq::Fq;
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::groups::mnt4;
|
use crate::groups::mnt4;
|
||||||
use algebra::mnt4_298::Parameters;
|
use algebra::mnt4_298::Parameters;
|
||||||
|
|
||||||
|
/// An element of G1 in the MNT4-298 bilinear group.
|
||||||
pub type G1Var = mnt4::G1Var<Parameters>;
|
pub type G1Var = mnt4::G1Var<Parameters>;
|
||||||
|
/// An element of G2 in the MNT4-298 bilinear group.
|
||||||
pub type G2Var = mnt4::G2Var<Parameters>;
|
pub type G2Var = mnt4::G2Var<Parameters>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
|
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
|
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ use algebra::mnt4_298::{Fq, Fq2Parameters, Fq4Parameters};
|
|||||||
|
|
||||||
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
|
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq2`.
|
||||||
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq4`.
|
||||||
pub type Fq4Var = Fp4Var<Fq4Parameters>;
|
pub type Fq4Var = Fp4Var<Fq4Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use algebra::mnt4_298::Parameters;
|
use algebra::mnt4_298::Parameters;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the MNT4-298 bilinear group.
|
||||||
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
|
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::groups::mnt4;
|
use crate::groups::mnt4;
|
||||||
use algebra::mnt4_753::Parameters;
|
use algebra::mnt4_753::Parameters;
|
||||||
|
|
||||||
|
/// An element of G1 in the MNT4-753 bilinear group.
|
||||||
pub type G1Var = mnt4::G1Var<Parameters>;
|
pub type G1Var = mnt4::G1Var<Parameters>;
|
||||||
|
/// An element of G2 in the MNT4-753 bilinear group.
|
||||||
pub type G2Var = mnt4::G2Var<Parameters>;
|
pub type G2Var = mnt4::G2Var<Parameters>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
|
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
|
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ use algebra::mnt4_753::{Fq, Fq2Parameters, Fq4Parameters};
|
|||||||
|
|
||||||
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
|
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq2`.
|
||||||
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
pub type Fq2Var = Fp2Var<Fq2Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq4`.
|
||||||
pub type Fq4Var = Fp4Var<Fq4Parameters>;
|
pub type Fq4Var = Fp4Var<Fq4Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use algebra::mnt4_753::Parameters;
|
use algebra::mnt4_753::Parameters;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the MNT4-753 bilinear group.
|
||||||
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
|
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::groups::mnt6;
|
use crate::groups::mnt6;
|
||||||
use algebra::mnt6_298::Parameters;
|
use algebra::mnt6_298::Parameters;
|
||||||
|
|
||||||
|
/// An element of G1 in the MNT6-298 bilinear group.
|
||||||
pub type G1Var = mnt6::G1Var<Parameters>;
|
pub type G1Var = mnt6::G1Var<Parameters>;
|
||||||
|
/// An element of G2 in the MNT6-298 bilinear group.
|
||||||
pub type G2Var = mnt6::G2Var<Parameters>;
|
pub type G2Var = mnt6::G2Var<Parameters>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
|
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
|
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ use algebra::mnt6_298::{Fq, Fq3Parameters, Fq6Parameters};
|
|||||||
|
|
||||||
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
|
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq3`.
|
||||||
pub type Fq3Var = Fp3Var<Fq3Parameters>;
|
pub type Fq3Var = Fp3Var<Fq3Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq6`.
|
||||||
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use algebra::mnt6_298::Parameters;
|
use algebra::mnt6_298::Parameters;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the MNT6-298 bilinear group.
|
||||||
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
|
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
use crate::groups::mnt6;
|
use crate::groups::mnt6;
|
||||||
use algebra::mnt6_753::Parameters;
|
use algebra::mnt6_753::Parameters;
|
||||||
|
|
||||||
|
/// An element of G1 in the MNT6-753 bilinear group.
|
||||||
pub type G1Var = mnt6::G1Var<Parameters>;
|
pub type G1Var = mnt6::G1Var<Parameters>;
|
||||||
|
/// An element of G2 in the MNT6-753 bilinear group.
|
||||||
pub type G2Var = mnt6::G2Var<Parameters>;
|
pub type G2Var = mnt6::G2Var<Parameters>;
|
||||||
|
|
||||||
|
/// Represents the cached precomputation that can be performed on a G1 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
|
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
|
||||||
|
/// Represents the cached precomputation that can be performed on a G2 element
|
||||||
|
/// which enables speeding up pairing computation.
|
||||||
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
|
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ use algebra::mnt6_753::{Fq, Fq3Parameters, Fq6Parameters};
|
|||||||
|
|
||||||
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
|
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
|
||||||
|
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`.
|
||||||
pub type FqVar = FpVar<Fq>;
|
pub type FqVar = FpVar<Fq>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq3`.
|
||||||
pub type Fq3Var = Fp3Var<Fq3Parameters>;
|
pub type Fq3Var = Fp3Var<Fq3Parameters>;
|
||||||
|
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq6`.
|
||||||
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
pub type Fq6Var = Fp6Var<Fq6Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use algebra::mnt6_753::Parameters;
|
use algebra::mnt6_753::Parameters;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the MNT6-753 bilinear group.
|
||||||
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
|
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,38 +1,50 @@
|
|||||||
|
/// This module implements the R1CS equivalent of `algebra::bls12_377`.
|
||||||
#[cfg(feature = "bls12_377")]
|
#[cfg(feature = "bls12_377")]
|
||||||
pub mod bls12_377;
|
pub mod bls12_377;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_bls12_377`.
|
||||||
#[cfg(feature = "ed_on_bls12_377")]
|
#[cfg(feature = "ed_on_bls12_377")]
|
||||||
pub mod ed_on_bls12_377;
|
pub mod ed_on_bls12_377;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_cp6_782`.
|
||||||
#[cfg(feature = "ed_on_cp6_782")]
|
#[cfg(feature = "ed_on_cp6_782")]
|
||||||
pub mod ed_on_cp6_782;
|
pub mod ed_on_cp6_782;
|
||||||
|
|
||||||
#[cfg(all(not(feature = "ed_on_cp6_782"), feature = "ed_on_bw6_761"))]
|
#[cfg(all(not(feature = "ed_on_cp6_782"), feature = "ed_on_bw6_761"))]
|
||||||
pub(crate) mod ed_on_cp6_782;
|
pub(crate) mod ed_on_cp6_782;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_bw6_761`.
|
||||||
#[cfg(feature = "ed_on_bw6_761")]
|
#[cfg(feature = "ed_on_bw6_761")]
|
||||||
pub mod ed_on_bw6_761;
|
pub mod ed_on_bw6_761;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_bn254`.
|
||||||
#[cfg(feature = "ed_on_bn254")]
|
#[cfg(feature = "ed_on_bn254")]
|
||||||
pub mod ed_on_bn254;
|
pub mod ed_on_bn254;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_bls12_381`.
|
||||||
#[cfg(feature = "ed_on_bls12_381")]
|
#[cfg(feature = "ed_on_bls12_381")]
|
||||||
pub mod ed_on_bls12_381;
|
pub mod ed_on_bls12_381;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_mnt4_298`.
|
||||||
#[cfg(feature = "ed_on_mnt4_298")]
|
#[cfg(feature = "ed_on_mnt4_298")]
|
||||||
pub mod ed_on_mnt4_298;
|
pub mod ed_on_mnt4_298;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::ed_on_mnt4_753`.
|
||||||
#[cfg(feature = "ed_on_mnt4_753")]
|
#[cfg(feature = "ed_on_mnt4_753")]
|
||||||
pub mod ed_on_mnt4_753;
|
pub mod ed_on_mnt4_753;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::mnt4_298`.
|
||||||
#[cfg(feature = "mnt4_298")]
|
#[cfg(feature = "mnt4_298")]
|
||||||
pub mod mnt4_298;
|
pub mod mnt4_298;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::mnt4_753`.
|
||||||
#[cfg(feature = "mnt4_753")]
|
#[cfg(feature = "mnt4_753")]
|
||||||
pub mod mnt4_753;
|
pub mod mnt4_753;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::mnt6_298`.
|
||||||
#[cfg(feature = "mnt6_298")]
|
#[cfg(feature = "mnt6_298")]
|
||||||
pub mod mnt6_298;
|
pub mod mnt6_298;
|
||||||
|
|
||||||
|
/// This module implements the R1CS equivalent of `algebra::mnt6_753`.
|
||||||
#[cfg(feature = "mnt6_753")]
|
#[cfg(feature = "mnt6_753")]
|
||||||
pub mod mnt6_753;
|
pub mod mnt6_753;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//! This crate implements common "gadgets" that make
|
||||||
|
//! programming rank-1 constraint systems easier.
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![deny(unused_import_braces, unused_qualifications, trivial_casts)]
|
#![deny(unused_import_braces, unused_qualifications, trivial_casts)]
|
||||||
#![deny(trivial_numeric_casts, variant_size_differences, unreachable_pub)]
|
#![deny(trivial_numeric_casts, variant_size_differences, unreachable_pub)]
|
||||||
@@ -5,21 +7,27 @@
|
|||||||
#![deny(unused_extern_crates, renamed_and_removed_lints, unused_allocation)]
|
#![deny(unused_extern_crates, renamed_and_removed_lints, unused_allocation)]
|
||||||
#![deny(unused_comparisons, bare_trait_objects, const_err, unused_must_use)]
|
#![deny(unused_comparisons, bare_trait_objects, const_err, unused_must_use)]
|
||||||
#![deny(unused_mut, unused_unsafe, private_in_public, unsafe_code)]
|
#![deny(unused_mut, unused_unsafe, private_in_public, unsafe_code)]
|
||||||
|
#![deny(missing_docs)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[cfg(all(test, not(feature = "std")))]
|
#[cfg(all(test, not(feature = "std")))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
extern crate alloc as ralloc;
|
extern crate alloc as ralloc;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate algebra;
|
extern crate algebra;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate derivative;
|
extern crate derivative;
|
||||||
|
|
||||||
|
/// Some utility macros for making downstream impls easier.
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
@@ -31,11 +39,14 @@ use std::vec::Vec;
|
|||||||
|
|
||||||
use algebra::prelude::Field;
|
use algebra::prelude::Field;
|
||||||
|
|
||||||
|
/// This module implements gadgets related to bit manipulation, such as `Boolean` and `UInt`s.
|
||||||
pub mod bits;
|
pub mod bits;
|
||||||
pub use self::bits::*;
|
pub use self::bits::*;
|
||||||
|
|
||||||
|
/// This module implements gadgets related to field arithmetic.
|
||||||
pub mod fields;
|
pub mod fields;
|
||||||
|
|
||||||
|
/// This module implements gadgets related to group arithmetic, and specifically elliptic curve arithmetic.
|
||||||
pub mod groups;
|
pub mod groups;
|
||||||
|
|
||||||
mod instantiated;
|
mod instantiated;
|
||||||
@@ -76,12 +87,17 @@ pub use instantiated::mnt6_298;
|
|||||||
#[cfg(feature = "mnt6_753")]
|
#[cfg(feature = "mnt6_753")]
|
||||||
pub use instantiated::mnt6_753;
|
pub use instantiated::mnt6_753;
|
||||||
|
|
||||||
|
/// This module implements gadgets related to computing pairings in bilinear groups.
|
||||||
pub mod pairing;
|
pub mod pairing;
|
||||||
|
|
||||||
|
/// This module describes a trait for allocating new variables in a constraint system.
|
||||||
pub mod alloc;
|
pub mod alloc;
|
||||||
|
/// This module describes a trait for checking equality of variables.
|
||||||
pub mod eq;
|
pub mod eq;
|
||||||
|
/// This module describes traits for conditionally selecting a variable from a list of variables.
|
||||||
pub mod select;
|
pub mod select;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
alloc::*,
|
alloc::*,
|
||||||
@@ -96,7 +112,9 @@ pub mod prelude {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait describes some core functionality that is common to high-level variables, such as `Boolean`s, `FieldVar`s, `GroupVar`s, etc.
|
||||||
pub trait R1CSVar<F: Field> {
|
pub trait R1CSVar<F: Field> {
|
||||||
|
/// The type of the "native" value that `Self` represents in the constraint system.
|
||||||
type Value: core::fmt::Debug + Eq + Clone;
|
type Value: core::fmt::Debug + Eq + Clone;
|
||||||
|
|
||||||
/// Returns the underlying `ConstraintSystemRef`.
|
/// Returns the underlying `ConstraintSystemRef`.
|
||||||
@@ -145,7 +163,9 @@ impl<'a, F: Field, T: 'a + R1CSVar<F>> R1CSVar<F> for &'a T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A utility trait to convert `Self` to `Result<T, SynthesisErrorA`.>
|
||||||
pub trait Assignment<T> {
|
pub trait Assignment<T> {
|
||||||
|
/// Converts `self` to `Result`.
|
||||||
fn get(self) -> Result<T, r1cs_core::SynthesisError>;
|
fn get(self) -> Result<T, r1cs_core::SynthesisError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
// Implements arithmetic operations with generic bounds.
|
/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type using the impl in `$impl`.
|
||||||
|
///
|
||||||
|
/// Used primarily for implementing these traits for `FieldVar`s and `GroupVar`s.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_ops {
|
macro_rules! impl_ops {
|
||||||
(
|
(
|
||||||
@@ -17,6 +19,11 @@ macro_rules! impl_ops {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type using the impl in `$impl`.
|
||||||
|
///
|
||||||
|
/// Used primarily for implementing these traits for `FieldVar`s and `GroupVar`s.
|
||||||
|
///
|
||||||
|
/// When compared to `impl_ops`, this macro allows specifying additional trait bounds.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_bounded_ops {
|
macro_rules! impl_bounded_ops {
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use algebra::{
|
|||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in a BLS12 bilinear group.
|
||||||
pub struct PairingVar<P: Bls12Parameters>(PhantomData<P>);
|
pub struct PairingVar<P: Bls12Parameters>(PhantomData<P>);
|
||||||
|
|
||||||
type Fp2V<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
|
type Fp2V<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ use algebra::{
|
|||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in a MNT4 bilinear group.
|
||||||
pub struct PairingVar<P: MNT4Parameters>(PhantomData<P>);
|
pub struct PairingVar<P: MNT4Parameters>(PhantomData<P>);
|
||||||
|
|
||||||
type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>;
|
type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>;
|
||||||
type Fp4G<P> = Fp4Var<<P as MNT4Parameters>::Fp4Params>;
|
type Fp4G<P> = Fp4Var<<P as MNT4Parameters>::Fp4Params>;
|
||||||
|
/// A variable corresponding to `algebra_core::mnt4::GT`.
|
||||||
pub type GTVar<P> = Fp4G<P>;
|
pub type GTVar<P> = Fp4G<P>;
|
||||||
|
|
||||||
impl<P: MNT4Parameters> PairingVar<P> {
|
impl<P: MNT4Parameters> PairingVar<P> {
|
||||||
@@ -92,7 +94,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
||||||
pub fn ate_miller_loop(
|
pub(crate) fn ate_miller_loop(
|
||||||
p: &G1PreparedVar<P>,
|
p: &G1PreparedVar<P>,
|
||||||
q: &G2PreparedVar<P>,
|
q: &G2PreparedVar<P>,
|
||||||
) -> Result<Fp4G<P>, SynthesisError> {
|
) -> Result<Fp4G<P>, SynthesisError> {
|
||||||
@@ -142,7 +144,7 @@ impl<P: MNT4Parameters> PairingVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs", skip(value))]
|
#[tracing::instrument(target = "r1cs", skip(value))]
|
||||||
pub fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> {
|
pub(crate) fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> {
|
||||||
let value_inv = value.inverse()?;
|
let value_inv = value.inverse()?;
|
||||||
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
||||||
let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
|
let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ use algebra::{
|
|||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in a MNT6 bilinear group.
|
||||||
pub struct PairingVar<P: MNT6Parameters>(PhantomData<P>);
|
pub struct PairingVar<P: MNT6Parameters>(PhantomData<P>);
|
||||||
|
|
||||||
type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>;
|
type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>;
|
||||||
type Fp6G<P> = Fp6Var<<P as MNT6Parameters>::Fp6Params>;
|
type Fp6G<P> = Fp6Var<<P as MNT6Parameters>::Fp6Params>;
|
||||||
|
/// A variable corresponding to `algebra_core::mnt6::GT`.
|
||||||
pub type GTVar<P> = Fp6G<P>;
|
pub type GTVar<P> = Fp6G<P>;
|
||||||
|
|
||||||
impl<P: MNT6Parameters> PairingVar<P> {
|
impl<P: MNT6Parameters> PairingVar<P> {
|
||||||
@@ -87,7 +89,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
#[tracing::instrument(target = "r1cs", skip(p, q))]
|
||||||
pub fn ate_miller_loop(
|
pub(crate) fn ate_miller_loop(
|
||||||
p: &G1PreparedVar<P>,
|
p: &G1PreparedVar<P>,
|
||||||
q: &G2PreparedVar<P>,
|
q: &G2PreparedVar<P>,
|
||||||
) -> Result<Fp6G<P>, SynthesisError> {
|
) -> Result<Fp6G<P>, SynthesisError> {
|
||||||
@@ -138,7 +140,7 @@ impl<P: MNT6Parameters> PairingVar<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
pub fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> {
|
pub(crate) fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> {
|
||||||
let value_inv = value.inverse()?;
|
let value_inv = value.inverse()?;
|
||||||
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?;
|
||||||
let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
|
let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
|
||||||
|
|||||||
@@ -3,36 +3,55 @@ use algebra::{Field, PairingEngine};
|
|||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
|
/// This module implements pairings for BLS12 bilinear groups.
|
||||||
pub mod bls12;
|
pub mod bls12;
|
||||||
|
/// This module implements pairings for MNT4 bilinear groups.
|
||||||
pub mod mnt4;
|
pub mod mnt4;
|
||||||
|
/// This module implements pairings for MNT6 bilinear groups.
|
||||||
pub mod mnt6;
|
pub mod mnt6;
|
||||||
|
|
||||||
|
/// Specifies the constraints for computing a pairing in the yybilinear group `E`.
|
||||||
pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> {
|
pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> {
|
||||||
|
/// An variable representing an element of `G1`.
|
||||||
|
/// This is the R1CS equivalent of `E::G1Projective`.
|
||||||
type G1Var: CurveVar<E::G1Projective, ConstraintF>
|
type G1Var: CurveVar<E::G1Projective, ConstraintF>
|
||||||
+ AllocVar<E::G1Projective, ConstraintF>
|
+ AllocVar<E::G1Projective, ConstraintF>
|
||||||
+ AllocVar<E::G1Affine, ConstraintF>;
|
+ AllocVar<E::G1Affine, ConstraintF>;
|
||||||
|
|
||||||
|
/// An variable representing an element of `G2`.
|
||||||
|
/// This is the R1CS equivalent of `E::G2Projective`.
|
||||||
type G2Var: CurveVar<E::G2Projective, ConstraintF>
|
type G2Var: CurveVar<E::G2Projective, ConstraintF>
|
||||||
+ AllocVar<E::G2Projective, ConstraintF>
|
+ AllocVar<E::G2Projective, ConstraintF>
|
||||||
+ AllocVar<E::G2Affine, ConstraintF>;
|
+ AllocVar<E::G2Affine, ConstraintF>;
|
||||||
|
|
||||||
|
/// An variable representing an element of `GT`.
|
||||||
|
/// This is the R1CS equivalent of `E::GT`.
|
||||||
type GTVar: FieldVar<E::Fqk, ConstraintF>;
|
type GTVar: FieldVar<E::Fqk, ConstraintF>;
|
||||||
|
|
||||||
|
/// An variable representing cached precomputation that can speed up pairings computations.
|
||||||
|
/// This is the R1CS equivalent of `E::G1Prepared`.
|
||||||
type G1PreparedVar: ToBytesGadget<ConstraintF>
|
type G1PreparedVar: ToBytesGadget<ConstraintF>
|
||||||
+ AllocVar<E::G1Prepared, ConstraintF>
|
+ AllocVar<E::G1Prepared, ConstraintF>
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Debug;
|
+ Debug;
|
||||||
|
/// An variable representing cached precomputation that can speed up pairings computations.
|
||||||
|
/// This is the R1CS equivalent of `E::G2Prepared`.
|
||||||
type G2PreparedVar: ToBytesGadget<ConstraintF>
|
type G2PreparedVar: ToBytesGadget<ConstraintF>
|
||||||
+ AllocVar<E::G2Prepared, ConstraintF>
|
+ AllocVar<E::G2Prepared, ConstraintF>
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Debug;
|
+ Debug;
|
||||||
|
|
||||||
|
/// Computes a multi-miller loop between elements
|
||||||
|
/// of `p` and `q`.
|
||||||
fn miller_loop(
|
fn miller_loop(
|
||||||
p: &[Self::G1PreparedVar],
|
p: &[Self::G1PreparedVar],
|
||||||
q: &[Self::G2PreparedVar],
|
q: &[Self::G2PreparedVar],
|
||||||
) -> Result<Self::GTVar, SynthesisError>;
|
) -> Result<Self::GTVar, SynthesisError>;
|
||||||
|
|
||||||
|
/// Computes a final exponentiation over `p`.
|
||||||
fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
|
fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
|
||||||
|
|
||||||
|
/// Computes a pairing over `p` and `q`.
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn pairing(
|
fn pairing(
|
||||||
p: Self::G1PreparedVar,
|
p: Self::G1PreparedVar,
|
||||||
@@ -42,7 +61,7 @@ pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>
|
|||||||
Self::final_exponentiation(&tmp)
|
Self::final_exponentiation(&tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a product of pairings.
|
/// Computes a product of pairings over the elements in `p` and `q`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[tracing::instrument(target = "r1cs")]
|
#[tracing::instrument(target = "r1cs")]
|
||||||
fn product_of_pairings(
|
fn product_of_pairings(
|
||||||
@@ -53,8 +72,10 @@ pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>
|
|||||||
Self::final_exponentiation(&miller_result)
|
Self::final_exponentiation(&miller_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs the precomputation to generate `Self::G1PreparedVar`.
|
||||||
fn prepare_g1(q: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError>;
|
fn prepare_g1(q: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError>;
|
||||||
|
|
||||||
|
/// Performs the precomputation to generate `Self::G2PreparedVar`.
|
||||||
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError>;
|
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ use crate::prelude::*;
|
|||||||
use algebra::Field;
|
use algebra::Field;
|
||||||
use r1cs_core::SynthesisError;
|
use r1cs_core::SynthesisError;
|
||||||
|
|
||||||
/// If condition is `true`, return `true_value`; else, select `false_value`.
|
/// Generates constraints for selecting between one of two values.
|
||||||
pub trait CondSelectGadget<ConstraintF: Field>
|
pub trait CondSelectGadget<ConstraintF: Field>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// If `cond == &Boolean::TRUE`, then this returns `true_value`; else, returns `false_value`.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// `Self::conditionally_select(cond, true_value, false_value)?` can be more succinctly written as
|
||||||
|
/// `cond.select(&true_value, &false_value)?`.
|
||||||
fn conditionally_select(
|
fn conditionally_select(
|
||||||
cond: &Boolean<ConstraintF>,
|
cond: &Boolean<ConstraintF>,
|
||||||
true_value: &Self,
|
true_value: &Self,
|
||||||
@@ -14,12 +19,23 @@ where
|
|||||||
) -> Result<Self, SynthesisError>;
|
) -> Result<Self, SynthesisError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uses two bits to perform a lookup into a table
|
/// Performs a lookup in a 4-element table using two bits.
|
||||||
pub trait TwoBitLookupGadget<ConstraintF: Field>
|
pub trait TwoBitLookupGadget<ConstraintF: Field>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// The type of values being looked up.
|
||||||
type TableConstant;
|
type TableConstant;
|
||||||
|
|
||||||
|
/// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1] << 1)`,
|
||||||
|
/// and then outputs `constants[b]`.
|
||||||
|
///
|
||||||
|
/// For example, if `bits == [0, 1]`, and `constants == [0, 1, 2, 3]`, this method
|
||||||
|
/// should output a variable corresponding to `2`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This method panics if `bits.len() != 2` or `constants.len() != 4`.
|
||||||
fn two_bit_lookup(
|
fn two_bit_lookup(
|
||||||
bits: &[Boolean<ConstraintF>],
|
bits: &[Boolean<ConstraintF>],
|
||||||
constants: &[Self::TableConstant],
|
constants: &[Self::TableConstant],
|
||||||
@@ -27,12 +43,25 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Uses three bits to perform a lookup into a table, where the last bit
|
/// Uses three bits to perform a lookup into a table, where the last bit
|
||||||
/// performs negation
|
/// conditionally negates the looked-up value.
|
||||||
pub trait ThreeBitCondNegLookupGadget<ConstraintF: Field>
|
pub trait ThreeBitCondNegLookupGadget<ConstraintF: Field>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// The type of values being looked up.
|
||||||
type TableConstant;
|
type TableConstant;
|
||||||
|
|
||||||
|
/// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1] << 1)`,
|
||||||
|
/// and then outputs `constants[b] * c`, where `c = if bits[2] { -1 } else { 1 };`.
|
||||||
|
///
|
||||||
|
/// That is, `bits[2]` conditionally negates the looked-up value.
|
||||||
|
///
|
||||||
|
/// For example, if `bits == [1, 0, 1]`, and `constants == [0, 1, 2, 3]`, this method
|
||||||
|
/// should output a variable corresponding to `-1`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This method panics if `bits.len() != 3` or `constants.len() != 4`.
|
||||||
fn three_bit_cond_neg_lookup(
|
fn three_bit_cond_neg_lookup(
|
||||||
bits: &[Boolean<ConstraintF>],
|
bits: &[Boolean<ConstraintF>],
|
||||||
b0b1: &Boolean<ConstraintF>,
|
b0b1: &Boolean<ConstraintF>,
|
||||||
|
|||||||
Reference in New Issue
Block a user