clean up -- moving zkp proof compiler to a new repo
This commit is contained in:
parent
815978b4e2
commit
26842ecae9
|
@ -5,8 +5,8 @@ authors = ["J. Ayo Akinyele <ayo@yeletech.org>"]
|
|||
description = "library for Blind Off-chain Lightweight Transactions (BOLT)"
|
||||
keywords = ["zcash", "payment channels", "bolt"]
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/yeletech/libbolt"
|
||||
repository = "https://github.com/yeletech/libbolt"
|
||||
homepage = "https://github.com/ZcashFoundation/libbolt"
|
||||
repository = "https://github.com/ZcashFoundation/libbolt"
|
||||
license = "MIT License"
|
||||
|
||||
[dependencies]
|
||||
|
|
276
bin/bolt.rs
276
bin/bolt.rs
|
@ -21,282 +21,6 @@ use libbolt::commit_scheme;
|
|||
use libbolt::bidirectional;
|
||||
use time::PreciseTime;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_formula_scalarlist {
|
||||
// Unbracket a statement
|
||||
(($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
||||
// Add a trailing +
|
||||
__compute_formula_scalarlist!(($publics,$scalars) $($x)* +)
|
||||
};
|
||||
// Inner part of the formula: give a list of &Scalars
|
||||
// Since there's a trailing +, we can just generate the list as normal...
|
||||
(($publics:ident, $scalars:ident)
|
||||
$( $point:ident * $scalar:ident +)+ ) => {
|
||||
&[ $( $scalars.$scalar ,)* ]
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_formula_pointlist {
|
||||
// Unbracket a statement
|
||||
(($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
||||
// Add a trailing +
|
||||
__compute_formula_pointlist!(($publics,$scalars) $($x)* +)
|
||||
};
|
||||
// Inner part of the formula: give a list of &Scalars
|
||||
// Since there's a trailing +, we can just generate the list as normal...
|
||||
(($publics:ident, $scalars:ident)
|
||||
$( $point:ident * $scalar:ident +)* ) => {
|
||||
&[ $( *($publics.$point) ,)* ]
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_commitments_consttime {
|
||||
(($publics:ident, $scalars:ident) $($lhs:ident = $statement:tt),+) => {
|
||||
Commitments {
|
||||
$( $lhs :
|
||||
multiscalar_mult(
|
||||
__compute_formula_scalarlist!(($publics, $scalars) $statement),
|
||||
__compute_formula_pointlist!(($publics, $scalars) $statement),
|
||||
)
|
||||
),+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __recompute_commitments_vartime {
|
||||
(($publics:ident, $scalars:ident, $minus_c:ident) $($lhs:ident = $statement:tt),+) => {
|
||||
Commitments {
|
||||
$( $lhs :
|
||||
multiscalar_mult(
|
||||
__compute_formula_scalarlist!(($publics, $scalars) $statement)
|
||||
.into_iter()
|
||||
.chain(iter::once(&($minus_c)))
|
||||
,
|
||||
__compute_formula_pointlist!(($publics, $scalars) $statement)
|
||||
.into_iter()
|
||||
.chain(iter::once($publics.$lhs))
|
||||
)
|
||||
),+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! generate_nipk {
|
||||
(
|
||||
$proof_module_name:ident // Name of the module to create
|
||||
,
|
||||
( $($secret:ident),+ ) // Secret variables, sep by commas
|
||||
,
|
||||
( $($public:ident),+ ) // Public variables, sep by commas
|
||||
:
|
||||
// List of statements to prove
|
||||
// Format: LHS = ( ... RHS expr ... ),
|
||||
$($lhs:ident = $statement:tt),+
|
||||
) => {
|
||||
mod $proof_module_name {
|
||||
extern crate sodiumoxide;
|
||||
|
||||
use bn::{Group, Fr, G1};
|
||||
use self::sodiumoxide::crypto::hash;
|
||||
use rand::Rng;
|
||||
use std::iter;
|
||||
use bincode::SizeLimit::Infinite;
|
||||
use bincode::rustc_serialize::encode;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Secrets<'a> {
|
||||
// Create a parameter for each secret value
|
||||
$(
|
||||
pub $secret : &'a Fr,
|
||||
)+
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Publics<'a> {
|
||||
// Create a parameter for each public value
|
||||
$(
|
||||
pub $public : &'a G1,
|
||||
)+
|
||||
}
|
||||
|
||||
// Hack because we can't concat identifiers,
|
||||
// so do responses.x instead of responses_x
|
||||
// rand.x instead of rand_x, etc.
|
||||
|
||||
struct Commitments {$($lhs: G1,)+ }
|
||||
struct Randomnesses {$($secret : Fr,)+}
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
struct Responses {$($secret : Fr,)+}
|
||||
|
||||
//#[derive(Serialize, Deserialize)]
|
||||
pub struct Proof {
|
||||
challenge: Fr,
|
||||
responses: Responses,
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
/// Create a `Proof`, in constant time, from the given
|
||||
/// `Publics` and `Secrets`.
|
||||
#[allow(dead_code)]
|
||||
pub fn create<R: Rng>(
|
||||
rng: &mut R,
|
||||
publics: Publics,
|
||||
secrets: Secrets,
|
||||
) -> Proof {
|
||||
let rand = Randomnesses{
|
||||
$(
|
||||
$secret : Fr::random(rng),
|
||||
)+
|
||||
};
|
||||
// $statement_rhs = `X * x + Y * y + Z * z`
|
||||
// should become
|
||||
// `publics.X * rand.x + publics.Y * rand.y + publics.Z * rand.z`
|
||||
let commitments: Commitments;
|
||||
commitments = __compute_commitments_consttime!(
|
||||
(publics, rand) $($lhs = $statement),*
|
||||
);
|
||||
|
||||
let mut hash_state = hash::State::new();
|
||||
|
||||
$(
|
||||
//let tmp$public: Vec<u8> = encode(&publics.$public, Infinite).unwrap();
|
||||
hash_state.update((encode(&publics.$public, Infinite).unwrap()).as_slice());
|
||||
//hash_state.update(publics.$public.as_bytes());
|
||||
)+
|
||||
$(
|
||||
//let tmp$lhs: Vec<u8> = encode(&commitments.$lhs, Infinite).unwrap();
|
||||
hash_state.update((encode(&commitments.$lhs, Infinite).unwrap()).as_slice());
|
||||
//hash_state.update(commitments.$lhs.as_bytes());
|
||||
)+
|
||||
|
||||
let digest = hash_state.finalize();
|
||||
let mut digest_buf: [u8; 64] = [0; 64];
|
||||
digest_buf.copy_from_slice(&digest[0..64]);
|
||||
let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
||||
|
||||
let responses = Responses{
|
||||
$(
|
||||
$secret : (challenge * *secrets.$secret) + rand.$secret,
|
||||
)+
|
||||
};
|
||||
|
||||
Proof{ challenge: challenge, responses: responses }
|
||||
}
|
||||
|
||||
/// Verify the `Proof` using the public parameters `Publics`.
|
||||
#[allow(dead_code)]
|
||||
pub fn verify(&self, publics: Publics) -> Result<(),()> {
|
||||
// `A = X * x + Y * y`
|
||||
// should become
|
||||
// `publics.X * responses.x + publics.Y * responses.y - publics.A * self.challenge`
|
||||
let responses = &self.responses;
|
||||
let minus_c = -self.challenge;
|
||||
let commitments = __recompute_commitments_vartime!(
|
||||
(publics, responses, minus_c) $($lhs = $statement),*
|
||||
);
|
||||
|
||||
let mut hash_state = hash::State::new();
|
||||
// Add each public point into the hash
|
||||
$(
|
||||
//let tmp$public: Vec<u8> = encode(&publics.$public, Infinite).unwrap();
|
||||
//hash_state.update(publics.$public.as_bytes());
|
||||
hash_state.update((encode(&publics.$public, Infinite).unwrap()).as_slice());
|
||||
)+
|
||||
// Add each (recomputed) commitment into the hash
|
||||
$(
|
||||
//let tmp$lhs: Vec<u8> = encode(&commitments.$lhs, Infinite).unwrap();
|
||||
hash_state.update((encode(&commitments.$lhs, Infinite).unwrap()).as_slice());
|
||||
)*
|
||||
|
||||
let digest = hash_state.finalize();
|
||||
let mut digest_buf: [u8; 64] = [0; 64];
|
||||
digest_buf.copy_from_slice(&digest[0..64]);
|
||||
// Recompute challenge
|
||||
let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
||||
|
||||
if challenge == self.challenge { Ok(()) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
extern crate test;
|
||||
|
||||
use $crate::rand;
|
||||
|
||||
use super::*;
|
||||
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
#[allow(dead_code)]
|
||||
fn create(b: &mut Bencher) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
//let mut rng = OsRng::new().unwrap();
|
||||
|
||||
// Need somewhere to actually put the public points
|
||||
struct DummyPublics { $( pub $public : G1, )+ }
|
||||
let dummy_publics = DummyPublics {
|
||||
$( $public : G1::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let publics = Publics {
|
||||
$( $public : &dummy_publics.$public , )+
|
||||
};
|
||||
|
||||
struct DummySecrets { $( pub $secret : Fr, )+ }
|
||||
let dummy_secrets = DummySecrets {
|
||||
$( $secret : Fr::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let secrets = Secrets {
|
||||
$( $secret : &dummy_secrets.$secret , )+
|
||||
};
|
||||
|
||||
b.iter(|| Proof::create(&mut rng, publics, secrets));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[allow(dead_code)]
|
||||
fn verify(b: &mut Bencher) {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
|
||||
// Need somewhere to actually put the public points
|
||||
struct DummyPublics { $( pub $public : G1, )+ }
|
||||
let dummy_publics = DummyPublics {
|
||||
$( $public : G1::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let publics = Publics {
|
||||
$( $public : &dummy_publics.$public , )+
|
||||
};
|
||||
|
||||
struct DummySecrets { $( pub $secret : Fr, )+ }
|
||||
let dummy_secrets = DummySecrets {
|
||||
$( $secret : Fr::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let secrets = Secrets {
|
||||
$( $secret : &dummy_secrets.$secret , )+
|
||||
};
|
||||
|
||||
let p = Proof::create(&mut rng, publics, secrets);
|
||||
|
||||
b.iter(|| p.verify(publics));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! measure {
|
||||
($x: expr) => {
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#![feature(test)]
|
||||
// clsigs.rs
|
||||
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
//use std::default;
|
||||
use rand;
|
||||
use bn::{Group, Fr, G1, G2, Gt, pairing};
|
||||
use debug_elem_in_hex;
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -538,8 +538,6 @@ impl<'a> SpendMessage<'a> {
|
|||
|
||||
////////////////////////////////// CL Sigs /////////////////////////////////////
|
||||
|
||||
////////////////////////////////// COMMITMENT //////////////////////////////////
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Message {
|
||||
sk: clsigs::SecretKey, // the secret key for the signature scheme (Is it possible to make this a generic field?)
|
||||
|
@ -584,9 +582,7 @@ impl Message {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////// COMMITMENT //////////////////////////////////
|
||||
|
||||
////////////////////////////////// NIZKP //////////////////////////////////
|
||||
////////////////////////////////// Utilities //////////////////////////////////
|
||||
|
||||
pub fn concat_to_vector(output: &mut Vec<u8>, t: &G2) {
|
||||
let t_vec: Vec<u8> = encode(t, Infinite).unwrap();
|
||||
|
@ -601,15 +597,8 @@ pub struct Proof {
|
|||
s2: Fr
|
||||
}
|
||||
|
||||
//pub fn hash(g: &G1, h: &G1, X: &G1, Y: &G1, T: &Gt) -> Fr {
|
||||
// let g_vec: Vec<u8> = encode(&g, Infinite).unwrap();
|
||||
//
|
||||
// // TODO: fix this
|
||||
// return Fr::from_str("1234567890").unwrap();
|
||||
//}
|
||||
|
||||
pub fn hashG1ToFr(x: &G1) -> Fr {
|
||||
// TODO: change to serde (instead of rustc_serialize)
|
||||
// TODO: use serde (instead of rustc_serialize)
|
||||
let x_vec: Vec<u8> = encode(&x, Infinite).unwrap();
|
||||
let sha2_digest = sha512::hash(x_vec.as_slice());
|
||||
|
||||
|
@ -848,7 +837,6 @@ impl RevokedMessage {
|
|||
// return InitMerchantData { T: keypair.pk, csk: csk_m };
|
||||
// }
|
||||
//
|
||||
// // TODO: requires NIZK proof system
|
||||
// pub fn establish_customer(pp: &PublicParams, t_m: &clsigs::PublicKey, csk_c: &CustSecretKey) {
|
||||
// println ! ("Run establish_customer algorithm...");
|
||||
// // set sk_0 to random bytes of length l
|
||||
|
|
500
src/zkp.rs
500
src/zkp.rs
|
@ -1,500 +0,0 @@
|
|||
// -*- coding: utf-8; mode: rust; -*-
|
||||
//
|
||||
// To the extent possible under law, the authors have waived all
|
||||
// copyright and related or neighboring rights to zkp,
|
||||
// using the Creative Commons "CC0" public domain dedication. See
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/> for full
|
||||
// details.
|
||||
//
|
||||
// Authors:
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! This crate has an experimental zero-knowledge proof compiler
|
||||
//! implemented using Rust macros.
|
||||
//!
|
||||
//! It provides a DSL resembing Camenisch-Stadler notation for proving
|
||||
//! statements about discrete logarithms in the Ristretto group on
|
||||
//! BLS-381, as implemented in
|
||||
//! [`bn module`](https://github.com/zcash-hackworks/bn).
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
#![feature(test)]
|
||||
|
||||
//extern crate serde;
|
||||
//
|
||||
//#[doc(hidden)]
|
||||
//#[macro_use]
|
||||
//pub extern crate serde_derive;
|
||||
//#[doc(hidden)]
|
||||
//pub extern crate bn;
|
||||
//#[doc(hidden)]
|
||||
//pub extern crate rand;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_formula_scalarlist {
|
||||
// Unbracket a statement
|
||||
(($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
||||
// Add a trailing +
|
||||
__compute_formula_scalarlist!(($publics,$scalars) $($x)* +)
|
||||
};
|
||||
// Inner part of the formula: give a list of &Scalars
|
||||
// Since there's a trailing +, we can just generate the list as normal...
|
||||
(($publics:ident, $scalars:ident)
|
||||
$( $point:ident * $scalar:ident +)+ ) => {
|
||||
&[ $( $scalars.$scalar ,)* ]
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_formula_pointlist {
|
||||
// Unbracket a statement
|
||||
(($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
||||
// Add a trailing +
|
||||
__compute_formula_pointlist!(($publics,$scalars) $($x)* +)
|
||||
};
|
||||
// Inner part of the formula: give a list of &Scalars
|
||||
// Since there's a trailing +, we can just generate the list as normal...
|
||||
(($publics:ident, $scalars:ident)
|
||||
$( $point:ident * $scalar:ident +)* ) => {
|
||||
&[ $( *($publics.$point) ,)* ]
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __compute_commitments_consttime {
|
||||
(($publics:ident, $scalars:ident) $($lhs:ident = $statement:tt),+) => {
|
||||
Commitments {
|
||||
$( $lhs :
|
||||
multiscalar_mult(
|
||||
__compute_formula_scalarlist!(($publics, $scalars) $statement),
|
||||
__compute_formula_pointlist!(($publics, $scalars) $statement),
|
||||
)
|
||||
),+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __recompute_commitments_vartime {
|
||||
(($publics:ident, $scalars:ident, $minus_c:ident) $($lhs:ident = $statement:tt),+) => {
|
||||
Commitments {
|
||||
$( $lhs :
|
||||
vartime::multiscalar_mult(
|
||||
__compute_formula_scalarlist!(($publics, $scalars) $statement)
|
||||
.into_iter()
|
||||
.chain(iter::once(&($minus_c)))
|
||||
,
|
||||
__compute_formula_pointlist!(($publics, $scalars) $statement)
|
||||
.into_iter()
|
||||
.chain(iter::once($publics.$lhs))
|
||||
)
|
||||
),+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a module with code required to produce a non-interactive
|
||||
/// zero-knowledge proof statement, to serialize it to wire format, to
|
||||
/// parse from wire format, and to verify the proof statement.
|
||||
///
|
||||
/// The statement is specified in an embedded DSL resembling
|
||||
/// Camenisch-Stadler notation. For instance, a proof of knowledge of
|
||||
/// two equal discrete logarithms ("DLEQ") is specified as:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// create_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) }
|
||||
/// ```
|
||||
///
|
||||
/// This creates a module `dleq` with code for proving knowledge of a
|
||||
/// secret `x: Scalar` such that `A = G*x`, `B = H*x` for public
|
||||
/// parameters `A, B, G, H: G1`. In general the syntax is
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// create_nipk!{
|
||||
/// module_name, // used to label proof statements
|
||||
/// (x,y,z,...), // secret variable names
|
||||
/// (A,B,C,...) // public parameter names
|
||||
/// :
|
||||
/// LHS = (A * x + B * y + C * z + ... ), // comma-seperated statements
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Statements have the form `LHS = (A * x + B * y + C * z + ... )`,
|
||||
/// where `LHS` is one of the points listed as a public parameter, and
|
||||
/// the right-hand side is a sum of public points multiplied by secret
|
||||
/// scalars.
|
||||
///
|
||||
/// Inside the generated module `module_name`, the macro defines three
|
||||
/// structs:
|
||||
///
|
||||
/// A `Publics` struct corresponding to the public parameters, of the
|
||||
/// form
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub struct Publics<'a> { pub A: &'a G1, ... }
|
||||
/// ```
|
||||
///
|
||||
/// A `Secrets` struct corresponding to the secret parameters, of the
|
||||
/// form
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub struct Secrets<'a> { pub x: &'a Scalar, ... }
|
||||
/// ```
|
||||
///
|
||||
/// A `Proof` struct, of the form
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// pub struct Proof { ... }
|
||||
///
|
||||
/// impl Proof {
|
||||
/// pub fn create<R: Rng>(
|
||||
/// rng: &mut R,
|
||||
/// publics: Publics,
|
||||
/// secrets: Secrets,
|
||||
/// ) -> Proof { ... }
|
||||
///
|
||||
/// pub fn verify(&self, publics: Publics) -> Result<(),()> { ... }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `Proof` struct derives the Serde traits, so it can be
|
||||
/// serialized and deserialized to various wire formats.
|
||||
///
|
||||
/// The `Publics` and `Secrets` structs are used to fake named
|
||||
/// arguments in the input to `create` and `verify`. Proof creation
|
||||
/// is done in constant time. Proof verification uses variable-time
|
||||
/// code.
|
||||
///
|
||||
/// As an example, we can create and verify a DLEQ proof as follows:
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate serde_derive;
|
||||
///
|
||||
/// #[macro_use]
|
||||
/// extern crate zkp;
|
||||
///
|
||||
/// extern crate rand;
|
||||
/// use rand;
|
||||
///
|
||||
/// extern crate bincode;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let mut rng = OsRng::new().unwrap();
|
||||
/// let G = &dalek_constants::RISTRETTO_BASEPOINT_POINT;
|
||||
/// let H = RistrettoPoint::hash_from_bytes::<Sha256>(G.compress().as_bytes());
|
||||
///
|
||||
/// create_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) }
|
||||
///
|
||||
/// let x = Fr::from_str("89327492234");
|
||||
/// let A = G * &x;
|
||||
/// let B = &H * &x;
|
||||
///
|
||||
/// let publics = dleq::Publics{A: &A, B: &B, G: G, H: &H};
|
||||
/// let secrets = dleq::Secrets{x: &x};
|
||||
///
|
||||
/// let proof = dleq::Proof::create(&mut rng, publics, secrets);
|
||||
///
|
||||
/// // Serialize to bincode representation
|
||||
/// let proof_bytes = bincode::serialize(&proof, bincode::Infinite).unwrap();
|
||||
///
|
||||
/// // Send bytes over the wire here ...
|
||||
///
|
||||
/// // Parse bytes back to in-memory representation
|
||||
/// let parsed_proof: dleq::Proof
|
||||
/// = bincode::deserialize(&proof_bytes).unwrap();
|
||||
///
|
||||
/// // Check the proof.
|
||||
/// assert!(parsed_proof.verify(publics).is_ok());
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! create_nipk {
|
||||
(
|
||||
$proof_module_name:ident // Name of the module to create
|
||||
,
|
||||
( $($secret:ident),+ ) // Secret variables, sep by commas
|
||||
,
|
||||
( $($public:ident),+ ) // Public variables, sep by commas
|
||||
:
|
||||
// List of statements to prove
|
||||
// Format: LHS = ( ... RHS expr ... ),
|
||||
$($lhs:ident = $statement:tt),+
|
||||
) => {
|
||||
mod $proof_module_name {
|
||||
use $crate::{Group, Fr, G1}
|
||||
use $crate::sodiumoxide::crypto::hash;
|
||||
// use $crate::sha2::{Digest, Sha512};
|
||||
use $crate::rand::Rng;
|
||||
|
||||
use std::iter;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Secrets<'a> {
|
||||
// Create a parameter for each secret value
|
||||
$(
|
||||
pub $secret : &'a Fr,
|
||||
)+
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Publics<'a> {
|
||||
// Create a parameter for each public value
|
||||
$(
|
||||
pub $public : &'a G1,
|
||||
)+
|
||||
}
|
||||
|
||||
// Hack because we can't concat identifiers,
|
||||
// so do responses.x instead of responses_x
|
||||
// rand.x instead of rand_x, etc.
|
||||
|
||||
struct Commitments {$($lhs: G1,)+ }
|
||||
struct Randomnesses {$($secret : Scalar,)+}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Responses {$($secret : Scalar,)+}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Proof {
|
||||
challenge: Fr,
|
||||
responses: Responses,
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
/// Create a `Proof`, in constant time, from the given
|
||||
/// `Publics` and `Secrets`.
|
||||
#[allow(dead_code)]
|
||||
pub fn create<R: Rng>(
|
||||
rng: &mut R,
|
||||
publics: Publics,
|
||||
secrets: Secrets,
|
||||
) -> Proof {
|
||||
let rand = Randomnesses{
|
||||
$(
|
||||
$secret : Fr::random(rng),
|
||||
)+
|
||||
};
|
||||
// $statement_rhs = `X * x + Y * y + Z * z`
|
||||
// should become
|
||||
// `publics.X * rand.x + publics.Y * rand.y + publics.Z * rand.z`
|
||||
let commitments: Commitments;
|
||||
commitments = __compute_commitments_consttime!(
|
||||
(publics, rand) $($lhs = $statement),*
|
||||
);
|
||||
|
||||
let mut hash_state = hash::State::new();
|
||||
|
||||
$(
|
||||
hash_state.update(publics.$public.as_bytes());
|
||||
)+
|
||||
$(
|
||||
hash_state.update(commitments.$lhs.as_bytes());
|
||||
)+
|
||||
|
||||
let digest = hash_state.finalize();
|
||||
let mut digest_buf: [u8; 64] = [0; 64];
|
||||
digest_buf.copy_from_slice(&digest[0..64]);
|
||||
let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
||||
|
||||
let responses = Responses{
|
||||
$(
|
||||
$secret : &(&challenge * secrets.$secret) + &rand.$secret,
|
||||
)+
|
||||
};
|
||||
|
||||
Proof{ challenge: challenge, responses: responses }
|
||||
}
|
||||
|
||||
/// Verify the `Proof` using the public parameters `Publics`.
|
||||
#[allow(dead_code)]
|
||||
pub fn verify(&self, publics: Publics) -> Result<(),()> {
|
||||
// `A = X * x + Y * y`
|
||||
// should become
|
||||
// `publics.X * responses.x + publics.Y * responses.y - publics.A * self.challenge`
|
||||
let responses = &self.responses;
|
||||
let minus_c = -&self.challenge;
|
||||
let commitments = __recompute_commitments_vartime!(
|
||||
(publics, responses, minus_c) $($lhs = $statement),*
|
||||
);
|
||||
|
||||
let mut hash_state = hash::State::new();
|
||||
// Add each public point into the hash
|
||||
$(
|
||||
hash_state.update(publics.$public.as_bytes());
|
||||
)+
|
||||
// Add each (recomputed) commitment into the hash
|
||||
$(
|
||||
hash_state.update(commitments.$lhs.as_bytes());
|
||||
)*
|
||||
|
||||
let digest = hash_state.finalize();
|
||||
let mut digest_buf: [u8; 64] = [0; 64];
|
||||
digest_buf.copy_from_slice(&digest[0..64]);
|
||||
// Recompute challenge
|
||||
let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
||||
|
||||
if challenge == self.challenge { Ok(()) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
extern crate test;
|
||||
|
||||
use $crate::rand;
|
||||
|
||||
use super::*;
|
||||
|
||||
use self::test::Bencher;
|
||||
|
||||
#[bench]
|
||||
#[allow(dead_code)]
|
||||
fn create(b: &mut Bencher) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
//let mut rng = OsRng::new().unwrap();
|
||||
|
||||
// Need somewhere to actually put the public points
|
||||
struct DummyPublics { $( pub $public : G1, )+ }
|
||||
let dummy_publics = DummyPublics {
|
||||
$( $public : G1::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let publics = Publics {
|
||||
$( $public : &dummy_publics.$public , )+
|
||||
};
|
||||
|
||||
struct DummySecrets { $( pub $secret : Fr, )+ }
|
||||
let dummy_secrets = DummySecrets {
|
||||
$( $secret : Fr::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let secrets = Secrets {
|
||||
$( $secret : &dummy_secrets.$secret , )+
|
||||
};
|
||||
|
||||
b.iter(|| Proof::create(&mut rng, publics, secrets));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[allow(dead_code)]
|
||||
fn verify(b: &mut Bencher) {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
|
||||
// Need somewhere to actually put the public points
|
||||
struct DummyPublics { $( pub $public : G1, )+ }
|
||||
let dummy_publics = DummyPublics {
|
||||
$( $public : G1::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let publics = Publics {
|
||||
$( $public : &dummy_publics.$public , )+
|
||||
};
|
||||
|
||||
struct DummySecrets { $( pub $secret : Fr, )+ }
|
||||
let dummy_secrets = DummySecrets {
|
||||
$( $secret : Fr::random(&mut rng) , )+
|
||||
};
|
||||
|
||||
let secrets = Secrets {
|
||||
$( $secret : &dummy_secrets.$secret , )+
|
||||
};
|
||||
|
||||
let p = Proof::create(&mut rng, publics, secrets);
|
||||
|
||||
b.iter(|| p.verify(publics));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate bincode;
|
||||
extern crate test;
|
||||
|
||||
use rand;
|
||||
use bn::{Group, Fr, G1};
|
||||
// use self::test::Bencher;
|
||||
|
||||
// use curve25519_dalek::constants as dalek_constants;
|
||||
// use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
// use curve25519_dalek::scalar::Scalar;
|
||||
|
||||
#[test]
|
||||
fn create_gen_dleq(b: &mut Bencher) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
let G = G1::random(rng); // &dalek_constants::RISTRETTO_BASEPOINT_POINT;
|
||||
let H = G1::random(rng); // RistrettoPoint::hash_from_bytes::<Sha256>(G.compress().as_bytes());
|
||||
|
||||
create_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) }
|
||||
|
||||
let x = Fr::from_str("89327492234").unwrap();
|
||||
let A = G * x;
|
||||
let B = H * x;
|
||||
|
||||
let publics = dleq::Publics{A: &A, B: &B, G: G, H: &H};
|
||||
let secrets = dleq::Secrets{x: &x};
|
||||
|
||||
let proof = dleq::Proof::create(&mut rng, publics, secrets);
|
||||
// serialize to bincode representation
|
||||
let proof_bytes = bincode::serialize(&proof, bincode::Infinite).unwrap();
|
||||
// parse bytes back to memory
|
||||
let parsed_proof: dleq::Proof
|
||||
= bincode::deserialize(&proof_bytes).unwrap();
|
||||
|
||||
assert!(parsed_proof.verify(publics).is_ok());
|
||||
|
||||
// b.iter(|| dleq::Proof::create(&mut rng, publics, secrets));
|
||||
}
|
||||
|
||||
// #[bench]
|
||||
// fn verify_gen_dleq(b: &mut Bencher) {
|
||||
// let mut rng = OsRng::new().unwrap();
|
||||
// let G = &dalek_constants::RISTRETTO_BASEPOINT_POINT;
|
||||
// let H = RistrettoPoint::hash_from_bytes::<Sha256>(G.compress().as_bytes());
|
||||
//
|
||||
// create_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) }
|
||||
//
|
||||
// let x = Scalar::from_u64(89327492234);
|
||||
// let A = G * &x;
|
||||
// let B = &H * &x;
|
||||
//
|
||||
// let publics = dleq::Publics{A: &A, B: &B, G: G, H: &H};
|
||||
// let secrets = dleq::Secrets{x: &x};
|
||||
//
|
||||
// let proof = dleq::Proof::create(&mut rng, publics, secrets);
|
||||
// b.iter(|| proof.verify(publics).is_ok());
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn create_and_verify_gen_dleq() {
|
||||
// let mut rng = OsRng::new().unwrap();
|
||||
// let G = &dalek_constants::RISTRETTO_BASEPOINT_POINT;
|
||||
// let H = RistrettoPoint::hash_from_bytes::<Sha256>(G.compress().as_bytes());
|
||||
//
|
||||
// create_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) }
|
||||
//
|
||||
// let x = Scalar::from_u64(89327492234);
|
||||
// let A = G * &x;
|
||||
// let B = &H * &x;
|
||||
//
|
||||
// let publics = dleq::Publics{A: &A, B: &B, G: G, H: &H};
|
||||
// let secrets = dleq::Secrets{x: &x};
|
||||
//
|
||||
// let proof = dleq::Proof::create(&mut rng, publics, secrets);
|
||||
// // serialize to bincode representation
|
||||
// let proof_bytes = bincode::serialize(&proof, bincode::Infinite).unwrap();
|
||||
// // parse bytes back to memory
|
||||
// let parsed_proof: dleq::Proof
|
||||
// = bincode::deserialize(&proof_bytes).unwrap();
|
||||
//
|
||||
// assert!(parsed_proof.verify(publics).is_ok());
|
||||
// }
|
||||
}
|
Loading…
Reference in New Issue