Merge pull request #237 from str4d/bellman-scalar

Replace E: ScalarEngine with Scalar: PrimeField
This commit is contained in:
str4d 2020-06-17 09:28:52 +12:00 committed by GitHub
commit 7b94622ae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 711 additions and 701 deletions

View File

@ -11,41 +11,40 @@
//! [`EvaluationDomain`]: crate::domain::EvaluationDomain
//! [Groth16]: https://eprint.iacr.org/2016/260
use ff::{Field, PrimeField, ScalarEngine};
use ff::PrimeField;
use group::CurveProjective;
use std::ops::{AddAssign, MulAssign, SubAssign};
use super::SynthesisError;
use super::multicore::Worker;
pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> {
pub struct EvaluationDomain<S: PrimeField, G: Group<S>> {
coeffs: Vec<G>,
exp: u32,
omega: E::Fr,
omegainv: E::Fr,
geninv: E::Fr,
minv: E::Fr,
omega: S,
omegainv: S,
geninv: S,
minv: S,
}
impl<E: ScalarEngine, G: Group<E>> AsRef<[G]> for EvaluationDomain<E, G> {
impl<S: PrimeField, G: Group<S>> AsRef<[G]> for EvaluationDomain<S, G> {
fn as_ref(&self) -> &[G] {
&self.coeffs
}
}
impl<E: ScalarEngine, G: Group<E>> AsMut<[G]> for EvaluationDomain<E, G> {
impl<S: PrimeField, G: Group<S>> AsMut<[G]> for EvaluationDomain<S, G> {
fn as_mut(&mut self) -> &mut [G] {
&mut self.coeffs
}
}
impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
impl<S: PrimeField, G: Group<S>> EvaluationDomain<S, G> {
pub fn into_coeffs(self) -> Vec<G> {
self.coeffs
}
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError> {
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<S, G>, SynthesisError> {
// Compute the size of our evaluation domain
let mut m = 1;
let mut exp = 0;
@ -55,14 +54,14 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
// The pairing-friendly curve may not be able to support
// large enough (radix2) evaluation domains.
if exp >= E::Fr::S {
if exp >= S::S {
return Err(SynthesisError::PolynomialDegreeTooLarge);
}
}
// Compute omega, the 2^exp primitive root of unity
let mut omega = E::Fr::root_of_unity();
for _ in exp..E::Fr::S {
let mut omega = S::root_of_unity();
for _ in exp..S::S {
omega = omega.square();
}
@ -74,11 +73,8 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
exp,
omega,
omegainv: omega.invert().unwrap(),
geninv: E::Fr::multiplicative_generator().invert().unwrap(),
minv: E::Fr::from_str(&format!("{}", m))
.unwrap()
.invert()
.unwrap(),
geninv: S::multiplicative_generator().invert().unwrap(),
minv: S::from_str(&format!("{}", m)).unwrap().invert().unwrap(),
})
}
@ -102,7 +98,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
});
}
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) {
pub fn distribute_powers(&mut self, worker: &Worker, g: S) {
worker.scope(self.coeffs.len(), |scope, chunk| {
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
scope.spawn(move |_scope| {
@ -117,7 +113,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
}
pub fn coset_fft(&mut self, worker: &Worker) {
self.distribute_powers(worker, E::Fr::multiplicative_generator());
self.distribute_powers(worker, S::multiplicative_generator());
self.fft(worker);
}
@ -130,9 +126,9 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
/// This evaluates t(tau) for this domain, which is
/// tau^m - 1 for these radix-2 domains.
pub fn z(&self, tau: &E::Fr) -> E::Fr {
pub fn z(&self, tau: &S) -> S {
let mut tmp = tau.pow_vartime(&[self.coeffs.len() as u64]);
tmp.sub_assign(&E::Fr::one());
tmp.sub_assign(&S::one());
tmp
}
@ -141,7 +137,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
/// evaluation domain, so we must perform division over
/// a coset.
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
let i = self.z(&E::Fr::multiplicative_generator()).invert().unwrap();
let i = self.z(&S::multiplicative_generator()).invert().unwrap();
worker.scope(self.coeffs.len(), |scope, chunk| {
for v in self.coeffs.chunks_mut(chunk) {
@ -155,7 +151,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
}
/// Perform O(n) multiplication of two polynomials in the domain.
pub fn mul_assign(&mut self, worker: &Worker, other: &EvaluationDomain<E, Scalar<E>>) {
pub fn mul_assign(&mut self, worker: &Worker, other: &EvaluationDomain<S, Scalar<S>>) {
assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| {
@ -174,7 +170,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
}
/// Perform O(n) subtraction of one polynomial from another in the domain.
pub fn sub_assign(&mut self, worker: &Worker, other: &EvaluationDomain<E, G>) {
pub fn sub_assign(&mut self, worker: &Worker, other: &EvaluationDomain<S, G>) {
assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| {
@ -193,9 +189,9 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
}
}
pub trait Group<E: ScalarEngine>: Sized + Copy + Clone + Send + Sync {
pub trait Group<Scalar: PrimeField>: Sized + Copy + Clone + Send + Sync {
fn group_zero() -> Self;
fn group_mul_assign(&mut self, by: &E::Fr);
fn group_mul_assign(&mut self, by: &Scalar);
fn group_add_assign(&mut self, other: &Self);
fn group_sub_assign(&mut self, other: &Self);
}
@ -216,7 +212,7 @@ impl<G: CurveProjective> Clone for Point<G> {
}
}
impl<G: CurveProjective, E: ScalarEngine<Fr = G::Scalar>> Group<E> for Point<G> {
impl<G: CurveProjective> Group<G::Scalar> for Point<G> {
fn group_zero() -> Self {
Point(G::identity())
}
@ -231,27 +227,27 @@ impl<G: CurveProjective, E: ScalarEngine<Fr = G::Scalar>> Group<E> for Point<G>
}
}
pub struct Scalar<E: ScalarEngine>(pub E::Fr);
pub struct Scalar<S: PrimeField>(pub S);
impl<E: ScalarEngine> PartialEq for Scalar<E> {
fn eq(&self, other: &Scalar<E>) -> bool {
impl<S: PrimeField> PartialEq for Scalar<S> {
fn eq(&self, other: &Scalar<S>) -> bool {
self.0 == other.0
}
}
impl<E: ScalarEngine> Copy for Scalar<E> {}
impl<S: PrimeField> Copy for Scalar<S> {}
impl<E: ScalarEngine> Clone for Scalar<E> {
fn clone(&self) -> Scalar<E> {
impl<S: PrimeField> Clone for Scalar<S> {
fn clone(&self) -> Scalar<S> {
*self
}
}
impl<E: ScalarEngine> Group<E> for Scalar<E> {
impl<S: PrimeField> Group<S> for Scalar<S> {
fn group_zero() -> Self {
Scalar(E::Fr::zero())
Scalar(S::zero())
}
fn group_mul_assign(&mut self, by: &E::Fr) {
fn group_mul_assign(&mut self, by: &S) {
self.0.mul_assign(by);
}
fn group_add_assign(&mut self, other: &Self) {
@ -262,7 +258,7 @@ impl<E: ScalarEngine> Group<E> for Scalar<E> {
}
}
fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) {
fn best_fft<S: PrimeField, T: Group<S>>(a: &mut [T], worker: &Worker, omega: &S, log_n: u32) {
let log_cpus = worker.log_num_cpus();
if log_n <= log_cpus {
@ -272,7 +268,7 @@ fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &
}
}
fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32) {
fn serial_fft<S: PrimeField, T: Group<S>>(a: &mut [T], omega: &S, log_n: u32) {
fn bitreverse(mut n: u32, l: u32) -> u32 {
let mut r = 0;
for _ in 0..l {
@ -298,7 +294,7 @@ fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u
let mut k = 0;
while k < n {
let mut w = E::Fr::one();
let mut w = S::one();
for j in 0..m {
let mut t = a[(k + j + m) as usize];
t.group_mul_assign(&w);
@ -316,10 +312,10 @@ fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u
}
}
fn parallel_fft<E: ScalarEngine, T: Group<E>>(
fn parallel_fft<S: PrimeField, T: Group<S>>(
a: &mut [T],
worker: &Worker,
omega: &E::Fr,
omega: &S,
log_n: u32,
log_cpus: u32,
) {
@ -339,7 +335,7 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
let omega_j = omega.pow_vartime(&[j as u64]);
let omega_step = omega.pow_vartime(&[(j as u64) << log_new_n]);
let mut elt = E::Fr::one();
let mut elt = S::one();
for (i, tmp) in tmp.iter_mut().enumerate() {
for s in 0..num_cpus {
let idx = (i + (s << log_new_n)) % (1 << log_n);
@ -379,23 +375,19 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
#[cfg(feature = "pairing")]
#[test]
fn polynomial_arith() {
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::RngCore;
fn test_mul<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_mul<S: PrimeField, R: RngCore>(rng: &mut R) {
let worker = Worker::new();
for coeffs_a in 0..70 {
for coeffs_b in 0..70 {
let mut a: Vec<_> = (0..coeffs_a)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect();
let mut b: Vec<_> = (0..coeffs_b)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect();
let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::<S>(S::random(rng))).collect();
let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::<S>(S::random(rng))).collect();
// naive evaluation
let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b];
let mut naive = vec![Scalar(S::zero()); coeffs_a + coeffs_b];
for (i1, a) in a.iter().enumerate() {
for (i2, b) in b.iter().enumerate() {
let mut prod = *a;
@ -404,8 +396,8 @@ fn polynomial_arith() {
}
}
a.resize(coeffs_a + coeffs_b, Scalar(E::Fr::zero()));
b.resize(coeffs_a + coeffs_b, Scalar(E::Fr::zero()));
a.resize(coeffs_a + coeffs_b, Scalar(S::zero()));
b.resize(coeffs_a + coeffs_b, Scalar(S::zero()));
let mut a = EvaluationDomain::from_coeffs(a).unwrap();
let mut b = EvaluationDomain::from_coeffs(b).unwrap();
@ -424,16 +416,16 @@ fn polynomial_arith() {
let rng = &mut rand::thread_rng();
test_mul::<Bls12, _>(rng);
test_mul::<Fr, _>(rng);
}
#[cfg(feature = "pairing")]
#[test]
fn fft_composition() {
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::RngCore;
fn test_comp<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_comp<S: PrimeField, R: RngCore>(rng: &mut R) {
let worker = Worker::new();
for coeffs in 0..10 {
@ -441,7 +433,7 @@ fn fft_composition() {
let mut v = vec![];
for _ in 0..coeffs {
v.push(Scalar::<E>(E::Fr::random(rng)));
v.push(Scalar::<S>(S::random(rng)));
}
let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap();
@ -462,17 +454,17 @@ fn fft_composition() {
let rng = &mut rand::thread_rng();
test_comp::<Bls12, _>(rng);
test_comp::<Fr, _>(rng);
}
#[cfg(feature = "pairing")]
#[test]
fn parallel_fft_consistency() {
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::RngCore;
use std::cmp::min;
fn test_consistency<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_consistency<S: PrimeField, R: RngCore>(rng: &mut R) {
let worker = Worker::new();
for _ in 0..5 {
@ -480,7 +472,7 @@ fn parallel_fft_consistency() {
let d = 1 << log_d;
let v1 = (0..d)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.map(|_| Scalar::<S>(S::random(rng)))
.collect::<Vec<_>>();
let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap();
let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap();
@ -497,5 +489,5 @@ fn parallel_fft_consistency() {
let rng = &mut rand::thread_rng();
test_consistency::<Bls12, _>(rng);
test_consistency::<Fr, _>(rng);
}

View File

@ -4,7 +4,7 @@
use super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32};
use crate::{ConstraintSystem, SynthesisError};
use ff::ScalarEngine;
use ff::PrimeField;
/*
2.1. Parameters
@ -79,7 +79,7 @@ const SIGMA: [[usize; 16]; 10] = [
END FUNCTION.
*/
fn mixing_g<E: ScalarEngine, CS: ConstraintSystem<E>, M>(
fn mixing_g<Scalar: PrimeField, CS: ConstraintSystem<Scalar>, M>(
mut cs: M,
v: &mut [UInt32],
a: usize,
@ -90,7 +90,7 @@ fn mixing_g<E: ScalarEngine, CS: ConstraintSystem<E>, M>(
y: &UInt32,
) -> Result<(), SynthesisError>
where
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{
v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 1"),
@ -164,7 +164,7 @@ where
END FUNCTION.
*/
fn blake2s_compression<E: ScalarEngine, CS: ConstraintSystem<E>>(
fn blake2s_compression<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
mut cs: CS,
h: &mut [UInt32],
m: &[UInt32],
@ -337,7 +337,7 @@ fn blake2s_compression<E: ScalarEngine, CS: ConstraintSystem<E>>(
END FUNCTION.
*/
pub fn blake2s<E: ScalarEngine, CS: ConstraintSystem<E>>(
pub fn blake2s<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
mut cs: CS,
input: &[Boolean],
personalization: &[u8],
@ -409,7 +409,7 @@ pub fn blake2s<E: ScalarEngine, CS: ConstraintSystem<E>>(
mod test {
use blake2s_simd::Params as Blake2sParams;
use hex_literal::hex;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -420,7 +420,7 @@ mod test {
#[test]
fn test_blank_hash() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits = vec![];
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
@ -443,7 +443,7 @@ mod test {
#[test]
fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
@ -461,7 +461,7 @@ mod test {
// Test that 512 fixed leading bits (constants)
// doesn't result in more constraints.
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
@ -481,7 +481,7 @@ mod test {
#[test]
fn test_blake2s_constant_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
@ -512,7 +512,7 @@ mod test {
let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![];
@ -559,7 +559,7 @@ mod test {
let data: Vec<u8> = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec();
assert_eq!(data.len(), 256);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![];
@ -596,7 +596,7 @@ mod test {
let data: Vec<u8> = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec();
assert_eq!(data.len(), 700);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![];
@ -651,7 +651,7 @@ mod test {
let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![];

View File

@ -1,6 +1,6 @@
//! Gadgets for allocating bits in the circuit and performing boolean logic.
use ff::{BitIterator, Field, PrimeField, ScalarEngine};
use ff::{BitIterator, PrimeField};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
@ -26,22 +26,22 @@ impl AllocatedBit {
/// Allocate a variable in the constraint system which can only be a
/// boolean value. Further, constrain that the boolean is false
/// unless the condition is false.
pub fn alloc_conditionally<E, CS>(
pub fn alloc_conditionally<Scalar, CS>(
mut cs: CS,
value: Option<bool>,
must_be_false: &AllocatedBit,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let var = cs.alloc(
|| "boolean",
|| {
if *value.get()? {
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -67,18 +67,18 @@ impl AllocatedBit {
/// Allocate a variable in the constraint system which can only be a
/// boolean value.
pub fn alloc<E, CS>(mut cs: CS, value: Option<bool>) -> Result<Self, SynthesisError>
pub fn alloc<Scalar, CS>(mut cs: CS, value: Option<bool>) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let var = cs.alloc(
|| "boolean",
|| {
if *value.get()? {
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -100,10 +100,10 @@ impl AllocatedBit {
/// Performs an XOR operation over the two operands, returning
/// an `AllocatedBit`.
pub fn xor<E, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
pub fn xor<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let mut result_value = None;
@ -113,11 +113,11 @@ impl AllocatedBit {
if *a.value.get()? ^ *b.value.get()? {
result_value = Some(true);
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
result_value = Some(false);
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -152,10 +152,10 @@ impl AllocatedBit {
/// Performs an AND operation over the two operands, returning
/// an `AllocatedBit`.
pub fn and<E, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
pub fn and<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let mut result_value = None;
@ -165,11 +165,11 @@ impl AllocatedBit {
if *a.value.get()? & *b.value.get()? {
result_value = Some(true);
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
result_value = Some(false);
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -190,10 +190,10 @@ impl AllocatedBit {
}
/// Calculates `a AND (NOT b)`.
pub fn and_not<E, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
pub fn and_not<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let mut result_value = None;
@ -203,11 +203,11 @@ impl AllocatedBit {
if *a.value.get()? & !*b.value.get()? {
result_value = Some(true);
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
result_value = Some(false);
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -228,10 +228,10 @@ impl AllocatedBit {
}
/// Calculates `(NOT a) AND (NOT b)`.
pub fn nor<E, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
pub fn nor<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let mut result_value = None;
@ -241,11 +241,11 @@ impl AllocatedBit {
if !*a.value.get()? & !*b.value.get()? {
result_value = Some(true);
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
result_value = Some(false);
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
},
)?;
@ -266,7 +266,7 @@ impl AllocatedBit {
}
}
pub fn u64_into_boolean_vec_le<E: ScalarEngine, CS: ConstraintSystem<E>>(
pub fn u64_into_boolean_vec_le<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
mut cs: CS,
value: Option<u64>,
) -> Result<Vec<Boolean>, SynthesisError> {
@ -297,16 +297,24 @@ pub fn u64_into_boolean_vec_le<E: ScalarEngine, CS: ConstraintSystem<E>>(
Ok(bits)
}
pub fn field_into_boolean_vec_le<E: ScalarEngine, CS: ConstraintSystem<E>, F: PrimeField>(
pub fn field_into_boolean_vec_le<
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
F: PrimeField,
>(
cs: CS,
value: Option<F>,
) -> Result<Vec<Boolean>, SynthesisError> {
let v = field_into_allocated_bits_le::<E, CS, F>(cs, value)?;
let v = field_into_allocated_bits_le::<Scalar, CS, F>(cs, value)?;
Ok(v.into_iter().map(Boolean::from).collect())
}
pub fn field_into_allocated_bits_le<E: ScalarEngine, CS: ConstraintSystem<E>, F: PrimeField>(
pub fn field_into_allocated_bits_le<
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
F: PrimeField,
>(
mut cs: CS,
value: Option<F>,
) -> Result<Vec<AllocatedBit>, SynthesisError> {
@ -366,10 +374,10 @@ impl Boolean {
}
}
pub fn enforce_equal<E, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError>
pub fn enforce_equal<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
match (a, b) {
(&Boolean::Constant(a), &Boolean::Constant(b)) => {
@ -384,7 +392,7 @@ impl Boolean {
|| "enforce equal to one",
|lc| lc,
|lc| lc,
|lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()),
|lc| lc + CS::one() - &a.lc(CS::one(), Scalar::one()),
);
Ok(())
@ -394,7 +402,7 @@ impl Boolean {
|| "enforce equal to zero",
|lc| lc,
|lc| lc,
|_| a.lc(CS::one(), E::Fr::one()),
|_| a.lc(CS::one(), Scalar::one()),
);
Ok(())
@ -404,7 +412,7 @@ impl Boolean {
|| "enforce equal",
|lc| lc,
|lc| lc,
|_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()),
|_| a.lc(CS::one(), Scalar::one()) - &b.lc(CS::one(), Scalar::one()),
);
Ok(())
@ -420,18 +428,22 @@ impl Boolean {
}
}
pub fn lc<E: ScalarEngine>(&self, one: Variable, coeff: E::Fr) -> LinearCombination<E> {
pub fn lc<Scalar: PrimeField>(
&self,
one: Variable,
coeff: Scalar,
) -> LinearCombination<Scalar> {
match *self {
Boolean::Constant(c) => {
if c {
LinearCombination::<E>::zero() + (coeff, one)
LinearCombination::<Scalar>::zero() + (coeff, one)
} else {
LinearCombination::<E>::zero()
LinearCombination::<Scalar>::zero()
}
}
Boolean::Is(ref v) => LinearCombination::<E>::zero() + (coeff, v.get_variable()),
Boolean::Is(ref v) => LinearCombination::<Scalar>::zero() + (coeff, v.get_variable()),
Boolean::Not(ref v) => {
LinearCombination::<E>::zero() + (coeff, one) - (coeff, v.get_variable())
LinearCombination::<Scalar>::zero() + (coeff, one) - (coeff, v.get_variable())
}
}
}
@ -451,10 +463,10 @@ impl Boolean {
}
/// Perform XOR over two boolean operands
pub fn xor<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
pub fn xor<'a, Scalar, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
match (a, b) {
(&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()),
@ -473,10 +485,10 @@ impl Boolean {
}
/// Perform AND over two boolean operands
pub fn and<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
pub fn and<'a, Scalar, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
match (a, b) {
// false AND x is always false
@ -502,15 +514,15 @@ impl Boolean {
}
/// Computes (a and b) xor ((not a) and c)
pub fn sha256_ch<'a, E, CS>(
pub fn sha256_ch<'a, Scalar, CS>(
mut cs: CS,
a: &'a Self,
b: &'a Self,
c: &'a Self,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let ch_value = match (a.get_value(), b.get_value(), c.get_value()) {
(Some(a), Some(b), Some(c)) => {
@ -589,16 +601,16 @@ impl Boolean {
|| {
ch_value
.get()
.map(|v| if *v { E::Fr::one() } else { E::Fr::zero() })
.map(|v| if *v { Scalar::one() } else { Scalar::zero() })
},
)?;
// a(b - c) = ch - c
cs.enforce(
|| "ch computation",
|_| b.lc(CS::one(), E::Fr::one()) - &c.lc(CS::one(), E::Fr::one()),
|_| a.lc(CS::one(), E::Fr::one()),
|lc| lc + ch - &c.lc(CS::one(), E::Fr::one()),
|_| b.lc(CS::one(), Scalar::one()) - &c.lc(CS::one(), Scalar::one()),
|_| a.lc(CS::one(), Scalar::one()),
|lc| lc + ch - &c.lc(CS::one(), Scalar::one()),
);
Ok(AllocatedBit {
@ -609,15 +621,15 @@ impl Boolean {
}
/// Computes (a and b) xor (a and c) xor (b and c)
pub fn sha256_maj<'a, E, CS>(
pub fn sha256_maj<'a, Scalar, CS>(
mut cs: CS,
a: &'a Self,
b: &'a Self,
c: &'a Self,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let maj_value = match (a.get_value(), b.get_value(), c.get_value()) {
(Some(a), Some(b), Some(c)) => {
@ -692,7 +704,7 @@ impl Boolean {
|| {
maj_value
.get()
.map(|v| if *v { E::Fr::one() } else { E::Fr::zero() })
.map(|v| if *v { Scalar::one() } else { Scalar::zero() })
},
)?;
@ -710,12 +722,12 @@ impl Boolean {
cs.enforce(
|| "maj computation",
|_| {
bc.lc(CS::one(), E::Fr::one()) + &bc.lc(CS::one(), E::Fr::one())
- &b.lc(CS::one(), E::Fr::one())
- &c.lc(CS::one(), E::Fr::one())
bc.lc(CS::one(), Scalar::one()) + &bc.lc(CS::one(), Scalar::one())
- &b.lc(CS::one(), Scalar::one())
- &c.lc(CS::one(), Scalar::one())
},
|_| a.lc(CS::one(), E::Fr::one()),
|_| bc.lc(CS::one(), E::Fr::one()) - maj,
|_| a.lc(CS::one(), Scalar::one()),
|_| bc.lc(CS::one(), Scalar::one()) - maj,
);
Ok(AllocatedBit {
@ -738,11 +750,11 @@ mod test {
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use ff::{Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr};
use pairing::bls12_381::Fr;
#[test]
fn test_allocated_bit() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
assert!(cs.get("boolean") == Fr::one());
@ -758,7 +770,7 @@ mod test {
fn test_xor() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::xor(&mut cs, &a, &b).unwrap();
@ -794,7 +806,7 @@ mod test {
fn test_and() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::and(&mut cs, &a, &b).unwrap();
@ -830,7 +842,7 @@ mod test {
fn test_and_not() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::and_not(&mut cs, &a, &b).unwrap();
@ -866,7 +878,7 @@ mod test {
fn test_nor() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::nor(&mut cs, &a, &b).unwrap();
@ -905,7 +917,7 @@ mod test {
for a_neg in [false, true].iter().cloned() {
for b_neg in [false, true].iter().cloned() {
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
@ -926,7 +938,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut a = Boolean::Constant(a_bool);
let mut b = Boolean::from(
@ -945,7 +957,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
@ -964,7 +976,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut a = Boolean::Constant(a_bool);
let mut b = Boolean::Constant(b_bool);
@ -993,7 +1005,7 @@ mod test {
#[test]
fn test_boolean_negation() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap());
@ -1085,7 +1097,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a;
let b;
@ -1294,7 +1306,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a;
let b;
@ -1515,7 +1527,7 @@ mod test {
#[test]
fn test_u64_into_boolean_vec_le() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let bits = u64_into_boolean_vec_le(&mut cs, Some(17234652694787248421)).unwrap();
@ -1536,7 +1548,7 @@ mod test {
#[test]
fn test_field_into_allocated_bits_le() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let r = Fr::from_str(
"9147677615426976802526883532204139322118074541891858454835346926874644257775",
@ -1573,7 +1585,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
for third_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a;
let b;
@ -1664,7 +1676,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
for third_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a;
let b;
@ -1745,7 +1757,7 @@ mod test {
#[test]
fn test_alloc_conditionally() {
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
let value = None;
@ -1761,7 +1773,7 @@ mod test {
{
// since value is true, b must be false, so it should succeed
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let value = Some(true);
let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
@ -1778,7 +1790,7 @@ mod test {
{
// since value is true, b must be false, so it should fail
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let value = Some(true);
let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
@ -1793,7 +1805,7 @@ mod test {
let value = Some(false);
//check with false bit
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1)
.unwrap();
@ -1801,7 +1813,7 @@ mod test {
assert!(cs.is_satisfied());
//check with true bit
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b2)
.unwrap();

View File

@ -1,7 +1,6 @@
//! Window table lookup gadgets.
use ff::{Field, ScalarEngine};
use std::ops::{AddAssign, Neg};
use ff::PrimeField;
use super::boolean::Boolean;
use super::num::{AllocatedNum, Num};
@ -9,9 +8,9 @@ use super::*;
use crate::ConstraintSystem;
// Synthesize the constants for each base pattern.
fn synth<'a, E: ScalarEngine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
fn synth<'a, Scalar: PrimeField, I>(window_size: usize, constants: I, assignment: &mut [Scalar])
where
I: IntoIterator<Item = &'a E::Fr>,
I: IntoIterator<Item = &'a Scalar>,
{
assert_eq!(assignment.len(), 1 << window_size);
@ -29,13 +28,13 @@ where
/// Performs a 3-bit window table lookup. `bits` is in
/// little-endian order.
pub fn lookup3_xy<E: ScalarEngine, CS>(
pub fn lookup3_xy<Scalar: PrimeField, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
coords: &[(Scalar, Scalar)],
) -> Result<(AllocatedNum<Scalar>, AllocatedNum<Scalar>), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8);
@ -69,10 +68,10 @@ where
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 8];
let mut y_coeffs = [E::Fr::zero(); 8];
synth::<E, _>(3, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(3, coords.iter().map(|c| &c.1), &mut y_coeffs);
let mut x_coeffs = [Scalar::zero(); 8];
let mut y_coeffs = [Scalar::zero(); 8];
synth::<Scalar, _>(3, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<Scalar, _>(3, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?;
@ -82,17 +81,17 @@ where
|| "x-coordinate lookup",
|lc| {
lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111])
+ &bits[1].lc::<Scalar>(one, x_coeffs[0b011])
+ &bits[2].lc::<Scalar>(one, x_coeffs[0b101])
+ &precomp.lc::<Scalar>(one, x_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| lc + &bits[0].lc::<Scalar>(one, Scalar::one()),
|lc| {
lc + res_x.get_variable()
- (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100])
- &precomp.lc::<E>(one, x_coeffs[0b110])
- &bits[1].lc::<Scalar>(one, x_coeffs[0b010])
- &bits[2].lc::<Scalar>(one, x_coeffs[0b100])
- &precomp.lc::<Scalar>(one, x_coeffs[0b110])
},
);
@ -100,17 +99,17 @@ where
|| "y-coordinate lookup",
|lc| {
lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111])
+ &bits[1].lc::<Scalar>(one, y_coeffs[0b011])
+ &bits[2].lc::<Scalar>(one, y_coeffs[0b101])
+ &precomp.lc::<Scalar>(one, y_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| lc + &bits[0].lc::<Scalar>(one, Scalar::one()),
|lc| {
lc + res_y.get_variable()
- (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100])
- &precomp.lc::<E>(one, y_coeffs[0b110])
- &bits[1].lc::<Scalar>(one, y_coeffs[0b010])
- &bits[2].lc::<Scalar>(one, y_coeffs[0b100])
- &precomp.lc::<Scalar>(one, y_coeffs[0b110])
},
);
@ -119,13 +118,13 @@ where
/// Performs a 3-bit window table lookup, where
/// one of the bits is a sign bit.
pub fn lookup3_xy_with_conditional_negation<E: ScalarEngine, CS>(
pub fn lookup3_xy_with_conditional_negation<Scalar: PrimeField, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
) -> Result<(Num<E>, Num<E>), SynthesisError>
coords: &[(Scalar, Scalar)],
) -> Result<(Num<Scalar>, Num<Scalar>), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4);
@ -158,10 +157,10 @@ where
let one = CS::one();
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 4];
let mut y_coeffs = [E::Fr::zero(); 4];
synth::<E, _>(2, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(2, coords.iter().map(|c| &c.1), &mut y_coeffs);
let mut x_coeffs = [Scalar::zero(); 4];
let mut y_coeffs = [Scalar::zero(); 4];
synth::<Scalar, _>(2, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<Scalar, _>(2, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
@ -171,15 +170,15 @@ where
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
let y_lc = precomp.lc::<Scalar>(one, y_coeffs[0b11])
+ &bits[1].lc::<Scalar>(one, y_coeffs[0b10])
+ &bits[0].lc::<Scalar>(one, y_coeffs[0b01])
+ (y_coeffs[0b00], one);
cs.enforce(
|| "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc,
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|lc| lc + &bits[2].lc::<Scalar>(one, Scalar::one()),
|lc| lc + &y_lc - y.get_variable(),
);
@ -191,9 +190,12 @@ mod test {
use super::*;
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
use pairing::bls12_381::{Bls12, Fr};
use ff::Field;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, Neg};
#[test]
fn test_lookup3_xy() {
@ -203,7 +205,7 @@ mod test {
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
@ -248,7 +250,7 @@ mod test {
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
@ -300,7 +302,7 @@ mod test {
.map(|_| Fr::random(&mut rng))
.collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment);
synth(window_size, &constants, &mut assignment);
for b in 0..(1 << window_size) {
let mut acc = Fr::zero();

View File

@ -1,16 +1,16 @@
use ff::{Field, PrimeField, ScalarEngine};
use ff::PrimeField;
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
pub struct MultiEq<E: ScalarEngine, CS: ConstraintSystem<E>> {
pub struct MultiEq<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> {
cs: CS,
ops: usize,
bits_used: usize,
lhs: LinearCombination<E>,
rhs: LinearCombination<E>,
lhs: LinearCombination<Scalar>,
rhs: LinearCombination<Scalar>,
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> MultiEq<Scalar, CS> {
pub fn new(cs: CS) -> Self {
MultiEq {
cs,
@ -40,17 +40,17 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
pub fn enforce_equal(
&mut self,
num_bits: usize,
lhs: &LinearCombination<E>,
rhs: &LinearCombination<E>,
lhs: &LinearCombination<Scalar>,
rhs: &LinearCombination<Scalar>,
) {
// Check if we will exceed the capacity
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
if (Scalar::CAPACITY as usize) <= (self.bits_used + num_bits) {
self.accumulate();
}
assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits));
assert!((Scalar::CAPACITY as usize) > (self.bits_used + num_bits));
let coeff = E::Fr::from_str("2")
let coeff = Scalar::from_str("2")
.unwrap()
.pow_vartime(&[self.bits_used as u64]);
self.lhs = self.lhs.clone() + (coeff, lhs);
@ -59,7 +59,7 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
}
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> Drop for MultiEq<Scalar, CS> {
fn drop(&mut self) {
if self.bits_used > 0 {
self.accumulate();
@ -67,7 +67,9 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
}
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> ConstraintSystem<Scalar>
for MultiEq<Scalar, CS>
{
type Root = Self;
fn one() -> Variable {
@ -76,7 +78,7 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -85,7 +87,7 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -96,9 +98,9 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
self.cs.enforce(annotation, a, b, c)
}

View File

@ -4,19 +4,18 @@ use super::boolean::Boolean;
use super::num::Num;
use super::Assignment;
use crate::{ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField, ScalarEngine};
use std::ops::AddAssign;
use ff::PrimeField;
/// Takes a sequence of booleans and exposes them as compact
/// public inputs
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
pub fn pack_into_inputs<Scalar, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for (i, bits) in bits.chunks(Scalar::CAPACITY as usize).enumerate() {
let mut num = Num::<Scalar>::zero();
let mut coeff = Scalar::one();
for bit in bits {
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
@ -28,7 +27,7 @@ where
// num * 1 = input
cs.enforce(
|| format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()),
|_| num.lc(Scalar::one()),
|lc| lc + CS::one(),
|lc| lc + input,
);
@ -51,12 +50,12 @@ pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
.collect()
}
pub fn compute_multipacking<E: ScalarEngine>(bits: &[bool]) -> Vec<E::Fr> {
pub fn compute_multipacking<Scalar: PrimeField>(bits: &[bool]) -> Vec<Scalar> {
let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
let mut cur = E::Fr::zero();
let mut coeff = E::Fr::one();
for bits in bits.chunks(Scalar::CAPACITY as usize) {
let mut cur = Scalar::zero();
let mut coeff = Scalar::one();
for bit in bits {
if *bit {
@ -75,7 +74,7 @@ pub fn compute_multipacking<E: ScalarEngine>(bits: &[bool]) -> Vec<E::Fr> {
#[test]
fn test_multipacking() {
use crate::ConstraintSystem;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -88,7 +87,7 @@ fn test_multipacking() {
]);
for num_bits in 0..1500 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
@ -102,7 +101,7 @@ fn test_multipacking() {
})
.collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits);
let expected_inputs = compute_multipacking(&bits);
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();

View File

@ -1,7 +1,6 @@
//! Gadgets representing numbers in the scalar field of the underlying curve.
use ff::{BitIterator, Field, PrimeField, ScalarEngine};
use std::ops::{AddAssign, MulAssign};
use ff::{BitIterator, PrimeField};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
@ -9,12 +8,12 @@ use super::Assignment;
use super::boolean::{self, AllocatedBit, Boolean};
pub struct AllocatedNum<E: ScalarEngine> {
value: Option<E::Fr>,
pub struct AllocatedNum<Scalar: PrimeField> {
value: Option<Scalar>,
variable: Variable,
}
impl<E: ScalarEngine> Clone for AllocatedNum<E> {
impl<Scalar: PrimeField> Clone for AllocatedNum<Scalar> {
fn clone(&self) -> Self {
AllocatedNum {
value: self.value,
@ -23,11 +22,11 @@ impl<E: ScalarEngine> Clone for AllocatedNum<E> {
}
}
impl<E: ScalarEngine> AllocatedNum<E> {
impl<Scalar: PrimeField> AllocatedNum<Scalar> {
pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError>,
CS: ConstraintSystem<Scalar>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
{
let mut new_value = None;
let var = cs.alloc(
@ -49,7 +48,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
@ -70,15 +69,15 @@ impl<E: ScalarEngine> AllocatedNum<E> {
/// congruency is not allowed.)
pub fn to_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
pub fn kary_and<E, CS>(
pub fn kary_and<Scalar, CS>(
mut cs: CS,
v: &[AllocatedBit],
) -> Result<AllocatedBit, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert!(!v.is_empty());
@ -104,7 +103,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
// We want to ensure that the bit representation of a is
// less than or equal to r - 1.
let mut a = self.value.map(|e| BitIterator::<u8, _>::new(e.to_repr()));
let b = (-E::Fr::one()).to_repr();
let b = (-Scalar::one()).to_repr();
let mut result = vec![];
@ -171,7 +170,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
// However, now we have to unpack self!
let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one();
let mut coeff = Scalar::one();
for bit in result.iter().rev() {
lc = lc + (coeff, bit.get_variable());
@ -192,12 +191,12 @@ impl<E: ScalarEngine> AllocatedNum<E> {
/// "in the field."
pub fn to_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one();
let mut coeff = Scalar::one();
for bit in bits.iter() {
lc = lc + (coeff, bit.get_variable());
@ -214,7 +213,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let mut value = None;
@ -246,7 +245,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let mut value = None;
@ -277,7 +276,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let inv = cs.alloc(
|| "ephemeral inverse",
@ -315,7 +314,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
condition: &Boolean,
) -> Result<(Self, Self), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<Scalar>,
{
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
if *condition.get_value().get()? {
@ -328,7 +327,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
cs.enforce(
|| "first conditional reversal",
|lc| lc + a.variable - b.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|_| condition.lc(CS::one(), Scalar::one()),
|lc| lc + a.variable - c.variable,
);
@ -343,14 +342,14 @@ impl<E: ScalarEngine> AllocatedNum<E> {
cs.enforce(
|| "second conditional reversal",
|lc| lc + b.variable - a.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|_| condition.lc(CS::one(), Scalar::one()),
|lc| lc + b.variable - d.variable,
);
Ok((c, d))
}
pub fn get_value(&self) -> Option<E::Fr> {
pub fn get_value(&self) -> Option<Scalar> {
self.value
}
@ -359,37 +358,37 @@ impl<E: ScalarEngine> AllocatedNum<E> {
}
}
pub struct Num<E: ScalarEngine> {
value: Option<E::Fr>,
lc: LinearCombination<E>,
pub struct Num<Scalar: PrimeField> {
value: Option<Scalar>,
lc: LinearCombination<Scalar>,
}
impl<E: ScalarEngine> From<AllocatedNum<E>> for Num<E> {
fn from(num: AllocatedNum<E>) -> Num<E> {
impl<Scalar: PrimeField> From<AllocatedNum<Scalar>> for Num<Scalar> {
fn from(num: AllocatedNum<Scalar>) -> Num<Scalar> {
Num {
value: num.value,
lc: LinearCombination::<E>::zero() + num.variable,
lc: LinearCombination::<Scalar>::zero() + num.variable,
}
}
}
impl<E: ScalarEngine> Num<E> {
impl<Scalar: PrimeField> Num<Scalar> {
pub fn zero() -> Self {
Num {
value: Some(E::Fr::zero()),
value: Some(Scalar::zero()),
lc: LinearCombination::zero(),
}
}
pub fn get_value(&self) -> Option<E::Fr> {
pub fn get_value(&self) -> Option<Scalar> {
self.value
}
pub fn lc(&self, coeff: E::Fr) -> LinearCombination<E> {
pub fn lc(&self, coeff: Scalar) -> LinearCombination<Scalar> {
LinearCombination::zero() + (coeff, &self.lc)
}
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self {
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: Scalar) -> Self {
let newval = match (self.value, bit.get_value()) {
(Some(mut curval), Some(bval)) => {
if bval {
@ -412,7 +411,7 @@ impl<E: ScalarEngine> Num<E> {
mod test {
use crate::ConstraintSystem;
use ff::{BitIterator, Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr};
use pairing::bls12_381::Fr;
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{Neg, SubAssign};
@ -422,7 +421,7 @@ mod test {
#[test]
fn test_allocated_num() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
AllocatedNum::alloc(&mut cs, || Ok(Fr::one())).unwrap();
@ -431,7 +430,7 @@ mod test {
#[test]
fn test_num_squaring() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
let n2 = n.square(&mut cs).unwrap();
@ -445,7 +444,7 @@ mod test {
#[test]
fn test_num_multiplication() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
@ -467,7 +466,7 @@ mod test {
0xbc, 0xe5,
]);
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
@ -481,7 +480,7 @@ mod test {
}
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
@ -498,7 +497,7 @@ mod test {
#[test]
fn test_num_nonzero() {
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
n.assert_nonzero(&mut cs).unwrap();
@ -508,7 +507,7 @@ mod test {
assert!(cs.which_is_unsatisfied() == Some("nonzero assertion constraint"));
}
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::zero())).unwrap();
assert!(n.assert_nonzero(&mut cs).is_err());
@ -519,7 +518,7 @@ mod test {
fn test_into_bits_strict() {
let negone = Fr::one().neg();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap();
n.to_bits_le_strict(&mut cs).unwrap();
@ -545,7 +544,7 @@ mod test {
for i in 0..200 {
let r = Fr::random(&mut rng);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap();

View File

@ -7,7 +7,7 @@ use super::boolean::Boolean;
use super::multieq::MultiEq;
use super::uint32::UInt32;
use crate::{ConstraintSystem, SynthesisError};
use ff::ScalarEngine;
use ff::PrimeField;
#[allow(clippy::unreadable_literal)]
const ROUND_CONSTANTS: [u32; 64] = [
@ -26,13 +26,13 @@ const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
pub fn sha256_block_no_padding<E, CS>(
pub fn sha256_block_no_padding<Scalar, CS>(
mut cs: CS,
input: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(input.len(), 512);
@ -44,10 +44,10 @@ where
)
}
pub fn sha256<E, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
pub fn sha256<Scalar, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert!(input.len() % 8 == 0);
@ -77,14 +77,14 @@ fn get_sha256_iv() -> Vec<UInt32> {
IV.iter().map(|&v| UInt32::constant(v)).collect()
}
fn sha256_compression_function<E, CS>(
fn sha256_compression_function<Scalar, CS>(
cs: CS,
input: &[Boolean],
current_hash_value: &[UInt32],
) -> Result<Vec<UInt32>, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(input.len(), 512);
assert_eq!(current_hash_value.len(), 8);
@ -128,11 +128,11 @@ where
}
impl Maybe {
fn compute<E, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
fn compute<Scalar, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{
Ok(match self {
Maybe::Concrete(ref v) => return Ok(v.clone()),
@ -274,7 +274,7 @@ mod test {
use crate::gadgets::boolean::AllocatedBit;
use crate::gadgets::test::TestConstraintSystem;
use hex_literal::hex;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -282,7 +282,7 @@ mod test {
fn test_blank_hash() {
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
input_bits[0] = Boolean::Constant(true);
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
@ -312,7 +312,7 @@ mod test {
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
Boolean::from(
@ -346,7 +346,7 @@ mod test {
h.input(&data);
let hash_result = h.result();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![];
for (byte_i, input_byte) in data.into_iter().enumerate() {

View File

@ -1,12 +1,11 @@
//! Helpers for testing circuit implementations.
use ff::{Endianness, Field, PrimeField, ScalarEngine};
use ff::{Endianness, PrimeField};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
use std::collections::HashMap;
use std::fmt::Write;
use std::ops::{AddAssign, MulAssign, Neg};
use byteorder::{BigEndian, ByteOrder};
use std::cmp::Ordering;
@ -22,17 +21,17 @@ enum NamedObject {
}
/// Constraint system for testing purposes.
pub struct TestConstraintSystem<E: ScalarEngine> {
pub struct TestConstraintSystem<Scalar: PrimeField> {
named_objects: HashMap<String, NamedObject>,
current_namespace: Vec<String>,
constraints: Vec<(
LinearCombination<E>,
LinearCombination<E>,
LinearCombination<E>,
LinearCombination<Scalar>,
LinearCombination<Scalar>,
LinearCombination<Scalar>,
String,
)>,
inputs: Vec<(E::Fr, String)>,
aux: Vec<(E::Fr, String)>,
inputs: Vec<(Scalar, String)>,
aux: Vec<(Scalar, String)>,
}
#[derive(Clone, Copy)]
@ -64,11 +63,11 @@ impl Ord for OrderedVariable {
}
}
fn proc_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable, E::Fr> {
fn proc_lc<Scalar: PrimeField>(terms: &[(Variable, Scalar)]) -> BTreeMap<OrderedVariable, Scalar> {
let mut map = BTreeMap::new();
for &(var, coeff) in terms {
map.entry(OrderedVariable(var))
.or_insert_with(E::Fr::zero)
.or_insert_with(Scalar::zero)
.add_assign(&coeff);
}
@ -87,8 +86,8 @@ fn proc_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVari
map
}
fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
let map = proc_lc::<E>(terms);
fn hash_lc<Scalar: PrimeField>(terms: &[(Variable, Scalar)], h: &mut Blake2sState) {
let map = proc_lc::<Scalar>(terms);
let mut buf = [0u8; 9 + 32];
BigEndian::write_u64(&mut buf[0..8], map.len() as u64);
@ -107,7 +106,7 @@ fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
}
let mut coeff_repr = coeff.to_repr();
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut coeff_repr);
<Scalar as PrimeField>::ReprEndianness::toggle_little_endian(&mut coeff_repr);
let coeff_be: Vec<_> = coeff_repr.as_ref().iter().cloned().rev().collect();
buf[9..].copy_from_slice(&coeff_be[..]);
@ -115,12 +114,12 @@ fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
}
}
fn eval_lc<E: ScalarEngine>(
terms: &[(Variable, E::Fr)],
inputs: &[(E::Fr, String)],
aux: &[(E::Fr, String)],
) -> E::Fr {
let mut acc = E::Fr::zero();
fn eval_lc<Scalar: PrimeField>(
terms: &[(Variable, Scalar)],
inputs: &[(Scalar, String)],
aux: &[(Scalar, String)],
) -> Scalar {
let mut acc = Scalar::zero();
for &(var, ref coeff) in terms {
let mut tmp = match var.get_unchecked() {
@ -128,26 +127,26 @@ fn eval_lc<E: ScalarEngine>(
Index::Aux(index) => aux[index].0,
};
tmp.mul_assign(&coeff);
tmp.mul_assign(coeff);
acc.add_assign(&tmp);
}
acc
}
impl<E: ScalarEngine> TestConstraintSystem<E> {
pub fn new() -> TestConstraintSystem<E> {
impl<Scalar: PrimeField> TestConstraintSystem<Scalar> {
pub fn new() -> TestConstraintSystem<Scalar> {
let mut map = HashMap::new();
map.insert(
"ONE".into(),
NamedObject::Var(TestConstraintSystem::<E>::one()),
NamedObject::Var(TestConstraintSystem::<Scalar>::one()),
);
TestConstraintSystem {
named_objects: map,
current_namespace: vec![],
constraints: vec![],
inputs: vec![(E::Fr::one(), "ONE".into())],
inputs: vec![(Scalar::one(), "ONE".into())],
aux: vec![],
}
}
@ -155,16 +154,16 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
pub fn pretty_print(&self) -> String {
let mut s = String::new();
let negone = E::Fr::one().neg();
let negone = Scalar::one().neg();
let powers_of_two = (0..E::Fr::NUM_BITS)
.map(|i| E::Fr::from_str("2").unwrap().pow_vartime(&[u64::from(i)]))
let powers_of_two = (0..Scalar::NUM_BITS)
.map(|i| Scalar::from_str("2").unwrap().pow_vartime(&[u64::from(i)]))
.collect::<Vec<_>>();
let pp = |s: &mut String, lc: &LinearCombination<E>| {
let pp = |s: &mut String, lc: &LinearCombination<Scalar>| {
write!(s, "(").unwrap();
let mut is_first = true;
for (var, coeff) in proc_lc::<E>(lc.as_ref()) {
for (var, coeff) in proc_lc::<Scalar>(lc.as_ref()) {
if coeff == negone {
write!(s, " - ").unwrap();
} else if !is_first {
@ -172,7 +171,7 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
}
is_first = false;
if coeff != E::Fr::one() && coeff != negone {
if coeff != Scalar::one() && coeff != negone {
for (i, x) in powers_of_two.iter().enumerate() {
if x == &coeff {
write!(s, "2^{} . ", i).unwrap();
@ -227,9 +226,9 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
}
for constraint in &self.constraints {
hash_lc::<E>(constraint.0.as_ref(), &mut h);
hash_lc::<E>(constraint.1.as_ref(), &mut h);
hash_lc::<E>(constraint.2.as_ref(), &mut h);
hash_lc::<Scalar>(constraint.0.as_ref(), &mut h);
hash_lc::<Scalar>(constraint.1.as_ref(), &mut h);
hash_lc::<Scalar>(constraint.2.as_ref(), &mut h);
}
let mut s = String::new();
@ -242,9 +241,9 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
pub fn which_is_unsatisfied(&self) -> Option<&str> {
for &(ref a, ref b, ref c, ref path) in &self.constraints {
let mut a = eval_lc::<E>(a.as_ref(), &self.inputs, &self.aux);
let b = eval_lc::<E>(b.as_ref(), &self.inputs, &self.aux);
let c = eval_lc::<E>(c.as_ref(), &self.inputs, &self.aux);
let mut a = eval_lc::<Scalar>(a.as_ref(), &self.inputs, &self.aux);
let b = eval_lc::<Scalar>(b.as_ref(), &self.inputs, &self.aux);
let c = eval_lc::<Scalar>(c.as_ref(), &self.inputs, &self.aux);
a.mul_assign(&b);
@ -264,7 +263,7 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
self.constraints.len()
}
pub fn set(&mut self, path: &str, to: E::Fr) {
pub fn set(&mut self, path: &str, to: Scalar) {
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0 = to,
@ -278,7 +277,7 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
}
}
pub fn verify(&self, expected: &[E::Fr]) -> bool {
pub fn verify(&self, expected: &[Scalar]) -> bool {
assert_eq!(expected.len() + 1, self.inputs.len());
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) {
@ -294,7 +293,7 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
self.inputs.len()
}
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr {
pub fn get_input(&mut self, index: usize, path: &str) -> Scalar {
let (assignment, name) = self.inputs[index].clone();
assert_eq!(path, name);
@ -302,7 +301,7 @@ impl<E: ScalarEngine> TestConstraintSystem<E> {
assignment
}
pub fn get(&mut self, path: &str) -> E::Fr {
pub fn get(&mut self, path: &str) -> Scalar {
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0,
@ -345,12 +344,12 @@ fn compute_path(ns: &[String], this: String) -> String {
name
}
impl<E: ScalarEngine> ConstraintSystem<E> for TestConstraintSystem<E> {
impl<Scalar: PrimeField> ConstraintSystem<Scalar> for TestConstraintSystem<Scalar> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -365,7 +364,7 @@ impl<E: ScalarEngine> ConstraintSystem<E> for TestConstraintSystem<E> {
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -382,9 +381,9 @@ impl<E: ScalarEngine> ConstraintSystem<E> for TestConstraintSystem<E> {
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
let path = compute_path(&self.current_namespace, annotation().into());
let index = self.constraints.len();
@ -419,10 +418,10 @@ impl<E: ScalarEngine> ConstraintSystem<E> for TestConstraintSystem<E> {
#[test]
fn test_cs() {
use ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr};
use ff::{Field, PrimeField};
use pairing::bls12_381::Fr;
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 0);
let a = cs
@ -443,7 +442,7 @@ fn test_cs() {
cs.set("a/var", Fr::from_str("4").unwrap());
let one = TestConstraintSystem::<Bls12>::one();
let one = TestConstraintSystem::<Fr>::one();
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
assert!(!cs.is_satisfied());

View File

@ -3,7 +3,7 @@
//!
//! [`sha256`]: crate::gadgets::sha256
use ff::{Field, PrimeField, ScalarEngine};
use ff::PrimeField;
use crate::{ConstraintSystem, LinearCombination, SynthesisError};
@ -43,10 +43,10 @@ impl UInt32 {
}
/// Allocate a `UInt32` in the constraint system
pub fn alloc<E, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
pub fn alloc<Scalar, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let values = match value {
Some(mut val) => {
@ -189,7 +189,7 @@ impl UInt32 {
}
}
fn triop<E, CS, F, U>(
fn triop<Scalar, CS, F, U>(
mut cs: CS,
a: &Self,
b: &Self,
@ -198,8 +198,8 @@ impl UInt32 {
circuit_fn: U,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>,
{
@ -225,10 +225,15 @@ impl UInt32 {
/// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
/// during SHA256.
pub fn sha256_maj<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
pub fn sha256_maj<Scalar, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
Self::triop(
cs,
@ -242,10 +247,15 @@ impl UInt32 {
/// Compute the `ch` value `(a and b) xor ((not a) and c)`
/// during SHA256.
pub fn sha256_ch<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
pub fn sha256_ch<Scalar, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self,
) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
Self::triop(
cs,
@ -258,10 +268,10 @@ impl UInt32 {
}
/// XOR this `UInt32` with another `UInt32`
pub fn xor<E, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
pub fn xor<Scalar, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => Some(a ^ b),
@ -283,15 +293,15 @@ impl UInt32 {
}
/// Perform modular addition of several `UInt32` objects.
pub fn addmany<E, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
pub fn addmany<Scalar, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{
// Make some arbitrary bounds for ourselves to avoid overflows
// in the scalar field
assert!(E::Fr::NUM_BITS >= 64);
assert!(Scalar::NUM_BITS >= 64);
assert!(operands.len() >= 2); // Weird trivial cases that should never happen
assert!(operands.len() <= 10);
@ -324,7 +334,7 @@ impl UInt32 {
// Iterate over each bit of the operand and add the operand to
// the linear combination
let mut coeff = E::Fr::one();
let mut coeff = Scalar::one();
for bit in &op.bits {
lc = lc + &bit.lc(CS::one(), coeff);
@ -352,7 +362,7 @@ impl UInt32 {
let mut result_lc = LinearCombination::zero();
// Allocate each bit of the result
let mut coeff = E::Fr::one();
let mut coeff = Scalar::one();
let mut i = 0;
while max_value != 0 {
// Allocate the bit
@ -392,7 +402,7 @@ mod test {
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use ff::Field;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -474,7 +484,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -519,7 +529,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -562,7 +572,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -675,7 +685,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -719,7 +729,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32();
let b = rng.next_u32();

View File

@ -2,7 +2,7 @@ use rand_core::RngCore;
use std::ops::{AddAssign, MulAssign};
use std::sync::Arc;
use ff::Field;
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, Group, Wnaf};
use pairing::Engine;
@ -22,7 +22,7 @@ pub fn generate_random_parameters<E, C, R>(
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
C: Circuit<E::Fr>,
R: RngCore,
{
let g1 = E::G1::random(rng);
@ -38,24 +38,24 @@ where
/// This is our assembly structure that we'll use to synthesize the
/// circuit into a QAP.
struct KeypairAssembly<E: Engine> {
struct KeypairAssembly<Scalar: PrimeField> {
num_inputs: usize,
num_aux: usize,
num_constraints: usize,
at_inputs: Vec<Vec<(E::Fr, usize)>>,
bt_inputs: Vec<Vec<(E::Fr, usize)>>,
ct_inputs: Vec<Vec<(E::Fr, usize)>>,
at_aux: Vec<Vec<(E::Fr, usize)>>,
bt_aux: Vec<Vec<(E::Fr, usize)>>,
ct_aux: Vec<Vec<(E::Fr, usize)>>,
at_inputs: Vec<Vec<(Scalar, usize)>>,
bt_inputs: Vec<Vec<(Scalar, usize)>>,
ct_inputs: Vec<Vec<(Scalar, usize)>>,
at_aux: Vec<Vec<(Scalar, usize)>>,
bt_aux: Vec<Vec<(Scalar, usize)>>,
ct_aux: Vec<Vec<(Scalar, usize)>>,
}
impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
impl<Scalar: PrimeField> ConstraintSystem<Scalar> for KeypairAssembly<Scalar> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -74,7 +74,7 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -95,14 +95,14 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
fn eval<E: Engine>(
l: LinearCombination<E>,
inputs: &mut [Vec<(E::Fr, usize)>],
aux: &mut [Vec<(E::Fr, usize)>],
fn eval<Scalar: PrimeField>(
l: LinearCombination<Scalar>,
inputs: &mut [Vec<(Scalar, usize)>],
aux: &mut [Vec<(Scalar, usize)>],
this_constraint: usize,
) {
for (index, coeff) in l.0 {
@ -165,7 +165,7 @@ pub fn generate_parameters<E, C>(
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
C: Circuit<E::Fr>,
{
let mut assembly = KeypairAssembly {
num_inputs: 0,
@ -192,7 +192,7 @@ where
}
// Create bases for blind evaluation of polynomials at tau
let powers_of_tau = vec![Scalar::<E>(E::Fr::zero()); assembly.num_constraints];
let powers_of_tau = vec![Scalar::<E::Fr>(E::Fr::zero()); assembly.num_constraints];
let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?;
// Compute G1 window table
@ -302,7 +302,7 @@ where
g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
// Lagrange coefficients for tau
powers_of_tau: &[Scalar<E>],
powers_of_tau: &[Scalar<E::Fr>],
// QAP polynomials
at: &[Vec<(E::Fr, usize)>],
@ -362,11 +362,11 @@ where
.zip(bt.iter())
.zip(ct.iter())
{
fn eval_at_tau<E: Engine>(
powers_of_tau: &[Scalar<E>],
p: &[(E::Fr, usize)],
) -> E::Fr {
let mut acc = E::Fr::zero();
fn eval_at_tau<S: PrimeField>(
powers_of_tau: &[Scalar<S>],
p: &[(S, usize)],
) -> S {
let mut acc = S::zero();
for &(ref coeff, index) in p {
let mut n = powers_of_tau[index].0;
@ -416,7 +416,7 @@ where
}
// Evaluate for inputs.
eval(
eval::<E>(
&g1_wnaf,
&g2_wnaf,
&powers_of_tau,
@ -434,7 +434,7 @@ where
);
// Evaluate for auxiliary variables.
eval(
eval::<E>(
&g1_wnaf,
&g2_wnaf,
&powers_of_tau,

View File

@ -479,20 +479,20 @@ mod test_with_bls12_381 {
use super::*;
use crate::{Circuit, ConstraintSystem, SynthesisError};
use ff::Field;
use ff::{Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr};
use rand::thread_rng;
use std::ops::MulAssign;
#[test]
fn serialization() {
struct MySillyCircuit<E: Engine> {
a: Option<E::Fr>,
b: Option<E::Fr>,
struct MySillyCircuit<Scalar: PrimeField> {
a: Option<Scalar>,
b: Option<Scalar>,
}
impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>(
impl<Scalar: PrimeField> Circuit<Scalar> for MySillyCircuit<Scalar> {
fn synthesize<CS: ConstraintSystem<Scalar>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
use futures::Future;
use ff::Field;
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective};
use pairing::Engine;
@ -18,14 +18,14 @@ use crate::multiexp::{multiexp, DensityTracker, FullDensity};
use crate::multicore::Worker;
fn eval<E: Engine>(
lc: &LinearCombination<E>,
fn eval<S: PrimeField>(
lc: &LinearCombination<S>,
mut input_density: Option<&mut DensityTracker>,
mut aux_density: Option<&mut DensityTracker>,
input_assignment: &[E::Fr],
aux_assignment: &[E::Fr],
) -> E::Fr {
let mut acc = E::Fr::zero();
input_assignment: &[S],
aux_assignment: &[S],
) -> S {
let mut acc = S::zero();
for &(index, coeff) in lc.0.iter() {
let mut tmp;
@ -45,7 +45,7 @@ fn eval<E: Engine>(
}
}
if coeff == E::Fr::one() {
if coeff == S::one() {
acc.add_assign(&tmp);
} else {
tmp.mul_assign(&coeff);
@ -56,28 +56,28 @@ fn eval<E: Engine>(
acc
}
struct ProvingAssignment<E: Engine> {
struct ProvingAssignment<S: PrimeField> {
// Density of queries
a_aux_density: DensityTracker,
b_input_density: DensityTracker,
b_aux_density: DensityTracker,
// Evaluations of A, B, C polynomials
a: Vec<Scalar<E>>,
b: Vec<Scalar<E>>,
c: Vec<Scalar<E>>,
a: Vec<Scalar<S>>,
b: Vec<Scalar<S>>,
c: Vec<Scalar<S>>,
// Assignments of variables
input_assignment: Vec<E::Fr>,
aux_assignment: Vec<E::Fr>,
input_assignment: Vec<S>,
aux_assignment: Vec<S>,
}
impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
impl<S: PrimeField> ConstraintSystem<S> for ProvingAssignment<S> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<S, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -90,7 +90,7 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
fn alloc_input<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<S, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -104,9 +104,9 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<S>) -> LinearCombination<S>,
LB: FnOnce(LinearCombination<S>) -> LinearCombination<S>,
LC: FnOnce(LinearCombination<S>) -> LinearCombination<S>,
{
let a = a(LinearCombination::zero());
let b = b(LinearCombination::zero());
@ -166,7 +166,7 @@ pub fn create_random_proof<E, C, R, P: ParameterSource<E>>(
) -> Result<Proof<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
C: Circuit<E::Fr>,
R: RngCore,
{
let r = E::Fr::random(rng);
@ -183,7 +183,7 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
) -> Result<Proof<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
C: Circuit<E::Fr>,
{
let mut prover = ProvingAssignment {
a_aux_density: DensityTracker::new(),

View File

@ -1,4 +1,4 @@
use ff::{Field, PrimeField, ScalarEngine};
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
use pairing::{Engine, PairingCurveAffine};
@ -324,11 +324,8 @@ impl PrimeField for Fr {
#[derive(Clone)]
pub struct DummyEngine;
impl ScalarEngine for DummyEngine {
type Fr = Fr;
}
impl Engine for DummyEngine {
type Fr = Fr;
type G1 = Fr;
type G1Affine = Fr;
type G2 = Fr;

View File

@ -1,5 +1,4 @@
use ff::{Field, PrimeField};
use pairing::Engine;
mod dummy_engine;
use self::dummy_engine::*;
@ -11,22 +10,22 @@ use crate::{Circuit, ConstraintSystem, SynthesisError};
use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof};
struct XORDemo<E: Engine> {
struct XORDemo<Scalar: PrimeField> {
a: Option<bool>,
b: Option<bool>,
_marker: PhantomData<E>,
_marker: PhantomData<Scalar>,
}
impl<E: Engine> Circuit<E> for XORDemo<E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
impl<Scalar: PrimeField> Circuit<Scalar> for XORDemo<Scalar> {
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let a_var = cs.alloc(
|| "a",
|| {
if self.a.is_some() {
if self.a.unwrap() {
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
} else {
Err(SynthesisError::AssignmentMissing)
@ -46,9 +45,9 @@ impl<E: Engine> Circuit<E> for XORDemo<E> {
|| {
if self.b.is_some() {
if self.b.unwrap() {
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
} else {
Err(SynthesisError::AssignmentMissing)
@ -68,9 +67,9 @@ impl<E: Engine> Circuit<E> for XORDemo<E> {
|| {
if self.a.is_some() && self.b.is_some() {
if self.a.unwrap() ^ self.b.unwrap() {
Ok(E::Fr::one())
Ok(Scalar::one())
} else {
Ok(E::Fr::zero())
Ok(Scalar::zero())
}
} else {
Err(SynthesisError::AssignmentMissing)
@ -100,13 +99,13 @@ fn test_xordemo() {
let tau = Fr::from_str("3673").unwrap();
let params = {
let c = XORDemo::<DummyEngine> {
let c = XORDemo {
a: None,
b: None,
_marker: PhantomData,
};
generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap()
generate_parameters::<DummyEngine, _>(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap()
};
// This will synthesize the constraint system:

View File

@ -22,12 +22,13 @@
//! },
//! groth16, Circuit, ConstraintSystem, SynthesisError,
//! };
//! use ff::PrimeField;
//! use pairing::{bls12_381::Bls12, Engine};
//! use rand::rngs::OsRng;
//! use sha2::{Digest, Sha256};
//!
//! /// Our own SHA-256d gadget. Input and output are in little-endian bit order.
//! fn sha256d<E: Engine, CS: ConstraintSystem<E>>(
//! fn sha256d<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
//! mut cs: CS,
//! data: &[Boolean],
//! ) -> Result<Vec<Boolean>, SynthesisError> {
@ -57,8 +58,8 @@
//! preimage: Option<[u8; 80]>,
//! }
//!
//! impl<E: Engine> Circuit<E> for MyCircuit {
//! fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
//! impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
//! fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
//! // Compute the values for the bits of the preimage. If we are verifying a proof,
//! // we still need to create the same constraints, so we return an equivalent-size
//! // Vec of None (indicating that the value of each bit is unknown).
@ -118,7 +119,7 @@
//!
//! // Pack the hash as inputs for proof verification.
//! let hash_bits = multipack::bytes_to_bits_le(&hash);
//! let inputs = multipack::compute_multipacking::<Bls12>(&hash_bits);
//! let inputs = multipack::compute_multipacking(&hash_bits);
//!
//! // Check the proof!
//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).unwrap());
@ -142,21 +143,21 @@ pub mod groth16;
pub mod multicore;
mod multiexp;
use ff::{Field, ScalarEngine};
use ff::PrimeField;
use std::error::Error;
use std::fmt;
use std::io;
use std::marker::PhantomData;
use std::ops::{Add, MulAssign, Neg, Sub};
use std::ops::{Add, Sub};
/// Computations are expressed in terms of arithmetic circuits, in particular
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
/// circuit that can be synthesized. The `synthesize` method is called during
/// CRS generation and during proving.
pub trait Circuit<E: ScalarEngine> {
pub trait Circuit<Scalar: PrimeField> {
/// Synthesize the circuit into a rank-1 quadratic constraint system
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>;
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError>;
}
/// Represents a variable in our constraint system.
@ -188,59 +189,59 @@ pub enum Index {
/// This represents a linear combination of some variables, with coefficients
/// in the scalar field of a pairing-friendly elliptic curve group.
#[derive(Clone)]
pub struct LinearCombination<E: ScalarEngine>(Vec<(Variable, E::Fr)>);
pub struct LinearCombination<Scalar: PrimeField>(Vec<(Variable, Scalar)>);
impl<E: ScalarEngine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
fn as_ref(&self) -> &[(Variable, E::Fr)] {
impl<Scalar: PrimeField> AsRef<[(Variable, Scalar)]> for LinearCombination<Scalar> {
fn as_ref(&self) -> &[(Variable, Scalar)] {
&self.0
}
}
impl<E: ScalarEngine> LinearCombination<E> {
pub fn zero() -> LinearCombination<E> {
impl<Scalar: PrimeField> LinearCombination<Scalar> {
pub fn zero() -> LinearCombination<Scalar> {
LinearCombination(vec![])
}
}
impl<E: ScalarEngine> Add<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<Scalar: PrimeField> Add<(Scalar, Variable)> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
fn add(mut self, (coeff, var): (Scalar, Variable)) -> LinearCombination<Scalar> {
self.0.push((var, coeff));
self
}
}
impl<E: ScalarEngine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<Scalar: PrimeField> Sub<(Scalar, Variable)> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
#[allow(clippy::suspicious_arithmetic_impl)]
fn sub(self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
fn sub(self, (coeff, var): (Scalar, Variable)) -> LinearCombination<Scalar> {
self + (coeff.neg(), var)
}
}
impl<E: ScalarEngine> Add<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<Scalar: PrimeField> Add<Variable> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
fn add(self, other: Variable) -> LinearCombination<E> {
self + (E::Fr::one(), other)
fn add(self, other: Variable) -> LinearCombination<Scalar> {
self + (Scalar::one(), other)
}
}
impl<E: ScalarEngine> Sub<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<Scalar: PrimeField> Sub<Variable> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
fn sub(self, other: Variable) -> LinearCombination<E> {
self - (E::Fr::one(), other)
fn sub(self, other: Variable) -> LinearCombination<Scalar> {
self - (Scalar::one(), other)
}
}
impl<'a, E: ScalarEngine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<'a, Scalar: PrimeField> Add<&'a LinearCombination<Scalar>> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
fn add(mut self, other: &'a LinearCombination<Scalar>) -> LinearCombination<Scalar> {
for s in &other.0 {
self = self + (s.1, s.0);
}
@ -249,10 +250,10 @@ impl<'a, E: ScalarEngine> Add<&'a LinearCombination<E>> for LinearCombination<E>
}
}
impl<'a, E: ScalarEngine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<'a, Scalar: PrimeField> Sub<&'a LinearCombination<Scalar>> for LinearCombination<Scalar> {
type Output = LinearCombination<Scalar>;
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
fn sub(mut self, other: &'a LinearCombination<Scalar>) -> LinearCombination<Scalar> {
for s in &other.0 {
self = self - (s.1, s.0);
}
@ -261,10 +262,15 @@ impl<'a, E: ScalarEngine> Sub<&'a LinearCombination<E>> for LinearCombination<E>
}
}
impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<'a, Scalar: PrimeField> Add<(Scalar, &'a LinearCombination<Scalar>)>
for LinearCombination<Scalar>
{
type Output = LinearCombination<Scalar>;
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
fn add(
mut self,
(coeff, other): (Scalar, &'a LinearCombination<Scalar>),
) -> LinearCombination<Scalar> {
for s in &other.0 {
let mut tmp = s.1;
tmp.mul_assign(&coeff);
@ -275,10 +281,15 @@ impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombi
}
}
impl<'a, E: ScalarEngine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
impl<'a, Scalar: PrimeField> Sub<(Scalar, &'a LinearCombination<Scalar>)>
for LinearCombination<Scalar>
{
type Output = LinearCombination<Scalar>;
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
fn sub(
mut self,
(coeff, other): (Scalar, &'a LinearCombination<Scalar>),
) -> LinearCombination<Scalar> {
for s in &other.0 {
let mut tmp = s.1;
tmp.mul_assign(&coeff);
@ -347,10 +358,10 @@ impl fmt::Display for SynthesisError {
/// Represents a constraint system which can have new variables
/// allocated and constrains between them formed.
pub trait ConstraintSystem<E: ScalarEngine>: Sized {
pub trait ConstraintSystem<Scalar: PrimeField>: Sized {
/// Represents the type of the "root" of this constraint system
/// so that nested namespaces can minimize indirection.
type Root: ConstraintSystem<E>;
type Root: ConstraintSystem<Scalar>;
/// Return the "one" input variable
fn one() -> Variable {
@ -363,7 +374,7 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
/// namespace.
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
@ -371,7 +382,7 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
/// determine the assignment of the variable.
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
@ -381,9 +392,9 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>;
/// Create a new (sub)namespace and enter into it. Not intended
/// for downstream use; use `namespace` instead.
@ -401,7 +412,7 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
fn get_root(&mut self) -> &mut Self::Root;
/// Begin a namespace for this constraint system.
fn namespace<NR, N>(&mut self, name_fn: N) -> Namespace<'_, E, Self::Root>
fn namespace<NR, N>(&mut self, name_fn: N) -> Namespace<'_, Scalar, Self::Root>
where
NR: Into<String>,
N: FnOnce() -> NR,
@ -414,9 +425,14 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
/// This is a "namespaced" constraint system which borrows a constraint system (pushing
/// a namespace context) and, when dropped, pops out of the namespace context.
pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem<E>>(&'a mut CS, PhantomData<E>);
pub struct Namespace<'a, Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
&'a mut CS,
PhantomData<Scalar>,
);
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
impl<'cs, Scalar: PrimeField, CS: ConstraintSystem<Scalar>> ConstraintSystem<Scalar>
for Namespace<'cs, Scalar, CS>
{
type Root = CS::Root;
fn one() -> Variable {
@ -425,7 +441,7 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -434,7 +450,7 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -445,9 +461,9 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
self.0.enforce(annotation, a, b, c)
}
@ -473,15 +489,17 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
}
}
impl<'a, E: ScalarEngine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
impl<'a, Scalar: PrimeField, CS: ConstraintSystem<Scalar>> Drop for Namespace<'a, Scalar, CS> {
fn drop(&mut self) {
self.get_root().pop_namespace()
}
}
/// Convenience implementation of ConstraintSystem<E> for mutable references to
/// Convenience implementation of ConstraintSystem<Scalar> for mutable references to
/// constraint systems.
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
impl<'cs, Scalar: PrimeField, CS: ConstraintSystem<Scalar>> ConstraintSystem<Scalar>
for &'cs mut CS
{
type Root = CS::Root;
fn one() -> Variable {
@ -490,7 +508,7 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -499,7 +517,7 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
@ -510,9 +528,9 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
(**self).enforce(annotation, a, b, c)
}

View File

@ -293,9 +293,6 @@ where
multiexp_inner(pool, bases, density_map, exponents, 0, c, true)
}
#[cfg(all(test, feature = "pairing"))]
use ff::ScalarEngine;
#[cfg(feature = "pairing")]
#[test]
fn test_with_bls12() {
@ -315,17 +312,16 @@ fn test_with_bls12() {
}
use group::Group;
use pairing::{bls12_381::Bls12, Engine};
use pairing::{
bls12_381::{Bls12, Fr},
Engine,
};
use rand;
const SAMPLES: usize = 1 << 14;
let rng = &mut rand::thread_rng();
let v = Arc::new(
(0..SAMPLES)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
.collect::<Vec<_>>(),
);
let v = Arc::new((0..SAMPLES).map(|_| Fr::random(rng)).collect::<Vec<_>>());
let g = Arc::new(
(0..SAMPLES)
.map(|_| <Bls12 as Engine>::G1::random(rng).to_affine())

View File

@ -4,13 +4,11 @@ use rand::thread_rng;
// For benchmarking
use std::time::{Duration, Instant};
// Bring in some tools for using pairing-friendly curves
use ff::{Field, ScalarEngine};
use pairing::Engine;
use std::ops::{AddAssign, MulAssign};
// Bring in some tools for using finite fiels
use ff::{Field, PrimeField};
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
use pairing::bls12_381::Bls12;
use pairing::bls12_381::{Bls12, Fr};
// We'll use these interfaces to construct our circuit.
use bellman::{Circuit, ConstraintSystem, SynthesisError};
@ -35,7 +33,7 @@ const MIMC_ROUNDS: usize = 322;
/// return xL
/// }
/// ```
fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
fn mimc<Scalar: PrimeField>(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
assert_eq!(constants.len(), MIMC_ROUNDS);
for i in 0..MIMC_ROUNDS {
@ -53,17 +51,17 @@ fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
/// This is our demo circuit for proving knowledge of the
/// preimage of a MiMC hash invocation.
struct MiMCDemo<'a, E: Engine> {
xl: Option<E::Fr>,
xr: Option<E::Fr>,
constants: &'a [E::Fr],
struct MiMCDemo<'a, Scalar: PrimeField> {
xl: Option<Scalar>,
xr: Option<Scalar>,
constants: &'a [Scalar],
}
/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
impl<'a, Scalar: PrimeField> Circuit<Scalar> for MiMCDemo<'a, Scalar> {
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
assert_eq!(self.constants.len(), MIMC_ROUNDS);
// Allocate the first component of the preimage.
@ -153,20 +151,20 @@ fn test_mimc() {
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
.map(|_| Fr::random(rng))
.collect::<Vec<_>>();
println!("Creating parameters...");
// Create parameters for our circuit
let params = {
let c = MiMCDemo::<Bls12> {
let c = MiMCDemo {
xl: None,
xr: None,
constants: &constants,
};
generate_random_parameters(c, rng).unwrap()
generate_random_parameters::<Bls12, _, _>(c, rng).unwrap()
};
// Prepare the verification key (for proof verification)
@ -185,9 +183,9 @@ fn test_mimc() {
for _ in 0..SAMPLES {
// Generate a random preimage and compute the image
let xl = <Bls12 as ScalarEngine>::Fr::random(rng);
let xr = <Bls12 as ScalarEngine>::Fr::random(rng);
let image = mimc::<Bls12>(xl, xr, &constants);
let xl = Fr::random(rng);
let xr = Fr::random(rng);
let image = mimc(xl, xr, &constants);
proof_vec.truncate(0);

View File

@ -213,14 +213,6 @@ pub trait PrimeField: Field + From<u64> {
fn root_of_unity() -> Self;
}
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
/// with well-defined relationships. Specific relationships (for example, a
/// pairing-friendly curve) can be defined in a subtrait.
pub trait ScalarEngine: Sized + 'static + Clone {
/// This is the scalar field of the engine's groups.
type Fr: PrimeField;
}
#[derive(Debug)]
pub struct BitIterator<T, E: AsRef<[T]>> {
t: E,

View File

@ -35,10 +35,6 @@ impl<T, Rhs, Output> ScalarMul<Rhs, Output> for T where T: Mul<Rhs, Output = Out
{}
/// A helper trait for references implementing group scalar multiplication.
///
/// This trait, in combination with `ScalarMul`, is necessary to address type constraint
/// issues in `pairing::Engine` (specifically, to ensure that [`ff::ScalarEngine::Fr`] is
/// correctly constrained to implement these traits required by [`Group::Scalar`]).
pub trait ScalarMulOwned<Rhs, Output = Self>: for<'r> ScalarMul<&'r Rhs, Output> {}
impl<T, Rhs, Output> ScalarMulOwned<Rhs, Output> for T where T: for<'r> ScalarMul<&'r Rhs, Output> {}

View File

@ -23,7 +23,7 @@ pub use self::fr::{Fr, FrRepr};
use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine};
use ff::{BitIterator, Field};
use group::CurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption;
@ -35,11 +35,8 @@ const BLS_X_IS_NEGATIVE: bool = true;
#[derive(Clone, Debug)]
pub struct Bls12;
impl ScalarEngine for Bls12 {
type Fr = Fr;
}
impl Engine for Bls12 {
type Fr = Fr;
type G1 = G1;
type G1Affine = G1Affine;
type G2 = G2;

View File

@ -21,14 +21,17 @@ pub mod tests;
pub mod bls12_381;
use core::ops::Mul;
use ff::{Field, PrimeField, ScalarEngine};
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned};
use subtle::CtOption;
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
/// with well-defined relationships. In particular, the G1/G2 curve groups are
/// of prime order `r`, and are equipped with a bilinear pairing function.
pub trait Engine: ScalarEngine {
pub trait Engine: Sized + 'static + Clone {
/// This is the scalar field of the engine's groups.
type Fr: PrimeField;
/// The projective representation of an element in G1.
type G1: CurveProjective<Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
+ From<Self::G1Affine>

View File

@ -19,7 +19,7 @@ fn main() {
println!("Creating sample parameters...");
let groth_params = generate_random_parameters::<Bls12, _, _>(
Spend {
Spend::<Bls12> {
params: jubjub_params,
value_commitment: None,
proof_generation_key: None,
@ -37,7 +37,7 @@ fn main() {
let mut total_time = Duration::new(0, 0);
for _ in 0..SAMPLES {
let value_commitment = ValueCommitment {
let value_commitment = ValueCommitment::<Bls12> {
value: 1,
randomness: fs::Fs::random(rng),
};

View File

@ -18,8 +18,8 @@ use bellman::gadgets::boolean::Boolean;
#[derive(Clone)]
pub struct EdwardsPoint<E: Engine> {
x: AllocatedNum<E>,
y: AllocatedNum<E>,
x: AllocatedNum<E::Fr>,
y: AllocatedNum<E::Fr>,
}
/// Perform a fixed-base scalar multiplication with
@ -31,7 +31,7 @@ pub fn fixed_base_multiplication<E, CS>(
params: &E::Params,
) -> Result<EdwardsPoint<E>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
E: JubjubEngine,
{
// Represents the result of the multiplication
@ -78,11 +78,11 @@ where
}
impl<E: JubjubEngine> EdwardsPoint<E> {
pub fn get_x(&self) -> &AllocatedNum<E> {
pub fn get_x(&self) -> &AllocatedNum<E::Fr> {
&self.x
}
pub fn get_y(&self) -> &AllocatedNum<E> {
pub fn get_y(&self) -> &AllocatedNum<E::Fr> {
&self.y
}
@ -92,7 +92,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
params: &E::Params,
) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
let tmp = self.double(cs.namespace(|| "first doubling"), params)?;
let tmp = tmp.double(cs.namespace(|| "second doubling"), params)?;
@ -109,7 +109,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
self.x.inputize(cs.namespace(|| "x"))?;
self.y.inputize(cs.namespace(|| "y"))?;
@ -120,7 +120,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
/// This converts the point into a representation.
pub fn repr<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
let mut tmp = vec![];
@ -142,7 +142,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
params: &E::Params,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
let p = p.map(|p| p.to_xy());
@ -163,7 +163,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
condition: &Boolean,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Compute x' = self.x if condition, and 0 otherwise
let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || {
@ -220,7 +220,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
params: &E::Params,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Represents the current "magnitude" of the base
// that we're operating over. Starts at self,
@ -267,12 +267,12 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
pub fn interpret<CS>(
mut cs: CS,
x: &AllocatedNum<E>,
y: &AllocatedNum<E>,
x: &AllocatedNum<E::Fr>,
y: &AllocatedNum<E::Fr>,
params: &E::Params,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// -x^2 + y^2 = 1 + dx^2y^2
@ -296,7 +296,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
pub fn double<CS>(&self, mut cs: CS, params: &E::Params) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Compute T = (x1 + y1) * (x1 + y1)
let t = AllocatedNum::alloc(cs.namespace(|| "T"), || {
@ -395,7 +395,7 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
params: &E::Params,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Compute U = (x1 + y1) * (x2 + y2)
let u = AllocatedNum::alloc(cs.namespace(|| "U"), || {
@ -492,8 +492,8 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
}
pub struct MontgomeryPoint<E: Engine> {
x: Num<E>,
y: Num<E>,
x: Num<E::Fr>,
y: Num<E::Fr>,
}
impl<E: JubjubEngine> MontgomeryPoint<E> {
@ -506,7 +506,7 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
params: &E::Params,
) -> Result<EdwardsPoint<E>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Compute u = (scale*x) / y
let u = AllocatedNum::alloc(cs.namespace(|| "u"), || {
@ -558,7 +558,7 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
/// in Montgomery, does not check that it's
/// on the curve. Useful for constants and
/// window table lookups.
pub fn interpret_unchecked(x: Num<E>, y: Num<E>) -> Self {
pub fn interpret_unchecked(x: Num<E::Fr>, y: Num<E::Fr>) -> Self {
MontgomeryPoint { x, y }
}
@ -571,7 +571,7 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
params: &E::Params,
) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Compute lambda = (y' - y) / (x' - x)
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
@ -673,7 +673,7 @@ mod test {
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let p = montgomery::Point::<Bls12, _>::rand(rng, params);
let (u, v) = edwards::Point::from_montgomery(&p, params).to_xy();
@ -682,7 +682,7 @@ mod test {
let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || Ok(x)).unwrap();
let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || Ok(y)).unwrap();
let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into());
let p = MontgomeryPoint::<Bls12>::interpret_unchecked(numx.into(), numy.into());
let q = p.into_edwards(&mut cs, params).unwrap();
@ -713,7 +713,7 @@ mod test {
for _ in 0..100 {
let p = edwards::Point::<Bls12, _>::rand(rng, &params);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let q = EdwardsPoint::witness(&mut cs, Some(p.clone()), &params).unwrap();
let p = p.to_xy();
@ -727,11 +727,11 @@ mod test {
let p = edwards::Point::<Bls12, _>::rand(rng, &params);
let (x, y) = p.to_xy();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x)).unwrap();
let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(y)).unwrap();
let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, &params).unwrap();
let p = EdwardsPoint::<Bls12>::interpret(&mut cs, &numx, &numy, &params).unwrap();
assert!(cs.is_satisfied());
assert_eq!(p.x.get_value().unwrap(), x);
@ -743,11 +743,11 @@ mod test {
let x = Fr::random(rng);
let y = Fr::random(rng);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x)).unwrap();
let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(y)).unwrap();
EdwardsPoint::interpret(&mut cs, &numx, &numy, &params).unwrap();
EdwardsPoint::<Bls12>::interpret(&mut cs, &numx, &numy, &params).unwrap();
assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check");
}
@ -762,7 +762,7 @@ mod test {
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let p = params.generator(FixedGenerators::NoteCommitmentRandomness);
let s = Fs::random(rng);
@ -783,7 +783,7 @@ mod test {
.map(|v| Boolean::from(v))
.collect::<Vec<_>>();
let q = fixed_base_multiplication(
let q = fixed_base_multiplication::<Bls12, _>(
cs.namespace(|| "multiplication"),
FixedGenerators::NoteCommitmentRandomness,
&s_bits,
@ -805,7 +805,7 @@ mod test {
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let p = edwards::Point::<Bls12, _>::rand(rng, params);
let s = Fs::random(rng);
@ -817,7 +817,7 @@ mod test {
let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap();
let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap();
let p = EdwardsPoint {
let p = EdwardsPoint::<Bls12> {
x: num_x0,
y: num_y0,
};
@ -857,7 +857,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let p = edwards::Point::<Bls12, _>::rand(rng, params);
@ -866,7 +866,7 @@ mod test {
let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap();
let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap();
let p = EdwardsPoint {
let p = EdwardsPoint::<Bls12> {
x: num_x0,
y: num_y0,
};
@ -933,7 +933,7 @@ mod test {
let (x1, y1) = p2.to_xy();
let (x2, y2) = p3.to_xy();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap();
let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap();
@ -941,7 +941,7 @@ mod test {
let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || Ok(x1)).unwrap();
let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || Ok(y1)).unwrap();
let p1 = EdwardsPoint {
let p1 = EdwardsPoint::<Bls12> {
x: num_x0,
y: num_y0,
};
@ -993,12 +993,12 @@ mod test {
let (x0, y0) = p1.to_xy();
let (x1, y1) = p2.to_xy();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap();
let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap();
let p1 = EdwardsPoint {
let p1 = EdwardsPoint::<Bls12> {
x: num_x0,
y: num_y0,
};
@ -1047,7 +1047,7 @@ mod test {
let (x1, y1) = p2.to_xy().unwrap();
let (x2, y2) = p3.to_xy().unwrap();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap();
let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap();
@ -1055,7 +1055,7 @@ mod test {
let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || Ok(x1)).unwrap();
let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || Ok(y1)).unwrap();
let p1 = MontgomeryPoint {
let p1 = MontgomeryPoint::<Bls12> {
x: num_x0.into(),
y: num_y0.into(),
};
@ -1092,7 +1092,7 @@ mod test {
let params = &JubjubBls12::new();
let check_small_order_from_p = |p: edwards::Point<Bls12, _>, is_small_order| {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let p = EdwardsPoint::witness(&mut cs, Some(p), params).unwrap();
assert!(cs.is_satisfied());

View File

@ -22,7 +22,7 @@ pub fn pedersen_hash<E: JubjubEngine, CS>(
params: &E::Params,
) -> Result<EdwardsPoint<E>, SynthesisError>
where
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
let personalization = get_constant_bools(&personalization);
assert_eq!(personalization.len(), 6);
@ -162,7 +162,7 @@ mod test {
]
.iter()
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let input: Vec<bool> = (0..n_bits).map(|_| rng.next_u32() % 2 != 0).collect();
@ -177,7 +177,7 @@ mod test {
})
.collect();
pedersen_hash(
pedersen_hash::<Bls12, _>(
cs.namespace(|| "pedersen hash"),
Personalization::NoteCommitment,
&input_bools,
@ -212,7 +212,7 @@ mod test {
for _ in 0..5 {
let input: Vec<bool> = (0..length).map(|_| rng.next_u32() % 2 != 0).collect();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let input_bools: Vec<Boolean> = input
.iter()
@ -225,7 +225,7 @@ mod test {
})
.collect();
let res = pedersen_hash(
let res = pedersen_hash::<Bls12, _>(
cs.namespace(|| "pedersen hash"),
Personalization::MerkleTree(1),
&input_bools,
@ -278,7 +278,7 @@ mod test {
for length in 300..302 {
let input: Vec<bool> = (0..length).map(|_| rng.next_u32() % 2 != 0).collect();
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let input_bools: Vec<Boolean> = input
.iter()
@ -291,7 +291,7 @@ mod test {
})
.collect();
let res = pedersen_hash(
let res = pedersen_hash::<Bls12, _>(
cs.namespace(|| "pedersen hash"),
Personalization::MerkleTree(1),
&input_bools,

View File

@ -74,7 +74,7 @@ fn expose_value_commitment<E, CS>(
) -> Result<Vec<boolean::Boolean>, SynthesisError>
where
E: JubjubEngine,
CS: ConstraintSystem<E>,
CS: ConstraintSystem<E::Fr>,
{
// Booleanize the value into little-endian bit order
let value_bits = boolean::u64_into_boolean_vec_le(
@ -83,7 +83,7 @@ where
)?;
// Compute the note value in the exponent
let value = ecc::fixed_base_multiplication(
let value = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "compute the value in the exponent"),
FixedGenerators::ValueCommitmentValue,
&value_bits,
@ -99,7 +99,7 @@ where
)?;
// Compute the randomness in the exponent
let rcv = ecc::fixed_base_multiplication(
let rcv = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "computation of rcv"),
FixedGenerators::ValueCommitmentRandomness,
&rcv,
@ -115,8 +115,8 @@ where
Ok(value_bits)
}
impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
impl<'a, E: JubjubEngine> Circuit<E::Fr> for Spend<'a, E> {
fn synthesize<CS: ConstraintSystem<E::Fr>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
// Prover witnesses ak (ensures that it's on the curve)
let ak = ecc::EdwardsPoint::witness(
cs.namespace(|| "ak"),
@ -134,7 +134,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let ar = boolean::field_into_boolean_vec_le(cs.namespace(|| "ar"), self.ar)?;
// Compute the randomness in the exponent
let ar = ecc::fixed_base_multiplication(
let ar = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "computation of randomization for the signing key"),
FixedGenerators::SpendingKeyGenerator,
&ar,
@ -161,7 +161,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// congruency then that's equivalent.
// Compute nk = [nsk] ProvingPublicKey
nk = ecc::fixed_base_multiplication(
nk = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "computation of nk"),
FixedGenerators::ProofGenerationKey,
&nsk,
@ -266,7 +266,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
);
// Compute the hash of the note contents
let mut cm = pedersen_hash::pedersen_hash(
let mut cm = pedersen_hash::pedersen_hash::<E, _>(
cs.namespace(|| "note content hash"),
pedersen_hash::Personalization::NoteCommitment,
&note_contents,
@ -281,7 +281,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
)?;
// Compute the note commitment randomness in the exponent
let rcm = ecc::fixed_base_multiplication(
let rcm = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "computation of commitment randomness"),
FixedGenerators::NoteCommitmentRandomness,
&rcm,
@ -342,7 +342,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
preimage.extend(xr.to_bits_le(cs.namespace(|| "xr into bits"))?);
// Compute the new subtree value
cur = pedersen_hash::pedersen_hash(
cur = pedersen_hash::pedersen_hash::<E, _>(
cs.namespace(|| "computation of pedersen hash"),
pedersen_hash::Personalization::MerkleTree(i),
&preimage,
@ -379,7 +379,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let mut rho = cm;
{
// Compute the position in the exponent
let position = ecc::fixed_base_multiplication(
let position = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "g^position"),
FixedGenerators::NullifierPosition,
&position_bits,
@ -410,8 +410,8 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
}
}
impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
impl<'a, E: JubjubEngine> Circuit<E::Fr> for Output<'a, E> {
fn synthesize<CS: ConstraintSystem<E::Fr>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
// Let's start to construct our note, which contains
// value (big endian)
let mut note_contents = vec![];
@ -494,7 +494,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
);
// Compute the hash of the note contents
let mut cm = pedersen_hash::pedersen_hash(
let mut cm = pedersen_hash::pedersen_hash::<E, _>(
cs.namespace(|| "note content hash"),
pedersen_hash::Personalization::NoteCommitment,
&note_contents,
@ -509,7 +509,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
)?;
// Compute the note commitment randomness in the exponent
let rcm = ecc::fixed_base_multiplication(
let rcm = ecc::fixed_base_multiplication::<E, _>(
cs.namespace(|| "computation of commitment randomness"),
FixedGenerators::NoteCommitmentRandomness,
&rcm,
@ -556,7 +556,7 @@ fn test_input_circuit_with_bls12_381() {
let tree_depth = 32;
for _ in 0..10 {
let value_commitment = ValueCommitment {
let value_commitment = ValueCommitment::<Bls12> {
value: rng.next_u64(),
randomness: fs::Fs::random(rng),
};
@ -638,10 +638,10 @@ fn test_input_circuit_with_bls12_381() {
let expected_nf = note.nf(&viewing_key, position, params);
let expected_nf = multipack::bytes_to_bits_le(&expected_nf);
let expected_nf = multipack::compute_multipacking::<Bls12>(&expected_nf);
let expected_nf = multipack::compute_multipacking(&expected_nf);
assert_eq!(expected_nf.len(), 2);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let instance = Spend {
params,
@ -732,7 +732,7 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
];
for i in 0..10 {
let value_commitment = ValueCommitment {
let value_commitment = ValueCommitment::<Bls12> {
value: i,
randomness: fs::Fs::from_str(&(1000 * (i + 1)).to_string()).unwrap(),
};
@ -822,10 +822,10 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
let expected_nf = note.nf(&viewing_key, position, params);
let expected_nf = multipack::bytes_to_bits_le(&expected_nf);
let expected_nf = multipack::compute_multipacking::<Bls12>(&expected_nf);
let expected_nf = multipack::compute_multipacking(&expected_nf);
assert_eq!(expected_nf.len(), 2);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let instance = Spend {
params: params,
@ -887,7 +887,7 @@ fn test_output_circuit_with_bls12_381() {
]);
for _ in 0..100 {
let value_commitment = ValueCommitment {
let value_commitment = ValueCommitment::<Bls12> {
value: rng.next_u64(),
randomness: fs::Fs::random(rng),
};
@ -921,7 +921,7 @@ fn test_output_circuit_with_bls12_381() {
let esk = fs::Fs::random(rng);
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::new();
let instance = Output {
params,

View File

@ -1,9 +1,9 @@
use bellman::gadgets::boolean::Boolean;
use bellman::gadgets::sha256::sha256;
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use ff::PrimeField;
pub fn note_comm<E, CS>(
pub fn note_comm<Scalar, CS>(
cs: CS,
a_pk: &[Boolean],
value: &[Boolean],
@ -11,8 +11,8 @@ pub fn note_comm<E, CS>(
r: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(a_pk.len(), 256);
assert_eq!(value.len(), 64);

View File

@ -1,7 +1,7 @@
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
use bellman::gadgets::sha256::sha256_block_no_padding;
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use ff::PrimeField;
use super::commitment::note_comm;
use super::prfs::*;
@ -13,7 +13,7 @@ pub struct InputNote {
}
impl InputNote {
pub fn compute<E, CS>(
pub fn compute<Scalar, CS>(
mut cs: CS,
a_sk: Option<SpendingKey>,
rho: Option<UniqueRandomness>,
@ -25,8 +25,8 @@ impl InputNote {
rt: &[Boolean],
) -> Result<InputNote, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let a_sk = witness_u252(
cs.namespace(|| "a_sk"),
@ -106,7 +106,7 @@ impl InputNote {
// if enforce is one, they must be equal
cs.enforce(
|| format!("conditionally enforce correct root for bit {}", i),
|_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()),
|_| cur.lc(CS::one(), Scalar::one()) - &rt.lc(CS::one(), Scalar::one()),
|lc| lc + enforce.get_variable(),
|lc| lc,
);
@ -118,15 +118,15 @@ impl InputNote {
/// Swaps two 256-bit blobs conditionally, returning the
/// 512-bit concatenation.
pub fn conditionally_swap_u256<E, CS>(
pub fn conditionally_swap_u256<Scalar, CS>(
mut cs: CS,
lhs: &[Boolean],
rhs: &[Boolean],
condition: &AllocatedBit,
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(lhs.len(), 256);
assert_eq!(rhs.len(), 256);
@ -155,9 +155,9 @@ where
// x = rhs
cs.enforce(
|| "conditional swap for x",
|lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &rhs.lc(CS::one(), Scalar::one()) - &lhs.lc(CS::one(), Scalar::one()),
|lc| lc + condition.get_variable(),
|lc| lc + &x.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &x.lc(CS::one(), Scalar::one()) - &lhs.lc(CS::one(), Scalar::one()),
);
let y = Boolean::from(AllocatedBit::alloc(
@ -171,9 +171,9 @@ where
// y - rhs = condition (lhs - rhs)
cs.enforce(
|| "conditional swap for y",
|lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &lhs.lc(CS::one(), Scalar::one()) - &rhs.lc(CS::one(), Scalar::one()),
|lc| lc + condition.get_variable(),
|lc| lc + &y.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &y.lc(CS::one(), Scalar::one()) - &rhs.lc(CS::one(), Scalar::one()),
);
new_lhs.push(x);

View File

@ -13,8 +13,7 @@
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
use bellman::gadgets::multipack::pack_into_inputs;
use bellman::{Circuit, ConstraintSystem, LinearCombination, SynthesisError};
use ff::Field;
use pairing::Engine;
use ff::PrimeField;
mod commitment;
mod input;
@ -55,8 +54,8 @@ pub struct JSOutput {
pub r: Option<CommitmentRandomness>,
}
impl<E: Engine> Circuit<E> for JoinSplit {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
impl<Scalar: PrimeField> Circuit<Scalar> for JoinSplit {
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
assert_eq!(self.inputs.len(), 2);
assert_eq!(self.outputs.len(), 2);
@ -219,10 +218,10 @@ pub struct NoteValue {
}
impl NoteValue {
fn new<E, CS>(mut cs: CS, value: Option<u64>) -> Result<NoteValue, SynthesisError>
fn new<Scalar, CS>(mut cs: CS, value: Option<u64>) -> Result<NoteValue, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let mut values;
match value {
@ -262,10 +261,10 @@ impl NoteValue {
/// Computes this value as a linear combination of
/// its bits.
fn lc<E: Engine>(&self) -> LinearCombination<E> {
fn lc<Scalar: PrimeField>(&self) -> LinearCombination<Scalar> {
let mut tmp = LinearCombination::zero();
let mut coeff = E::Fr::one();
let mut coeff = Scalar::one();
for b in &self.bits {
tmp = tmp + (coeff, b.get_variable());
coeff = coeff.double();
@ -281,15 +280,15 @@ impl NoteValue {
/// Witnesses some bytes in the constraint system,
/// skipping the first `skip_bits`.
fn witness_bits<E, CS>(
fn witness_bits<Scalar, CS>(
mut cs: CS,
value: Option<&[u8]>,
num_bits: usize,
skip_bits: usize,
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let bit_values = if let Some(value) = value {
let mut tmp = vec![];
@ -318,18 +317,18 @@ where
Ok(bits)
}
fn witness_u256<E, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
fn witness_u256<Scalar, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
witness_bits(cs, value, 256, 0)
}
fn witness_u252<E, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
fn witness_u252<Scalar, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
witness_bits(cs, value, 252, 4)
}
@ -338,7 +337,7 @@ where
#[ignore]
fn test_sprout_constraints() {
use bellman::gadgets::test::*;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
@ -356,7 +355,7 @@ fn test_sprout_constraints() {
}
while test_vector.len() != 0 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut cs = TestConstraintSystem::<Fr>::new();
let phi = Some(get_u256(&mut test_vector));
let rt = Some(get_u256(&mut test_vector));
@ -462,7 +461,7 @@ fn test_sprout_constraints() {
use bellman::gadgets::multipack;
let expected_inputs = multipack::bytes_to_bits(&expected_inputs);
let expected_inputs = multipack::compute_multipacking::<Bls12>(&expected_inputs);
let expected_inputs = multipack::compute_multipacking(&expected_inputs);
assert!(cs.verify(&expected_inputs));
}

View File

@ -1,6 +1,6 @@
use bellman::gadgets::boolean::Boolean;
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use ff::PrimeField;
use super::commitment::note_comm;
use super::prfs::*;
@ -11,7 +11,7 @@ pub struct OutputNote {
}
impl OutputNote {
pub fn compute<E, CS>(
pub fn compute<Scalar, CS>(
mut cs: CS,
a_pk: Option<PayingKey>,
value: &NoteValue,
@ -21,8 +21,8 @@ impl OutputNote {
nonce: bool,
) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
let rho = prf_rho(cs.namespace(|| "rho"), phi, h_sig, nonce)?;

View File

@ -1,9 +1,9 @@
use bellman::gadgets::boolean::Boolean;
use bellman::gadgets::sha256::sha256_block_no_padding;
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use ff::PrimeField;
fn prf<E, CS>(
fn prf<Scalar, CS>(
cs: CS,
a: bool,
b: bool,
@ -13,8 +13,8 @@ fn prf<E, CS>(
y: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
assert_eq!(x.len(), 252);
assert_eq!(y.len(), 256);
@ -32,10 +32,10 @@ where
sha256_block_no_padding(cs, &image)
}
pub fn prf_a_pk<E, CS>(cs: CS, a_sk: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
pub fn prf_a_pk<Scalar, CS>(cs: CS, a_sk: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
prf(
cs,
@ -50,40 +50,40 @@ where
)
}
pub fn prf_nf<E, CS>(
pub fn prf_nf<Scalar, CS>(
cs: CS,
a_sk: &[Boolean],
rho: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
prf(cs, true, true, true, false, a_sk, rho)
}
pub fn prf_pk<E, CS>(
pub fn prf_pk<Scalar, CS>(
cs: CS,
a_sk: &[Boolean],
h_sig: &[Boolean],
nonce: bool,
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
prf(cs, false, nonce, false, false, a_sk, h_sig)
}
pub fn prf_rho<E, CS>(
pub fn prf_rho<Scalar, CS>(
cs: CS,
phi: &[Boolean],
h_sig: &[Boolean],
nonce: bool,
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
Scalar: PrimeField,
CS: ConstraintSystem<Scalar>,
{
prf(cs, false, nonce, true, false, phi, h_sig)
}

View File

@ -145,7 +145,7 @@ impl SaplingProvingContext {
// Add the nullifier through multiscalar packing
{
let nullifier = multipack::bytes_to_bits_le(&nullifier);
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);
let nullifier = multipack::compute_multipacking(&nullifier);
assert_eq!(nullifier.len(), 2);

View File

@ -97,7 +97,7 @@ impl SaplingVerificationContext {
// Add the nullifier through multiscalar packing
{
let nullifier = multipack::bytes_to_bits_le(nullifier);
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);
let nullifier = multipack::compute_multipacking(&nullifier);
assert_eq!(nullifier.len(), 2);

View File

@ -161,7 +161,7 @@ pub fn verify_proof(
public_input.extend(&vpub_new.to_le_bytes());
let public_input = multipack::bytes_to_bits(&public_input);
let public_input = multipack::compute_multipacking::<Bls12>(&public_input);
let public_input = multipack::compute_multipacking(&public_input);
let proof = match Proof::read(&proof[..]) {
Ok(p) => p,