mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-14 10:45:47 +00:00
Hash the constraint systems to check integrity.
This commit is contained in:
parent
23d17b9042
commit
4441a0da41
@ -18,6 +18,8 @@ blake2 = "0.7"
|
||||
digest = "0.7"
|
||||
bellman = "0.0.8"
|
||||
|
||||
byteorder = "1"
|
||||
|
||||
[features]
|
||||
default = ["u128-support"]
|
||||
u128-support = ["pairing/u128-support"]
|
||||
|
@ -397,94 +397,6 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_input_circuit_with_bls12_381() {
|
||||
use pairing::bls12_381::*;
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use ::circuit::test::*;
|
||||
use jubjub::{JubjubBls12, fs};
|
||||
|
||||
let params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let tree_depth = 29;
|
||||
|
||||
let value: u64 = 1;
|
||||
let value_randomness: fs::Fs = rng.gen();
|
||||
let ak: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
||||
let g_d: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let rsk: fs::Fs = rng.gen();
|
||||
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
|
||||
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let instance = Spend {
|
||||
params: params,
|
||||
value: Some(value),
|
||||
value_randomness: Some(value_randomness),
|
||||
rsk: Some(rsk),
|
||||
ak: Some(ak),
|
||||
g_d: Some(g_d),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
auth_path: auth_path
|
||||
};
|
||||
|
||||
instance.synthesize(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
assert_eq!(cs.num_constraints(), 97379);
|
||||
}
|
||||
|
||||
// use bellman::groth16::*;
|
||||
|
||||
// let groth_params = generate_random_parameters::<Bls12, _, _>(Spend {
|
||||
// params: params,
|
||||
// value: None,
|
||||
// value_randomness: None,
|
||||
// rsk: None,
|
||||
// ak: None,
|
||||
// g_d: None,
|
||||
// commitment_randomness: None,
|
||||
// auth_path: vec![None; 29]
|
||||
// }, rng).unwrap();
|
||||
|
||||
// let pvk = prepare_verifying_key(&groth_params.vk);
|
||||
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// // Let's benchmark stuff!
|
||||
// const SAMPLES: u32 = 50;
|
||||
// let mut total_proving = Duration::new(0, 0);
|
||||
|
||||
// for _ in 0..SAMPLES {
|
||||
// let start = Instant::now();
|
||||
// {
|
||||
// let c = Spend {
|
||||
// params: params,
|
||||
// value: Some(1),
|
||||
// value_randomness: Some(value_randomness.clone()),
|
||||
// rsk: Some(rsk.clone()),
|
||||
// ak: Some(ak.clone()),
|
||||
// g_d: Some(g_d.clone()),
|
||||
// commitment_randomness: Some(commitment_randomness.clone()),
|
||||
// auth_path: auth_path.clone()
|
||||
// };
|
||||
|
||||
// create_random_proof(c, &groth_params, rng).unwrap();
|
||||
// }
|
||||
// total_proving += start.elapsed();
|
||||
// }
|
||||
|
||||
// let proving_avg = total_proving / SAMPLES;
|
||||
// let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
// + (proving_avg.as_secs() as f64);
|
||||
|
||||
// panic!("Average proving time: {:?} seconds", proving_avg);
|
||||
}
|
||||
|
||||
/// This is an output circuit instance.
|
||||
pub struct Output<'a, E: JubjubEngine> {
|
||||
pub params: &'a E::Params,
|
||||
@ -747,7 +659,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_circuit_with_bls12_381() {
|
||||
fn test_input_circuit_with_bls12_381() {
|
||||
use pairing::bls12_381::*;
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use ::circuit::test::*;
|
||||
@ -756,6 +668,48 @@ fn test_output_circuit_with_bls12_381() {
|
||||
let params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let tree_depth = 29;
|
||||
|
||||
let value: u64 = 1;
|
||||
let value_randomness: fs::Fs = rng.gen();
|
||||
let ak: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
||||
let g_d: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
||||
let commitment_randomness: fs::Fs = rng.gen();
|
||||
let rsk: fs::Fs = rng.gen();
|
||||
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
|
||||
|
||||
{
|
||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||
|
||||
let instance = Spend {
|
||||
params: params,
|
||||
value: Some(value),
|
||||
value_randomness: Some(value_randomness),
|
||||
rsk: Some(rsk),
|
||||
ak: Some(ak),
|
||||
g_d: Some(g_d),
|
||||
commitment_randomness: Some(commitment_randomness),
|
||||
auth_path: auth_path
|
||||
};
|
||||
|
||||
instance.synthesize(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 97379);
|
||||
assert_eq!(cs.hash(), "4d8e71c91a621e41599ea488ee89f035c892a260a595d3c85a20a82daa2d1654");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_circuit_with_bls12_381() {
|
||||
use pairing::bls12_381::*;
|
||||
use rand::{SeedableRng, Rng, XorShiftRng};
|
||||
use ::circuit::test::*;
|
||||
use jubjub::{JubjubBls12, fs};
|
||||
|
||||
let params = &JubjubBls12::new();
|
||||
let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
let value: u64 = 1;
|
||||
let value_randomness: fs::Fs = rng.gen();
|
||||
let g_d: edwards::Point<Bls12, Unknown> = edwards::Point::rand(rng, params);
|
||||
@ -779,51 +733,7 @@ fn test_output_circuit_with_bls12_381() {
|
||||
instance.synthesize(&mut cs).unwrap();
|
||||
|
||||
assert!(cs.is_satisfied());
|
||||
|
||||
assert_eq!(cs.num_constraints(), 7827);
|
||||
assert_eq!(cs.hash(), "225a2df7e21b9af8b436ffb9dadd645e4df843a5151c7481b0553422d5eaa793");
|
||||
}
|
||||
|
||||
// use bellman::groth16::*;
|
||||
|
||||
// let groth_params = generate_random_parameters::<Bls12, _, _>(Output {
|
||||
// params: params,
|
||||
// value: None,
|
||||
// value_randomness: None,
|
||||
// g_d: None,
|
||||
// p_d: None,
|
||||
// commitment_randomness: None,
|
||||
// esk: None
|
||||
// }, rng).unwrap();
|
||||
|
||||
// let pvk = prepare_verifying_key(&groth_params.vk);
|
||||
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// // Let's benchmark stuff!
|
||||
// const SAMPLES: u32 = 50;
|
||||
// let mut total_proving = Duration::new(0, 0);
|
||||
|
||||
// for _ in 0..SAMPLES {
|
||||
// let start = Instant::now();
|
||||
// {
|
||||
// let c = Output {
|
||||
// params: params,
|
||||
// value: Some(1),
|
||||
// value_randomness: Some(value_randomness),
|
||||
// g_d: Some(g_d.clone()),
|
||||
// p_d: Some(p_d.clone()),
|
||||
// commitment_randomness: Some(commitment_randomness),
|
||||
// esk: Some(esk.clone())
|
||||
// };
|
||||
|
||||
// create_random_proof(c, &groth_params, rng).unwrap();
|
||||
// }
|
||||
// total_proving += start.elapsed();
|
||||
// }
|
||||
|
||||
// let proving_avg = total_proving / SAMPLES;
|
||||
// let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64
|
||||
// + (proving_avg.as_secs() as f64);
|
||||
|
||||
// panic!("Average proving time: {:?} seconds", proving_avg);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use pairing::{
|
||||
Engine,
|
||||
Field
|
||||
Field,
|
||||
PrimeField,
|
||||
PrimeFieldRepr
|
||||
};
|
||||
|
||||
use bellman::{
|
||||
@ -12,6 +14,13 @@ use bellman::{
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
|
||||
use blake2::{Blake2s};
|
||||
use digest::{FixedOutput, Input};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NamedObject {
|
||||
@ -34,6 +43,90 @@ pub struct TestConstraintSystem<E: Engine> {
|
||||
aux: Vec<(E::Fr, String)>
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct OrderedVariable(Variable);
|
||||
|
||||
impl Eq for OrderedVariable {}
|
||||
impl PartialEq for OrderedVariable {
|
||||
fn eq(&self, other: &OrderedVariable) -> bool {
|
||||
match (self.0.get_unchecked(), other.0.get_unchecked()) {
|
||||
(Index::Input(ref a), Index::Input(ref b)) => a == b,
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a == b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PartialOrd for OrderedVariable {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl Ord for OrderedVariable {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.get_unchecked(), other.0.get_unchecked()) {
|
||||
(Index::Input(ref a), Index::Input(ref b)) => a.cmp(b),
|
||||
(Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b),
|
||||
(Index::Input(_), Index::Aux(_)) => Ordering::Less,
|
||||
(Index::Aux(_), Index::Input(_)) => Ordering::Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn proc_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
) -> BTreeMap<OrderedVariable, E::Fr>
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
for &(var, coeff) in terms {
|
||||
map.entry(OrderedVariable(var))
|
||||
.or_insert(E::Fr::zero())
|
||||
.add_assign(&coeff);
|
||||
}
|
||||
|
||||
// Remove terms that have a zero coefficient to normalize
|
||||
let mut to_remove = vec![];
|
||||
for (var, coeff) in map.iter() {
|
||||
if coeff.is_zero() {
|
||||
to_remove.push(var.clone())
|
||||
}
|
||||
}
|
||||
|
||||
for var in to_remove {
|
||||
map.remove(&var);
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn hash_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
h: &mut Blake2s
|
||||
)
|
||||
{
|
||||
let map = proc_lc::<E>(terms);
|
||||
|
||||
let mut buf = [0u8; 9 + 32];
|
||||
BigEndian::write_u64(&mut buf[0..8], map.len() as u64);
|
||||
h.process(&buf[0..8]);
|
||||
|
||||
for (var, coeff) in map {
|
||||
match var.0.get_unchecked() {
|
||||
Index::Input(i) => {
|
||||
buf[0] = b'I';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
},
|
||||
Index::Aux(i) => {
|
||||
buf[0] = b'A';
|
||||
BigEndian::write_u64(&mut buf[1..9], i as u64);
|
||||
}
|
||||
}
|
||||
|
||||
coeff.into_repr().write_be(&mut buf[9..]).unwrap();
|
||||
|
||||
h.process(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_lc<E: Engine>(
|
||||
terms: &[(Variable, E::Fr)],
|
||||
inputs: &[(E::Fr, String)],
|
||||
@ -69,6 +162,98 @@ impl<E: Engine> TestConstraintSystem<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pretty_print(&self) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
let negone = {
|
||||
let mut tmp = E::Fr::one();
|
||||
tmp.negate();
|
||||
tmp
|
||||
};
|
||||
|
||||
let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| {
|
||||
E::Fr::from_str("2").unwrap().pow(&[i as u64])
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let pp = |s: &mut String, lc: &LinearCombination<E>| {
|
||||
write!(s, "(").unwrap();
|
||||
let mut is_first = true;
|
||||
for (var, coeff) in proc_lc::<E>(lc.as_ref()) {
|
||||
if coeff == negone {
|
||||
write!(s, " - ").unwrap();
|
||||
} else if !is_first {
|
||||
write!(s, " + ").unwrap();
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
if coeff != E::Fr::one() && coeff != negone {
|
||||
for (i, x) in powers_of_two.iter().enumerate() {
|
||||
if x == &coeff {
|
||||
write!(s, "2^{} . ", i).unwrap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
write!(s, "{} . ", coeff).unwrap();
|
||||
}
|
||||
|
||||
match var.0.get_unchecked() {
|
||||
Index::Input(i) => {
|
||||
write!(s, "`{}`", &self.inputs[i].1).unwrap();
|
||||
},
|
||||
Index::Aux(i) => {
|
||||
write!(s, "`{}`", &self.aux[i].1).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_first {
|
||||
// Nothing was visited, print 0.
|
||||
write!(s, "0").unwrap();
|
||||
}
|
||||
write!(s, ")").unwrap();
|
||||
};
|
||||
|
||||
for &(ref a, ref b, ref c, ref name) in &self.constraints {
|
||||
write!(&mut s, "\n").unwrap();
|
||||
|
||||
write!(&mut s, "{}: ", name).unwrap();
|
||||
pp(&mut s, a);
|
||||
write!(&mut s, " * ").unwrap();
|
||||
pp(&mut s, b);
|
||||
write!(&mut s, " = ").unwrap();
|
||||
pp(&mut s, c);
|
||||
}
|
||||
|
||||
write!(&mut s, "\n").unwrap();
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> String {
|
||||
let mut h = Blake2s::new_keyed(&[], 32);
|
||||
{
|
||||
let mut buf = [0u8; 24];
|
||||
|
||||
BigEndian::write_u64(&mut buf[0..8], self.inputs.len() as u64);
|
||||
BigEndian::write_u64(&mut buf[8..16], self.aux.len() as u64);
|
||||
BigEndian::write_u64(&mut buf[16..24], self.constraints.len() as u64);
|
||||
h.process(&buf);
|
||||
}
|
||||
|
||||
for constraint in &self.constraints {
|
||||
hash_lc::<E>(constraint.0.as_ref(), &mut h);
|
||||
hash_lc::<E>(constraint.1.as_ref(), &mut h);
|
||||
hash_lc::<E>(constraint.2.as_ref(), &mut h);
|
||||
}
|
||||
|
||||
let mut s = String::new();
|
||||
for b in h.fixed_result().as_ref() {
|
||||
s += &format!("{:02x}", b);
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
pub fn which_is_unsatisfied(&self) -> Option<&str> {
|
||||
for &(ref a, ref b, ref c, ref path) in &self.constraints {
|
||||
let mut a = eval_lc::<E>(a.as_ref(), &self.inputs, &self.aux);
|
||||
|
@ -4,6 +4,8 @@ extern crate blake2;
|
||||
extern crate digest;
|
||||
extern crate rand;
|
||||
|
||||
extern crate byteorder;
|
||||
|
||||
pub mod jubjub;
|
||||
pub mod circuit;
|
||||
pub mod group_hash;
|
||||
|
Loading…
x
Reference in New Issue
Block a user