libbolt/bin/bolt.rs

408 lines
14 KiB
Rust
Raw Normal View History

2018-02-16 05:54:59 -08:00
extern crate bn;
extern crate rand;
2018-02-24 00:12:58 -08:00
extern crate libbolt;
2018-04-02 07:47:19 -07:00
extern crate bincode;
#[macro_use]
extern crate serde_derive;
extern crate serde;
2018-02-16 05:54:59 -08:00
use bn::{Group, Fr, G1, G2, pairing};
2018-04-02 07:47:19 -07:00
use bincode::SizeLimit::Infinite;
use bincode::rustc_serialize::{encode, decode};
2018-02-16 05:54:59 -08:00
2018-03-24 21:03:59 -07:00
use libbolt::sym;
2018-03-24 06:44:45 -07:00
use libbolt::clsigs;
use libbolt::commit_scheme;
2018-04-02 07:47:19 -07:00
#[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));
}
}
}
}
}
2018-02-16 05:54:59 -08:00
fn main() {
let rng = &mut rand::thread_rng();
// Generate private keys
let alice_sk = Fr::random(rng);
//println!("alice_sk: {}", alice_sk);
let bob_sk = Fr::random(rng);
let carol_sk = Fr::random(rng);
// Generate public keys in G1 and G2
let (alice_pk1, alice_pk2) = (G1::one() * alice_sk, G2::one() * alice_sk);
let (bob_pk1, bob_pk2) = (G1::one() * bob_sk, G2::one() * bob_sk);
let (carol_pk1, carol_pk2) = (G1::one() * carol_sk, G2::one() * carol_sk);
// Each party computes the shared secret
let alice_ss = pairing(bob_pk1, carol_pk2).pow(alice_sk);
let bob_ss = pairing(carol_pk1, alice_pk2).pow(bob_sk);
let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk);
assert!(alice_ss == bob_ss && bob_ss == carol_ss);
2018-03-24 06:44:45 -07:00
println!("All bn unit tests succeeded!");
2018-03-24 21:03:59 -07:00
println!("******************************************");
// 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());
//
// // simple ZKP
// generate_nipk!{dleq, (x), (A, G) : A = (G * x) }
//
// let x = Fr::from_str("89327492234").unwrap();
// let A = G * x;
// let B = H * x;
//
// let publics = dleq::Publics{A: &A, G: G};
// let secrets = dleq::Secrets{x: &x};
2018-03-24 06:44:45 -07:00
2018-02-24 00:12:58 -08:00
// generate_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;
//
2018-04-02 07:47:19 -07:00
// 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());
2018-03-24 06:44:45 -07:00
println!("******************************************");
2018-04-02 07:47:19 -07:00
// sym::init();
// // SymKeyEnc tests
// let l = 128; // TODO: figure out how to apply this to secretbox
// let key1 = sym::keygen(l);
// //let key2 = sym::keygen(l);
//
// // println!("key: {:?}", key);
//
// let pt1 = String::from("hello world");
// let ciphertext = sym::encrypt(&key1, &pt1);
// println!("{}", ciphertext);
//
// let pt2 = sym::decrypt(&key1, &ciphertext);
// println!("Recovered plaintext: {}", pt2);
// assert!(pt1 == pt2);
//
//// let pt3 = sym::decrypt(&key2, &ciphertext);
//// assert!(pt1 != pt3);
// println!("SymKeyEnc is complete!");
// println!("******************************************");
//
// // CL sig tests
// let mpk = clsigs::setup();
// let keypair = clsigs::keygen(&mpk);
// println!("{}", keypair.pk);
//
// let msg1 = libbolt::RefundMessage::new(alice_sk, 10).hash(); // TODO: add ck (l-bit key)
// let msg2 = libbolt::RefundMessage::new(alice_sk, 11).hash(); // TODO: add ck (l-bit key)
// let signature = clsigs::sign(&keypair.sk, msg1);
// println!("{}", signature);
// assert!(clsigs::verify(&mpk, &keypair.pk, msg1, &signature) == true);
// assert!(clsigs::verify(&mpk, &keypair.pk, msg2, &signature) == false);
//
// println!("CL signature verified!");
//
// println!("******************************************");
// // commitment scheme tests
// let pk = commit_scheme::setup();
// // let sk = libbolt::SecretKeySigs { x: Fr::random(rng), y: Fr::random(rng) };
// // let msg = String::from("Hello, World!");
// let msg1 = libbolt::Message::new(keypair.sk, alice_sk, bob_sk, 10).hash();
// let msg2 = libbolt::Message::new(keypair.sk, alice_sk, bob_sk, 11).hash();
// let msg3 = libbolt::Message::new(keypair.sk, bob_sk, alice_sk, 10).hash();
//
// let cm = commit_scheme::commit(&pk, msg1, None);
//
// assert!(commit_scheme::decommit(&pk, &cm, msg1) == true);
// assert!(commit_scheme::decommit(&pk, &cm, msg2) == false);
// assert!(commit_scheme::decommit(&pk, &cm, msg3) == false);
// println!("Commitment scheme works!");
//
// println!("******************************************");
2018-02-24 23:46:52 -08:00
2018-03-24 06:44:45 -07:00
// TODO: write tests
2018-02-16 05:54:59 -08:00
}