update tools for more clear messages about hashes of files
This commit is contained in:
parent
2edd90248c
commit
8260b7dfa9
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1,3 +1,5 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
|
@ -302,6 +302,7 @@ impl<E:Engine, P: PowersOfTauParameters> BachedAccumulator<E, P> {
|
|||||||
println!("Invalid ratio power_pairs(&after.beta_tau_powers_g1), (tau_powers_g2_0, tau_powers_g2_1)");
|
println!("Invalid ratio power_pairs(&after.beta_tau_powers_g1), (tau_powers_g2_0, tau_powers_g2_1)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
println!("Done processing {} powers of tau", end);
|
||||||
} else {
|
} else {
|
||||||
panic!("Chunk does not have a min and max");
|
panic!("Chunk does not have a min and max");
|
||||||
}
|
}
|
||||||
@ -321,6 +322,7 @@ impl<E:Engine, P: PowersOfTauParameters> BachedAccumulator<E, P> {
|
|||||||
println!("Invalid ratio power_pairs(&after.tau_powers_g1), (tau_powers_g2_0, tau_powers_g2_1) in extra TauG1 contribution");
|
println!("Invalid ratio power_pairs(&after.tau_powers_g1), (tau_powers_g2_0, tau_powers_g2_1) in extra TauG1 contribution");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
println!("Done processing {} powers of tau", end);
|
||||||
} else {
|
} else {
|
||||||
panic!("Chunk does not have a min and max");
|
panic!("Chunk does not have a min and max");
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use std::fs::OpenOptions;
|
|||||||
use bellman::pairing::bn256::Bn256;
|
use bellman::pairing::bn256::Bn256;
|
||||||
use memmap::*;
|
use memmap::*;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use powersoftau::parameters::PowersOfTauParameters;
|
use powersoftau::parameters::PowersOfTauParameters;
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ fn main() {
|
|||||||
let current_accumulator_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&readable_map);
|
let current_accumulator_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&readable_map);
|
||||||
|
|
||||||
{
|
{
|
||||||
println!("Contributing on top of the hash:");
|
println!("`challenge` file contains decompressed points and has a hash:");
|
||||||
for line in current_accumulator_hash.as_slice().chunks(16) {
|
for line in current_accumulator_hash.as_slice().chunks(16) {
|
||||||
print!("\t");
|
print!("\t");
|
||||||
for section in line.chunks(4) {
|
for section in line.chunks(4) {
|
||||||
@ -131,6 +131,24 @@ fn main() {
|
|||||||
writable_map.flush().expect("unable to write hash to `./response`");
|
writable_map.flush().expect("unable to write hash to `./response`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut challenge_hash = [0; 64];
|
||||||
|
let memory_slice = readable_map.get(0..64).expect("must read point data from file");
|
||||||
|
memory_slice.clone().read_exact(&mut challenge_hash).expect("couldn't read hash of challenge file from response file");
|
||||||
|
|
||||||
|
println!("`challenge` file claims (!!! Must not be blindly trusted) that it was based on the original contribution with a hash:");
|
||||||
|
for line in challenge_hash.chunks(16) {
|
||||||
|
print!("\t");
|
||||||
|
for section in line.chunks(4) {
|
||||||
|
for b in section {
|
||||||
|
print!("{:02x}", b);
|
||||||
|
}
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Construct our keypair using the RNG we created above
|
// Construct our keypair using the RNG we created above
|
||||||
let (pubkey, privkey) = keypair(&mut rng, current_accumulator_hash.as_ref());
|
let (pubkey, privkey) = keypair(&mut rng, current_accumulator_hash.as_ref());
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ fn main() {
|
|||||||
|
|
||||||
let current_accumulator_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&challenge_readable_map);
|
let current_accumulator_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&challenge_readable_map);
|
||||||
|
|
||||||
println!("Previous challenge hash");
|
println!("Hash of the `challenge` file for verification:");
|
||||||
for line in current_accumulator_hash.as_slice().chunks(16) {
|
for line in current_accumulator_hash.as_slice().chunks(16) {
|
||||||
print!("\t");
|
print!("\t");
|
||||||
for section in line.chunks(4) {
|
for section in line.chunks(4) {
|
||||||
@ -94,7 +94,7 @@ fn main() {
|
|||||||
let memory_slice = response_readable_map.get(0..64).expect("must read point data from file");
|
let memory_slice = response_readable_map.get(0..64).expect("must read point data from file");
|
||||||
memory_slice.clone().read_exact(&mut response_challenge_hash).expect("couldn't read hash of challenge file from response file");
|
memory_slice.clone().read_exact(&mut response_challenge_hash).expect("couldn't read hash of challenge file from response file");
|
||||||
|
|
||||||
println!("Response was based on the hash");
|
println!("`response` was based on the hash:");
|
||||||
for line in response_challenge_hash.chunks(16) {
|
for line in response_challenge_hash.chunks(16) {
|
||||||
print!("\t");
|
print!("\t");
|
||||||
for section in line.chunks(4) {
|
for section in line.chunks(4) {
|
||||||
@ -118,6 +118,8 @@ fn main() {
|
|||||||
|
|
||||||
// check that it follows the protocol
|
// check that it follows the protocol
|
||||||
|
|
||||||
|
println!("Verifying a contribution to contain proper powers and correspond to the public key...");
|
||||||
|
|
||||||
let valid = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::verify_transformation(
|
let valid = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::verify_transformation(
|
||||||
&challenge_readable_map,
|
&challenge_readable_map,
|
||||||
&response_readable_map,
|
&response_readable_map,
|
||||||
@ -136,10 +138,9 @@ fn main() {
|
|||||||
println!("Verification succeeded!");
|
println!("Verification succeeded!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let response_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&response_readable_map);
|
let response_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&response_readable_map);
|
||||||
|
|
||||||
println!("Here's the BLAKE2b hash of the participant's response file:");
|
println!("Here's the BLAKE2b hash of the participant's original compressed `response` file:");
|
||||||
|
|
||||||
for line in response_hash.as_slice().chunks(16) {
|
for line in response_hash.as_slice().chunks(16) {
|
||||||
print!("\t");
|
print!("\t");
|
||||||
@ -184,6 +185,23 @@ fn main() {
|
|||||||
|
|
||||||
writable_map.flush().expect("must flush the memory map");
|
writable_map.flush().expect("must flush the memory map");
|
||||||
|
|
||||||
|
let new_challenge_readable_map = writable_map.make_read_only().expect("must make a map readonly");
|
||||||
|
|
||||||
|
let recompressed_hash = BachedAccumulator::<Bn256, Bn256CeremonyParameters>::calculate_hash(&new_challenge_readable_map);
|
||||||
|
|
||||||
|
println!("Here's the BLAKE2b hash of the decompressed participant's response as `new_challenge` file:");
|
||||||
|
|
||||||
|
for line in recompressed_hash.as_slice().chunks(16) {
|
||||||
|
print!("\t");
|
||||||
|
for section in line.chunks(4) {
|
||||||
|
for b in section {
|
||||||
|
print!("{:02x}", b);
|
||||||
|
}
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
println!("Done! `./new_challenge` contains the new challenge file. The other files");
|
println!("Done! `./new_challenge` contains the new challenge file. The other files");
|
||||||
println!("were left alone.");
|
println!("were left alone.");
|
||||||
}
|
}
|
||||||
|
209
src/utils.rs
209
src/utils.rs
@ -7,7 +7,7 @@ extern crate typenum;
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate bellman;
|
extern crate bellman;
|
||||||
|
|
||||||
use bellman::pairing::ff::{Field, PrimeField};
|
use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
use byteorder::{ReadBytesExt, BigEndian};
|
use byteorder::{ReadBytesExt, BigEndian};
|
||||||
use rand::{SeedableRng, Rng, Rand};
|
use rand::{SeedableRng, Rng, Rand};
|
||||||
use rand::chacha::ChaChaRng;
|
use rand::chacha::ChaChaRng;
|
||||||
@ -65,50 +65,65 @@ fn test_hash_to_g2() {
|
|||||||
/// e(g, (as)*r1 + (bs)*r2 + (cs)*r3) = e(g^s, a*r1 + b*r2 + c*r3)
|
/// e(g, (as)*r1 + (bs)*r2 + (cs)*r3) = e(g^s, a*r1 + b*r2 + c*r3)
|
||||||
///
|
///
|
||||||
/// ... with high probability.
|
/// ... with high probability.
|
||||||
|
// fn merge_pairs<E: Engine, G: CurveAffine<Engine = E, Scalar = E::Fr>>(v1: &[G], v2: &[G]) -> (G, G)
|
||||||
|
// {
|
||||||
|
// use std::sync::{Arc, Mutex};
|
||||||
|
// use self::rand::{thread_rng};
|
||||||
|
|
||||||
|
// assert_eq!(v1.len(), v2.len());
|
||||||
|
|
||||||
|
// let chunk = (v1.len() / num_cpus::get()) + 1;
|
||||||
|
|
||||||
|
// let s = Arc::new(Mutex::new(G::Projective::zero()));
|
||||||
|
// let sx = Arc::new(Mutex::new(G::Projective::zero()));
|
||||||
|
|
||||||
|
// crossbeam::scope(|scope| {
|
||||||
|
// for (v1, v2) in v1.chunks(chunk).zip(v2.chunks(chunk)) {
|
||||||
|
// let s = s.clone();
|
||||||
|
// let sx = sx.clone();
|
||||||
|
|
||||||
|
// scope.spawn(move || {
|
||||||
|
// // We do not need to be overly cautious of the RNG
|
||||||
|
// // used for this check.
|
||||||
|
// let rng = &mut thread_rng();
|
||||||
|
|
||||||
|
// let mut wnaf = Wnaf::new();
|
||||||
|
// let mut local_s = G::Projective::zero();
|
||||||
|
// let mut local_sx = G::Projective::zero();
|
||||||
|
|
||||||
|
// for (v1, v2) in v1.iter().zip(v2.iter()) {
|
||||||
|
// let rho = G::Scalar::rand(rng);
|
||||||
|
// let mut wnaf = wnaf.scalar(rho.into_repr());
|
||||||
|
// let v1 = wnaf.base(v1.into_projective());
|
||||||
|
// let v2 = wnaf.base(v2.into_projective());
|
||||||
|
|
||||||
|
// local_s.add_assign(&v1);
|
||||||
|
// local_sx.add_assign(&v2);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// s.lock().unwrap().add_assign(&local_s);
|
||||||
|
// sx.lock().unwrap().add_assign(&local_sx);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let s = s.lock().unwrap().into_affine();
|
||||||
|
// let sx = sx.lock().unwrap().into_affine();
|
||||||
|
|
||||||
|
// (s, sx)
|
||||||
|
// }
|
||||||
|
|
||||||
fn merge_pairs<E: Engine, G: CurveAffine<Engine = E, Scalar = E::Fr>>(v1: &[G], v2: &[G]) -> (G, G)
|
fn merge_pairs<E: Engine, G: CurveAffine<Engine = E, Scalar = E::Fr>>(v1: &[G], v2: &[G]) -> (G, G)
|
||||||
{
|
{
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use self::rand::{thread_rng};
|
use self::rand::{thread_rng};
|
||||||
|
|
||||||
assert_eq!(v1.len(), v2.len());
|
assert_eq!(v1.len(), v2.len());
|
||||||
|
let rng = &mut thread_rng();
|
||||||
|
|
||||||
let chunk = (v1.len() / num_cpus::get()) + 1;
|
let randomness: Vec<<G::Scalar as PrimeField>::Repr> = (0..v1.len()).map(|_| G::Scalar::rand(rng).into_repr()).collect();
|
||||||
|
|
||||||
let s = Arc::new(Mutex::new(G::Projective::zero()));
|
let s = dense_multiexp(&v1, &randomness[..]).into_affine();
|
||||||
let sx = Arc::new(Mutex::new(G::Projective::zero()));
|
let sx = dense_multiexp(&v2, &randomness[..]).into_affine();
|
||||||
|
|
||||||
crossbeam::scope(|scope| {
|
|
||||||
for (v1, v2) in v1.chunks(chunk).zip(v2.chunks(chunk)) {
|
|
||||||
let s = s.clone();
|
|
||||||
let sx = sx.clone();
|
|
||||||
|
|
||||||
scope.spawn(move || {
|
|
||||||
// We do not need to be overly cautious of the RNG
|
|
||||||
// used for this check.
|
|
||||||
let rng = &mut thread_rng();
|
|
||||||
|
|
||||||
let mut wnaf = Wnaf::new();
|
|
||||||
let mut local_s = G::Projective::zero();
|
|
||||||
let mut local_sx = G::Projective::zero();
|
|
||||||
|
|
||||||
for (v1, v2) in v1.iter().zip(v2.iter()) {
|
|
||||||
let rho = G::Scalar::rand(rng);
|
|
||||||
let mut wnaf = wnaf.scalar(rho.into_repr());
|
|
||||||
let v1 = wnaf.base(v1.into_projective());
|
|
||||||
let v2 = wnaf.base(v2.into_projective());
|
|
||||||
|
|
||||||
local_s.add_assign(&v1);
|
|
||||||
local_sx.add_assign(&v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock().unwrap().add_assign(&local_s);
|
|
||||||
sx.lock().unwrap().add_assign(&local_sx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let s = s.lock().unwrap().into_affine();
|
|
||||||
let sx = sx.lock().unwrap().into_affine();
|
|
||||||
|
|
||||||
(s, sx)
|
(s, sx)
|
||||||
}
|
}
|
||||||
@ -165,3 +180,121 @@ pub fn compute_g2_s<E: Engine> (
|
|||||||
|
|
||||||
hash_to_g2::<E>(h.result().as_ref()).into_affine()
|
hash_to_g2::<E>(h.result().as_ref()).into_affine()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform multi-exponentiation. The caller is responsible for ensuring that
|
||||||
|
/// the number of bases is the same as the number of exponents.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn dense_multiexp<G: CurveAffine>(
|
||||||
|
bases: & [G],
|
||||||
|
exponents: & [<G::Scalar as PrimeField>::Repr]
|
||||||
|
) -> <G as CurveAffine>::Projective
|
||||||
|
{
|
||||||
|
if exponents.len() != bases.len() {
|
||||||
|
panic!("invalid length")
|
||||||
|
}
|
||||||
|
let c = if exponents.len() < 32 {
|
||||||
|
3u32
|
||||||
|
} else {
|
||||||
|
(f64::from(exponents.len() as u32)).ln().ceil() as u32
|
||||||
|
};
|
||||||
|
|
||||||
|
dense_multiexp_inner(bases, exponents, 0, c, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dense_multiexp_inner<G: CurveAffine>(
|
||||||
|
bases: & [G],
|
||||||
|
exponents: & [<G::Scalar as PrimeField>::Repr],
|
||||||
|
mut skip: u32,
|
||||||
|
c: u32,
|
||||||
|
handle_trivial: bool
|
||||||
|
) -> <G as CurveAffine>::Projective
|
||||||
|
{
|
||||||
|
use std::sync::{Mutex};
|
||||||
|
// Perform this region of the multiexp. We use a different strategy - go over region in parallel,
|
||||||
|
// then over another region, etc. No Arc required
|
||||||
|
let chunk = (bases.len() / num_cpus::get()) + 1;
|
||||||
|
let this = {
|
||||||
|
// let mask = (1u64 << c) - 1u64;
|
||||||
|
let this_region = Mutex::new(<G as CurveAffine>::Projective::zero());
|
||||||
|
let arc = Arc::new(this_region);
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
for (base, exp) in bases.chunks(chunk).zip(exponents.chunks(chunk)) {
|
||||||
|
let this_region_rwlock = arc.clone();
|
||||||
|
// let handle =
|
||||||
|
scope.spawn(move || {
|
||||||
|
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
|
||||||
|
// Accumulate the result
|
||||||
|
let mut acc = G::Projective::zero();
|
||||||
|
let zero = G::Scalar::zero().into_repr();
|
||||||
|
let one = G::Scalar::one().into_repr();
|
||||||
|
|
||||||
|
for (base, &exp) in base.iter().zip(exp.iter()) {
|
||||||
|
// let index = (exp.as_ref()[0] & mask) as usize;
|
||||||
|
|
||||||
|
// if index != 0 {
|
||||||
|
// buckets[index - 1].add_assign_mixed(base);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// exp.shr(c as u32);
|
||||||
|
|
||||||
|
if exp != zero {
|
||||||
|
if exp == one {
|
||||||
|
if handle_trivial {
|
||||||
|
acc.add_assign_mixed(base);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut exp = exp;
|
||||||
|
exp.shr(skip);
|
||||||
|
let exp = exp.as_ref()[0] % (1 << c);
|
||||||
|
if exp != 0 {
|
||||||
|
buckets[(exp - 1) as usize].add_assign_mixed(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buckets are filled with the corresponding accumulated value, now sum
|
||||||
|
let mut running_sum = G::Projective::zero();
|
||||||
|
for exp in buckets.into_iter().rev() {
|
||||||
|
running_sum.add_assign(&exp);
|
||||||
|
acc.add_assign(&running_sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut guard = match this_region_rwlock.lock() {
|
||||||
|
Ok(guard) => guard,
|
||||||
|
Err(_) => {
|
||||||
|
panic!("poisoned!");
|
||||||
|
// poisoned.into_inner()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(*guard).add_assign(&acc);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let this_region = Arc::try_unwrap(arc).unwrap();
|
||||||
|
let this_region = this_region.into_inner().unwrap();
|
||||||
|
|
||||||
|
this_region
|
||||||
|
};
|
||||||
|
|
||||||
|
skip += c;
|
||||||
|
|
||||||
|
if skip >= <G::Scalar as PrimeField>::NUM_BITS {
|
||||||
|
// There isn't another region, and this will be the highest region
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
// next region is actually higher than this one, so double it enough times
|
||||||
|
let mut next_region = dense_multiexp_inner(
|
||||||
|
bases, exponents, skip, c, false);
|
||||||
|
for _ in 0..c {
|
||||||
|
next_region.double();
|
||||||
|
}
|
||||||
|
|
||||||
|
next_region.add_assign(&this);
|
||||||
|
|
||||||
|
return next_region;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user