From 623cb0c873f12ee463b13b46521ccef035ddbaa1 Mon Sep 17 00:00:00 2001 From: "J. Ayo Akinyele" Date: Sat, 9 Jun 2018 03:14:50 -0400 Subject: [PATCH] signifcant improvements --- bin/bolt.rs | 178 +++++++++++++++++++------------------------ docs/bolt_design.tex | 2 +- src/clsigs.rs | 18 ++--- src/commit_scheme.rs | 49 +++++++----- src/lib.rs | 82 +++++++++++--------- 5 files changed, 164 insertions(+), 165 deletions(-) diff --git a/bin/bolt.rs b/bin/bolt.rs index 557be7c..cd96c9a 100644 --- a/bin/bolt.rs +++ b/bin/bolt.rs @@ -18,6 +18,7 @@ use libbolt::ote; use libbolt::clsigs; use libbolt::commit_scheme; use time::PreciseTime; +use libbolt::bidirectional; #[doc(hidden)] #[macro_export] @@ -374,121 +375,102 @@ fn main() { println!("{} seconds for verifying invalid signatures.", end1.to(end2)); -// 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::(G.compress().as_bytes()); +// println!("******************************************"); +// let b = keypair.pk.Z2.len(); +// let mut bases: Vec = Vec::new(); +// bases.push(mpk.g2); +// for i in 0 .. b { +// bases.push(keypair.pk.Z2[i]); +// } // -// // simple ZKP -// generate_nipk!{dleq, (x), (A, G) : A = (G * x) } +// // generate sample commitment +// //let mut m: Vec = Vec::new(); +// let mut C = mpk.g2 * m1[0]; +// for i in 0 .. b { +// println!("index: {}", i); +// C = C + (keypair.pk.Z2[i] * m1[i+1]); +// } +// let msg = "Sample Commit output:"; +// libbolt::debug_g2_in_hex(msg, &C); // -// let x = Fr::from_str("89327492234").unwrap(); -// let A = G * x; -// let B = H * x; +// let cm_csp = commit_scheme::setup(b, keypair.pk.Z2, mpk.g2); +// let r = m1[0]; +// let w_com = commit_scheme::commit(&cm_csp, &m1, r); // -// let publics = dleq::Publics{A: &A, G: G}; -// let secrets = dleq::Secrets{x: &x}; +// assert!(commit_scheme::decommit(&cm_csp, &w_com, &m1)); +// +// //let msg = "Commmit Scheme output:"; +// //libbolt::debug_g2_in_hex(msg, &w_com.c); +// +// //assert_eq!(C, w_com.c); +// println!("Commitment scheme consistent!!"); +// let proof = clsigs::bs_gen_nizk_proof(&m1, &cm_csp.pub_bases, w_com.c); +// // old -> let proof = clsigs::bs_gen_nizk_proof(&m1, &bases, C); +// +// let int_sig = clsigs::bs_gen_signature(&mpk, &keypair.sk, &proof); +// +// println!("Generated signature interactively!"); -// generate_nipk!{dleq, (x), (A, B, G, H) : A = (G * x), B = (H * x) } +// let proof = clsigs::bs_gen_nizk_proof(&m1, &bases, C); // -// let x = Fr::from_str("89327492234").unwrap(); -// let A = G * x; -// let B = H * x; +// let int_sig = clsigs::bs_gen_signature(&mpk, &keypair.sk, &proof); // -// let publics = dleq::Publics{A: &A, B: &B, G: G, H: &H}; -// let secrets = dleq::Secrets{x: &x}; +// println!("Generated signature interactively!"); +// // int_sig = interactively generated signature +// assert!(clsigs::verifyD(&mpk, &keypair.pk, &m1, &int_sig) == true); // -// 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(); +// println!("Verified interactively produced signature!"); // -// assert!(parsed_proof.verify(publics).is_ok()); +// let blind_sigs = clsigs::prover_generate_blinded_sig(&int_sig); +// let common_params = clsigs::gen_common_params(&mpk, &keypair.pk, &int_sig); +// let proof_vs = clsigs::vs_gen_nizk_proof(&m1, &common_params, common_params.vx); +// assert!(clsigs::vs_verify_blind_sig(&mpk, &keypair.pk, &proof_vs, &blind_sigs)); +// +// println!("Verified blind signature!"); + println!("******************************************"); - let b = keypair.pk.Z2.len(); - let mut bases: Vec = Vec::new(); - bases.push(mpk.g2); - for i in 0 .. b { - bases.push(keypair.pk.Z2[i]); - } - // generate sample commitment - let mut C = mpk.g2 * m1[0]; - for i in 0 .. b { - C = C + (keypair.pk.Z2[i] * m1[i+1]); - } - let proof = clsigs::bs_gen_nizk_proof(&m1, &bases, C); + println!("[1] libbolt - setup bidirecitonal scheme params"); + let pp = bidirectional::setup(); - let int_sig = clsigs::bs_gen_signature(&mpk, &keypair.sk, &proof); + // generate long-lived keypair for merchant -- used to identify + // it to all customers + println!("[2] libbolt - generate long-lived key pair for merchant"); + let merch_keypair = bidirectional::keygen(&pp); - println!("Generated signature interactively!"); - // int_sig = interactively generated signature - assert!(clsigs::verifyD(&mpk, &keypair.pk, &m1, &int_sig) == true); + // customer gnerates an ephemeral keypair for use on a single channel + println!("[3] libbolt - generate ephemeral key pair for customer (use with one channel)"); + let cust_keypair = bidirectional::keygen(&pp); - println!("Verified interactively produced signature!"); + // bidirectional::init_merchant_state(); - let blind_sigs = clsigs::prover_generate_blinded_sig(&int_sig); - let common_params = clsigs::gen_common_params(&mpk, &keypair.pk, &int_sig); - let proof_vs = clsigs::vs_gen_nizk_proof(&m1, &common_params, common_params.vx); - assert!(clsigs::vs_verify_blind_sig(&mpk, &keypair.pk, &proof_vs, &blind_sigs)); + println!("[4] libbolt - generate the channel identifier"); + let b0_cust = 10; + let b0_merch = 15; + let cid = bidirectional::generate_channel_id(); + let mut msg = "Open Channel ID: "; + libbolt::debug_elem_in_hex(msg, &cid); - println!("Verified blind signature!"); + // each party executes the init algorithm on the agreed initial challence balance + // in order to derive the channel tokens + println!("[5a] libbolt - initialize on the customer side with balance {}", b0_cust); + let mut init_cust_data = bidirectional::init_customer(&pp, cid, b0_cust, &cust_keypair); -// 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!("******************************************"); + println!("[5b] libbolt - initialize on the merchant side with balance {}", b0_merch); + let mut init_merch_data = bidirectional::init_merchant(&pp, b0_merch, &merch_keypair); - // TODO: write tests + println!("[6a] libbolt - entering the establish protocol for the channel"); + let proof1 = bidirectional::establish_customer_phase1(&pp, &init_cust_data); + + println!("[6b] libbolt - obtain the wallet signature from the merchant"); + let wallet_sig = bidirectional::establish_merchant_phase2(&pp, &init_merch_data, &proof1); + + println!("[6c] libbolt - complete channel establishment"); + let is_established = bidirectional::establish_customer_phase3(wallet_sig, &mut init_cust_data.csk); + + assert!(is_established); + + println!("Channel has been established! Woohoo!"); } diff --git a/docs/bolt_design.tex b/docs/bolt_design.tex index df9833f..f9e250f 100644 --- a/docs/bolt_design.tex +++ b/docs/bolt_design.tex @@ -528,7 +528,7 @@ The bidirectional payment construction enables compact closure and compact walle \item Customer generates wallet commitment by sampling random coins $r$. \item Compute ephemeral keypair $(wpk, wsk) \leftarrow {\sf KeyGen}({\sf PP})$. \item Compute ${\sf wCom} = {\sf Commit}({\sf cID}, wpk, \BC; r)$. -\item For $i = 1$ to $\BC$, sample $ck_i \rightarrow {\sf SymKeyGen}(1^\lambda)$ to form the vector $\vec{ck}$. +%\item For $i = 1$ to $\BC$, sample $ck_i \rightarrow {\sf SymKeyGen}(1^\lambda)$ to form the vector $\vec{ck}$. \item Output ${\sf T}_{\sf c} = (pk_c, {\sf wCom})$ and retains secret $csk_{\sf c} = (sk_c, {\sf cID}, wpk, wsk, r, \BC)$. \end{itemize} diff --git a/src/clsigs.rs b/src/clsigs.rs index 0c51380..cb9b825 100644 --- a/src/clsigs.rs +++ b/src/clsigs.rs @@ -188,7 +188,7 @@ pub fn setupD() -> PublicParams { return mpk; } -pub fn keygenD(mpk : &PublicParams, l: i32) -> KeyPairD { +pub fn keygenD(mpk : &PublicParams, l: usize) -> KeyPairD { let rng = &mut rand::thread_rng(); let x = Fr::random(rng); let y = Fr::random(rng); @@ -342,8 +342,8 @@ pub fn bs_gen_nizk_proof(x: &Vec, pub_bases: &Vec, C: G2) -> ProofCV { // hash T to get the challenge let c = hashG2ToFr(&T); - //let msg = "challenge -> c"; - //debug_elem_in_hex(msg, &c); + let msg = "challenge -> c"; + debug_elem_in_hex(msg, &c); // compute s values let mut s: Vec = Vec::new(); @@ -368,8 +368,8 @@ pub fn bs_gen_signature(mpk: &PublicParams, sk: &SecretKeyD, proof: &ProofCV) -> fn part1_verify_proof(proof: &ProofCV) -> bool { // if proof is valid, then call part let c = hashG2ToFr(&proof.T); - //let mut msg = "(in verify proof) challenge -> c"; - //debug_elem_in_hex(msg, &c); + let mut msg = "(in verify proof) challenge -> c"; + debug_elem_in_hex(msg, &c); let l = proof.s.len(); assert!(l > 1); @@ -379,12 +379,12 @@ fn part1_verify_proof(proof: &ProofCV) -> bool { //println!("(in verify proof) i => {}", i); lhs = lhs + (proof.pub_bases[i] * proof.s[i]); } - //msg = "(in verify proof) lhs => "; - //debug_g2_in_hex(msg, &lhs); + msg = "(in verify proof) lhs => "; + debug_g2_in_hex(msg, &lhs); let rhs = (proof.C * c) + proof.T; - //msg = "(in verify proof) rhs => "; - //debug_g2_in_hex(msg, &rhs); + msg = "(in verify proof) rhs => "; + debug_g2_in_hex(msg, &rhs); return lhs == rhs; } diff --git a/src/commit_scheme.rs b/src/commit_scheme.rs index 05eed7d..76dea9e 100644 --- a/src/commit_scheme.rs +++ b/src/commit_scheme.rs @@ -26,8 +26,7 @@ pub struct Commitment { #[derive(Clone)] pub struct CSParams { - pub_bases: Vec, - h: G2 + pub pub_bases: Vec } impl fmt::Display for PublicKey { @@ -126,29 +125,35 @@ Implements the setup algorithm for the Pedersen92 commitment scheme over a vector of messages. */ -pub fn setup(len: usize, pub_bases: Option>) -> CSParams { +pub fn setup(len: usize, pub_bases: Vec, h: G2) -> CSParams { let rng = &mut rand::thread_rng(); - let h = G2::random(rng); - if pub_bases.is_none() { - let mut p: Vec = Vec::new(); - for i in 0 .. len { - p.push(G2::random(rng)); - } - return CSParams { pub_bases: p, h: h }; - } + //let base_h = h.unwrap_or(G2::random(rng)); + let mut p: Vec = Vec::new(); + p.push(h); - let p = pub_bases.unwrap(); - assert_eq!(p.len(), len); - return CSParams { pub_bases: p, h: h }; +// if pub_bases.is_none() { +// for i in 1 .. len-1 { +// p.push(G2::random(rng)); +// } +// return CSParams { pub_bases: p }; +// } + + let _p = pub_bases; + for i in 0 .. _p.len() { + p.push(_p[i]); + } + return CSParams { pub_bases: p }; } -pub fn commit(csp: &CSParams, x: &Vec, R: Option) -> Commitment { +pub fn commit(csp: &CSParams, x: &Vec, r: Fr) -> Commitment { let rng = &mut rand::thread_rng(); - let r = R.unwrap_or(Fr::random(rng)); + //let r = R.unwrap_or(Fr::random(rng)); // c = g1^m1 * ... * gn^mn * h^r - let mut c = (csp.h * r); - for i in 0 .. x.len() { + //println!("(commit) index: 0"); + let mut c = (csp.pub_bases[0] * r); + for i in 1 .. x.len() { + //println!("(commit) index: {}", i); c = c + (csp.pub_bases[i] * x[i]); } // return (c, r) <- r @@ -160,10 +165,12 @@ pub fn commit(csp: &CSParams, x: &Vec, R: Option) -> Commitment { } pub fn decommit(csp: &CSParams, cm: &Commitment, x: &Vec) -> bool { - let mut dc = (csp.h * cm.r); + //let mut dc = (csp.h * cm.r); let l = x.len(); - assert!(csp.pub_bases.len() == l); - for i in 0 .. l { + //assert!(csp.pub_bases.len() == l); + // pub_base[0] => h, x[0] => r + let mut dc = csp.pub_bases[0] * cm.r; + for i in 1 .. l { dc = dc + (csp.pub_bases[i] * x[i]); } return dc == cm.c; diff --git a/src/lib.rs b/src/lib.rs index 2728d95..9bb414c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -780,9 +780,9 @@ pub mod bidirectional { use secp256k1; // ::{Secp256k1, PublicKey, SecretKey}; pub struct PublicParams { - cm_csp: commit_scheme::CSParams, + // cm_csp: commit_scheme::CSParams, cl_mpk: clsigs::PublicParams, - l_bits: i32 + l: usize // messages for committment // TODO: add NIZK proof system pub params } @@ -791,14 +791,15 @@ pub mod bidirectional { pk: clsigs::PublicKeyD } - pub struct CustSecretKey { + pub struct CustomerWallet { sk: clsigs::SecretKeyD, // the secret key for the signature scheme (Is it possible to make this a generic field?) cid: Fr, // channel Id wpk: secp256k1::PublicKey, // signature verification key wsk: secp256k1::SecretKey, // signature signing key r: Fr, // random coins for commitment scheme balance: i32, // the balance for the user - ck_vec: Vec + signature: Option + // ck_vec: Vec } pub struct MerchSecretKey { @@ -807,32 +808,38 @@ pub mod bidirectional { } pub struct InitCustomerData { - T: ChannelToken, - csk: CustSecretKey + pub T: ChannelToken, + pub csk: CustomerWallet, + pub bases: Vec } pub struct InitMerchantData { - T: clsigs::PublicKeyD, - csk: MerchSecretKey + pub T: clsigs::PublicKeyD, + pub csk: MerchSecretKey } pub fn setup() -> PublicParams { // TODO: provide option for generating CRS parameters - let cm_pp = commit_scheme::setup(3, None); + //let cm_pp = commit_scheme::setup(3, None); let cl_mpk = clsigs::setupD(); - let l = 256; + let l = 3; // let nizk = "nizk proof system"; - let pp = PublicParams { cm_csp: cm_pp, cl_mpk: cl_mpk, l_bits: l }; + let pp = PublicParams { cl_mpk: cl_mpk, l: l }; // cm_csp: cm_pp, return pp; } pub fn keygen(pp: &PublicParams) -> clsigs::KeyPairD { // TODO: figure out what we need from public params to generate keys println!("Run Keygen..."); - let keypair = clsigs::keygenD(&pp.cl_mpk, 3); + let keypair = clsigs::keygenD(&pp.cl_mpk, pp.l); return keypair; } + pub fn generate_channel_id() -> Fr { + let rng = &mut rand::thread_rng(); + return Fr::random(rng); + } + pub fn init_customer(pp: &PublicParams, channelId: Fr, b0_customer: i32, keypair: &clsigs::KeyPairD) -> InitCustomerData { println!("Run Init customer..."); sym::init(); @@ -853,24 +860,23 @@ pub mod bidirectional { let r = Fr::random(rng); //let msg = Message::new(keypair.sk, k1, k2, b0_customer).hash(); - let mut ck_vec: Vec = Vec::new(); - // generate the vector ck of sym keys - for i in 1 .. b0_customer { - let ck = sym::keygen(l); - ck_vec.push(ck); - } + let b = keypair.pk.Z2.len(); + let bases = keypair.pk.Z2.clone(); + let cm_csp = commit_scheme::setup(pp.l, bases, pp.cl_mpk.g2); let mut x: Vec = Vec::new(); + x.push(r); // set randomness for commitment x.push(channelId); x.push(h_wpk); x.push(b0); // TODO: hash (wpk) and convert b0_customer into Fr - let w_com = commit_scheme::commit(&pp.cm_csp, &x, Some(r)); + let w_com = commit_scheme::commit(&cm_csp, &x, r); + let t_c = ChannelToken { w_com: w_com, pk: keypair.pk.clone() }; - let csk_c = CustSecretKey { sk: keypair.sk.clone(), cid: channelId, wpk: wpk, wsk: wsk, - r: r, balance: b0_customer, ck_vec: ck_vec }; - return InitCustomerData { T: t_c, csk: csk_c }; + let csk_c = CustomerWallet { sk: keypair.sk.clone(), cid: channelId, wpk: wpk, wsk: wsk, + r: r, balance: b0_customer, signature: None }; + return InitCustomerData { T: t_c, csk: csk_c, bases: cm_csp.pub_bases }; } pub fn init_merchant(pp: &PublicParams, b0_merchant: i32, keypair: &clsigs::KeyPairD) -> InitMerchantData { @@ -879,45 +885,49 @@ pub mod bidirectional { return InitMerchantData { T: keypair.pk.clone(), csk: csk_m }; } - // TODO: requires NIZK proof system - pub fn establish_customer(pp: &PublicParams, t_m: &clsigs::PublicKeyD, c_data: &InitCustomerData) -> clsigs::ProofCV { + pub fn establish_customer_phase1(pp: &PublicParams, c_data: &InitCustomerData) -> clsigs::ProofCV { println ! ("Run establish_customer algorithm..."); - // set sk_0 to random bytes of length l - // let sk_0 = random_bytes(pp.l); - let buf_len: usize = pp.l_bits as usize; - let mut sk0 = vec![0; buf_len]; - randombytes::randombytes_into(&mut sk0); - // obtain customer init data let t_c = &c_data.T; let csk_c = &c_data.csk; + let pub_bases = &c_data.bases; let h_wpk = hashPubKeyToFr(&csk_c.wpk); let b0 = Fr::from_str(csk_c.balance.to_string().as_str()).unwrap(); // collect secrets let mut x: Vec = Vec::new(); + x.push(t_c.w_com.r); // set randomness used to generate commitment x.push(csk_c.cid); x.push(h_wpk); x.push(b0); - // collect bases - let mut pub_bases: Vec = Vec::new(); let proof_1 = clsigs::bs_gen_nizk_proof(&x, &pub_bases, t_c.w_com.c); return proof_1; } // the merchant calls this method after obtaining - pub fn estalibsh_merchant(proof: &clsigs::ProofCV) { + pub fn establish_merchant_phase2(pp: &PublicParams, m_data: &InitMerchantData, proof: &clsigs::ProofCV) -> clsigs::SignatureD { + // verifies proof and produces + let wallet_sig = clsigs::bs_gen_signature(&pp.cl_mpk, &m_data.csk.sk, &proof); + return wallet_sig; + } + pub fn establish_customer_phase3(sig: clsigs::SignatureD, wallet: &mut CustomerWallet) -> bool { + if wallet.signature.is_none() { + wallet.signature = Some(sig); + return true; + } + return false; } // TODO: requires NIZK proof system calls - pub fn pay_by_customer() { + pub fn payment_by_customer_phase1(pp: &PublicParams, old_w: &CustomerWallet) { println!("Run pay algorithm by Customer - phase 1."); + } - pub fn pay_by_merchant() { - println!("Run pay algorithm by Merchant - phase 1"); + pub fn payment_by_merchant_phase2() { + println!("Run pay algorithm by Merchant - phase 2"); } // pub fn refund(pp: &PublicParams, imd : &InitMerchantData, w: Wallet) {