new libbolt interface with fixes and improvements to internal state management
This commit is contained in:
parent
2cd297ce00
commit
1c91cf03fe
112
README.md
112
README.md
|
@ -80,121 +80,111 @@ A bidirectional payment channel enables two parties to exchange arbitrary positi
|
|||
|
||||
### Channel Setup and Key Generation
|
||||
|
||||
The first part of setting up bi-directional payment channels involve generating initial setup parameters, channel state and key generation for both parties.
|
||||
The first part of setting up bi-directional payment channels involve generating initial setup parameters using curve BLS12-381 with channel state.
|
||||
|
||||
use bolt::bidirectional;
|
||||
|
||||
// setup bidirectional scheme params
|
||||
let pp = bidirectional::setup(true);
|
||||
|
||||
// generate the initial channel state
|
||||
// second argument represents third-party mode
|
||||
let mut channel = bidirectional::ChannelState::new(String::from("My New Channel A <-> B"), false);
|
||||
let mut channel_state = bidirectional::ChannelState::<Bls12>::new(String::from("Channel A -> B"), false);
|
||||
let mut rng = &mut rand::thread_rng();
|
||||
|
||||
To generate keys for both parties, call the `bidirectional::keygen()` routine with the public parameters as input.
|
||||
|
||||
// merchant generates a long-lived key pair
|
||||
let m_keypair = bidirectional::keygen(&pp);
|
||||
|
||||
// customer generates an ephemeral keypair for use on a single channel
|
||||
let c_keypair = bidirectional::keygen(&pp);
|
||||
// generate fresh public parameters
|
||||
channel_state.setup(&mut rng);
|
||||
|
||||
### Initialization
|
||||
|
||||
To initialize the channel for both parties, do the following:
|
||||
To initialize wallet/keys for both parties, call the ``bidirectional::init_merchant()`` and ``bidirectional::init_customer()``:
|
||||
|
||||
let b0_merch = 10;
|
||||
let b0_cust = 100;
|
||||
// initialize on the merchant side with balance, b0_merch
|
||||
let mut m_data = bidirectional::init_merchant(&pp, b0_merch, &m_keypair));
|
||||
|
||||
// generate the public params for the commitment scheme
|
||||
let cm_csp = bidirectional::generate_commit_setup(&pp, &m_keypair.pk);
|
||||
// initialize the merchant wallet and initialize with balance
|
||||
let (mut channel_token, mut merch_wallet) = bidirectional::init_merchant(rng, &mut channel_state, "Bob");
|
||||
|
||||
// initialize on the customer side with balance, b0_cust
|
||||
let mut c_data = bidirectional::init_customer(&pp, // public params
|
||||
&channel, // channel state
|
||||
// initialize the balance for merch_wallet
|
||||
merch_wallet.init_balance(b0_merch);
|
||||
|
||||
// generate the customer wallet using the channel token from the merchant
|
||||
let mut cust_wallet = bidirectional::init_customer(rng, // rng
|
||||
&mut channel_state, // channel state
|
||||
&mut channel_token, // channel token
|
||||
b0_cust, // init customer balance
|
||||
b0_merch, // init merchant balance
|
||||
&cm_csp, // commitment pub params
|
||||
&c_keypair)); // customer keypair
|
||||
"Alice")); // channel name/purpose
|
||||
|
||||
|
||||
### Establish Protocol
|
||||
|
||||
When opening a payment channel, execute the establishment protocol API to escrow funds privately as follows:
|
||||
|
||||
// entering the establish protocol for the channel
|
||||
let proof1 = bidirectional::establish_customer_phase1(&pp, &c_data, &m_data.bases);
|
||||
// establish the channel by generating initial wallet commitment proof
|
||||
let (com, com_proof) = bidirectional::establish_customer_generate_proof(rng, &mut channel_token, &mut cust_wallet);
|
||||
|
||||
// obtain the wallet signature from the merchant
|
||||
let w_sig = bidirectional::establish_merchant_phase2(&pp, &mut channel, &m_data, &proof1));
|
||||
// obtain close token for closing out channel
|
||||
let close_token = bidirectional::establish_merchant_issue_close_token(rng, &channel_state, &com, &com_proof, &merch_wallet);
|
||||
|
||||
// complete channel establishment");
|
||||
assert!(bidirectional::establish_customer_final(&pp, &m_keypair.pk, &mut c_data.csk, w_sig));
|
||||
// customer verifies that close-token
|
||||
assert!(cust_wallet.verify_close_token(&channel_state, &close_token));
|
||||
|
||||
// form funding tx and wait for network confirmation
|
||||
|
||||
// obtain payment token after confirming funding tx
|
||||
let pay_token = bidirectional::establish_merchant_issue_pay_token(rng, &channel_state, &com, &merch_wallet);
|
||||
|
||||
// customer
|
||||
assert!(bidirectional::establish_final(&mut channel_state, &mut cust_wallet, &pay_token));
|
||||
|
||||
// confirm that the channel state is now established
|
||||
assert!(channel.channel_established);
|
||||
assert!(channel_state.channel_established);
|
||||
|
||||
### Pay protocol
|
||||
|
||||
To spend on the channel, execute the pay protocol API (can be executed as many times as necessary):
|
||||
|
||||
// precomputation phase that customer does offline prior to a spend
|
||||
bidirectional::pay_by_customer_phase1_precompute(&pp, &c_data.channel_token, &m_keypair.pk, &mut c_data.csk);
|
||||
// phase 1 - payment proof and new cust wallet
|
||||
let (payment, new_cust_wallet) = bidirectional::generate_payment(rng, &channel_state, &cust_wallet, 10);
|
||||
|
||||
// generate new channel token, new wallet and payment proof
|
||||
// send the payment proof to the merchant
|
||||
let (t_c, new_w, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel,
|
||||
&c_data.channel_token, // channel token
|
||||
&m_keypair.pk, // merchant verification key
|
||||
&c_data.csk, // current wallet
|
||||
5); // balance increment
|
||||
// phase 1 - merchant verifies the payment proof and returns a close-token
|
||||
let new_close_token = bidirectional::verify_payment(rng, &channel_state, &payment, &mut merch_wallet);
|
||||
|
||||
// get the refund token (rt_w) from the merchant
|
||||
let rt_w = bidirectional::pay_by_merchant_phase1(&pp, &mut channel, &pay_proof, &m_data));
|
||||
// phase 2 - verify the close-token, update cust wallet and generate a revoke token for previous cust wallet state
|
||||
let revoke_token = bidirectional::generate_revoke_token(&channel_state, &mut cust_wallet, new_cust_wallet, &new_close_token);
|
||||
|
||||
// generate the revocation token (rv_w) on the old public key (wpk)
|
||||
let rv_w = bidirectional::pay_by_customer_phase2(&pp, &c_data.csk, &new_w, &m_keypair.pk, &rt_w));
|
||||
// phase 2 - merchant verifies the revoke token and sends back the pay-token in response
|
||||
let new_pay_token = bidirectional::verify_revoke_token(&revoke_token, &mut merch_wallet);
|
||||
|
||||
// get the signature on the new wallet from merchant
|
||||
let new_w_sig = bidirectional::pay_by_merchant_phase2(&pp, &mut channel, &pay_proof, &mut m_data, &rv_w));
|
||||
// final - customer verifies the pay token and updates internal state
|
||||
assert!(cust_wallet.verify_pay_token(&channel_state, &new_pay_token));
|
||||
|
||||
// complete the final step of pay protocol - verify merchant signature on wallet
|
||||
assert!(bidirectional::pay_by_customer_final(&pp, &m_keypair.pk, &mut c_data, t_c, new_w, new_w_sig));
|
||||
|
||||
### Channel Closure Algorithms
|
||||
### Channel Closure Algorithms (TODO)
|
||||
|
||||
To close a channel, the customer must execute the `bidirectional::customer_refund()` routine as follows:
|
||||
|
||||
let cust_wallet = &c_data.csk;
|
||||
let rc_c = bidirectional::customer_refund(&pp, &channel, &m_keypair.pk, &cust_wallet);
|
||||
let cust_close = bidirectional::customer_refund(&channel_state, &cust_wallet);
|
||||
|
||||
The merchant can dispute a customer's claim by executing the `bidirectional::merchant_retute()` routine as follows:
|
||||
|
||||
let channel_token = &c_data.channel_token;
|
||||
let rc_m = bidirectional::merchant_refute(&pp, &mut channel, &channel_token, &m_data, &rc_c, &rv_w.signature);
|
||||
let merch_close = bidirectional::merchant_refute(&mut channel_state, &channel_token, &cust_close, &rv_w.signature);
|
||||
|
||||
|
||||
To resolve a dispute between a customer and a merchant, the following routine is executed by the network:
|
||||
|
||||
let (new_b0_cust, new_b0_merch) = bidirectional::resolve(&pp, &c_data, &m_data,
|
||||
let (new_b0_cust, new_b0_merch) = bidirectional::resolve(&c_data, &m_data,
|
||||
Some(rc_c), Some(rc_m), Some(rt_w));
|
||||
|
||||
`new_b0_cust` and `new_b0_merch` represent the new balances for the customer and merchant (respectively).
|
||||
|
||||
## Third-party Payments
|
||||
## Third-party Payments (TODO)
|
||||
|
||||
The bidirectional payment channels can be used to construct third-party payments in which a party **A** pays a second party **B** through an untrusted intermediary (**I**) to which both **A** and **B** have already established a channel. With BOLT, the intermediary learns nothing about the payment from **A** to **B** and cannot link transactions to individual users.
|
||||
|
||||
To enable third-party payment support, initialize each payment channel as follows:
|
||||
|
||||
|
||||
let pp = bidirectional::setup(true);
|
||||
|
||||
// create the channel state for each channel and indicate third-party support
|
||||
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 mut channel_a = bidirectional::ChannelState::<Bls12>::new(String::from("Channel A <-> I"), true);
|
||||
let mut channel_b = bidirectional::ChannelState::<Bls12>::new(String::from("Channel B <-> I"), true);
|
||||
|
||||
Moreover, the intermediary can set a channel fee as follows:
|
||||
|
||||
|
@ -207,13 +197,13 @@ The channel establishment still works as described before and the pay protocol i
|
|||
|
||||
let payment_amount = 20;
|
||||
// get payment proof on first channel with party A (and I)
|
||||
let (t_c1, new_w1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel_a,
|
||||
let (t_c1, new_w1, pay_proof1) = bidirectional::pay_by_customer_phase1(&channel_a,
|
||||
&c1_data.channel_token, // channel token
|
||||
&merch_keys.pk, // merchant pub key
|
||||
&c1_data.csk, // wallet
|
||||
payment_amount); // bal inc
|
||||
// get payment proof on second channel with party B (and I)
|
||||
let (t_c2, new_w2, pay_proof2) = bidirectional::pay_by_customer_phase1(&pp, &channel2,
|
||||
let (t_c2, new_w2, pay_proof2) = bidirectional::pay_by_customer_phase1(&channel2,
|
||||
&c2_data.channel_token, // channel token
|
||||
&m_keys.pk, // merchant pub key
|
||||
&c2_data.csk, // wallet
|
||||
|
@ -227,7 +217,7 @@ The channel establishment still works as described before and the pay protocol i
|
|||
|
||||
See the `third_party_payment_basics_work()` unit test in `src/lib.rs` for more details.
|
||||
|
||||
# Documentation
|
||||
# Documentation (TODO)
|
||||
|
||||
Build the api documentation by simply running `make doc`. Documentation will be generated in your local `target/doc` directory.
|
||||
|
||||
|
|
|
@ -36,144 +36,148 @@ macro_rules! measure_ret_mut {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
println!("******************************************");
|
||||
// libbolt tests below
|
||||
println!("Testing the channel setup...");
|
||||
|
||||
//println!("[1a] libbolt - setup bidirectional scheme params");
|
||||
let (pp, setup_time1) = measure!(bidirectional::setup(false));
|
||||
|
||||
//println!("[1b] libbolt - generate the initial channel state");
|
||||
let mut channel = bidirectional::ChannelState::new(String::from("My New Channel A"), false);
|
||||
|
||||
println!("Setup time: {}", setup_time1);
|
||||
|
||||
//let msg = "Open Channel ID: ";
|
||||
//libbolt::debug_elem_in_hex(msg, &channel.cid);
|
||||
|
||||
let b0_cust = 50;
|
||||
let b0_merch = 50;
|
||||
|
||||
// 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, _) = measure!(bidirectional::keygen(&pp));
|
||||
|
||||
// customer generates 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, _) = measure!(bidirectional::keygen(&pp));
|
||||
|
||||
// each party executes the init algorithm on the agreed initial challenge balance
|
||||
// in order to derive the channel tokens
|
||||
println!("[5a] libbolt - initialize on the merchant side with balance {}", b0_merch);
|
||||
let (mut merch_data, initm_time) = measure_ret_mut!(bidirectional::init_merchant(&pp, b0_merch, &merch_keypair));
|
||||
println!(">> TIME for init_merchant: {}", initm_time);
|
||||
|
||||
println!("[5b] libbolt - initialize on the customer side with balance {}", b0_cust);
|
||||
let cm_csp = bidirectional::generate_commit_setup(&pp, &merch_keypair.pk);
|
||||
let (mut cust_data, initc_time) = measure_ret_mut!(bidirectional::init_customer(&pp, &mut channel, b0_cust, b0_merch, &cm_csp, &cust_keypair));
|
||||
println!(">> TIME for init_customer: {}", initc_time);
|
||||
println!("******************************************");
|
||||
// libbolt tests below
|
||||
println!("Testing the establish protocol...");
|
||||
|
||||
println!("[6a] libbolt - entering the establish protocol for the channel");
|
||||
let (proof1, est_cust_time1) = measure!(bidirectional::establish_customer_phase1(&pp, &cust_data, &merch_data.bases));
|
||||
println!(">> TIME for establish_customer_phase1: {}", est_cust_time1);
|
||||
|
||||
println!("[6b] libbolt - obtain the wallet signature from the merchant");
|
||||
let (wallet_sig, est_merch_time2) = measure!(bidirectional::establish_merchant_phase2(&pp, &mut channel, &merch_data, &proof1));
|
||||
println!(">> TIME for establish_merchant_phase2: {}", est_merch_time2);
|
||||
|
||||
println!("[6c] libbolt - complete channel establishment");
|
||||
assert!(bidirectional::establish_customer_final(&pp, &merch_keypair.pk, &mut cust_data.csk, wallet_sig));
|
||||
|
||||
assert!(channel.channel_established);
|
||||
|
||||
println!("Channel has been established!");
|
||||
println!("******************************************");
|
||||
|
||||
println!("Testing the pay protocol...");
|
||||
// let's test the pay protocol
|
||||
bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.channel_token, &merch_keypair.pk, &mut cust_data.csk);
|
||||
let s = PreciseTime::now();
|
||||
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.channel_token, // channel token
|
||||
&merch_keypair.pk, // merchant pub key
|
||||
&cust_data.csk, // wallet
|
||||
5); // balance increment
|
||||
let e = PreciseTime::now();
|
||||
println!(">> TIME for pay_by_customer_phase1: {}", s.to(e));
|
||||
|
||||
// get the refund token (rt_w)
|
||||
let (rt_w, pay_merch_time1) = measure!(bidirectional::pay_by_merchant_phase1(&pp, &mut channel, &pay_proof, &merch_data));
|
||||
println!(">> TIME for pay_by_merchant_phase1: {}", pay_merch_time1);
|
||||
|
||||
// get the revocation token (rv_w) on the old public key (wpk)
|
||||
let (rv_w, pay_cust_time2) = measure!(bidirectional::pay_by_customer_phase2(&pp, &cust_data.csk, &new_wallet, &merch_keypair.pk, &rt_w));
|
||||
println!(">> TIME for pay_by_customer_phase2: {}", pay_cust_time2);
|
||||
|
||||
// get the new wallet sig (new_wallet_sig) on the new wallet
|
||||
let (new_wallet_sig, pay_merch_time2) = measure!(bidirectional::pay_by_merchant_phase2(&pp, &mut channel, &pay_proof, &mut merch_data, &rv_w));
|
||||
println!(">> TIME for pay_by_merchant_phase2: {}", pay_merch_time2);
|
||||
|
||||
assert!(bidirectional::pay_by_customer_final(&pp, &merch_keypair.pk, &mut cust_data, t_c, new_wallet, rt_w, new_wallet_sig));
|
||||
|
||||
{
|
||||
// scope localizes the immutable borrow here (for debug purposes only)
|
||||
let cust_wallet = &cust_data.csk;
|
||||
let merch_wallet = &merch_data.csk;
|
||||
println!("Customer balance: {}", cust_wallet.balance);
|
||||
println!("Merchant balance: {}", merch_wallet.balance);
|
||||
}
|
||||
|
||||
bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.channel_token, &merch_keypair.pk, &mut cust_data.csk);
|
||||
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.channel_token, // channel token
|
||||
&merch_keypair.pk, // merchant pub key
|
||||
&cust_data.csk, // wallet
|
||||
-10); // balance increment
|
||||
|
||||
// get the refund token (rt_w)
|
||||
let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, &mut channel, &pay_proof1, &merch_data);
|
||||
|
||||
// get the revocation token (rv_w) on the old public key (wpk)
|
||||
let rv_w1 = bidirectional::pay_by_customer_phase2(&pp, &cust_data.csk, &new_wallet1, &merch_keypair.pk, &rt_w1);
|
||||
|
||||
// get the new wallet sig (new_wallet_sig) on the new wallet
|
||||
let new_wallet_sig1 = bidirectional::pay_by_merchant_phase2(&pp, &mut channel, &pay_proof1, &mut merch_data, &rv_w1);
|
||||
|
||||
assert!(bidirectional::pay_by_customer_final(&pp, &merch_keypair.pk, &mut cust_data, t_c1, new_wallet1, rt_w1, new_wallet_sig1));
|
||||
|
||||
{
|
||||
let cust_wallet = &cust_data.csk;
|
||||
let merch_wallet = &merch_data.csk;
|
||||
println!("Updated balances...");
|
||||
println!("Customer balance: {}", cust_wallet.balance);
|
||||
println!("Merchant balance: {}", merch_wallet.balance);
|
||||
let updated_cust_bal = b0_cust + 5;
|
||||
let updated_merch_bal = b0_merch - 5;
|
||||
assert_eq!(updated_cust_bal, cust_wallet.balance);
|
||||
assert_eq!(updated_merch_bal, merch_wallet.balance);
|
||||
}
|
||||
println!("Pay protocol complete!");
|
||||
|
||||
println!("******************************************");
|
||||
println!("Testing the dispute algorithms...");
|
||||
|
||||
{
|
||||
let cust_wallet = &cust_data.csk;
|
||||
// get channel closure message
|
||||
let rc_c = bidirectional::customer_refund(&pp, &channel, &merch_keypair.pk, &cust_wallet);
|
||||
println!("Obtained the channel closure message: {}", rc_c.message.msgtype);
|
||||
|
||||
let channel_token = &cust_data.channel_token;
|
||||
let rc_m = bidirectional::merchant_refute(&pp, &mut channel, &channel_token, &merch_data, &rc_c, &rv_w1.signature);
|
||||
println!("Merchant has refuted the refund request!");
|
||||
|
||||
let (new_b0_cust, new_b0_merch) = bidirectional::resolve(&pp, &cust_data, &merch_data,
|
||||
Some(rc_c), Some(rc_m));
|
||||
println!("Resolved! Customer = {}, Merchant = {}", new_b0_cust, new_b0_merch);
|
||||
}
|
||||
|
||||
// TODO: add tests for customer/merchant cheating scenarios
|
||||
println!("******************************************");
|
||||
println!("Hello world!");
|
||||
}
|
||||
|
||||
//fn main() {
|
||||
// println!("******************************************");
|
||||
// // libbolt tests below
|
||||
// println!("Testing the channel setup...");
|
||||
//
|
||||
// //println!("[1a] libbolt - setup bidirectional scheme params");
|
||||
// let (pp, setup_time1) = measure!(bidirectional::setup(false));
|
||||
//
|
||||
// //println!("[1b] libbolt - generate the initial channel state");
|
||||
// let mut channel = bidirectional::ChannelState::new(String::from("My New Channel A"), false);
|
||||
//
|
||||
// println!("Setup time: {}", setup_time1);
|
||||
//
|
||||
// //let msg = "Open Channel ID: ";
|
||||
// //libbolt::debug_elem_in_hex(msg, &channel.cid);
|
||||
//
|
||||
// let b0_cust = 50;
|
||||
// let b0_merch = 50;
|
||||
//
|
||||
// // 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, _) = measure!(bidirectional::keygen(&pp));
|
||||
//
|
||||
// // customer generates 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, _) = measure!(bidirectional::keygen(&pp));
|
||||
//
|
||||
// // each party executes the init algorithm on the agreed initial challenge balance
|
||||
// // in order to derive the channel tokens
|
||||
// println!("[5a] libbolt - initialize on the merchant side with balance {}", b0_merch);
|
||||
// let (mut merch_data, initm_time) = measure_ret_mut!(bidirectional::init_merchant(&pp, b0_merch, &merch_keypair));
|
||||
// println!(">> TIME for init_merchant: {}", initm_time);
|
||||
//
|
||||
// println!("[5b] libbolt - initialize on the customer side with balance {}", b0_cust);
|
||||
// let cm_csp = bidirectional::generate_commit_setup(&pp, &merch_keypair.pk);
|
||||
// let (mut cust_data, initc_time) = measure_ret_mut!(bidirectional::init_customer(&pp, &mut channel, b0_cust, b0_merch, &cm_csp, &cust_keypair));
|
||||
// println!(">> TIME for init_customer: {}", initc_time);
|
||||
// println!("******************************************");
|
||||
// // libbolt tests below
|
||||
// println!("Testing the establish protocol...");
|
||||
//
|
||||
// println!("[6a] libbolt - entering the establish protocol for the channel");
|
||||
// let (proof1, est_cust_time1) = measure!(bidirectional::establish_customer_phase1(&pp, &cust_data, &merch_data.bases));
|
||||
// println!(">> TIME for establish_customer_phase1: {}", est_cust_time1);
|
||||
//
|
||||
// println!("[6b] libbolt - obtain the wallet signature from the merchant");
|
||||
// let (wallet_sig, est_merch_time2) = measure!(bidirectional::establish_merchant_phase2(&pp, &mut channel, &merch_data, &proof1));
|
||||
// println!(">> TIME for establish_merchant_phase2: {}", est_merch_time2);
|
||||
//
|
||||
// println!("[6c] libbolt - complete channel establishment");
|
||||
// assert!(bidirectional::establish_customer_final(&pp, &merch_keypair.pk, &mut cust_data.csk, wallet_sig));
|
||||
//
|
||||
// assert!(channel.channel_established);
|
||||
//
|
||||
// println!("Channel has been established!");
|
||||
// println!("******************************************");
|
||||
//
|
||||
// println!("Testing the pay protocol...");
|
||||
// // let's test the pay protocol
|
||||
// bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.channel_token, &merch_keypair.pk, &mut cust_data.csk);
|
||||
// let s = PreciseTime::now();
|
||||
// let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.channel_token, // channel token
|
||||
// &merch_keypair.pk, // merchant pub key
|
||||
// &cust_data.csk, // wallet
|
||||
// 5); // balance increment
|
||||
// let e = PreciseTime::now();
|
||||
// println!(">> TIME for pay_by_customer_phase1: {}", s.to(e));
|
||||
//
|
||||
// // get the refund token (rt_w)
|
||||
// let (rt_w, pay_merch_time1) = measure!(bidirectional::pay_by_merchant_phase1(&pp, &mut channel, &pay_proof, &merch_data));
|
||||
// println!(">> TIME for pay_by_merchant_phase1: {}", pay_merch_time1);
|
||||
//
|
||||
// // get the revocation token (rv_w) on the old public key (wpk)
|
||||
// let (rv_w, pay_cust_time2) = measure!(bidirectional::pay_by_customer_phase2(&pp, &cust_data.csk, &new_wallet, &merch_keypair.pk, &rt_w));
|
||||
// println!(">> TIME for pay_by_customer_phase2: {}", pay_cust_time2);
|
||||
//
|
||||
// // get the new wallet sig (new_wallet_sig) on the new wallet
|
||||
// let (new_wallet_sig, pay_merch_time2) = measure!(bidirectional::pay_by_merchant_phase2(&pp, &mut channel, &pay_proof, &mut merch_data, &rv_w));
|
||||
// println!(">> TIME for pay_by_merchant_phase2: {}", pay_merch_time2);
|
||||
//
|
||||
// assert!(bidirectional::pay_by_customer_final(&pp, &merch_keypair.pk, &mut cust_data, t_c, new_wallet, rt_w, new_wallet_sig));
|
||||
//
|
||||
// {
|
||||
// // scope localizes the immutable borrow here (for debug purposes only)
|
||||
// let cust_wallet = &cust_data.csk;
|
||||
// let merch_wallet = &merch_data.csk;
|
||||
// println!("Customer balance: {}", cust_wallet.balance);
|
||||
// println!("Merchant balance: {}", merch_wallet.balance);
|
||||
// }
|
||||
//
|
||||
// bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.channel_token, &merch_keypair.pk, &mut cust_data.csk);
|
||||
// let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.channel_token, // channel token
|
||||
// &merch_keypair.pk, // merchant pub key
|
||||
// &cust_data.csk, // wallet
|
||||
// -10); // balance increment
|
||||
//
|
||||
// // get the refund token (rt_w)
|
||||
// let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, &mut channel, &pay_proof1, &merch_data);
|
||||
//
|
||||
// // get the revocation token (rv_w) on the old public key (wpk)
|
||||
// let rv_w1 = bidirectional::pay_by_customer_phase2(&pp, &cust_data.csk, &new_wallet1, &merch_keypair.pk, &rt_w1);
|
||||
//
|
||||
// // get the new wallet sig (new_wallet_sig) on the new wallet
|
||||
// let new_wallet_sig1 = bidirectional::pay_by_merchant_phase2(&pp, &mut channel, &pay_proof1, &mut merch_data, &rv_w1);
|
||||
//
|
||||
// assert!(bidirectional::pay_by_customer_final(&pp, &merch_keypair.pk, &mut cust_data, t_c1, new_wallet1, rt_w1, new_wallet_sig1));
|
||||
//
|
||||
// {
|
||||
// let cust_wallet = &cust_data.csk;
|
||||
// let merch_wallet = &merch_data.csk;
|
||||
// println!("Updated balances...");
|
||||
// println!("Customer balance: {}", cust_wallet.balance);
|
||||
// println!("Merchant balance: {}", merch_wallet.balance);
|
||||
// let updated_cust_bal = b0_cust + 5;
|
||||
// let updated_merch_bal = b0_merch - 5;
|
||||
// assert_eq!(updated_cust_bal, cust_wallet.balance);
|
||||
// assert_eq!(updated_merch_bal, merch_wallet.balance);
|
||||
// }
|
||||
// println!("Pay protocol complete!");
|
||||
//
|
||||
// println!("******************************************");
|
||||
// println!("Testing the dispute algorithms...");
|
||||
//
|
||||
// {
|
||||
// let cust_wallet = &cust_data.csk;
|
||||
// // get channel closure message
|
||||
// let rc_c = bidirectional::customer_refund(&pp, &channel, &merch_keypair.pk, &cust_wallet);
|
||||
// println!("Obtained the channel closure message: {}", rc_c.message.msgtype);
|
||||
//
|
||||
// let channel_token = &cust_data.channel_token;
|
||||
// let rc_m = bidirectional::merchant_refute(&pp, &mut channel, &channel_token, &merch_data, &rc_c, &rv_w1.signature);
|
||||
// println!("Merchant has refuted the refund request!");
|
||||
//
|
||||
// let (new_b0_cust, new_b0_merch) = bidirectional::resolve(&pp, &cust_data, &merch_data,
|
||||
// Some(rc_c), Some(rc_m));
|
||||
// println!("Resolved! Customer = {}, Merchant = {}", new_b0_cust, new_b0_merch);
|
||||
// }
|
||||
//
|
||||
// // TODO: add tests for customer/merchant cheating scenarios
|
||||
// println!("******************************************");
|
||||
//}
|
||||
|
|
|
@ -15,7 +15,7 @@ use pairing::bls12_381::{Bls12};
|
|||
use ff::PrimeField;
|
||||
use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup};
|
||||
use ped92::{CSParams, Commitment, CSMultiParams};
|
||||
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, CommitmentProof};
|
||||
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, CommitmentProof, RevokedMessage};
|
||||
use rand::Rng;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
|
@ -26,9 +26,9 @@ use nizk::{NIZKPublicParams, Proof};
|
|||
use wallet::Wallet;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
struct PubKeyMap {
|
||||
wpk: secp256k1::PublicKey,
|
||||
revoke_token: Option<secp256k1::Signature>
|
||||
pub struct PubKeyMap {
|
||||
pub wpk: secp256k1::PublicKey,
|
||||
pub revoke_token: Option<secp256k1::Signature>
|
||||
}
|
||||
|
||||
//#[derive(Clone, Serialize, Deserialize)]
|
||||
|
@ -43,7 +43,6 @@ pub struct ChannelParams<E: Engine> {
|
|||
//#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelState<E: Engine> {
|
||||
keys: HashMap<String, PubKeyMap>,
|
||||
R: i32,
|
||||
tx_fee: i32,
|
||||
pub cp: Option<ChannelParams<E>>,
|
||||
|
@ -82,7 +81,6 @@ impl<E: Engine> ChannelState<E> {
|
|||
|
||||
pub fn new(name: String, third_party_support: bool) -> ChannelState<E> {
|
||||
ChannelState {
|
||||
keys: HashMap::new(), // store wpks/revoke_tokens
|
||||
R: 0,
|
||||
tx_fee: 0,
|
||||
cp: None,
|
||||
|
@ -143,6 +141,7 @@ struct WalletKeyPair {
|
|||
/// Customer wallet consists of a keypair (NEW)
|
||||
///
|
||||
pub struct CustomerWallet<E: Engine> {
|
||||
pub name: String,
|
||||
pub pk_c: secp256k1::PublicKey,
|
||||
sk_c: secp256k1::SecretKey,
|
||||
cust_balance: i32, //
|
||||
|
@ -159,7 +158,7 @@ pub struct CustomerWallet<E: Engine> {
|
|||
}
|
||||
|
||||
impl<E: Engine> CustomerWallet<E> {
|
||||
pub fn new<R: Rng>(csprng: &mut R, channel: &mut ChannelState<E>, channel_token: &mut ChannelToken<E>, cust_bal: i32, merch_bal: i32) -> Self {
|
||||
pub fn new<R: Rng>(csprng: &mut R, channel: &mut ChannelState<E>, channel_token: &mut ChannelToken<E>, cust_bal: i32, merch_bal: i32, name: String) -> Self {
|
||||
assert!(!channel_token.is_init());
|
||||
let mut kp = secp256k1::Secp256k1::new();
|
||||
kp.randomize(csprng);
|
||||
|
@ -192,6 +191,7 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
|
||||
println!("Customer wallet formed -> now returning the structure to the caller.");
|
||||
return CustomerWallet {
|
||||
name: name,
|
||||
pk_c: pk_c,
|
||||
sk_c: sk_c,
|
||||
cust_balance: cust_bal,
|
||||
|
@ -209,7 +209,7 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
}
|
||||
|
||||
// generate nizk proof of knowledge of commitment opening
|
||||
pub fn generate_proof<R: Rng>(&mut self, csprng: &mut R, channel_token: &ChannelToken<E>) -> CommitmentProof<E> {
|
||||
pub fn generate_proof<R: Rng>(&self, csprng: &mut R, channel_token: &ChannelToken<E>) -> CommitmentProof<E> {
|
||||
return CommitmentProof::<E>::new(csprng, &channel_token.comParams, &self.w_com.c, &self.wallet.as_fr_vec(), &self.r);
|
||||
}
|
||||
|
||||
|
@ -218,6 +218,7 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
let close_wallet = self.wallet.with_close(String::from("close"));
|
||||
let cp = channel.cp.as_ref().unwrap();
|
||||
let mpk = cp.pub_params.mpk.clone();
|
||||
//println!("verify_close_token - Wallet: {}", &self.wallet);
|
||||
|
||||
let is_close_valid = cp.pub_params.keypair.verify(&mpk, &close_wallet, &self.r, &close_token);
|
||||
if is_close_valid {
|
||||
|
@ -232,14 +233,16 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
return is_valid;
|
||||
}
|
||||
|
||||
panic!("Channel establish - Verification failed for close token!");
|
||||
panic!("Customer - Verification failed for close token!");
|
||||
}
|
||||
|
||||
pub fn verify_pay_token(&mut self, channel: &ChannelState<E>, pay_token: &Signature<E>) -> bool {
|
||||
// unblind and verify signature
|
||||
let cp = channel.cp.as_ref().unwrap();
|
||||
let mpk = cp.pub_params.mpk.clone();
|
||||
let wallet = self.wallet.as_fr_vec();
|
||||
// we don't want to include "close" prefix here (even if it is set)
|
||||
let wallet = self.wallet.without_close();
|
||||
//println!("verify_pay_token - Wallet: {}", &self.wallet);
|
||||
|
||||
let is_pay_valid = cp.pub_params.keypair.verify(&mpk, &wallet, &self.r, &pay_token);
|
||||
if is_pay_valid {
|
||||
|
@ -253,11 +256,18 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
return is_valid;
|
||||
}
|
||||
|
||||
panic!("verify_pay_token - Channel establish - Verification failed for pay token!") ;
|
||||
panic!("Customer - Verification failed for pay token!");
|
||||
}
|
||||
|
||||
pub fn has_tokens(&self) -> bool {
|
||||
let index = self.index - 1;
|
||||
let is_ct = self.close_tokens.get(&index).is_some();
|
||||
let is_pt = self.pay_tokens.get(&index).is_some();
|
||||
return is_ct && is_pt;
|
||||
}
|
||||
|
||||
// for channel pay
|
||||
pub fn generate_payment<R: Rng>(&mut self, csprng: &mut R, channel: &ChannelState<E>, amount: i32) -> (Proof<E>, Commitment<E>, secp256k1::PublicKey, CustomerWallet<E>) {
|
||||
pub fn generate_payment<R: Rng>(&self, csprng: &mut R, channel: &ChannelState<E>, amount: i32) -> (Proof<E>, Commitment<E>, secp256k1::PublicKey, CustomerWallet<E>) {
|
||||
// 1 - chooose new wpk/wsk pair
|
||||
let mut kp = secp256k1::Secp256k1::new();
|
||||
kp.randomize(csprng);
|
||||
|
@ -269,26 +279,47 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
let new_merch_bal = self.merch_balance + amount;
|
||||
let new_r = E::Fr::rand(csprng);
|
||||
|
||||
println!("old wallet close => {}", self.wallet.close.unwrap());
|
||||
//println!("old wallet close => {}", self.wallet.close.unwrap());
|
||||
|
||||
let cp = channel.cp.as_ref().unwrap();
|
||||
let old_wallet = Wallet { pkc: self.wallet.pkc.clone(), wpk: self.wallet.wpk.clone(), bc: self.cust_balance, bm: self.merch_balance, close: None };
|
||||
let new_wallet = Wallet { pkc: self.wallet.pkc.clone(), wpk: wpk_h, bc: new_cust_bal, bm: new_merch_bal, close: Some(self.wallet.close.unwrap()) };
|
||||
let new_wcom = cp.pub_params.comParams.commit(&new_wallet.as_fr_vec(), &new_r);
|
||||
|
||||
// turn this into a isolated test to make sure we are handling transition between close/pay tokens
|
||||
// println!("<==============================>");
|
||||
// println!("new wcom: {}", new_wcom);
|
||||
//
|
||||
// let new_wcom_pay= cp.pub_params.comParams.commit(&new_wallet.without_close(), &new_r);
|
||||
// println!("new pay com: {}", new_wcom_pay);
|
||||
// println!("<==============================>");
|
||||
//
|
||||
// let x = hash_to_fr::<E>(String::from("close").into_bytes() );
|
||||
// let ext_new_wcom = cp.pub_params.comParams.extend_commit(&new_wcom_pay, &x);
|
||||
// assert!( ext_new_wcom.c == new_wcom.c );
|
||||
//
|
||||
// // remove
|
||||
// let rm_close_new_wcom = cp.pub_params.comParams.remove_commit(&ext_new_wcom, &x);
|
||||
// println!("removed close from ext new wcom: {}", rm_close_new_wcom);
|
||||
// assert!( rm_close_new_wcom.c == new_wcom_pay.c );
|
||||
//
|
||||
// panic!("they are all equal!");
|
||||
|
||||
|
||||
// 3 - generate new blinded and randomized pay token
|
||||
let i = self.index - 1;
|
||||
let mut prev_pay_token = self.pay_tokens.get(&i).unwrap();
|
||||
|
||||
println!("OLD {}", &self.wallet);
|
||||
println!("NEW {}", &new_wallet);
|
||||
println!("{}", &prev_pay_token);
|
||||
// println!("OLD {}", &self.wallet);
|
||||
// println!("NEW {}", &new_wallet);
|
||||
// println!("{}", &prev_pay_token);
|
||||
|
||||
let pay_proof = cp.pub_params.prove(csprng, self.r.clone(), old_wallet, new_wallet.clone(),
|
||||
new_wcom.clone(), new_r, &prev_pay_token);
|
||||
|
||||
// update internal state after proof has been verified by remote
|
||||
let new_cw = CustomerWallet {
|
||||
name: self.name.clone(),
|
||||
pk_c: self.pk_c.clone(),
|
||||
sk_c: self.sk_c.clone(),
|
||||
cust_balance: new_cust_bal,
|
||||
|
@ -310,6 +341,7 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
// update the internal state of the customer wallet
|
||||
pub fn update(&mut self, new_wallet: CustomerWallet<E>) -> bool {
|
||||
// update everything except for the wpk/wsk pair
|
||||
assert!(self.name == new_wallet.name);
|
||||
self.cust_balance = new_wallet.cust_balance;
|
||||
self.merch_balance = new_wallet.merch_balance;
|
||||
self.r = new_wallet.r;
|
||||
|
@ -330,7 +362,7 @@ impl<E: Engine> CustomerWallet<E> {
|
|||
let old_wallet = self.old_kp.unwrap();
|
||||
// proceed with generating the close token
|
||||
let secp = secp256k1::Secp256k1::new();
|
||||
let rm = RevokedMessage::new(String::from("revoked"), old_wallet.wpk, None);
|
||||
let mut rm = RevokedMessage::new(String::from("revoked"), old_wallet.wpk, None);
|
||||
let revoke_msg = secp256k1::Message::from_slice(&rm.hash_to_slice()).unwrap();
|
||||
// msg = "revoked"|| old wsk (for old wallet)
|
||||
let revoke_token = secp.sign(&revoke_msg, &old_wallet.wsk);
|
||||
|
@ -363,7 +395,9 @@ pub struct MerchantWallet<E: Engine> {
|
|||
balance: i32,
|
||||
pk: secp256k1::PublicKey, // pk_m
|
||||
sk: secp256k1::SecretKey, // sk_m
|
||||
comParams: CSMultiParams<E>
|
||||
comParams: CSMultiParams<E>,
|
||||
pub keys: HashMap<String, PubKeyMap>,
|
||||
pub pay_tokens: HashMap<String, cl::Signature<E>>
|
||||
}
|
||||
|
||||
impl<E: Engine> MerchantWallet<E> {
|
||||
|
@ -379,7 +413,9 @@ impl<E: Engine> MerchantWallet<E> {
|
|||
balance: 0,
|
||||
pk: wpk,
|
||||
sk: wsk,
|
||||
comParams: cp.pub_params.comParams.clone()
|
||||
comParams: cp.pub_params.comParams.clone(),
|
||||
keys: HashMap::new(), // store wpks/revoke_tokens
|
||||
pay_tokens: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,19 +429,31 @@ impl<E: Engine> MerchantWallet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn issue_close_token<R: Rng>(&self, csprng: &mut R, cp: &ChannelParams<E>, com: &Commitment<E>, extend: bool) -> Signature<E> {
|
||||
pub fn init_balance(&mut self, balance: i32) {
|
||||
// set by the escrow/funding transactionf for the channel
|
||||
self.balance = balance;
|
||||
}
|
||||
|
||||
pub fn issue_close_token<R: Rng>(&self, csprng: &mut R, cp: &ChannelParams<E>, com: &Commitment<E>, extend_close: bool) -> Signature<E> {
|
||||
println!("issue_close_token => generating token");
|
||||
let x = hash_to_fr::<E>(String::from("close").into_bytes() );
|
||||
let close_com = match extend {
|
||||
let close_com = match extend_close {
|
||||
true => self.comParams.extend_commit(com, &x),
|
||||
false => com.clone()
|
||||
};
|
||||
//println!("com for close-token: {}", &close_com);
|
||||
return self.keypair.sign_blind(csprng, &cp.pub_params.mpk, close_com);
|
||||
}
|
||||
|
||||
pub fn issue_pay_token<R: Rng>(&self, csprng: &mut R, cp: &ChannelParams<E>, com: &Commitment<E>) -> Signature<E> {
|
||||
pub fn issue_pay_token<R: Rng>(&self, csprng: &mut R, cp: &ChannelParams<E>, com: &Commitment<E>, remove_close: bool) -> Signature<E> {
|
||||
println!("issue_pay_token => generating token");
|
||||
return self.keypair.sign_blind(csprng, &cp.pub_params.mpk, com.clone());
|
||||
let x = hash_to_fr::<E>(String::from("close").into_bytes() );
|
||||
let pay_com = match remove_close {
|
||||
true => self.comParams.remove_commit(com, &x),
|
||||
false => com.clone()
|
||||
};
|
||||
//println!("com for pay-token: {}", &pay_com);
|
||||
return self.keypair.sign_blind(csprng, &cp.pub_params.mpk, pay_com);
|
||||
}
|
||||
|
||||
pub fn verify_proof<R: Rng>(&self, csprng: &mut R, channel: &ChannelState<E>, com: &Commitment<E>, com_proof: &CommitmentProof<E>) -> (Signature<E>, Signature<E>) {
|
||||
|
@ -414,35 +462,50 @@ impl<E: Engine> MerchantWallet<E> {
|
|||
if is_valid {
|
||||
println!("Commitment PoK is valid!");
|
||||
let close_token = self.issue_close_token(csprng, cp, com, true);
|
||||
let pay_token = self.issue_pay_token(csprng, cp, com);
|
||||
let pay_token = self.issue_pay_token(csprng, cp, com, false);
|
||||
return (close_token, pay_token);
|
||||
}
|
||||
panic!("verify_proof - Failed to verify PoK of commitment opening");
|
||||
}
|
||||
|
||||
pub fn verify_payment<R: Rng>(&self, csprng: &mut R, channel: &ChannelState<E>, proof: &Proof<E>, com: &Commitment<E>, wpk: &secp256k1::PublicKey, amount: i32) -> (Signature<E>, Signature<E>) {
|
||||
fn store_wpk_with_token(&mut self, wpk: &secp256k1::PublicKey, pay_token: Signature<E>) {
|
||||
// compute fingerprint on wpk
|
||||
let wpk_str = util::compute_pub_key_fingerprint(&wpk);
|
||||
self.pay_tokens.insert(wpk_str, pay_token);
|
||||
}
|
||||
|
||||
fn get_pay_token(&self, wpk: &secp256k1::PublicKey) -> Signature<E> {
|
||||
let wpk_str = util::compute_pub_key_fingerprint(&wpk);
|
||||
return self.pay_tokens.get(&wpk_str).unwrap().clone();
|
||||
}
|
||||
|
||||
pub fn verify_payment<R: Rng>(&mut self, csprng: &mut R, channel: &ChannelState<E>, proof: &Proof<E>, com: &Commitment<E>, wpk: &secp256k1::PublicKey, amount: i32) -> Signature<E> {
|
||||
let cp = channel.cp.as_ref().unwrap();
|
||||
let pay_proof = proof.clone();
|
||||
let prev_wpk = hash_pubkey_to_fr::<E>(&wpk);
|
||||
let epsilon = E::Fr::from_str(&amount.to_string()).unwrap();
|
||||
|
||||
if cp.pub_params.verify(pay_proof, epsilon, com, prev_wpk) {
|
||||
|
||||
// 1 - proceed with generating close token
|
||||
// 1 - proceed with generating close and pay token
|
||||
let close_token = self.issue_close_token(csprng, cp, com, false);
|
||||
let pay_token = self.issue_pay_token(csprng, cp, com);
|
||||
return (close_token, pay_token);
|
||||
let pay_token = self.issue_pay_token(csprng, cp, com, true);
|
||||
// let's store the pay token with the wpk for now
|
||||
self.store_wpk_with_token(wpk, pay_token);
|
||||
return close_token;
|
||||
}
|
||||
|
||||
panic!("verify_payment - Failed to validate NIZK PoK for payment.");
|
||||
}
|
||||
|
||||
pub fn verify_revoke_token(&self, revoke_token: &secp256k1::Signature, revoke_msg: &RevokedMessage, wpk: &secp256k1::PublicKey) -> bool {
|
||||
pub fn verify_revoke_token(&self, revoke_token: &secp256k1::Signature, revoke_msg: &RevokedMessage, wpk: &secp256k1::PublicKey) -> Signature<E> {
|
||||
let secp = secp256k1::Secp256k1::new();
|
||||
let msg = secp256k1::Message::from_slice(&revoke_msg.hash_to_slice()).unwrap();
|
||||
// verify that the revocation token is valid
|
||||
return secp.verify(&msg, revoke_token, wpk).is_ok();
|
||||
if secp.verify(&msg, revoke_token, wpk).is_ok() {
|
||||
return self.get_pay_token(wpk);
|
||||
}
|
||||
panic!("verify_revoke_token - Failed to verify the revoke token for wpk!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -456,7 +519,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn channel_util_works() {
|
||||
println!("Initializing channels...");
|
||||
let mut channel = ChannelState::<Bls12>::new(String::from("Channel A <-> B"), false);
|
||||
let mut rng = &mut rand::thread_rng();
|
||||
|
||||
|
@ -475,7 +537,7 @@ mod tests {
|
|||
|
||||
// retrieve commitment setup params (using merchant long lived pk params)
|
||||
// initialize on the customer side with balance: b0_cust
|
||||
let mut cust_wallet = CustomerWallet::<Bls12>::new(rng, &mut channel, &mut channel_token, b0_cust, b0_merch);
|
||||
let mut cust_wallet = CustomerWallet::<Bls12>::new(rng, &mut channel, &mut channel_token, b0_cust, b0_merch, String::from("Alice"));
|
||||
|
||||
// lets establish the channel
|
||||
let cust_com_proof = cust_wallet.generate_proof(rng, &mut channel_token);
|
||||
|
@ -483,40 +545,43 @@ mod tests {
|
|||
// first return the close token, then wait for escrow-tx confirmation
|
||||
// then send the pay-token after confirmation
|
||||
let (close_token, pay_token) = merch_wallet.verify_proof(rng, &channel, &cust_wallet.w_com, &cust_com_proof);
|
||||
|
||||
// unblind tokens and verify signatures
|
||||
assert!(cust_wallet.verify_pay_token(&channel, &pay_token));
|
||||
|
||||
assert!(cust_wallet.verify_close_token(&channel, &close_token));
|
||||
|
||||
assert!(cust_wallet.verify_pay_token(&channel, &pay_token));
|
||||
|
||||
println!("Done!");
|
||||
|
||||
// pay protocol tests
|
||||
let amount = 10;
|
||||
let (pay_proof, new_com, old_wpk, new_cw) = cust_wallet.generate_payment(rng, &channel, amount);
|
||||
|
||||
println!("{}", new_com);
|
||||
println!("wpk => {}", old_wpk);
|
||||
println!("{}", new_cw);
|
||||
// println!("{}", new_com);
|
||||
// println!("wpk => {}", old_wpk);
|
||||
// println!("{}", new_cw);
|
||||
|
||||
// new pay_token is not sent until revoke_token is obtained from the customer
|
||||
let (new_close_token, new_pay_token) = merch_wallet.verify_payment(rng, &channel, &pay_proof, &new_com, &old_wpk, amount);
|
||||
let new_close_token = merch_wallet.verify_payment(rng, &channel, &pay_proof, &new_com, &old_wpk, amount);
|
||||
|
||||
println!("Close Token : {}", new_close_token);
|
||||
//println!("1 - Updated close Token : {}", new_close_token);
|
||||
// unblind tokens and verify signatures
|
||||
|
||||
// assuming the pay_proof checks out, can go ahead and update internal state of cust_wallet
|
||||
assert!(cust_wallet.update(new_cw));
|
||||
//println!("2 - updated customer wallet!");
|
||||
|
||||
assert!(cust_wallet.verify_close_token(&channel, &new_close_token));
|
||||
//println!("3 - verified the close token!");
|
||||
|
||||
// invalidate the previous state only if close token checks out
|
||||
let (revoke_msg, revoke_token) = cust_wallet.generate_revoke_token(&channel, &new_close_token);
|
||||
let (revoke_msg, revoke_sig) = cust_wallet.generate_revoke_token(&channel, &new_close_token);
|
||||
//println!("4 - Generated revoke token successfully.");
|
||||
|
||||
//println!("5 - Revoke token => {}", revoke_token);
|
||||
|
||||
let new_pay_token = merch_wallet.verify_revoke_token(&revoke_sig, &revoke_msg, &old_wpk);
|
||||
assert!(cust_wallet.verify_pay_token(&channel, &new_pay_token));
|
||||
|
||||
println!("Revoke token => {}", revoke_token);
|
||||
|
||||
assert!(merch_wallet.verify_revoke_token(&revoke_token, &revoke_msg, &old_wpk));
|
||||
|
||||
println!("Validated revoke token!");
|
||||
//println!("Validated revoke token!");
|
||||
}
|
||||
}
|
|
@ -90,6 +90,12 @@ pub struct Signature<E: Engine> {
|
|||
pub H: E::G1,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Signature<E> {
|
||||
fn eq(&self, other: &Signature<E>) -> bool {
|
||||
self.h == other.h && self.H == other.H
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KeyPair<E: Engine> {
|
||||
pub secret: SecretKey<E>,
|
||||
|
|
3047
src/lib.rs
3047
src/lib.rs
File diff suppressed because it is too large
Load Diff
17
src/ped92.rs
17
src/ped92.rs
|
@ -1,7 +1,7 @@
|
|||
// ped92.rs
|
||||
use rand::{thread_rng, Rng};
|
||||
use pairing::{Engine, CurveProjective};
|
||||
use ff::Rand;
|
||||
use ff::{Rand, Field};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -128,6 +128,19 @@ impl<E: Engine> CSMultiParams<E> {
|
|||
return Commitment { c };
|
||||
}
|
||||
|
||||
pub fn remove_commit(&self, com: &Commitment<E>, x: &E::Fr) -> Commitment<E> {
|
||||
// c = com * gn+1 ^ x
|
||||
let len = self.pub_bases.len();
|
||||
let mut c = self.pub_bases[len-1].clone();
|
||||
let xx = x.clone();
|
||||
c.mul_assign(xx);
|
||||
c.negate();
|
||||
c.add_assign(&com.c);
|
||||
|
||||
return Commitment { c };
|
||||
}
|
||||
|
||||
|
||||
pub fn decommit(&self, cm: &Commitment<E>, x: &Vec<E::Fr>, r: &E::Fr) -> bool {
|
||||
let l = x.len();
|
||||
// pub_base[0] => h, x[0] => r
|
||||
|
@ -208,4 +221,6 @@ mod tests {
|
|||
let c2 = csp.commit(&m2, &r);
|
||||
assert_eq!(csp.decommit(&c2, &m2, &r), true);
|
||||
}
|
||||
|
||||
// add tests for extend/remove commits dynamically
|
||||
}
|
||||
|
|
57
src/util.rs
57
src/util.rs
|
@ -5,6 +5,7 @@ use ff::PrimeField;
|
|||
use rand::Rng;
|
||||
use ped92::CSMultiParams;
|
||||
use secp256k1::{Signature, PublicKey};
|
||||
use cl::Signature as clSignature;
|
||||
|
||||
pub fn hash_g1_to_fr<E: Engine>(x: &Vec<E::G1>) -> E::Fr {
|
||||
let mut x_vec: Vec<u8> = Vec::new();
|
||||
|
@ -63,6 +64,14 @@ pub fn convert_int_to_fr<E: Engine>(value: i32) -> E::Fr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn compute_pub_key_fingerprint(wpk: &secp256k1::PublicKey) -> String {
|
||||
let x_slice = wpk.serialize();
|
||||
let sha2_digest = sha512::hash(&x_slice);
|
||||
let h = format!("{:x}", HexSlice::new(&sha2_digest[0..16]));
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
pub struct CommitmentProof<E: Engine> {
|
||||
pub T: E::G1,
|
||||
pub z: Vec<E::Fr>
|
||||
|
@ -187,54 +196,6 @@ impl RevokedMessage {
|
|||
}
|
||||
}
|
||||
|
||||
// refund message
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct CloseMessage<E: Engine> {
|
||||
pub msgtype: String, // purpose type of message
|
||||
pub wpk: secp256k1::PublicKey,
|
||||
pub balance: usize, // the balance
|
||||
pub r: Option<E::Fr>, // randomness from customer wallet
|
||||
pub rt: Option<cl::Signature<E>> // refund token
|
||||
}
|
||||
|
||||
impl<E: Engine> CloseMessage<E> {
|
||||
pub fn new(_msgtype: String, _wpk: secp256k1::PublicKey,
|
||||
_balance: usize, _r: Option<E::Fr>, _rt: Option<cl::Signature<E>>) -> CloseMessage<E> {
|
||||
RefundMessage {
|
||||
msgtype: _msgtype, wpk: _wpk, balance: _balance, r: _r, rt: _rt
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn hash(&self) -> Vec<E::Fr> {
|
||||
// let mut v: Vec<Fr> = Vec::new();
|
||||
// let mut input_buf = Vec::new();
|
||||
// input_buf.extend_from_slice(self.msgtype.as_bytes());
|
||||
// v.push(convert_to_fr::<E>(&input_buf));
|
||||
//
|
||||
// v.push(hash_pubkey_to_fr::<E>(&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(convert_to_fr(&b_buf));
|
||||
//
|
||||
// //let r_vec: Vec<u8> = encode(&self.r, Infinite).unwrap();
|
||||
// if !self.r.is_none() {
|
||||
// v.push(self.r.unwrap().clone());
|
||||
// }
|
||||
//
|
||||
// if !self.rt.is_none() {
|
||||
// let rt = {
|
||||
// &self.rt.clone()
|
||||
// };
|
||||
// let rt_ref = rt.as_ref();
|
||||
// v.push(rt_ref.unwrap().hash(&self.msgtype));
|
||||
// }
|
||||
//
|
||||
// return v;
|
||||
// }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -24,6 +24,10 @@ impl<E: Engine> Wallet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn without_close(&self) -> Vec<E::Fr> {
|
||||
vec!(self.pkc, self.wpk, E::Fr::from_str(&self.bc.to_string()).unwrap(), E::Fr::from_str(&self.bm.to_string()).unwrap())
|
||||
}
|
||||
|
||||
pub fn with_close(&mut self, msg: String) -> Vec<E::Fr> {
|
||||
let m = hash_to_fr::<E>(msg.into_bytes() );
|
||||
self.close = Some(m.clone());
|
||||
|
|
Loading…
Reference in New Issue