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 //! [`EvaluationDomain`]: crate::domain::EvaluationDomain
//! [Groth16]: https://eprint.iacr.org/2016/260 //! [Groth16]: https://eprint.iacr.org/2016/260
use ff::{Field, PrimeField, ScalarEngine}; use ff::PrimeField;
use group::CurveProjective; use group::CurveProjective;
use std::ops::{AddAssign, MulAssign, SubAssign};
use super::SynthesisError; use super::SynthesisError;
use super::multicore::Worker; use super::multicore::Worker;
pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> { pub struct EvaluationDomain<S: PrimeField, G: Group<S>> {
coeffs: Vec<G>, coeffs: Vec<G>,
exp: u32, exp: u32,
omega: E::Fr, omega: S,
omegainv: E::Fr, omegainv: S,
geninv: E::Fr, geninv: S,
minv: E::Fr, 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] { fn as_ref(&self) -> &[G] {
&self.coeffs &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] { fn as_mut(&mut self) -> &mut [G] {
&mut self.coeffs &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> { pub fn into_coeffs(self) -> Vec<G> {
self.coeffs 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 // Compute the size of our evaluation domain
let mut m = 1; let mut m = 1;
let mut exp = 0; 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 // The pairing-friendly curve may not be able to support
// large enough (radix2) evaluation domains. // large enough (radix2) evaluation domains.
if exp >= E::Fr::S { if exp >= S::S {
return Err(SynthesisError::PolynomialDegreeTooLarge); return Err(SynthesisError::PolynomialDegreeTooLarge);
} }
} }
// Compute omega, the 2^exp primitive root of unity // Compute omega, the 2^exp primitive root of unity
let mut omega = E::Fr::root_of_unity(); let mut omega = S::root_of_unity();
for _ in exp..E::Fr::S { for _ in exp..S::S {
omega = omega.square(); omega = omega.square();
} }
@ -74,11 +73,8 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
exp, exp,
omega, omega,
omegainv: omega.invert().unwrap(), omegainv: omega.invert().unwrap(),
geninv: E::Fr::multiplicative_generator().invert().unwrap(), geninv: S::multiplicative_generator().invert().unwrap(),
minv: E::Fr::from_str(&format!("{}", m)) minv: S::from_str(&format!("{}", m)).unwrap().invert().unwrap(),
.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| { worker.scope(self.coeffs.len(), |scope, chunk| {
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
scope.spawn(move |_scope| { 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) { 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); 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 /// This evaluates t(tau) for this domain, which is
/// tau^m - 1 for these radix-2 domains. /// 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]); let mut tmp = tau.pow_vartime(&[self.coeffs.len() as u64]);
tmp.sub_assign(&E::Fr::one()); tmp.sub_assign(&S::one());
tmp tmp
} }
@ -141,7 +137,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
/// evaluation domain, so we must perform division over /// evaluation domain, so we must perform division over
/// a coset. /// a coset.
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) { 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| { worker.scope(self.coeffs.len(), |scope, chunk| {
for v in self.coeffs.chunks_mut(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. /// 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()); assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| { 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. /// 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()); assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| { 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_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_add_assign(&mut self, other: &Self);
fn group_sub_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 { fn group_zero() -> Self {
Point(G::identity()) 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> { impl<S: PrimeField> PartialEq for Scalar<S> {
fn eq(&self, other: &Scalar<E>) -> bool { fn eq(&self, other: &Scalar<S>) -> bool {
self.0 == other.0 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> { impl<S: PrimeField> Clone for Scalar<S> {
fn clone(&self) -> Scalar<E> { fn clone(&self) -> Scalar<S> {
*self *self
} }
} }
impl<E: ScalarEngine> Group<E> for Scalar<E> { impl<S: PrimeField> Group<S> for Scalar<S> {
fn group_zero() -> Self { 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); self.0.mul_assign(by);
} }
fn group_add_assign(&mut self, other: &Self) { 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(); let log_cpus = worker.log_num_cpus();
if log_n <= log_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 { fn bitreverse(mut n: u32, l: u32) -> u32 {
let mut r = 0; let mut r = 0;
for _ in 0..l { 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; let mut k = 0;
while k < n { while k < n {
let mut w = E::Fr::one(); let mut w = S::one();
for j in 0..m { for j in 0..m {
let mut t = a[(k + j + m) as usize]; let mut t = a[(k + j + m) as usize];
t.group_mul_assign(&w); 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], a: &mut [T],
worker: &Worker, worker: &Worker,
omega: &E::Fr, omega: &S,
log_n: u32, log_n: u32,
log_cpus: 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_j = omega.pow_vartime(&[j as u64]);
let omega_step = omega.pow_vartime(&[(j as u64) << log_new_n]); 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 (i, tmp) in tmp.iter_mut().enumerate() {
for s in 0..num_cpus { for s in 0..num_cpus {
let idx = (i + (s << log_new_n)) % (1 << log_n); 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")] #[cfg(feature = "pairing")]
#[test] #[test]
fn polynomial_arith() { fn polynomial_arith() {
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::RngCore; 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(); let worker = Worker::new();
for coeffs_a in 0..70 { for coeffs_a in 0..70 {
for coeffs_b in 0..70 { for coeffs_b in 0..70 {
let mut a: Vec<_> = (0..coeffs_a) let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::<S>(S::random(rng))).collect();
.map(|_| Scalar::<E>(E::Fr::random(rng))) let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::<S>(S::random(rng))).collect();
.collect();
let mut b: Vec<_> = (0..coeffs_b)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect();
// naive evaluation // 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 (i1, a) in a.iter().enumerate() {
for (i2, b) in b.iter().enumerate() { for (i2, b) in b.iter().enumerate() {
let mut prod = *a; let mut prod = *a;
@ -404,8 +396,8 @@ fn polynomial_arith() {
} }
} }
a.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(E::Fr::zero())); b.resize(coeffs_a + coeffs_b, Scalar(S::zero()));
let mut a = EvaluationDomain::from_coeffs(a).unwrap(); let mut a = EvaluationDomain::from_coeffs(a).unwrap();
let mut b = EvaluationDomain::from_coeffs(b).unwrap(); let mut b = EvaluationDomain::from_coeffs(b).unwrap();
@ -424,16 +416,16 @@ fn polynomial_arith() {
let rng = &mut rand::thread_rng(); let rng = &mut rand::thread_rng();
test_mul::<Bls12, _>(rng); test_mul::<Fr, _>(rng);
} }
#[cfg(feature = "pairing")] #[cfg(feature = "pairing")]
#[test] #[test]
fn fft_composition() { fn fft_composition() {
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::RngCore; 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(); let worker = Worker::new();
for coeffs in 0..10 { for coeffs in 0..10 {
@ -441,7 +433,7 @@ fn fft_composition() {
let mut v = vec![]; let mut v = vec![];
for _ in 0..coeffs { 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(); let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap();
@ -462,17 +454,17 @@ fn fft_composition() {
let rng = &mut rand::thread_rng(); let rng = &mut rand::thread_rng();
test_comp::<Bls12, _>(rng); test_comp::<Fr, _>(rng);
} }
#[cfg(feature = "pairing")] #[cfg(feature = "pairing")]
#[test] #[test]
fn parallel_fft_consistency() { fn parallel_fft_consistency() {
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::RngCore; use rand_core::RngCore;
use std::cmp::min; 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(); let worker = Worker::new();
for _ in 0..5 { for _ in 0..5 {
@ -480,7 +472,7 @@ fn parallel_fft_consistency() {
let d = 1 << log_d; let d = 1 << log_d;
let v1 = (0..d) let v1 = (0..d)
.map(|_| Scalar::<E>(E::Fr::random(rng))) .map(|_| Scalar::<S>(S::random(rng)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap();
let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).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(); 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 super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32};
use crate::{ConstraintSystem, SynthesisError}; use crate::{ConstraintSystem, SynthesisError};
use ff::ScalarEngine; use ff::PrimeField;
/* /*
2.1. Parameters 2.1. Parameters
@ -79,7 +79,7 @@ const SIGMA: [[usize; 16]; 10] = [
END FUNCTION. END FUNCTION.
*/ */
fn mixing_g<E: ScalarEngine, CS: ConstraintSystem<E>, M>( fn mixing_g<Scalar: PrimeField, CS: ConstraintSystem<Scalar>, M>(
mut cs: M, mut cs: M,
v: &mut [UInt32], v: &mut [UInt32],
a: usize, a: usize,
@ -90,7 +90,7 @@ fn mixing_g<E: ScalarEngine, CS: ConstraintSystem<E>, M>(
y: &UInt32, y: &UInt32,
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
where where
M: ConstraintSystem<E, Root = MultiEq<E, CS>>, M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{ {
v[a] = UInt32::addmany( v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 1"), cs.namespace(|| "mixing step 1"),
@ -164,7 +164,7 @@ where
END FUNCTION. END FUNCTION.
*/ */
fn blake2s_compression<E: ScalarEngine, CS: ConstraintSystem<E>>( fn blake2s_compression<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
mut cs: CS, mut cs: CS,
h: &mut [UInt32], h: &mut [UInt32],
m: &[UInt32], m: &[UInt32],
@ -337,7 +337,7 @@ fn blake2s_compression<E: ScalarEngine, CS: ConstraintSystem<E>>(
END FUNCTION. END FUNCTION.
*/ */
pub fn blake2s<E: ScalarEngine, CS: ConstraintSystem<E>>( pub fn blake2s<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
mut cs: CS, mut cs: CS,
input: &[Boolean], input: &[Boolean],
personalization: &[u8], personalization: &[u8],
@ -409,7 +409,7 @@ pub fn blake2s<E: ScalarEngine, CS: ConstraintSystem<E>>(
mod test { mod test {
use blake2s_simd::Params as Blake2sParams; use blake2s_simd::Params as Blake2sParams;
use hex_literal::hex; use hex_literal::hex;
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
@ -420,7 +420,7 @@ mod test {
#[test] #[test]
fn test_blank_hash() { fn test_blank_hash() {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits = vec![]; let input_bits = vec![];
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied()); assert!(cs.is_satisfied());
@ -443,7 +443,7 @@ mod test {
#[test] #[test]
fn test_blake2s_constraints() { fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits: Vec<_> = (0..512) let input_bits: Vec<_> = (0..512)
.map(|i| { .map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
@ -461,7 +461,7 @@ mod test {
// Test that 512 fixed leading bits (constants) // Test that 512 fixed leading bits (constants)
// doesn't result in more constraints. // doesn't result in more constraints.
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5, 0xbc, 0xe5,
@ -481,7 +481,7 @@ mod test {
#[test] #[test]
fn test_blake2s_constant_constraints() { fn test_blake2s_constant_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut rng = XorShiftRng::from_seed([ let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5, 0xbc, 0xe5,
@ -512,7 +512,7 @@ mod test {
let hash_result = h.finalize(); let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![]; let mut input_bits = vec![];
@ -559,7 +559,7 @@ mod test {
let data: Vec<u8> = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec(); let data: Vec<u8> = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec();
assert_eq!(data.len(), 256); assert_eq!(data.len(), 256);
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![]; let mut input_bits = vec![];
@ -596,7 +596,7 @@ mod test {
let data: Vec<u8> = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec(); let data: Vec<u8> = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec();
assert_eq!(data.len(), 700); assert_eq!(data.len(), 700);
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![]; let mut input_bits = vec![];
@ -651,7 +651,7 @@ mod test {
let hash_result = h.finalize(); let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![]; let mut input_bits = vec![];

View File

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

View File

@ -1,7 +1,6 @@
//! Window table lookup gadgets. //! Window table lookup gadgets.
use ff::{Field, ScalarEngine}; use ff::PrimeField;
use std::ops::{AddAssign, Neg};
use super::boolean::Boolean; use super::boolean::Boolean;
use super::num::{AllocatedNum, Num}; use super::num::{AllocatedNum, Num};
@ -9,9 +8,9 @@ use super::*;
use crate::ConstraintSystem; use crate::ConstraintSystem;
// Synthesize the constants for each base pattern. // 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 where
I: IntoIterator<Item = &'a E::Fr>, I: IntoIterator<Item = &'a Scalar>,
{ {
assert_eq!(assignment.len(), 1 << window_size); assert_eq!(assignment.len(), 1 << window_size);
@ -29,13 +28,13 @@ where
/// Performs a 3-bit window table lookup. `bits` is in /// Performs a 3-bit window table lookup. `bits` is in
/// little-endian order. /// little-endian order.
pub fn lookup3_xy<E: ScalarEngine, CS>( pub fn lookup3_xy<Scalar: PrimeField, CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean], bits: &[Boolean],
coords: &[(E::Fr, E::Fr)], coords: &[(Scalar, Scalar)],
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError> ) -> Result<(AllocatedNum<Scalar>, AllocatedNum<Scalar>), SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert_eq!(bits.len(), 3); assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8); assert_eq!(coords.len(), 8);
@ -69,10 +68,10 @@ where
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?; let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
// Compute the coefficients for the lookup constraints // Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 8]; let mut x_coeffs = [Scalar::zero(); 8];
let mut y_coeffs = [E::Fr::zero(); 8]; let mut y_coeffs = [Scalar::zero(); 8];
synth::<E, _>(3, coords.iter().map(|c| &c.0), &mut x_coeffs); synth::<Scalar, _>(3, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(3, coords.iter().map(|c| &c.1), &mut y_coeffs); synth::<Scalar, _>(3, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?; let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?;
@ -82,17 +81,17 @@ where
|| "x-coordinate lookup", || "x-coordinate lookup",
|lc| { |lc| {
lc + (x_coeffs[0b001], one) lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011]) + &bits[1].lc::<Scalar>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101]) + &bits[2].lc::<Scalar>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111]) + &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| {
lc + res_x.get_variable() lc + res_x.get_variable()
- (x_coeffs[0b000], one) - (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010]) - &bits[1].lc::<Scalar>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100]) - &bits[2].lc::<Scalar>(one, x_coeffs[0b100])
- &precomp.lc::<E>(one, x_coeffs[0b110]) - &precomp.lc::<Scalar>(one, x_coeffs[0b110])
}, },
); );
@ -100,17 +99,17 @@ where
|| "y-coordinate lookup", || "y-coordinate lookup",
|lc| { |lc| {
lc + (y_coeffs[0b001], one) lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011]) + &bits[1].lc::<Scalar>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101]) + &bits[2].lc::<Scalar>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111]) + &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| {
lc + res_y.get_variable() lc + res_y.get_variable()
- (y_coeffs[0b000], one) - (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010]) - &bits[1].lc::<Scalar>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100]) - &bits[2].lc::<Scalar>(one, y_coeffs[0b100])
- &precomp.lc::<E>(one, y_coeffs[0b110]) - &precomp.lc::<Scalar>(one, y_coeffs[0b110])
}, },
); );
@ -119,13 +118,13 @@ where
/// Performs a 3-bit window table lookup, where /// Performs a 3-bit window table lookup, where
/// one of the bits is a sign bit. /// 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, mut cs: CS,
bits: &[Boolean], bits: &[Boolean],
coords: &[(E::Fr, E::Fr)], coords: &[(Scalar, Scalar)],
) -> Result<(Num<E>, Num<E>), SynthesisError> ) -> Result<(Num<Scalar>, Num<Scalar>), SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert_eq!(bits.len(), 3); assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4); assert_eq!(coords.len(), 4);
@ -158,10 +157,10 @@ where
let one = CS::one(); let one = CS::one();
// Compute the coefficients for the lookup constraints // Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 4]; let mut x_coeffs = [Scalar::zero(); 4];
let mut y_coeffs = [E::Fr::zero(); 4]; let mut y_coeffs = [Scalar::zero(); 4];
synth::<E, _>(2, coords.iter().map(|c| &c.0), &mut x_coeffs); synth::<Scalar, _>(2, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(2, coords.iter().map(|c| &c.1), &mut y_coeffs); synth::<Scalar, _>(2, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; 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, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) let y_lc = precomp.lc::<Scalar>(one, y_coeffs[0b11])
+ &bits[1].lc::<E>(one, y_coeffs[0b10]) + &bits[1].lc::<Scalar>(one, y_coeffs[0b10])
+ &bits[0].lc::<E>(one, y_coeffs[0b01]) + &bits[0].lc::<Scalar>(one, y_coeffs[0b01])
+ (y_coeffs[0b00], one); + (y_coeffs[0b00], one);
cs.enforce( cs.enforce(
|| "y-coordinate lookup", || "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc, |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(), |lc| lc + &y_lc - y.get_variable(),
); );
@ -191,9 +190,12 @@ mod test {
use super::*; use super::*;
use crate::gadgets::boolean::{AllocatedBit, Boolean}; use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*; 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_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, Neg};
#[test] #[test]
fn test_lookup3_xy() { fn test_lookup3_xy() {
@ -203,7 +205,7 @@ mod test {
]); ]);
for _ in 0..100 { 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_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
@ -248,7 +250,7 @@ mod test {
]); ]);
for _ in 0..100 { 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_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
@ -300,7 +302,7 @@ mod test {
.map(|_| Fr::random(&mut rng)) .map(|_| Fr::random(&mut rng))
.collect(); .collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment); synth(window_size, &constants, &mut assignment);
for b in 0..(1 << window_size) { for b in 0..(1 << window_size) {
let mut acc = Fr::zero(); 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}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
pub struct MultiEq<E: ScalarEngine, CS: ConstraintSystem<E>> { pub struct MultiEq<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> {
cs: CS, cs: CS,
ops: usize, ops: usize,
bits_used: usize, bits_used: usize,
lhs: LinearCombination<E>, lhs: LinearCombination<Scalar>,
rhs: LinearCombination<E>, 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 { pub fn new(cs: CS) -> Self {
MultiEq { MultiEq {
cs, cs,
@ -40,17 +40,17 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
pub fn enforce_equal( pub fn enforce_equal(
&mut self, &mut self,
num_bits: usize, num_bits: usize,
lhs: &LinearCombination<E>, lhs: &LinearCombination<Scalar>,
rhs: &LinearCombination<E>, rhs: &LinearCombination<Scalar>,
) { ) {
// Check if we will exceed the capacity // 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(); 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() .unwrap()
.pow_vartime(&[self.bits_used as u64]); .pow_vartime(&[self.bits_used as u64]);
self.lhs = self.lhs.clone() + (coeff, lhs); 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) { fn drop(&mut self) {
if self.bits_used > 0 { if self.bits_used > 0 {
self.accumulate(); 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; type Root = Self;
fn one() -> Variable { 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> fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where where
F: FnOnce() -> Result<E::Fr, SynthesisError>, F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, 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> fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where where
F: FnOnce() -> Result<E::Fr, SynthesisError>, F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, AR: Into<String>,
{ {
@ -96,9 +98,9 @@ impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E
where where
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{ {
self.cs.enforce(annotation, a, b, c) self.cs.enforce(annotation, a, b, c)
} }

View File

@ -4,19 +4,18 @@ use super::boolean::Boolean;
use super::num::Num; use super::num::Num;
use super::Assignment; use super::Assignment;
use crate::{ConstraintSystem, SynthesisError}; use crate::{ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField, ScalarEngine}; use ff::PrimeField;
use std::ops::AddAssign;
/// Takes a sequence of booleans and exposes them as compact /// Takes a sequence of booleans and exposes them as compact
/// public inputs /// 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() { for (i, bits) in bits.chunks(Scalar::CAPACITY as usize).enumerate() {
let mut num = Num::<E>::zero(); let mut num = Num::<Scalar>::zero();
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
for bit in bits { for bit in bits {
num = num.add_bool_with_coeff(CS::one(), bit, coeff); num = num.add_bool_with_coeff(CS::one(), bit, coeff);
@ -28,7 +27,7 @@ where
// num * 1 = input // num * 1 = input
cs.enforce( cs.enforce(
|| format!("packing constraint {}", i), || format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()), |_| num.lc(Scalar::one()),
|lc| lc + CS::one(), |lc| lc + CS::one(),
|lc| lc + input, |lc| lc + input,
); );
@ -51,12 +50,12 @@ pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
.collect() .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![]; let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize) { for bits in bits.chunks(Scalar::CAPACITY as usize) {
let mut cur = E::Fr::zero(); let mut cur = Scalar::zero();
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
for bit in bits { for bit in bits {
if *bit { if *bit {
@ -75,7 +74,7 @@ pub fn compute_multipacking<E: ScalarEngine>(bits: &[bool]) -> Vec<E::Fr> {
#[test] #[test]
fn test_multipacking() { fn test_multipacking() {
use crate::ConstraintSystem; use crate::ConstraintSystem;
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
@ -88,7 +87,7 @@ fn test_multipacking() {
]); ]);
for num_bits in 0..1500 { 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(); let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
@ -102,7 +101,7 @@ fn test_multipacking() {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits); let expected_inputs = compute_multipacking(&bits);
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap(); 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. //! Gadgets representing numbers in the scalar field of the underlying curve.
use ff::{BitIterator, Field, PrimeField, ScalarEngine}; use ff::{BitIterator, PrimeField};
use std::ops::{AddAssign, MulAssign};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
@ -9,12 +8,12 @@ use super::Assignment;
use super::boolean::{self, AllocatedBit, Boolean}; use super::boolean::{self, AllocatedBit, Boolean};
pub struct AllocatedNum<E: ScalarEngine> { pub struct AllocatedNum<Scalar: PrimeField> {
value: Option<E::Fr>, value: Option<Scalar>,
variable: Variable, variable: Variable,
} }
impl<E: ScalarEngine> Clone for AllocatedNum<E> { impl<Scalar: PrimeField> Clone for AllocatedNum<Scalar> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
AllocatedNum { AllocatedNum {
value: self.value, 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> pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
F: FnOnce() -> Result<E::Fr, SynthesisError>, F: FnOnce() -> Result<Scalar, SynthesisError>,
{ {
let mut new_value = None; let mut new_value = None;
let var = cs.alloc( let var = cs.alloc(
@ -49,7 +48,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError> pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?; let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
@ -70,15 +69,15 @@ impl<E: ScalarEngine> AllocatedNum<E> {
/// congruency is not allowed.) /// congruency is not allowed.)
pub fn to_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> pub fn to_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
pub fn kary_and<E, CS>( pub fn kary_and<Scalar, CS>(
mut cs: CS, mut cs: CS,
v: &[AllocatedBit], v: &[AllocatedBit],
) -> Result<AllocatedBit, SynthesisError> ) -> Result<AllocatedBit, SynthesisError>
where where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert!(!v.is_empty()); assert!(!v.is_empty());
@ -104,7 +103,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
// We want to ensure that the bit representation of a is // We want to ensure that the bit representation of a is
// less than or equal to r - 1. // less than or equal to r - 1.
let mut a = self.value.map(|e| BitIterator::<u8, _>::new(e.to_repr())); 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![]; let mut result = vec![];
@ -171,7 +170,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
// However, now we have to unpack self! // However, now we have to unpack self!
let mut lc = LinearCombination::zero(); let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
for bit in result.iter().rev() { for bit in result.iter().rev() {
lc = lc + (coeff, bit.get_variable()); lc = lc + (coeff, bit.get_variable());
@ -192,12 +191,12 @@ impl<E: ScalarEngine> AllocatedNum<E> {
/// "in the field." /// "in the field."
pub fn to_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> pub fn to_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?; let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
let mut lc = LinearCombination::zero(); let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
for bit in bits.iter() { for bit in bits.iter() {
lc = lc + (coeff, bit.get_variable()); 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> pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let mut value = None; let mut value = None;
@ -246,7 +245,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError> pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let mut value = None; let mut value = None;
@ -277,7 +276,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError> pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let inv = cs.alloc( let inv = cs.alloc(
|| "ephemeral inverse", || "ephemeral inverse",
@ -315,7 +314,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
condition: &Boolean, condition: &Boolean,
) -> Result<(Self, Self), SynthesisError> ) -> Result<(Self, Self), SynthesisError>
where where
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || { let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
if *condition.get_value().get()? { if *condition.get_value().get()? {
@ -328,7 +327,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
cs.enforce( cs.enforce(
|| "first conditional reversal", || "first conditional reversal",
|lc| lc + a.variable - b.variable, |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, |lc| lc + a.variable - c.variable,
); );
@ -343,14 +342,14 @@ impl<E: ScalarEngine> AllocatedNum<E> {
cs.enforce( cs.enforce(
|| "second conditional reversal", || "second conditional reversal",
|lc| lc + b.variable - a.variable, |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, |lc| lc + b.variable - d.variable,
); );
Ok((c, d)) Ok((c, d))
} }
pub fn get_value(&self) -> Option<E::Fr> { pub fn get_value(&self) -> Option<Scalar> {
self.value self.value
} }
@ -359,37 +358,37 @@ impl<E: ScalarEngine> AllocatedNum<E> {
} }
} }
pub struct Num<E: ScalarEngine> { pub struct Num<Scalar: PrimeField> {
value: Option<E::Fr>, value: Option<Scalar>,
lc: LinearCombination<E>, lc: LinearCombination<Scalar>,
} }
impl<E: ScalarEngine> From<AllocatedNum<E>> for Num<E> { impl<Scalar: PrimeField> From<AllocatedNum<Scalar>> for Num<Scalar> {
fn from(num: AllocatedNum<E>) -> Num<E> { fn from(num: AllocatedNum<Scalar>) -> Num<Scalar> {
Num { Num {
value: num.value, 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 { pub fn zero() -> Self {
Num { Num {
value: Some(E::Fr::zero()), value: Some(Scalar::zero()),
lc: LinearCombination::zero(), lc: LinearCombination::zero(),
} }
} }
pub fn get_value(&self) -> Option<E::Fr> { pub fn get_value(&self) -> Option<Scalar> {
self.value self.value
} }
pub fn lc(&self, coeff: E::Fr) -> LinearCombination<E> { pub fn lc(&self, coeff: Scalar) -> LinearCombination<Scalar> {
LinearCombination::zero() + (coeff, &self.lc) 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()) { let newval = match (self.value, bit.get_value()) {
(Some(mut curval), Some(bval)) => { (Some(mut curval), Some(bval)) => {
if bval { if bval {
@ -412,7 +411,7 @@ impl<E: ScalarEngine> Num<E> {
mod test { mod test {
use crate::ConstraintSystem; use crate::ConstraintSystem;
use ff::{BitIterator, Field, PrimeField}; use ff::{BitIterator, Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr}; use pairing::bls12_381::Fr;
use rand_core::SeedableRng; use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use std::ops::{Neg, SubAssign}; use std::ops::{Neg, SubAssign};
@ -422,7 +421,7 @@ mod test {
#[test] #[test]
fn test_allocated_num() { fn test_allocated_num() {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::new();
AllocatedNum::alloc(&mut cs, || Ok(Fr::one())).unwrap(); AllocatedNum::alloc(&mut cs, || Ok(Fr::one())).unwrap();
@ -431,7 +430,7 @@ mod test {
#[test] #[test]
fn test_num_squaring() { 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 n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
let n2 = n.square(&mut cs).unwrap(); let n2 = n.square(&mut cs).unwrap();
@ -445,7 +444,7 @@ mod test {
#[test] #[test]
fn test_num_multiplication() { fn test_num_multiplication() {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::new();
let n = let n =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
@ -467,7 +466,7 @@ mod test {
0xbc, 0xe5, 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 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(); 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 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(); let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
@ -498,7 +497,7 @@ mod test {
#[test] #[test]
fn test_num_nonzero() { 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(); let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
n.assert_nonzero(&mut cs).unwrap(); n.assert_nonzero(&mut cs).unwrap();
@ -508,7 +507,7 @@ mod test {
assert!(cs.which_is_unsatisfied() == Some("nonzero assertion constraint")); 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(); let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::zero())).unwrap();
assert!(n.assert_nonzero(&mut cs).is_err()); assert!(n.assert_nonzero(&mut cs).is_err());
@ -519,7 +518,7 @@ mod test {
fn test_into_bits_strict() { fn test_into_bits_strict() {
let negone = Fr::one().neg(); 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(); let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap();
n.to_bits_le_strict(&mut cs).unwrap(); n.to_bits_le_strict(&mut cs).unwrap();
@ -545,7 +544,7 @@ mod test {
for i in 0..200 { for i in 0..200 {
let r = Fr::random(&mut rng); 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(); 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::multieq::MultiEq;
use super::uint32::UInt32; use super::uint32::UInt32;
use crate::{ConstraintSystem, SynthesisError}; use crate::{ConstraintSystem, SynthesisError};
use ff::ScalarEngine; use ff::PrimeField;
#[allow(clippy::unreadable_literal)] #[allow(clippy::unreadable_literal)]
const ROUND_CONSTANTS: [u32; 64] = [ const ROUND_CONSTANTS: [u32; 64] = [
@ -26,13 +26,13 @@ const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 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, mut cs: CS,
input: &[Boolean], input: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert_eq!(input.len(), 512); 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert!(input.len() % 8 == 0); assert!(input.len() % 8 == 0);
@ -77,14 +77,14 @@ fn get_sha256_iv() -> Vec<UInt32> {
IV.iter().map(|&v| UInt32::constant(v)).collect() IV.iter().map(|&v| UInt32::constant(v)).collect()
} }
fn sha256_compression_function<E, CS>( fn sha256_compression_function<Scalar, CS>(
cs: CS, cs: CS,
input: &[Boolean], input: &[Boolean],
current_hash_value: &[UInt32], current_hash_value: &[UInt32],
) -> Result<Vec<UInt32>, SynthesisError> ) -> Result<Vec<UInt32>, SynthesisError>
where where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert_eq!(input.len(), 512); assert_eq!(input.len(), 512);
assert_eq!(current_hash_value.len(), 8); assert_eq!(current_hash_value.len(), 8);
@ -128,11 +128,11 @@ where
} }
impl Maybe { 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>, M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{ {
Ok(match self { Ok(match self {
Maybe::Concrete(ref v) => return Ok(v.clone()), Maybe::Concrete(ref v) => return Ok(v.clone()),
@ -274,7 +274,7 @@ mod test {
use crate::gadgets::boolean::AllocatedBit; use crate::gadgets::boolean::AllocatedBit;
use crate::gadgets::test::TestConstraintSystem; use crate::gadgets::test::TestConstraintSystem;
use hex_literal::hex; use hex_literal::hex;
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
@ -282,7 +282,7 @@ mod test {
fn test_blank_hash() { fn test_blank_hash() {
let iv = get_sha256_iv(); 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(); let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
input_bits[0] = Boolean::Constant(true); input_bits[0] = Boolean::Constant(true);
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap(); let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
@ -312,7 +312,7 @@ mod test {
let iv = get_sha256_iv(); let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let input_bits: Vec<_> = (0..512) let input_bits: Vec<_> = (0..512)
.map(|i| { .map(|i| {
Boolean::from( Boolean::from(
@ -346,7 +346,7 @@ mod test {
h.input(&data); h.input(&data);
let hash_result = h.result(); let hash_result = h.result();
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let mut input_bits = vec![]; let mut input_bits = vec![];
for (byte_i, input_byte) in data.into_iter().enumerate() { for (byte_i, input_byte) in data.into_iter().enumerate() {

View File

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

View File

@ -3,7 +3,7 @@
//! //!
//! [`sha256`]: crate::gadgets::sha256 //! [`sha256`]: crate::gadgets::sha256
use ff::{Field, PrimeField, ScalarEngine}; use ff::PrimeField;
use crate::{ConstraintSystem, LinearCombination, SynthesisError}; use crate::{ConstraintSystem, LinearCombination, SynthesisError};
@ -43,10 +43,10 @@ impl UInt32 {
} }
/// Allocate a `UInt32` in the constraint system /// 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let values = match value { let values = match value {
Some(mut val) => { Some(mut val) => {
@ -189,7 +189,7 @@ impl UInt32 {
} }
} }
fn triop<E, CS, F, U>( fn triop<Scalar, CS, F, U>(
mut cs: CS, mut cs: CS,
a: &Self, a: &Self,
b: &Self, b: &Self,
@ -198,8 +198,8 @@ impl UInt32 {
circuit_fn: U, circuit_fn: U,
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
F: Fn(u32, u32, u32) -> u32, F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>, 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) /// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
/// during SHA256. /// 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
Self::triop( Self::triop(
cs, cs,
@ -242,10 +247,15 @@ impl UInt32 {
/// Compute the `ch` value `(a and b) xor ((not a) and c)` /// Compute the `ch` value `(a and b) xor ((not a) and c)`
/// during SHA256. /// 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
Self::triop( Self::triop(
cs, cs,
@ -258,10 +268,10 @@ impl UInt32 {
} }
/// XOR this `UInt32` with another `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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let new_value = match (self.value, other.value) { let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => Some(a ^ b), (Some(a), Some(b)) => Some(a ^ b),
@ -283,15 +293,15 @@ impl UInt32 {
} }
/// Perform modular addition of several `UInt32` objects. /// 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 where
E: ScalarEngine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>, M: ConstraintSystem<Scalar, Root = MultiEq<Scalar, CS>>,
{ {
// Make some arbitrary bounds for ourselves to avoid overflows // Make some arbitrary bounds for ourselves to avoid overflows
// in the scalar field // 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() >= 2); // Weird trivial cases that should never happen
assert!(operands.len() <= 10); assert!(operands.len() <= 10);
@ -324,7 +334,7 @@ impl UInt32 {
// Iterate over each bit of the operand and add the operand to // Iterate over each bit of the operand and add the operand to
// the linear combination // the linear combination
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
for bit in &op.bits { for bit in &op.bits {
lc = lc + &bit.lc(CS::one(), coeff); lc = lc + &bit.lc(CS::one(), coeff);
@ -352,7 +362,7 @@ impl UInt32 {
let mut result_lc = LinearCombination::zero(); let mut result_lc = LinearCombination::zero();
// Allocate each bit of the result // Allocate each bit of the result
let mut coeff = E::Fr::one(); let mut coeff = Scalar::one();
let mut i = 0; let mut i = 0;
while max_value != 0 { while max_value != 0 {
// Allocate the bit // Allocate the bit
@ -392,7 +402,7 @@ mod test {
use crate::gadgets::test::*; use crate::gadgets::test::*;
use crate::ConstraintSystem; use crate::ConstraintSystem;
use ff::Field; use ff::Field;
use pairing::bls12_381::Bls12; use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng}; use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
@ -474,7 +484,7 @@ mod test {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32(); let a = rng.next_u32();
let b = rng.next_u32(); let b = rng.next_u32();
@ -519,7 +529,7 @@ mod test {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32(); let a = rng.next_u32();
let b = rng.next_u32(); let b = rng.next_u32();
@ -562,7 +572,7 @@ mod test {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32(); let a = rng.next_u32();
let b = rng.next_u32(); let b = rng.next_u32();
@ -675,7 +685,7 @@ mod test {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32(); let a = rng.next_u32();
let b = rng.next_u32(); let b = rng.next_u32();
@ -719,7 +729,7 @@ mod test {
]); ]);
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a = rng.next_u32(); let a = rng.next_u32();
let b = 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::ops::{AddAssign, MulAssign};
use std::sync::Arc; use std::sync::Arc;
use ff::Field; use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, Group, Wnaf}; use group::{CurveAffine, CurveProjective, Group, Wnaf};
use pairing::Engine; use pairing::Engine;
@ -22,7 +22,7 @@ pub fn generate_random_parameters<E, C, R>(
) -> Result<Parameters<E>, SynthesisError> ) -> Result<Parameters<E>, SynthesisError>
where where
E: Engine, E: Engine,
C: Circuit<E>, C: Circuit<E::Fr>,
R: RngCore, R: RngCore,
{ {
let g1 = E::G1::random(rng); let g1 = E::G1::random(rng);
@ -38,24 +38,24 @@ where
/// This is our assembly structure that we'll use to synthesize the /// This is our assembly structure that we'll use to synthesize the
/// circuit into a QAP. /// circuit into a QAP.
struct KeypairAssembly<E: Engine> { struct KeypairAssembly<Scalar: PrimeField> {
num_inputs: usize, num_inputs: usize,
num_aux: usize, num_aux: usize,
num_constraints: usize, num_constraints: usize,
at_inputs: Vec<Vec<(E::Fr, usize)>>, at_inputs: Vec<Vec<(Scalar, usize)>>,
bt_inputs: Vec<Vec<(E::Fr, usize)>>, bt_inputs: Vec<Vec<(Scalar, usize)>>,
ct_inputs: Vec<Vec<(E::Fr, usize)>>, ct_inputs: Vec<Vec<(Scalar, usize)>>,
at_aux: Vec<Vec<(E::Fr, usize)>>, at_aux: Vec<Vec<(Scalar, usize)>>,
bt_aux: Vec<Vec<(E::Fr, usize)>>, bt_aux: Vec<Vec<(Scalar, usize)>>,
ct_aux: Vec<Vec<(E::Fr, 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; type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError> fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where where
F: FnOnce() -> Result<E::Fr, SynthesisError>, F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, 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> fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where where
F: FnOnce() -> Result<E::Fr, SynthesisError>, F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, AR: Into<String>,
{ {
@ -95,14 +95,14 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
where where
A: FnOnce() -> AR, A: FnOnce() -> AR,
AR: Into<String>, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>, LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{ {
fn eval<E: Engine>( fn eval<Scalar: PrimeField>(
l: LinearCombination<E>, l: LinearCombination<Scalar>,
inputs: &mut [Vec<(E::Fr, usize)>], inputs: &mut [Vec<(Scalar, usize)>],
aux: &mut [Vec<(E::Fr, usize)>], aux: &mut [Vec<(Scalar, usize)>],
this_constraint: usize, this_constraint: usize,
) { ) {
for (index, coeff) in l.0 { for (index, coeff) in l.0 {
@ -165,7 +165,7 @@ pub fn generate_parameters<E, C>(
) -> Result<Parameters<E>, SynthesisError> ) -> Result<Parameters<E>, SynthesisError>
where where
E: Engine, E: Engine,
C: Circuit<E>, C: Circuit<E::Fr>,
{ {
let mut assembly = KeypairAssembly { let mut assembly = KeypairAssembly {
num_inputs: 0, num_inputs: 0,
@ -192,7 +192,7 @@ where
} }
// Create bases for blind evaluation of polynomials at tau // 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)?; let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?;
// Compute G1 window table // Compute G1 window table
@ -302,7 +302,7 @@ where
g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>, g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
// Lagrange coefficients for tau // Lagrange coefficients for tau
powers_of_tau: &[Scalar<E>], powers_of_tau: &[Scalar<E::Fr>],
// QAP polynomials // QAP polynomials
at: &[Vec<(E::Fr, usize)>], at: &[Vec<(E::Fr, usize)>],
@ -362,11 +362,11 @@ where
.zip(bt.iter()) .zip(bt.iter())
.zip(ct.iter()) .zip(ct.iter())
{ {
fn eval_at_tau<E: Engine>( fn eval_at_tau<S: PrimeField>(
powers_of_tau: &[Scalar<E>], powers_of_tau: &[Scalar<S>],
p: &[(E::Fr, usize)], p: &[(S, usize)],
) -> E::Fr { ) -> S {
let mut acc = E::Fr::zero(); let mut acc = S::zero();
for &(ref coeff, index) in p { for &(ref coeff, index) in p {
let mut n = powers_of_tau[index].0; let mut n = powers_of_tau[index].0;
@ -416,7 +416,7 @@ where
} }
// Evaluate for inputs. // Evaluate for inputs.
eval( eval::<E>(
&g1_wnaf, &g1_wnaf,
&g2_wnaf, &g2_wnaf,
&powers_of_tau, &powers_of_tau,
@ -434,7 +434,7 @@ where
); );
// Evaluate for auxiliary variables. // Evaluate for auxiliary variables.
eval( eval::<E>(
&g1_wnaf, &g1_wnaf,
&g2_wnaf, &g2_wnaf,
&powers_of_tau, &powers_of_tau,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -213,14 +213,6 @@ pub trait PrimeField: Field + From<u64> {
fn root_of_unity() -> Self; 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)] #[derive(Debug)]
pub struct BitIterator<T, E: AsRef<[T]>> { pub struct BitIterator<T, E: AsRef<[T]>> {
t: E, 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. /// 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> {} 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> {} 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 super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine}; use ff::{BitIterator, Field};
use group::CurveAffine; use group::CurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption; use subtle::CtOption;
@ -35,11 +35,8 @@ const BLS_X_IS_NEGATIVE: bool = true;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Bls12; pub struct Bls12;
impl ScalarEngine for Bls12 {
type Fr = Fr;
}
impl Engine for Bls12 { impl Engine for Bls12 {
type Fr = Fr;
type G1 = G1; type G1 = G1;
type G1Affine = G1Affine; type G1Affine = G1Affine;
type G2 = G2; type G2 = G2;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
use bellman::gadgets::boolean::Boolean; use bellman::gadgets::boolean::Boolean;
use bellman::{ConstraintSystem, SynthesisError}; use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine; use ff::PrimeField;
use super::commitment::note_comm; use super::commitment::note_comm;
use super::prfs::*; use super::prfs::*;
@ -11,7 +11,7 @@ pub struct OutputNote {
} }
impl OutputNote { impl OutputNote {
pub fn compute<E, CS>( pub fn compute<Scalar, CS>(
mut cs: CS, mut cs: CS,
a_pk: Option<PayingKey>, a_pk: Option<PayingKey>,
value: &NoteValue, value: &NoteValue,
@ -21,8 +21,8 @@ impl OutputNote {
nonce: bool, nonce: bool,
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
let rho = prf_rho(cs.namespace(|| "rho"), phi, h_sig, nonce)?; 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::boolean::Boolean;
use bellman::gadgets::sha256::sha256_block_no_padding; use bellman::gadgets::sha256::sha256_block_no_padding;
use bellman::{ConstraintSystem, SynthesisError}; use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine; use ff::PrimeField;
fn prf<E, CS>( fn prf<Scalar, CS>(
cs: CS, cs: CS,
a: bool, a: bool,
b: bool, b: bool,
@ -13,8 +13,8 @@ fn prf<E, CS>(
y: &[Boolean], y: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
assert_eq!(x.len(), 252); assert_eq!(x.len(), 252);
assert_eq!(y.len(), 256); assert_eq!(y.len(), 256);
@ -32,10 +32,10 @@ where
sha256_block_no_padding(cs, &image) 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 where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
prf( prf(
cs, cs,
@ -50,40 +50,40 @@ where
) )
} }
pub fn prf_nf<E, CS>( pub fn prf_nf<Scalar, CS>(
cs: CS, cs: CS,
a_sk: &[Boolean], a_sk: &[Boolean],
rho: &[Boolean], rho: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
prf(cs, true, true, true, false, a_sk, rho) prf(cs, true, true, true, false, a_sk, rho)
} }
pub fn prf_pk<E, CS>( pub fn prf_pk<Scalar, CS>(
cs: CS, cs: CS,
a_sk: &[Boolean], a_sk: &[Boolean],
h_sig: &[Boolean], h_sig: &[Boolean],
nonce: bool, nonce: bool,
) -> Result<Vec<Boolean>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
prf(cs, false, nonce, false, false, a_sk, h_sig) prf(cs, false, nonce, false, false, a_sk, h_sig)
} }
pub fn prf_rho<E, CS>( pub fn prf_rho<Scalar, CS>(
cs: CS, cs: CS,
phi: &[Boolean], phi: &[Boolean],
h_sig: &[Boolean], h_sig: &[Boolean],
nonce: bool, nonce: bool,
) -> Result<Vec<Boolean>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where where
E: Engine, Scalar: PrimeField,
CS: ConstraintSystem<E>, CS: ConstraintSystem<Scalar>,
{ {
prf(cs, false, nonce, true, false, phi, h_sig) prf(cs, false, nonce, true, false, phi, h_sig)
} }

View File

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

View File

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

View File

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