From 6622e4cbf4e5a5f9fbdc0d5c055d6a9ea6fa55b4 Mon Sep 17 00:00:00 2001 From: "J. Ayo Akinyele" Date: Fri, 4 Oct 2019 10:32:49 -0400 Subject: [PATCH 1/6] adding routines for intermediaries --- src/lib.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0befdc9..64a92c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -303,8 +303,40 @@ pub mod bidirectional { } /// - /// Verify third party payment proof from two bi-directional channel payments with intermediary + /// Verify third party payment proof from two bi-directional channel payments with intermediary (payment amount /// + pub fn verify_multiple_payment_proofs(csprng: &mut R, + channel_state_sender: &ChannelState, + channel_state_receiver: &ChannelState, + sender_payment: &Payment, + receiver_payment: &Payment, + merch_state: &mut MerchantState) + -> (Option>, Option>) { + let tx_fee = channel_state_sender.get_channel_fee() + channel_state_receiver.get_channel_fee(); + let amount = sender_payment.amount + receiver_payment.amount; + if (amount != 0) { // we want to check this relation in ZK without knowing the amount + println!("payments do not offset"); + return (None, None); + } + + let payment_amount= match tx_fee > 0 { + true => sender_payment.amount + tx_fee, + false => sender_payment.amount + }; + + let new_close_token = merch_state.verify_payment(csprng, &channel_state_sender, + &sender_payment.proof, &sender_payment.com, &sender_payment.wpk, payment_amount).unwrap(); + + let cond_close_token = merch_state.verify_payment(csprng, &channel_state_receiver, + &receiver_payment.proof, &receiver_payment.com, &sender_payment.wpk, -payment_amount).unwrap(); + + // store the wpk since it has been revealed + update_merchant_state(&mut merch_state.keys, &sender_payment.wpk, None); + update_merchant_state(&mut merch_state.keys, &receiver_payment.wpk, None); + + return (Some(new_close_token), Some(cond_close_token)); + } + // pub fn verify_third_party_payment(pp: &PublicParams, fee: i64, proof1: &BalanceProof, proof2: &BalanceProof) -> bool { // if proof1.third_party && proof2.third_party { // let vcom1 = &proof1.proof_vcom.as_ref().unwrap(); @@ -817,6 +849,60 @@ mod tests { } + #[test] + fn intermediary_payment_basics_works() { + println!("Intermediary test..."); + let mut rng = &mut rand::thread_rng(); + + let b0_alice = rng.gen_range(100, 1000); + let b0_bob = rng.gen_range(100, 1000); + let b0_merch = 100; + let mut channel_state = bidirectional::ChannelState::::new(String::from("New Channel State"), true); + + let merch_name = "Hub"; + // each party executes the init algorithm on the agreed initial challenge balance + // in order to derive the channel tokens + // initialize on the merchant side with balance: b0_merch + let (mut channel_token, mut merch_state, mut channel_state) = bidirectional::init_merchant(rng, &mut channel_state, merch_name); + + // initialize on the customer side with balance: b0_cust + let mut channel_token_alice = channel_token.clone(); + let mut channel_token_bob = channel_token.clone(); + + let mut alice_cust_state = bidirectional::init_customer(rng, &mut channel_token_alice, b0_alice, b0_merch, "Alice"); + + let mut bob_cust_state = bidirectional::init_customer(rng, &mut channel_token_bob, b0_bob, b0_merch, "Bob"); + + // run establish protocol for customer and merchant channel + let mut channel_state_alice = channel_state.clone(); + let mut channel_state_bob = channel_state.clone(); + + execute_establish_protocol_helper(&mut channel_state_alice, &mut channel_token_alice, b0_alice, b0_merch, &mut merch_state, &mut alice_cust_state); + execute_establish_protocol_helper(&mut channel_state_bob, &mut channel_token_bob, b0_bob, b0_merch, &mut merch_state, &mut bob_cust_state); + + assert!(channel_state_alice.channel_established); + assert!(channel_state_bob.channel_established); + + // run pay protocol - flow for third-party + + let amount = 30; + let (sender_payment, new_alice_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state_alice, &alice_cust_state, amount); + + let (receiver_payment, new_bob_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state_bob, &bob_cust_state, -amount); + + // TODO: figure out how to attach conditions on payment recipients close token that they must (1) produce revocation token for sender's old wallet and (2) must have channel open + + // intermediary executes the following on the two payment proofs + let (sender_close_token, receiver_cond_close_token) = bidirectional::verify_multiple_payment_proofs(rng, + &channel_state_alice, + &channel_state_bob, + &sender_payment, + &receiver_payment, + &mut merch_state); + + } + + // fn execute_third_party_pay_protocol_helper(pp: &bidirectional::PublicParams, // channel1: &mut bidirectional::ChannelState, channel2: &mut bidirectional::ChannelState, // merch_keys: &cl::KeyPairD, merch1_data: &mut bidirectional::InitMerchantData, From 34594fb77641291a70bf5c20afd51207cae76fae Mon Sep 17 00:00:00 2001 From: Gijs Van Laer Date: Thu, 10 Oct 2019 14:39:43 -0400 Subject: [PATCH 2/6] intermediary: fix verifying multiple payment proofs + add verifying multiple revoke tokens --- src/lib.rs | 239 ++++++++++++++--------------------------------------- 1 file changed, 63 insertions(+), 176 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 64a92c0..1d1af47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,77 +306,30 @@ pub mod bidirectional { /// Verify third party payment proof from two bi-directional channel payments with intermediary (payment amount /// pub fn verify_multiple_payment_proofs(csprng: &mut R, - channel_state_sender: &ChannelState, - channel_state_receiver: &ChannelState, + channel_state: &ChannelState, sender_payment: &Payment, receiver_payment: &Payment, merch_state: &mut MerchantState) - -> (Option>, Option>) { - let tx_fee = channel_state_sender.get_channel_fee() + channel_state_receiver.get_channel_fee(); + -> BoltResult<(cl::Signature, cl::Signature)> { + let tx_fee = channel_state.get_channel_fee(); let amount = sender_payment.amount + receiver_payment.amount; - if (amount != 0) { // we want to check this relation in ZK without knowing the amount - println!("payments do not offset"); - return (None, None); + if amount != 0 { // we want to check this relation in ZK without knowing the amount + return Err(String::from("payments do not offset")); } - let payment_amount= match tx_fee > 0 { - true => sender_payment.amount + tx_fee, - false => sender_payment.amount - }; + let new_close_token = merch_state.verify_payment(csprng, &channel_state, + &sender_payment.proof, &sender_payment.com, &sender_payment.wpk, sender_payment.amount + tx_fee).unwrap(); - let new_close_token = merch_state.verify_payment(csprng, &channel_state_sender, - &sender_payment.proof, &sender_payment.com, &sender_payment.wpk, payment_amount).unwrap(); - - let cond_close_token = merch_state.verify_payment(csprng, &channel_state_receiver, - &receiver_payment.proof, &receiver_payment.com, &sender_payment.wpk, -payment_amount).unwrap(); + let cond_close_token = merch_state.verify_payment(csprng, &channel_state, + &receiver_payment.proof, &receiver_payment.com, &receiver_payment.wpk, receiver_payment.amount + tx_fee).unwrap(); // store the wpk since it has been revealed update_merchant_state(&mut merch_state.keys, &sender_payment.wpk, None); update_merchant_state(&mut merch_state.keys, &receiver_payment.wpk, None); - return (Some(new_close_token), Some(cond_close_token)); + return Ok(Some((new_close_token, cond_close_token))); } -// pub fn verify_third_party_payment(pp: &PublicParams, fee: i64, proof1: &BalanceProof, proof2: &BalanceProof) -> bool { -// if proof1.third_party && proof2.third_party { -// let vcom1 = &proof1.proof_vcom.as_ref().unwrap(); -// let vcom2 = &proof2.proof_vcom.as_ref().unwrap(); -// let rproof1 = &proof1.proof_vrange.as_ref().unwrap(); -// let rproof2 = &proof2.proof_vrange.as_ref().unwrap(); -// let pc_gens1 = PedersenGens::default(); -// let pc_gens2 = PedersenGens::default(); -// let mut transcript1 = Transcript::new(b"Range Proof for Balance Increment"); -// let range_proof1_valid = rproof1.range_proof.0.verify_single(&pp.bp_gens, &pc_gens1, -// &mut transcript1, -// &rproof1.range_proof.1, -// pp.range_proof_bits).is_ok(); -// -// let mut transcript2 = Transcript::new(b"Range Proof for Balance Increment"); -// let range_proof2_valid = rproof2.range_proof.0.verify_single(&pp.bp_gens, &pc_gens2, -// &mut transcript2, -// &rproof2.range_proof.1, -// pp.range_proof_bits).is_ok(); -// -// let len = vcom1.pub_bases.len(); -// assert!(len >= 2 && vcom1.pub_bases.len() == vcom2.pub_bases.len()); -// -// // g^(e1 + -e2 + fee) * h^(r1 + r2) ==> should be equal to g^(fee) * h^(r1 + r2) -// // lets add commitments for vcom1 and vcom2 to check -// let added_commits = vcom1.C + vcom2.C; -// let tx_fee = vcom1.pub_bases[1] * -convert_int_to_fr(fee); -// // compute h^r1 + r2 -// let h_r1_r2 = (vcom1.pub_bases[0] * proof1.vcom.unwrap().r) + -// (vcom2.pub_bases[0] * proof2.vcom.unwrap().r) + tx_fee; -// -// let is_pay_plus_fee = added_commits == h_r1_r2; -// return clproto::bs_verify_nizk_proof(&vcom1) && -// clproto::bs_verify_nizk_proof(&vcom2) && -// range_proof1_valid && range_proof2_valid && -// is_pay_plus_fee; -// } -// panic!("verify_third_party_payment - third-party payment not enabled for both proofs"); -// } - /// /// generate_revoke_token (phase 2) - takes as input the public params, old wallet, new wallet, @@ -396,8 +349,8 @@ pub mod bidirectional { } /// - /// verify_revoke_token (phase 2) - takes as input revoke message and signature, - /// merchant state, from the customer. If the revocation token is valid, + /// verify_revoke_token (phase 2) - takes as input revoke message and signature + /// from the customer and the merchant state. If the revocation token is valid, /// generate a new signature for the new wallet (from the PoK of committed values in new wallet). /// pub fn verify_revoke_token(rt: &RevokeToken, merch_state: &mut MerchantState) -> BoltResult> { @@ -410,6 +363,26 @@ pub mod bidirectional { Ok(Some(new_pay_token)) } + /// + /// verify_multiple_revoke_tokens (phase 2) - takes as input revoke messages and signatures + /// from the sender and receiver and the merchant state of the intermediary. + /// If the revocation tokens are valid, generate new signatures for the new wallets of both + /// sender and receiver (from the PoK of committed values in new wallet). + /// + pub fn verify_multiple_revoke_tokens(rt_sender: &RevokeToken, rt_receiver: &RevokeToken, merch_state: &mut MerchantState) -> BoltResult<(cl::Signature, cl::Signature)> { + let pay_token_sender_result = merch_state.verify_revoke_token(&rt_sender.signature, &rt_sender.message, &rt_sender.message.wpk); + let pay_token_receiver_result = merch_state.verify_revoke_token(&rt_receiver.signature, &rt_receiver.message, &rt_receiver.message.wpk); + let new_pay_token_sender = match pay_token_sender_result { + Ok(n) => n, + Err(err) => return Err(String::from(err.to_string())) + }; + let new_pay_token_receiver = match pay_token_receiver_result { + Ok(n) => n, + Err(err) => return Err(String::from(err.to_string())) + }; + Ok(Some((new_pay_token_sender, new_pay_token_receiver))) + } + ///// end of pay protocol // for customer => on input a wallet w, it outputs a customer channel closure message @@ -595,7 +568,7 @@ mod tests { //let pk_h = hash_pubkey_to_fr::(&cust_state.pk_c.clone()); let pk_c = cust_state.get_public_key(); let option = bidirectional::establish_merchant_issue_close_token(rng, &channel_state, &com, &com_proof, &pk_c, - cust_balance, merch_balance, &merch_state); + cust_balance, merch_balance, &merch_state); let close_token = match option { Ok(n) => n.unwrap(), Err(e) => panic!("Failed - bidirectional::establish_merchant_issue_close_token(): {}", e) @@ -856,8 +829,11 @@ mod tests { let b0_alice = rng.gen_range(100, 1000); let b0_bob = rng.gen_range(100, 1000); - let b0_merch = 100; + let b0_merch_a = rng.gen_range(100, 1000); + let b0_merch_b = rng.gen_range(100, 1000); + let tx_fee = rng.gen_range(1, 5); let mut channel_state = bidirectional::ChannelState::::new(String::from("New Channel State"), true); + channel_state.set_channel_fee(tx_fee); let merch_name = "Hub"; // each party executes the init algorithm on the agreed initial challenge balance @@ -866,137 +842,48 @@ mod tests { let (mut channel_token, mut merch_state, mut channel_state) = bidirectional::init_merchant(rng, &mut channel_state, merch_name); // initialize on the customer side with balance: b0_cust - let mut channel_token_alice = channel_token.clone(); - let mut channel_token_bob = channel_token.clone(); + let mut alice_cust_state = bidirectional::init_customer(rng, &mut channel_token, b0_alice, b0_merch_a, "Alice"); - let mut alice_cust_state = bidirectional::init_customer(rng, &mut channel_token_alice, b0_alice, b0_merch, "Alice"); - - let mut bob_cust_state = bidirectional::init_customer(rng, &mut channel_token_bob, b0_bob, b0_merch, "Bob"); + let mut bob_cust_state = bidirectional::init_customer(rng, &mut channel_token, b0_bob, b0_merch_b, "Bob"); // run establish protocol for customer and merchant channel - let mut channel_state_alice = channel_state.clone(); - let mut channel_state_bob = channel_state.clone(); + //let mut channel_state_alice = channel_state.clone(); + //let mut channel_state_bob = channel_state.clone(); - execute_establish_protocol_helper(&mut channel_state_alice, &mut channel_token_alice, b0_alice, b0_merch, &mut merch_state, &mut alice_cust_state); - execute_establish_protocol_helper(&mut channel_state_bob, &mut channel_token_bob, b0_bob, b0_merch, &mut merch_state, &mut bob_cust_state); + execute_establish_protocol_helper(&mut channel_state, &mut channel_token, b0_alice, b0_merch_a, &mut merch_state, &mut alice_cust_state); + execute_establish_protocol_helper(&mut channel_state, &mut channel_token, b0_bob, b0_merch_b, &mut merch_state, &mut bob_cust_state); - assert!(channel_state_alice.channel_established); - assert!(channel_state_bob.channel_established); + assert!(channel_state.channel_established); + //assert!(channel_state_bob.channel_established); // run pay protocol - flow for third-party - let amount = 30; - let (sender_payment, new_alice_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state_alice, &alice_cust_state, amount); + let amount = rng.gen_range(5, 100); + let (sender_payment, new_alice_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state, &alice_cust_state, amount); - let (receiver_payment, new_bob_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state_bob, &bob_cust_state, -amount); + let (receiver_payment, new_bob_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state, &bob_cust_state, -amount); // TODO: figure out how to attach conditions on payment recipients close token that they must (1) produce revocation token for sender's old wallet and (2) must have channel open // intermediary executes the following on the two payment proofs - let (sender_close_token, receiver_cond_close_token) = bidirectional::verify_multiple_payment_proofs(rng, - &channel_state_alice, - &channel_state_bob, - &sender_payment, - &receiver_payment, - &mut merch_state); + let close_token_result = bidirectional::verify_multiple_payment_proofs(rng, &channel_state, &sender_payment, &receiver_payment, &mut merch_state); + let (alice_close_token, bob_cond_close_token) = handle_bolt_result!(close_token_result).unwrap(); + // both alice and bob generate a revoke token + let revoke_token_alice = bidirectional::generate_revoke_token(&channel_state, &mut alice_cust_state, new_alice_cust_state, &alice_close_token); + let revoke_token_bob = bidirectional::generate_revoke_token(&channel_state, &mut bob_cust_state, new_bob_cust_state, &bob_cond_close_token); + + // send both revoke tokens to intermediary and get pay-tokens in response + let new_pay_token_result: BoltResult<(cl::Signature,cl::Signature)> = bidirectional::verify_multiple_revoke_tokens(&revoke_token_alice, &revoke_token_bob, &mut merch_state); + let (new_pay_token_alice, new_pay_token_bob) = handle_bolt_result!(new_pay_token_result).unwrap(); + + // verify the pay tokens and update internal state + assert!(alice_cust_state.verify_pay_token(&channel_state, &new_pay_token_alice)); + assert!(bob_cust_state.verify_pay_token(&channel_state, &new_pay_token_bob)); + + println!("Successful payment with intermediary!"); } - -// fn execute_third_party_pay_protocol_helper(pp: &bidirectional::PublicParams, -// channel1: &mut bidirectional::ChannelState, channel2: &mut bidirectional::ChannelState, -// merch_keys: &cl::KeyPairD, merch1_data: &mut bidirectional::InitMerchantData, -// merch2_data: &mut bidirectional::InitMerchantData, -// cust1_keys: &cl::KeyPairD, cust1_data: &mut bidirectional::InitCustomerData, -// cust2_keys: &cl::KeyPairD, cust2_data: &mut bidirectional::InitCustomerData, -// payment_increment: i64) { -// // let's test the pay protocol -// bidirectional::pay_by_customer_phase1_precompute(&pp, &cust1_data.channel_token, &merch_keys.pk, &mut cust1_data.csk); -// bidirectional::pay_by_customer_phase1_precompute(&pp, &cust2_data.channel_token, &merch_keys.pk, &mut cust2_data.csk); -// -// println!("Channel 1 fee: {}", channel1.get_channel_fee()); -// let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel1, -// &cust1_data.channel_token, // channel token -// &merch_keys.pk, // merchant pub key -// &cust1_data.csk, // wallet -// payment_increment); // balance increment -// println!("Channel 2 fee: {}", channel2.get_channel_fee()); -// let (t_c2, new_wallet2, pay_proof2) = bidirectional::pay_by_customer_phase1(&pp, &channel2, -// &cust2_data.channel_token, // channel token -// &merch_keys.pk, // merchant pub key -// &cust2_data.csk, // wallet -// -payment_increment); // balance decrement -// -// // validate pay_proof1 and pay_proof2 (and the channel state for the fee paying channel, if fee > 0) -// let tx_fee = channel1.get_channel_fee() + channel2.get_channel_fee(); -// assert!(bidirectional::verify_third_party_payment(&pp, tx_fee, &pay_proof1.bal_proof, &pay_proof2.bal_proof)); -// -// // get the refund token (rt_w) -// let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, channel1, &pay_proof1, &merch1_data); -// -// // get the refund token (rt_w) -// let rt_w2 = bidirectional::pay_by_merchant_phase1(&pp, channel2, &pay_proof2, &merch2_data); -// -// // get the revocation token (rv_w) on the old public key (wpk) -// let rv_w1 = bidirectional::pay_by_customer_phase2(&pp, &cust1_data.csk, &new_wallet1, &merch_keys.pk, &rt_w1); -// -// // get the revocation token (rv_w) on the old public key (wpk) -// let rv_w2 = bidirectional::pay_by_customer_phase2(&pp, &cust2_data.csk, &new_wallet2, &merch_keys.pk, &rt_w2); -// -// // get the new wallet sig (new_wallet_sig) on the new wallet -// let new_wallet_sig1 = bidirectional::pay_by_merchant_phase2(&pp, channel1, &pay_proof1, merch1_data, &rv_w1); -// -// // get the new wallet sig (new_wallet_sig) on the new wallet -// let new_wallet_sig2 = bidirectional::pay_by_merchant_phase2(&pp, channel2, &pay_proof2, merch2_data, &rv_w2); -// -// assert!(bidirectional::pay_by_customer_final(&pp, &merch_keys.pk, cust1_data, t_c1, new_wallet1, rt_w1, new_wallet_sig1)); -// -// assert!(bidirectional::pay_by_customer_final(&pp, &merch_keys.pk, cust2_data, t_c2, new_wallet2, rt_w2, new_wallet_sig2)); -// } -// -// #[test] -// #[ignore] -// fn third_party_payment_basics_work() { -// let pp = bidirectional::setup(true); -// -// // third party -- so indicate so in the channel state -// let mut channel_a = bidirectional::ChannelState::new(String::from("Channel A <-> I"), true); -// let mut channel_b = bidirectional::ChannelState::new(String::from("Channel B <-> I"), true); -// -// let fee = 2; -// channel_a.set_channel_fee(fee); -// -// let total_payment = 20; -// let b0_alice = 30; -// let b0_bob = 30; -// let b0_merchant_a = 40; -// let b0_merchant_b = 40; -// -// let (merch_keys, mut merch_data_a, alice_keys, mut alice_data) = setup_new_channel_helper(&pp, &mut channel_a, b0_alice, b0_merchant_a); -// -// let (mut merch_data_b, bob_keys, mut bob_data) = -// setup_new_channel_existing_merchant_helper(&pp, &mut channel_b, b0_bob, b0_merchant_b, &merch_keys); -// -// // run establish protocol for alice and merchant channel -// execute_establish_protocol_helper(&pp, &mut channel_a, &merch_keys, &mut merch_data_a, &alice_keys, &mut alice_data); -// -// // run establish protocol for bob and merchant channel -// execute_establish_protocol_helper(&pp, &mut channel_b, &merch_keys, &mut merch_data_b, &bob_keys, &mut bob_data); -// -// assert!(channel_a.channel_established); -// assert!(channel_b.channel_established); -// -// // alice can pay bob through the merchant -// execute_third_party_pay_protocol_helper(&pp, &mut channel_a, &mut channel_b, -// &merch_keys, &mut merch_data_a, &mut merch_data_b, -// &alice_keys, &mut alice_data, &bob_keys, &mut bob_data, total_payment); -// -// println!("Customer alice balance: {}", alice_data.csk.balance); -// println!("Merchant channel balance with alice: {}", merch_data_a.csk.balance); -// println!("Customer bob balance: {}", bob_data.csk.balance); -// println!("Merchant channel balance with bob: {}", merch_data_b.csk.balance); -// } - #[test] fn serialization_tests() { let mut channel_state = bidirectional::ChannelState::::new(String::from("Channel A -> B"), false); From 1b640f0ca9a1b24ab5bbe245c23ff7e4549c3e36 Mon Sep 17 00:00:00 2001 From: Gijs Van Laer Date: Thu, 10 Oct 2019 14:45:33 -0400 Subject: [PATCH 3/6] intermediare: update_merchant_state after verifying multiple revoke tokens --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1d1af47..9b9fc51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -380,6 +380,10 @@ pub mod bidirectional { Ok(n) => n, Err(err) => return Err(String::from(err.to_string())) }; + + update_merchant_state(&mut merch_state.keys, &rt_sender.message.wpk, Some(rt_sender.signature.clone())); + update_merchant_state(&mut merch_state.keys, &rt_receiver.message.wpk, Some(rt_receiver.signature.clone())); + Ok(Some((new_pay_token_sender, new_pay_token_receiver))) } From b624dd875007998fff94f65a0b2236c080b40c51 Mon Sep 17 00:00:00 2001 From: Gijs Van Laer Date: Fri, 11 Oct 2019 12:55:30 -0400 Subject: [PATCH 4/6] intermediary: add the multi-verifications to go and python --- go/libbolt.go | 160 ++++++++++++++++++++++++++++++++++++---------- include/libbolt.h | 2 + py/libbolt.py | 18 ++++++ src/ffishim.rs | 116 +++++++++++++++++++++++---------- 4 files changed, 231 insertions(+), 65 deletions(-) diff --git a/go/libbolt.go b/go/libbolt.go index aa730c9..ec08337 100644 --- a/go/libbolt.go +++ b/go/libbolt.go @@ -10,29 +10,33 @@ import ( ) type setupResp struct { - ChannelState string `json:"channel_state"` - ChannelToken string `json:"channel_token"` - CustState string `json:"cust_state"` - MerchState string `json:"merch_state"` - Com string `json:"com"` - ComProof string `json:"com_proof"` - IsTokenValid bool `json:"is_token_valid,string"` - IsEstablished bool `json:"is_established,string"` - IsPayValid bool `json:"is_pay_valid,string"` - Payment string `json:"payment"` - CloseToken string `json:"close_token"` - RevokeToken string `json:"revoke_token"` - PayToken string `json:"pay_token"` - CustClose string `json:"cust_close"` - MerchClose string `json:"merch_close"` - Wpk string `json:"wpk"` - Error string `json:"error"` - Result string `json:"result"` + ChannelState string `json:"channel_state"` + ChannelToken string `json:"channel_token"` + CustState string `json:"cust_state"` + MerchState string `json:"merch_state"` + Com string `json:"com"` + ComProof string `json:"com_proof"` + IsTokenValid bool `json:"is_token_valid,string"` + IsEstablished bool `json:"is_established,string"` + IsPayValid bool `json:"is_pay_valid,string"` + Payment string `json:"payment"` + CloseToken string `json:"close_token"` + SenderCloseToken string `json:"sender_close_token"` + ReceiverCondCloseToken string `json:"receiver_cond_close_token"` + RevokeToken string `json:"revoke_token"` + PayToken string `json:"pay_token"` + SenderPayToken string `json:"sender_pay_token"` + ReceiverPayToken string `json:"receiver_pay_token"` + CustClose string `json:"cust_close"` + MerchClose string `json:"merch_close"` + Wpk string `json:"wpk"` + Error string `json:"error"` + Result string `json:"result"` } type ChannelState struct { R int `json:"R"` - TxFee int64 `json:"tx_fee"` + TxFee int64 `json:"tx_fee"` Cp interface{} `json:"cp"` Name string `json:"name"` PayInit bool `json:"pay_init"` @@ -41,7 +45,7 @@ type ChannelState struct { } type MerchState struct { - Id string `json:"id"` + Id string `json:"id"` KeyPair KeyPair `json:"keypair"` NizkParams interface{} `json:"nizkParams"` Pk string `json:"pk"` @@ -55,8 +59,8 @@ type CustState struct { Name string `json:"name"` PkC string `json:"pk_c"` SkC string `json:"sk_c"` - CustBalance int64 `json:"cust_balance"` - MerchBalance int64 `json:"merch_balance"` + CustBalance int64 `json:"cust_balance"` + MerchBalance int64 `json:"merch_balance"` Wpk string `json:"wpk"` Wsk string `json:"wsk"` OldKP *KP `json:"old_kp,omitempty"` @@ -80,8 +84,8 @@ type Commitment struct { type Wallet struct { Pkc []string `json:"pkc"` Wpk []string `json:"wpk"` - Bc int64 `json:"bc"` - Bm int64 `json:"bm"` + Bc int64 `json:"bc"` + Bm int64 `json:"bm"` Close []string `json:"close"` } @@ -95,6 +99,21 @@ type SecretKey struct { Y [][]string `json:"y"` } +type Payment struct { + Proof Proof `json:"proof"` + Com Commitment `json:"com"` + Wpk string `json:"wpk"` + Amount int64 `json:"amount"` +} + +type Proof struct { + Sig Signature `json:"sig"` + SigProof interface{} `json:"sigProof"` + ComProof CommitmentProof `json:"comProof"` + RangeProofBC interface{} `json:"rpBC"` + RangeProofBM interface{} `json:"rpBM"` +} + type PublicKey struct { X1 string `json:"X1"` X2 string `json:"X2"` @@ -331,7 +350,7 @@ func BidirectionalEstablishCustomerFinal(channelState ChannelState, custState Cu resp := C.GoString(C.ffishim_bidirectional_establish_customer_final(C.CString(string(serChannelState)), C.CString(string(serCustState)), C.CString(string(serPayToken)))) r, err := processCResponse(resp) if err != nil { - return false,ChannelState{}, CustState{}, err + return false, ChannelState{}, CustState{}, err } err = json.Unmarshal([]byte(r.ChannelState), &channelState) if err != nil { @@ -341,34 +360,43 @@ func BidirectionalEstablishCustomerFinal(channelState ChannelState, custState Cu return r.IsEstablished, channelState, custState, err } -func BidirectionalPayGeneratePaymentProof(channelState ChannelState, custState CustState, amount int) (string, CustState, error) { +func BidirectionalPayGeneratePaymentProof(channelState ChannelState, custState CustState, amount int) (Payment, CustState, error) { serChannelState, err := json.Marshal(channelState) if err != nil { - return "", CustState{}, err + return Payment{}, CustState{}, err } serCustState, err := json.Marshal(custState) if err != nil { - return "", CustState{}, err + return Payment{}, CustState{}, err } resp := C.GoString(C.ffishim_bidirectional_pay_generate_payment_proof(C.CString(string(serChannelState)), C.CString(string(serCustState)), C.longlong(amount))) r, err := processCResponse(resp) if err != nil { - return "", CustState{}, err + return Payment{}, CustState{}, err + } + payProof := Payment{} + err = json.Unmarshal([]byte(r.Payment), &payProof) + if err != nil { + return Payment{}, CustState{}, err } err = json.Unmarshal([]byte(r.CustState), &custState) - return r.Payment, custState, err + return payProof, custState, err } -func BidirectionalPayVerifyPaymentProof(channelState ChannelState, serPayProof string, merchState MerchState) (Signature, MerchState, error) { +func BidirectionalPayVerifyPaymentProof(channelState ChannelState, payProof Payment, merchState MerchState) (Signature, MerchState, error) { serChannelState, err := json.Marshal(channelState) if err != nil { return Signature{}, MerchState{}, err } + serPayProof, err := json.Marshal(payProof) + if err != nil { + return Signature{}, MerchState{}, err + } serMerchState, err := json.Marshal(merchState) if err != nil { return Signature{}, MerchState{}, err } - resp := C.GoString(C.ffishim_bidirectional_pay_verify_payment_proof(C.CString(string(serChannelState)), C.CString(serPayProof), C.CString(string(serMerchState)))) + resp := C.GoString(C.ffishim_bidirectional_pay_verify_payment_proof(C.CString(string(serChannelState)), C.CString(string(serPayProof)), C.CString(string(serMerchState)))) r, err := processCResponse(resp) if err != nil { return Signature{}, MerchState{}, err @@ -382,6 +410,42 @@ func BidirectionalPayVerifyPaymentProof(channelState ChannelState, serPayProof s return *closeToken, merchState, err } +func BidirectionalPayVerifyMultiplePaymentProofs(channelState ChannelState, senderPayProof Payment, receiverPayProof Payment, merchState MerchState) (Signature, Signature, MerchState, error) { + serChannelState, err := json.Marshal(channelState) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + serSenderPayProof, err := json.Marshal(senderPayProof) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + serReceiverPayProof, err := json.Marshal(receiverPayProof) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + serMerchState, err := json.Marshal(merchState) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + resp := C.GoString(C.ffishim_bidirectional_pay_verify_multiple_payment_proofs(C.CString(string(serChannelState)), C.CString(string(serSenderPayProof)), C.CString(string(serReceiverPayProof)), C.CString(string(serMerchState)))) + r, err := processCResponse(resp) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + err = json.Unmarshal([]byte(r.MerchState), &merchState) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + senderCloseToken := &Signature{} + err = json.Unmarshal([]byte(r.SenderCloseToken), senderCloseToken) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + receiverCondCloseToken := &Signature{} + err = json.Unmarshal([]byte(r.ReceiverCondCloseToken), receiverCondCloseToken) + return *senderCloseToken, *receiverCondCloseToken, merchState, err +} + func BidirectionalPayGenerateRevokeToken(channelState ChannelState, custState CustState, newCustState CustState, closeToken Signature) (RevokeToken, CustState, error) { serChannelState, err := json.Marshal(channelState) if err != nil { @@ -436,6 +500,38 @@ func BidirectionalPayVerifyRevokeToken(revokeToken RevokeToken, merchState Merch return *payToken, merchState, err } +func BidirectionalPayVerifyMultipleRevokeTokens(senderRevokeToken RevokeToken, receiverRevokeToken RevokeToken, merchState MerchState) (Signature, Signature, MerchState, error) { + serMerchState, err := json.Marshal(merchState) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + serSenderRevokeToken, err := json.Marshal(senderRevokeToken) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + serReceiverRevokeToken, err := json.Marshal(receiverRevokeToken) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + resp := C.GoString(C.ffishim_bidirectional_pay_verify_multiple_revoke_tokens(C.CString(string(serSenderRevokeToken)), C.CString(string(serReceiverRevokeToken)), C.CString(string(serMerchState)))) + r, err := processCResponse(resp) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + err = json.Unmarshal([]byte(r.MerchState), &merchState) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + senderPayToken := &Signature{} + err = json.Unmarshal([]byte(r.SenderPayToken), senderPayToken) + if err != nil { + return Signature{}, Signature{}, MerchState{}, err + } + receiverPayToken := &Signature{} + err = json.Unmarshal([]byte(r.ReceiverPayToken), receiverPayToken) + return *senderPayToken, *receiverPayToken, merchState, err +} + func BidirectionalPayVerifyPaymentToken(channelState ChannelState, custState CustState, payToken Signature) (CustState, bool, error) { serChannelState, err := json.Marshal(channelState) if err != nil { diff --git a/include/libbolt.h b/include/libbolt.h index 50fa513..df4e45d 100644 --- a/include/libbolt.h +++ b/include/libbolt.h @@ -30,8 +30,10 @@ char* ffishim_bidirectional_establish_customer_final(const char *ser_channel_sta // channel pay protocol routines char* ffishim_bidirectional_pay_generate_payment_proof(const char *ser_channel_state, const char *ser_customer_wallet, long long int amount); char* ffishim_bidirectional_pay_verify_payment_proof(const char *ser_channel_state, const char *ser_pay_proof, const char *ser_merch_state); +char* ffishim_bidirectional_pay_verify_multiple_payment_proofs(const char *ser_channel_state, const char *ser_sender_pay_proof, const char *ser_receiver_pay_proof, const char *ser_merch_state); char* ffishim_bidirectional_pay_generate_revoke_token(const char *ser_channel_state, const char *ser_cust_state, const char *ser_new_cust_state, const char *ser_close_token); char* ffishim_bidirectional_pay_verify_revoke_token(const char *ser_revoke_token, const char *ser_merch_state); +char* ffishim_bidirectional_pay_verify_multiple_revoke_tokens(const char *ser_sender_revoke_token, const char *ser_receiver_revoke_token, const char *ser_merch_state); char* ffishim_bidirectional_pay_verify_payment_token(const char *ser_channel_state, const char *ser_cust_state, const char *ser_pay_token); // closing routines for both sides diff --git a/py/libbolt.py b/py/libbolt.py index e754b20..d9a7f68 100644 --- a/py/libbolt.py +++ b/py/libbolt.py @@ -49,12 +49,18 @@ class Libbolt(object): self.lib.ffishim_bidirectional_pay_verify_payment_proof.argtypes = (c_void_p, c_void_p, c_void_p) self.lib.ffishim_bidirectional_pay_verify_payment_proof.restype = c_void_p + self.lib.ffishim_bidirectional_pay_verify_multiple_payment_proofs.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p) + self.lib.ffishim_bidirectional_pay_verify_multiple_payment_proofs.restype = c_void_p + self.lib.ffishim_bidirectional_pay_generate_revoke_token.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p) self.lib.ffishim_bidirectional_pay_generate_revoke_token.restype = c_void_p self.lib.ffishim_bidirectional_pay_verify_revoke_token.argtypes = (c_void_p, c_void_p) self.lib.ffishim_bidirectional_pay_verify_revoke_token.restype = c_void_p + self.lib.ffishim_bidirectional_pay_verify_multiple_revoke_tokens.argtypes = (c_void_p, c_void_p, c_void_p) + self.lib.ffishim_bidirectional_pay_verify_multiple_revoke_tokens.restype = c_void_p + self.lib.ffishim_bidirectional_pay_verify_payment_token.argtypes = (c_void_p, c_void_p) self.lib.ffishim_bidirectional_pay_verify_payment_token.restype = c_void_p @@ -136,6 +142,12 @@ class Libbolt(object): output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) return (output_dictionary.get('close_token'), output_dictionary.get('merch_state')) + # verify multiple payment proof + def bidirectional_pay_verify_multiple_payment_proofs(self, channel_state, sender_pay_proof, receiver_pay_proof, merch_state): + output_string = self.lib.ffishim_bidirectional_pay_verify_multiple_payment_proofs(channel_state.encode(), sender_pay_proof.encode(), receiver_pay_proof.encode(), merch_state.encode()) + output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) + return (output_dictionary.get('sender_close_token'), output_dictionary.get('receiver_cond_close_token'), output_dictionary.get('merch_state')) + # generate revoke token def bidirectional_pay_generate_revoke_token(self, channel_state, cust_state, new_cust_state, close_token): output_string = self.lib.ffishim_bidirectional_pay_generate_revoke_token(channel_state.encode(), cust_state.encode(), @@ -149,6 +161,12 @@ class Libbolt(object): output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) return (output_dictionary.get('pay_token'), output_dictionary.get('merch_state')) + # verify multiple revoke tokens + def bidirectional_pay_verify_multiple_revoke_tokens(self, sender_revoke_token, receiver_revoke_token, merch_state): + output_string = self.lib.ffishim_bidirectional_pay_verify_multiple_revoke_tokens(sender_revoke_token.encode(), receiver_revoke_token.encode(), merch_state.encode()) + output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) + return (output_dictionary.get('sender_pay_token'), output_dictionary.get('receiver_pay_token'), output_dictionary.get('merch_state')) + # verify payment token def bidirectional_pay_verify_payment_token(self, channel_state, cust_state, pay_token): output_string = self.lib.ffishim_bidirectional_pay_verify_payment_token(channel_state.encode(), cust_state.encode(), pay_token.encode()) diff --git a/src/ffishim.rs b/src/ffishim.rs index f8aaf3d..2aa5a98 100644 --- a/src/ffishim.rs +++ b/src/ffishim.rs @@ -4,7 +4,7 @@ pub mod ffishim { use bidirectional; use ff::Rand; - use pairing::bls12_381::{Bls12}; + use pairing::bls12_381::Bls12; use serde::Deserialize; @@ -56,8 +56,8 @@ pub mod ffishim { // } fn deserialize_result_object<'a, T>(serialized: *mut c_char) -> ResultSerdeType - where - T: Deserialize<'a>, + where + T: Deserialize<'a>, { let bytes = unsafe { CStr::from_ptr(serialized).to_bytes() }; let string: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8 @@ -66,8 +66,8 @@ pub mod ffishim { #[no_mangle] pub extern fn ffishim_free_string(pointer: *mut c_char) { - unsafe{ - if pointer.is_null() { return } + unsafe { + if pointer.is_null() { return; } CString::from_raw(pointer) }; } @@ -81,7 +81,6 @@ pub mod ffishim { let ser = ["{\'result\':\'", serde_json::to_string(&res).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() - } #[no_mangle] @@ -108,31 +107,31 @@ pub mod ffishim { let channel_state_result: ResultSerdeType> = deserialize_result_object(ser_channel_state); let mut channel_state = handle_errors!(channel_state_result); - let bytes = unsafe { CStr::from_ptr(name_ptr).to_bytes() }; - let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8 + let bytes = unsafe { CStr::from_ptr(name_ptr).to_bytes() }; + let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8 let (channel_token, merch_state, channel_state) = bidirectional::init_merchant(rng, &mut channel_state, name); - let ser = ["{\'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str(), "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str() ,"\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str() ,"\'}"].concat(); + let ser = ["{\'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str(), "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } #[no_mangle] - pub extern fn ffishim_bidirectional_init_customer(ser_channel_token: *mut c_char, balance_customer: i64, balance_merchant: i64, name_ptr: *const c_char) -> *mut c_char { + pub extern fn ffishim_bidirectional_init_customer(ser_channel_token: *mut c_char, balance_customer: i64, balance_merchant: i64, name_ptr: *const c_char) -> *mut c_char { let rng = &mut rand::thread_rng(); // Deserialize the channel token let channel_token_result: ResultSerdeType> = deserialize_result_object(ser_channel_token); let mut channel_token = handle_errors!(channel_token_result); // Deserialize the name - let bytes = unsafe { CStr::from_ptr(name_ptr).to_bytes() }; - let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8 + let bytes = unsafe { CStr::from_ptr(name_ptr).to_bytes() }; + let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8 // We change the channel state let cust_state = bidirectional::init_customer(rng, &mut channel_token, balance_customer, balance_merchant, name); - let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), "\', \'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str() ,"\'}"].concat(); + let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), "\', \'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -142,21 +141,21 @@ pub mod ffishim { #[no_mangle] // bidirectional::establish_customer_generate_proof(rng, &mut channel_token, &mut cust_state); pub extern fn ffishim_bidirectional_establish_customer_generate_proof(ser_channel_token: *mut c_char, ser_customer_state: *mut c_char) -> *mut c_char { let rng = &mut rand::thread_rng(); - // Deserialize the channel token + // Deserialize the channel token let channel_token_result: ResultSerdeType> = deserialize_result_object(ser_channel_token); let mut channel_token = handle_errors!(channel_token_result); // Deserialize the cust state let cust_state_result: ResultSerdeType> = deserialize_result_object(ser_customer_state); - let mut cust_state= handle_errors!(cust_state_result); + let mut cust_state = handle_errors!(cust_state_result); let (com, com_proof) = bidirectional::establish_customer_generate_proof(rng, &mut channel_token, &mut cust_state); let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), - "\', \'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str(), - "\', \'com\':\'", serde_json::to_string(&com).unwrap().as_str(), - "\', \'com_proof\':\'", serde_json::to_string(&com_proof).unwrap().as_str(), - "\'}"].concat(); + "\', \'channel_token\':\'", serde_json::to_string(&channel_token).unwrap().as_str(), + "\', \'com\':\'", serde_json::to_string(&com).unwrap().as_str(), + "\', \'com_proof\':\'", serde_json::to_string(&com_proof).unwrap().as_str(), + "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -203,7 +202,7 @@ pub mod ffishim { // Deserialize the commitment let com_result: ResultSerdeType> = deserialize_result_object(ser_com); - let com= handle_errors!(com_result); + let com = handle_errors!(com_result); // Deserialize the merchant state let merch_state_result: ResultSerdeType> = deserialize_result_object(ser_merch_state); @@ -221,7 +220,7 @@ pub mod ffishim { // Deserialize the channel state let channel_state_result: ResultSerdeType> = deserialize_result_object(ser_channel_state); let mut channel_state = handle_errors!(channel_state_result); - + // Deserialize the cust state let cust_state_result: ResultSerdeType> = deserialize_result_object(ser_customer_state); let mut cust_state = handle_errors!(cust_state_result); @@ -233,8 +232,8 @@ pub mod ffishim { let is_close_token_valid = cust_state.verify_close_token(&mut channel_state, &close_token); let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), - "\', \'is_token_valid\':\'", serde_json::to_string(&is_close_token_valid).unwrap().as_str(), - "\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'is_token_valid\':\'", serde_json::to_string(&is_close_token_valid).unwrap().as_str(), + "\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -257,8 +256,8 @@ pub mod ffishim { let is_channel_established = bidirectional::establish_customer_final(&mut channel_state, &mut cust_state, &pay_token); let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), - "\', \'is_established\':\'", serde_json::to_string(&is_channel_established).unwrap().as_str(), - "\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'is_established\':\'", serde_json::to_string(&is_channel_established).unwrap().as_str(), + "\', \'channel_state\':\'", serde_json::to_string(&channel_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -281,7 +280,7 @@ pub mod ffishim { let (payment, new_cust_state) = bidirectional::generate_payment_proof(rng, &channel_state, &cust_state, amount); // Serialize the results and return to caller let ser = ["{\'payment\':\'", serde_json::to_string(&payment).unwrap().as_str(), - "\', \'cust_state\':\'", serde_json::to_string(&new_cust_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'cust_state\':\'", serde_json::to_string(&new_cust_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -303,7 +302,34 @@ pub mod ffishim { let close_token = bidirectional::verify_payment_proof(rng, &channel_state, &payment, &mut merch_state); let ser = ["{\'close_token\':\'", serde_json::to_string(&close_token).unwrap().as_str(), - "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); + let cser = CString::new(ser).unwrap(); + cser.into_raw() + } + + #[no_mangle] + pub extern fn ffishim_bidirectional_pay_verify_multiple_payment_proofs(ser_channel_state: *mut c_char, ser_sender_pay_proof: *mut c_char, ser_receiver_pay_proof: *mut c_char, ser_merch_state: *mut c_char) -> *mut c_char { + let rng = &mut rand::thread_rng(); + // Deserialize the channel state + let channel_state_result: ResultSerdeType> = deserialize_result_object(ser_channel_state); + let channel_state = handle_errors!(channel_state_result); + + // Deserialize the payment proofs + let sender_payment_result: ResultSerdeType> = deserialize_result_object(ser_sender_pay_proof); + let sender_payment = handle_errors!(sender_payment_result); + + let receiver_payment_result: ResultSerdeType> = deserialize_result_object(ser_receiver_pay_proof); + let receiver_payment = handle_errors!(receiver_payment_result); + + // Deserialize the merch state + let merch_state_result: ResultSerdeType> = deserialize_result_object(ser_merch_state); + let mut merch_state = handle_errors!(merch_state_result); + + let close_token_result = bidirectional::verify_multiple_payment_proofs(rng, &channel_state, &sender_payment, &receiver_payment, &mut merch_state); + let (sender_close_token, receiver_cond_close_token) = handle_errors!(close_token_result).unwrap(); + let ser = ["{\'sender_close_token\':\'", serde_json::to_string(&sender_close_token).unwrap().as_str(), + "\'receiver_cond_close_token\':\'", serde_json::to_string(&receiver_cond_close_token).unwrap().as_str(), + "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -328,7 +354,7 @@ pub mod ffishim { let revoke_token = bidirectional::generate_revoke_token(&channel_state, &mut cust_state, new_cust_state, &close_token); let ser = ["{\'revoke_token\':\'", serde_json::to_string(&revoke_token).unwrap().as_str(), - "\', \'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -337,7 +363,7 @@ pub mod ffishim { pub extern fn ffishim_bidirectional_pay_verify_revoke_token(ser_revoke_token: *mut c_char, ser_merch_state: *mut c_char) -> *mut c_char { // Deserialize the revoke token let revoke_token_result: ResultSerdeType = deserialize_result_object(ser_revoke_token); - let revoke_token= handle_errors!(revoke_token_result); + let revoke_token = handle_errors!(revoke_token_result); // Deserialize the cust state let merch_state_result: ResultSerdeType> = deserialize_result_object(ser_merch_state); @@ -348,7 +374,31 @@ pub mod ffishim { let pay_token = handle_errors!(pay_token_result); let ser = ["{\'pay_token\':\'", serde_json::to_string(&pay_token.unwrap()).unwrap().as_str(), - "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str() ,"\'}"].concat(); + "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); + let cser = CString::new(ser).unwrap(); + cser.into_raw() + } + + #[no_mangle] + pub extern fn ffishim_bidirectional_pay_verify_multiple_revoke_tokens(ser_sender_revoke_token: *mut c_char, ser_receiver_revoke_token: *mut c_char, ser_merch_state: *mut c_char) -> *mut c_char { + // Deserialize the revoke tokens + let sender_revoke_token_result: ResultSerdeType = deserialize_result_object(ser_sender_revoke_token); + let sender_revoke_token = handle_errors!(sender_revoke_token_result); + + let receiver_revoke_token_result: ResultSerdeType = deserialize_result_object(ser_receiver_revoke_token); + let receiver_revoke_token = handle_errors!(receiver_revoke_token_result); + + // Deserialize the cust state + let merch_state_result: ResultSerdeType> = deserialize_result_object(ser_merch_state); + let mut merch_state = handle_errors!(merch_state_result); + + // send revoke token and get pay-token in response + let pay_token_result = bidirectional::verify_multiple_revoke_tokens(&sender_revoke_token, &receiver_revoke_token, &mut merch_state); + let (sender_pay_token, receiver_pay_token) = handle_errors!(pay_token_result).unwrap(); + + let ser = ["{\'sender_pay_token\':\'", serde_json::to_string(&sender_pay_token).unwrap().as_str(), + "\'receiver_pay_token\':\'", serde_json::to_string(&receiver_pay_token).unwrap().as_str(), + "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -371,7 +421,7 @@ pub mod ffishim { // verify the pay token and update internal state let is_pay_valid = cust_state.verify_pay_token(&channel_state, &pay_token); let ser = ["{\'cust_state\':\'", serde_json::to_string(&cust_state).unwrap().as_str(), - "\', \'is_pay_valid\':\'", serde_json::to_string(&is_pay_valid).unwrap().as_str(), "\'}"].concat(); + "\', \'is_pay_valid\':\'", serde_json::to_string(&is_pay_valid).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } @@ -400,7 +450,7 @@ pub mod ffishim { let channel_state_result: ResultSerdeType> = deserialize_result_object(ser_channel_state); let channel_state = handle_errors!(channel_state_result); - // Deserialize the channel token + // Deserialize the channel token let channel_token_result: ResultSerdeType> = deserialize_result_object(ser_channel_token); let channel_token = handle_errors!(channel_token_result); @@ -425,7 +475,7 @@ pub mod ffishim { let merch_close: bidirectional::ChannelcloseM = merch_state.sign_revoke_message(address.to_string(), &keys.revoke_token); let ser = ["{\'wpk\':\'", serde_json::to_string(&keys.wpk).unwrap().as_str(), - "\', \'merch_close\':\'", serde_json::to_string(&merch_close).unwrap().as_str(), "\'}"].concat(); + "\', \'merch_close\':\'", serde_json::to_string(&merch_close).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() } From 56009d423f5a5f21fee98d05779f875063abaa12 Mon Sep 17 00:00:00 2001 From: Gijs Van Laer Date: Fri, 11 Oct 2019 13:42:02 -0400 Subject: [PATCH 5/6] go: deserialize everything --- go/libbolt.go | 89 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/go/libbolt.go b/go/libbolt.go index ec08337..f2ab52b 100644 --- a/go/libbolt.go +++ b/go/libbolt.go @@ -35,24 +35,62 @@ type setupResp struct { } type ChannelState struct { - R int `json:"R"` - TxFee int64 `json:"tx_fee"` - Cp interface{} `json:"cp"` - Name string `json:"name"` - PayInit bool `json:"pay_init"` - ChannelEstablished bool `json:"channel_established"` - ThirdParty bool `json:"third_party"` + R int `json:"R"` + TxFee int64 `json:"tx_fee"` + Cp *ChannelParams `json:"cp"` + Name string `json:"name"` + PayInit bool `json:"pay_init"` + ChannelEstablished bool `json:"channel_established"` + ThirdParty bool `json:"third_party"` +} + +type ChannelParams struct { + ExtraVerify bool `json:"extra_verify"` + L int64 `json:"l"` + PubParams PubParams `json:"pub_params"` +} + +type PubParams struct { + ComParams ComParams `json:"comParams"` + Mpk MPK `json:"mpk"` + Pk PublicKey `json:"pk"` + RpParams RpPubParams `json:"rpParams"` +} + +type RpPubParams struct { + ComParams ComParams `json:"csParams"` + L int64 `json:"l"` + U int64 `json:"u"` + Mpk MPK `json:"mpk"` + Pk PublicKey `json:"pk"` + Signatures map[string]Signature `json:"signatures"` } type MerchState struct { - Id string `json:"id"` - KeyPair KeyPair `json:"keypair"` - NizkParams interface{} `json:"nizkParams"` - Pk string `json:"pk"` - Sk string `json:"sk"` - ComParams ComParams `json:"comParams"` - Keys interface{} `json:"keys"` - PayTokens interface{} `json:"pay_tokens"` + Id string `json:"id"` + KeyPair KeyPair `json:"keypair"` + NizkParams NIZKParams `json:"nizkParams"` + Pk string `json:"pk"` + Sk string `json:"sk"` + ComParams ComParams `json:"comParams"` + Keys map[string]RevokedKey `json:"keys"` + PayTokens map[string]Signature `json:"pay_tokens"` +} + +type RevokedKey struct { + Wpk string `json:"wpk"` + RevokeToken *string `json:"revoke_token"` +} + +type NIZKParams struct { + PubParams PubParams `json:"pubParams"` + KeyPair KeyPair `json:"keypair"` + RpParams RpParams `json:"rpParams"` +} + +type RpParams struct { + PubParams RpPubParams `json:"pubParams"` + KeyPair KeyPair `json:"kp"` } type CustState struct { @@ -108,10 +146,25 @@ type Payment struct { type Proof struct { Sig Signature `json:"sig"` - SigProof interface{} `json:"sigProof"` + SigProof SigProof `json:"sigProof"` ComProof CommitmentProof `json:"comProof"` - RangeProofBC interface{} `json:"rpBC"` - RangeProofBM interface{} `json:"rpBM"` + RangeProofBC RangeProof `json:"rpBC"` + RangeProofBM RangeProof `json:"rpBM"` +} + +type SigProof struct { + Zsig [][]string `json:"zsig"` + Zv []string `json:"zv"` + A interface{} `json:"a"` +} + +type RangeProof struct { + V []Signature `json:"V"` + D string `json:"D"` + Com Commitment `json:"comm"` + SigProofs []SigProof `json:"sigProofs"` + Zr []string `json:"zr"` + Zs [][]string `json:"zs"` } type PublicKey struct { From 4f0913b21ddf0314d93d81de0775a95ace16ba8e Mon Sep 17 00:00:00 2001 From: Gijs Van Laer Date: Fri, 11 Oct 2019 16:54:11 -0400 Subject: [PATCH 6/6] intermediary: fix ffishim for multi verify + add go tests for payment with intermediary --- go/libbolt_test.go | 53 ++++++++++++++++++++++++++++++++++++++++++++++ src/ffishim.rs | 4 ++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/go/libbolt_test.go b/go/libbolt_test.go index 6196a4d..d3e5885 100644 --- a/go/libbolt_test.go +++ b/go/libbolt_test.go @@ -83,6 +83,59 @@ func Test_Pay(t *testing.T) { assert.True(t, isTokenValid) } +func Test_IntermediaryPay(t *testing.T) { + b0Alice := 1000 + b0Bob := 100 + b0Intermediary := 100 + channelState, err := BidirectionalChannelSetup("Test Channel", false) + assert.Nil(t, err) + channelToken, merchState, channelState, err := BidirectionalInitMerchant(channelState, "Hub") + assert.Nil(t, err) + channelToken, custStateAlice, err := BidirectionalInitCustomer(channelToken, b0Alice, b0Intermediary, "Alice") + assert.Nil(t, err) + channelToken, custStateAlice, com, comProof, err := BidirectionalEstablishCustomerGenerateProof(channelToken, custStateAlice) + assert.Nil(t, err) + closeToken, err := BidirectionalEstablishMerchantIssueCloseToken(channelState, com, comProof, custStateAlice.PkC, b0Alice, b0Intermediary, merchState) + assert.Nil(t, err) + _, channelState, custStateAlice, err = BidirectionalVerifyCloseToken(channelState, custStateAlice, closeToken) + assert.Nil(t, err) + payToken, err := BidirectionalEstablishMerchantIssuePayToken(channelState, com, merchState) + assert.Nil(t, err) + _, channelState, custStateAlice, err = BidirectionalEstablishCustomerFinal(channelState, custStateAlice, payToken) + assert.Nil(t, err) + channelToken, custStateBob, err := BidirectionalInitCustomer(channelToken, b0Bob, b0Intermediary, "Bob") + assert.Nil(t, err) + channelToken, custStateBob, com, comProof, err = BidirectionalEstablishCustomerGenerateProof(channelToken, custStateBob) + assert.Nil(t, err) + closeToken, err = BidirectionalEstablishMerchantIssueCloseToken(channelState, com, comProof, custStateBob.PkC, b0Bob, b0Intermediary, merchState) + assert.Nil(t, err) + _, channelState, custStateBob, err = BidirectionalVerifyCloseToken(channelState, custStateBob, closeToken) + assert.Nil(t, err) + payToken, err = BidirectionalEstablishMerchantIssuePayToken(channelState, com, merchState) + assert.Nil(t, err) + _, channelState, custStateBob, err = BidirectionalEstablishCustomerFinal(channelState, custStateBob, payToken) + assert.Nil(t, err) + + paymentA, newCustStateAlice, err := BidirectionalPayGeneratePaymentProof(channelState, custStateAlice, 10) + assert.Nil(t, err) + paymentB, newCustStateBob, err := BidirectionalPayGeneratePaymentProof(channelState, custStateBob, -10) + assert.Nil(t, err) + closeTokenA, closeTokenB, merchState, err := BidirectionalPayVerifyMultiplePaymentProofs(channelState, paymentA, paymentB, merchState) + assert.Nil(t, err) + revokeTokenA, custStateAlice, err := BidirectionalPayGenerateRevokeToken(channelState, custStateAlice, newCustStateAlice, closeTokenA) + assert.Nil(t, err) + revokeTokenB, custStateBob, err := BidirectionalPayGenerateRevokeToken(channelState, custStateBob, newCustStateBob, closeTokenB) + assert.Nil(t, err) + payTokenA, payTokenB, merchState, err := BidirectionalPayVerifyMultipleRevokeTokens(revokeTokenA, revokeTokenB, merchState) + assert.Nil(t, err) + custStateAlice, isTokenValid, err := BidirectionalPayVerifyPaymentToken(channelState, custStateAlice, payTokenA) + assert.Nil(t, err) + assert.True(t, isTokenValid) + custStateBob, isTokenValid, err = BidirectionalPayVerifyPaymentToken(channelState, custStateBob, payTokenB) + assert.Nil(t, err) + assert.True(t, isTokenValid) +} + func Test_Close(t *testing.T) { b0Cust := 1000 b0Merch := 100 diff --git a/src/ffishim.rs b/src/ffishim.rs index 2aa5a98..1516f4b 100644 --- a/src/ffishim.rs +++ b/src/ffishim.rs @@ -328,7 +328,7 @@ pub mod ffishim { let close_token_result = bidirectional::verify_multiple_payment_proofs(rng, &channel_state, &sender_payment, &receiver_payment, &mut merch_state); let (sender_close_token, receiver_cond_close_token) = handle_errors!(close_token_result).unwrap(); let ser = ["{\'sender_close_token\':\'", serde_json::to_string(&sender_close_token).unwrap().as_str(), - "\'receiver_cond_close_token\':\'", serde_json::to_string(&receiver_cond_close_token).unwrap().as_str(), + "\', \'receiver_cond_close_token\':\'", serde_json::to_string(&receiver_cond_close_token).unwrap().as_str(), "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw() @@ -397,7 +397,7 @@ pub mod ffishim { let (sender_pay_token, receiver_pay_token) = handle_errors!(pay_token_result).unwrap(); let ser = ["{\'sender_pay_token\':\'", serde_json::to_string(&sender_pay_token).unwrap().as_str(), - "\'receiver_pay_token\':\'", serde_json::to_string(&receiver_pay_token).unwrap().as_str(), + "\', \'receiver_pay_token\':\'", serde_json::to_string(&receiver_pay_token).unwrap().as_str(), "\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str(), "\'}"].concat(); let cser = CString::new(ser).unwrap(); cser.into_raw()