diff --git a/bin/bolt.rs b/bin/bolt.rs index cd96c9a..f332960 100644 --- a/bin/bolt.rs +++ b/bin/bolt.rs @@ -6,6 +6,7 @@ extern crate bincode; extern crate serde_derive; extern crate serde; extern crate time; +extern crate secp256k1; use std::fmt; use bn::{Group, Fr, G1, G2, pairing}; @@ -374,6 +375,31 @@ fn main() { println!("{} seconds for verifying valid signatures.", start1.to(end1)); println!("{} seconds for verifying invalid signatures.", end1.to(end2)); + let mut schnorr = secp256k1::Secp256k1::new(); + schnorr.randomize(rng); + let (wsk, wpk) = schnorr.generate_keypair(rng).unwrap(); + + let balance = 100; + let r = Fr::random(rng); + let cid = Fr::random(rng); + let rm1 = libbolt::RefundMessage::new("refundUnsigned", cid, wpk, balance, Some(&r), None).hash(); + + println!("RefundMessage => "); + for i in 0 .. rm1.len() { + let p = format!("rm1[{}] = ", i); + libbolt::debug_elem_in_hex(&p, &rm1[i]); + } + + let rm2 = libbolt::RefundMessage::new("refundToken", cid, wpk, balance+15, None, Some(&signature)).hash(); + println!("RefundMessage (token) => "); + for i in 0 .. rm2.len() { + let p = format!("rm2[{}] = ", i); + libbolt::debug_elem_in_hex(&p, &rm2[i]); + } + + assert!(clsigs::verifyD(&mpk, &keypair.pk, &m1, &signature) == true); + println!("All good in the hood!"); + // println!("******************************************"); // let b = keypair.pk.Z2.len(); @@ -432,45 +458,45 @@ fn main() { println!("******************************************"); - println!("[1] libbolt - setup bidirecitonal scheme params"); - let pp = bidirectional::setup(); - - // 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); - - // 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); - - // bidirectional::init_merchant_state(); - - 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); - - // 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); - - 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); - - 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!"); +// println!("[1] libbolt - setup bidirecitonal scheme params"); +// let pp = bidirectional::setup(); +// +// // 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); +// +// // 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); +// +// // bidirectional::init_merchant_state(); +// +// 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); +// +// // 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); +// +// 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); +// +// 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 f9e250f..e72400e 100644 --- a/docs/bolt_design.tex +++ b/docs/bolt_design.tex @@ -645,7 +645,7 @@ The customer obtains a new wallet $w_{\sf new} := (B - \epsilon, wpk', wsk', r', \begin{enumerate} \item If a merchant sees a channel closure message, it first parses ${\sf T}_{C}$ to obtain $pk_c$. \item Parse tuple $(m, \sigma) \leftarrow {\sf rc}_{C}$ -\item ${\sf Verify}(pk_c, \sigma) = 1$ or $\bot$ +\item ${\sf Verify}(pk_c, m, \sigma) = 1$ or $\bot$ \item If signature $\sigma$ verifies, then parse tuple $({\sf cID}, wpk, B) \leftarrow m$. \item Verify that {\sf cID} matches the channel. \item If previous record of $(wpk, \sigma_{rev}) \in {\bf S}$, then output ${\sf rc}_{M} = (({\sf revoked}, \sigma_{rev}), \sigma)$. diff --git a/src/clsigs.rs b/src/clsigs.rs index cb9b825..82151f1 100644 --- a/src/clsigs.rs +++ b/src/clsigs.rs @@ -97,9 +97,9 @@ impl fmt::Display for Signature { } } -// scheme A - for single messages +// scheme A - for a single message -pub fn setup_A() -> PublicParams { +pub fn setupA() -> PublicParams { let rng = &mut rand::thread_rng(); let g1 = G1::random(rng); let g2 = G2::random(rng); @@ -107,7 +107,7 @@ pub fn setup_A() -> PublicParams { return mpk; } -pub fn keygen_A(mpk : &PublicParams) -> KeyPair { +pub fn keygenA(mpk : &PublicParams) -> KeyPair { let rng = &mut rand::thread_rng(); let x = Fr::random(rng); let y = Fr::random(rng); @@ -118,7 +118,7 @@ pub fn keygen_A(mpk : &PublicParams) -> KeyPair { return KeyPair { sk: sk, pk: pk } } -pub fn sign_A(sk: &SecretKey, m: Fr) -> Signature { +pub fn signA(sk: &SecretKey, m: Fr) -> Signature { let rng = &mut rand::thread_rng(); let a = G2::random(rng); @@ -128,7 +128,7 @@ pub fn sign_A(sk: &SecretKey, m: Fr) -> Signature { return sig; } -pub fn verify_A(mpk: &PublicParams, pk: &PublicKey, m: Fr, sig: &Signature) -> bool { +pub fn verifyA(mpk: &PublicParams, pk: &PublicKey, m: Fr, sig: &Signature) -> bool { let lhs1 = pairing(pk.Y, sig.a); let rhs1 = pairing(mpk.g1, sig.b); let lhs2 = pairing(pk.X, sig.a) * (pairing(pk.X, sig.b).pow(m)); diff --git a/src/lib.rs b/src/lib.rs index 9bb414c..4ff0deb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use bincode::SizeLimit::Infinite; use bincode::rustc_serialize::{encode, decode}; use sodiumoxide::randombytes; use sodiumoxide::crypto::hash::sha512; +use std::collections::HashMap; pub mod prf; pub mod sym; @@ -472,51 +473,41 @@ pub fn print(g: &G1) -> String { ////////////////////////////////// SymKeyEnc /////////////////////////////////// -////////////////////////////////// CL Sigs ///////////////////////////////////// - -// refund message -#[derive(Clone)] -pub struct RefundMessage<'a> { - prefix: &'a str, // string prefix for the prefix - c_id: Fr, // uniquely identifies the - index: i32, // index - // ck: Fr, // TODO: l-bit key (from SymKeyEnc) -} - -impl<'a> RefundMessage<'a> { - pub fn new(_c_id: Fr, _index: i32) -> RefundMessage<'a> { - RefundMessage { - prefix: "refund", c_id: _c_id, index: _index, - } - } - - pub fn hash(&self) -> Fr { - let mut input_buf = Vec::new(); - input_buf.extend_from_slice(self.prefix.as_bytes()); - let c_id_vec: Vec = encode(&self.c_id, Infinite).unwrap(); - // encode cId in the vector - input_buf.extend(c_id_vec); - // encoee the balance as a hex string - let b = format!("{:x}", self.index); - input_buf.extend_from_slice(b.as_bytes()); - // TODO: add the ck vector (l-bit key) -// let mut in_str = String::new(); -// for y in input_buf.iter() { -// in_str = format!("{}{:x}", in_str, y); +// OLD RefundMessage +//impl<'a> RefundMessage<'a> { +// pub fn new(_c_id: Fr, _index: i32) -> RefundMessage<'a> { +// RefundMessage { +// prefix: "refund", c_id: _c_id, index: _index, // } -// println!("input_buf: {}", in_str); +// } +// +// pub fn hash(&self) -> Fr { +// let mut input_buf = Vec::new(); +// input_buf.extend_from_slice(self.prefix.as_bytes()); +// let c_id_vec: Vec = encode(&self.c_id, Infinite).unwrap(); +// // encode cId in the vector +// input_buf.extend(c_id_vec); +// // encoee the balance as a hex string +// let b = format!("{:x}", self.index); +// input_buf.extend_from_slice(b.as_bytes()); +// // TODO: add the ck vector (l-bit key) +//// let mut in_str = String::new(); +//// for y in input_buf.iter() { +//// in_str = format!("{}{:x}", in_str, y); +//// } +//// println!("input_buf: {}", in_str); +// +// // hash the inputs via SHA256 +// let sha2_digest = sha512::hash(input_buf.as_slice()); +// // println!("hash: {:?}", sha2_digest); +// // let h = format!("{:x}", HexSlice::new(&sha2_digest)); +// let mut hash_buf: [u8; 64] = [0; 64]; +// hash_buf.copy_from_slice(&sha2_digest[0..64]); +// return Fr::interpret(&hash_buf); +// } +//} - // hash the inputs via SHA256 - let sha2_digest = sha512::hash(input_buf.as_slice()); - // println!("hash: {:?}", sha2_digest); - // let h = format!("{:x}", HexSlice::new(&sha2_digest)); - let mut hash_buf: [u8; 64] = [0; 64]; - hash_buf.copy_from_slice(&sha2_digest[0..64]); - return Fr::interpret(&hash_buf); - } -} - -// spend message +// spend message (for unidirectional scheme) #[derive(Clone)] pub struct SpendMessage<'a> { prefix: &'a str, @@ -639,6 +630,87 @@ pub fn hashPubKeyToFr(wpk: &secp256k1::PublicKey) -> Fr { // return Fr::interpret(&hash_buf); //} +fn convertToFr(input_buf: &Vec) -> Fr { + // hash the inputs via SHA256 + let sha2_digest = sha512::hash(input_buf.as_slice()); + // println!("hash: {:?}", sha2_digest); + // let h = format!("{:x}", HexSlice::new(&sha2_digest)); + let mut hash_buf: [u8; 64] = [0; 64]; + hash_buf.copy_from_slice(&sha2_digest[0..64]); + return Fr::interpret(&hash_buf); +} + +// refund message +#[derive(Clone)] +pub struct RefundMessage<'a> { + prefix: &'a str, // string prefix for the prefix + cid: Fr, // channel identifier + wpk: secp256k1::PublicKey, + balance: usize, // the balance + r: Option<&'a Fr>, // randomness from customer wallet + rt: Option<&'a clsigs::SignatureD> // refund token +} + +impl<'a> RefundMessage<'a> { + pub fn new(_prefix: &'a str, _cid: Fr, _wpk: secp256k1::PublicKey, + _balance: usize, _r: Option<&'a Fr>, _rt: Option<&'a clsigs::SignatureD>) -> RefundMessage<'a> { + RefundMessage { + prefix: _prefix, cid: _cid, wpk: _wpk, balance: _balance, r: _r, rt: _rt + } + } + + pub fn hash(&self) -> Vec { + let mut v: Vec = Vec::new(); + let mut input_buf = Vec::new(); + input_buf.extend_from_slice(self.prefix.as_bytes()); + v.push(convertToFr(&input_buf)); + + v.push(self.cid.clone()); + + v.push(hashPubKeyToFr(&self.wpk)); + + // encoee the balance as a hex string + let b = format!("{:x}", self.balance); + let mut b_buf = Vec::new(); + b_buf.extend_from_slice(b.as_bytes()); + v.push(convertToFr(&b_buf)); + + //let r_vec: Vec = encode(&self.r, Infinite).unwrap(); + if (!self.r.is_none()) { + v.push(self.r.unwrap().clone()); + } + + if (!self.rt.is_none()) { + // TODO: compute hash over the signature contents + } + + return v; + } +} + +#[derive(Clone)] +pub struct RevokedMessage<'a> { + prefix: &'a str, + sig: clsigs::SignatureD +} + +impl<'a> RevokedMessage<'a> { + pub fn new(_prefix: &'a str, _sig: clsigs::SignatureD) -> RevokedMessage<'a> { + RevokedMessage { + prefix: _prefix, sig: _sig + } + } + + pub fn hash(&self) -> Vec { + let mut v: Vec = Vec::new(); + let mut input_buf = Vec::new(); + input_buf.extend_from_slice(self.prefix.as_bytes()); + v.push(convertToFr(&input_buf)); + + // TODO: compute hash over the signature + return v; + } +} //pub fn create_nizk_proof_one(pp: &PublicParams, pk: &clsigs::PublicKeyD, sk: &clsigs::SecretKeyD) -> Proof { // let rng = &mut rand::thread_rng(); @@ -656,10 +728,6 @@ pub fn hashPubKeyToFr(wpk: &secp256k1::PublicKey) -> Fr { // return Proof { T: T, c: c, s1: s1, s2: s2 }; //} -pub fn verify_nizk_proof_one(proof: &Proof) -> bool { - // how do we verify the proof? - return true; -} ////////////////////////////////// NIZKP ////////////////////////////////// //pub mod unidirectional { @@ -778,6 +846,8 @@ pub mod bidirectional { use hashPubKeyToFr; use sodiumoxide::randombytes; use secp256k1; // ::{Secp256k1, PublicKey, SecretKey}; + use RefundMessage; + use RevokedMessage; pub struct PublicParams { // cm_csp: commit_scheme::CSParams, @@ -799,11 +869,10 @@ pub mod bidirectional { r: Fr, // random coins for commitment scheme balance: i32, // the balance for the user signature: Option - // ck_vec: Vec } pub struct MerchSecretKey { - sk: clsigs::SecretKeyD, + sk: clsigs::SecretKeyD, // merchant signing key balance: i32 } @@ -818,6 +887,22 @@ pub mod bidirectional { pub csk: MerchSecretKey } + pub struct ChannelState { + //pub pub_keys: HashMap, + pub cid: Fr, + pub pay_init: bool + } + + pub struct ChannelClosure_C<'a> { + message: RefundMessage<'a>, + signature: clsigs::SignatureD + } + + pub struct ChannelClosure_M<'a> { + message: RevokedMessage<'a>, + signature: clsigs::SignatureD + } + pub fn setup() -> PublicParams { // TODO: provide option for generating CRS parameters //let cm_pp = commit_scheme::setup(3, None); @@ -842,7 +927,6 @@ pub mod bidirectional { pub fn init_customer(pp: &PublicParams, channelId: Fr, b0_customer: i32, keypair: &clsigs::KeyPairD) -> InitCustomerData { println!("Run Init customer..."); - sym::init(); let rng = &mut rand::thread_rng(); // pick two distinct seeds let l = 256; @@ -905,16 +989,17 @@ pub mod bidirectional { return proof_1; } - // the merchant calls this method after obtaining - pub fn establish_merchant_phase2(pp: &PublicParams, m_data: &InitMerchantData, proof: &clsigs::ProofCV) -> clsigs::SignatureD { + // the merchant calls this method after obtaining proof from the customer + 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); + pub fn establish_customer_phase3(sig: clsigs::SignatureD, w: &mut CustomerWallet) -> bool { + if w.signature.is_none() { + w.signature = Some(sig); return true; } return false; @@ -930,15 +1015,85 @@ pub mod bidirectional { println!("Run pay algorithm by Merchant - phase 2"); } -// pub fn refund(pp: &PublicParams, imd : &InitMerchantData, w: Wallet) { -// println!("Run Refund..."); -// } -// -// pub fn refute() { -// println!("Run Refute..."); -// } -// -// pub fn resolve() { -// println!("Run Resolve..."); -// } + // for customer => on input a wallet w, it outputs a customer channel closure message rc_c + pub fn refund<'a>(pp: &PublicParams, state: &ChannelState, m_data: &InitMerchantData, + c_data: &InitCustomerData, w: &'a CustomerWallet) -> ChannelClosure_C<'a> { + println!("Run Refund..."); + let mut m; + let balance = w.balance as usize; + if state.pay_init { + // if channel has already been activated, then take unspent funds + m = RefundMessage::new("refundToken", state.cid, w.wpk, balance, Some(&w.r), None); + } else { + // pay protocol not invoked so take the balane + //let rng = &mut rand::thread_rng(); + // let rt // TODO: replace with the H(rt_w) signature from pay protocol + m = RefundMessage::new("refundUnsigned", state.cid, w.wpk, balance, None, None); + } + + // generate signature on the balance/channel id, etc to obtain funds back + let m_vec = m.hash(); + let sigma = clsigs::signD(&w.sk, &m_vec); + return ChannelClosure_C { message: m, signature: sigma }; + } + + fn exist_in_merchant_state(s: &ChannelState, wpk: &secp256k1::PublicKey, sig_rev: &clsigs::SignatureD) -> bool { + // TODO: check the database for the fingerprint for the wpk + sig? + return true; + } + + fn update_merchant_state(s: &mut ChannelState, wpk: &secp256k1::PublicKey) -> bool { + // TODO: implement this method to update channel state db with current public key hash? + return true; + } + + // for merchant => on input the merchant's current state S_old and a customer channel closure message, + // outputs a merchant channel closure message rc_m and updated merchant state S_new + pub fn refute<'a>(pp: &PublicParams, T_c: &ChannelToken, m_data: &InitMerchantData, + state: &mut ChannelState, rc_c: ChannelClosure_C<'a>) -> Option> { + println!("Run Refute..."); + + let is_valid = clsigs::verifyD(&pp.cl_mpk, &T_c.pk, &rc_c.message.hash(), &rc_c.signature); + if is_valid { + let wpk = rc_c.message.wpk; + let sig_rev = rc_c.signature; // TODO: change to \sigma_rev + let balance = rc_c.message.balance; + if exist_in_merchant_state(&state, &wpk, &sig_rev) { + let rm = RevokedMessage::new("revoked", sig_rev); + let signature = clsigs::signD(&m_data.csk.sk, &rm.hash()); + return Some(ChannelClosure_M { message: rm, signature: signature }); + } else { + // update state to include the user's wallet key + assert!(update_merchant_state(state, &wpk)); + return None; + } + } else { + panic!("Signature on customer closure message is invalid!"); + } + } + + // on input th ecustmomer and merchant channel tokens T_c, T_m + // along with closure messages rc_c, rc_m + pub fn resolve<'a>(pp: &PublicParams, c: &InitCustomerData, m: &InitMerchantData, // cust and merch + rc_c: Option>, rc_m: Option>) -> (i32, i32) { + println!("Run Resolve..."); + let b_total = c.csk.balance + m.csk.balance; + if (rc_c.is_none() && rc_m.is_none()) { + panic!("Did not specify channel closure messages for either customer or merchant!"); + } + + if rc_c.is_none() { + return (0, 0); + } + + let pk_c = &c.T.pk; + let w_com = &c.T.w_com; + + let pk_m = &m.T; + + let rc_cust = rc_c.unwrap(); + //clsigs::verifyD(&pp.cl_mpk); + + return (b_total, 0); + } }