add third-party payment option
This commit is contained in:
parent
ca4f790cee
commit
fb261a917b
|
@ -102,7 +102,7 @@ fn main() {
|
||||||
// let's test the pay protocol
|
// let's test the pay protocol
|
||||||
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &init_cust_data.T, &merch_keypair.pk, &mut init_cust_data.csk));
|
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &init_cust_data.T, &merch_keypair.pk, &mut init_cust_data.csk));
|
||||||
let s = PreciseTime::now();
|
let s = PreciseTime::now();
|
||||||
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &init_cust_data.T, // channel token
|
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel, &init_cust_data.T, // channel token
|
||||||
&merch_keypair.pk, // merchant pub key
|
&merch_keypair.pk, // merchant pub key
|
||||||
&init_cust_data.csk, // wallet
|
&init_cust_data.csk, // wallet
|
||||||
5); // balance increment
|
5); // balance increment
|
||||||
|
@ -132,7 +132,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &init_cust_data.T, &merch_keypair.pk, &mut init_cust_data.csk));
|
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &init_cust_data.T, &merch_keypair.pk, &mut init_cust_data.csk));
|
||||||
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &init_cust_data.T, // channel token
|
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel, &init_cust_data.T, // channel token
|
||||||
&merch_keypair.pk, // merchant pub key
|
&merch_keypair.pk, // merchant pub key
|
||||||
&init_cust_data.csk, // wallet
|
&init_cust_data.csk, // wallet
|
||||||
-10); // balance increment
|
-10); // balance increment
|
||||||
|
|
|
@ -332,7 +332,7 @@ mod tests {
|
||||||
|
|
||||||
let cm_csp = commit_scheme::setup(b, m_keypair.pk.Z2.clone(), mpk.g2.clone());
|
let cm_csp = commit_scheme::setup(b, m_keypair.pk.Z2.clone(), mpk.g2.clone());
|
||||||
let r = m1[0];
|
let r = m1[0];
|
||||||
let (w_com, _) = commit_scheme::commit(&cm_csp, &m1, r);
|
let w_com = commit_scheme::commit(&cm_csp, &m1, r);
|
||||||
|
|
||||||
assert!(commit_scheme::decommit(&cm_csp, &w_com, &m1));
|
assert!(commit_scheme::decommit(&cm_csp, &w_com, &m1));
|
||||||
|
|
||||||
|
|
|
@ -155,27 +155,23 @@ pub fn setup_gen_params(len: usize) -> CSParams {
|
||||||
return CSParams { pub_bases: p };
|
return CSParams { pub_bases: p };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(csp: &CSParams, x: &Vec<Fr>, r: Fr) -> (Commitment, Vec<G2>) {
|
pub fn commit(csp: &CSParams, x: &Vec<Fr>, r: Fr) -> Commitment {
|
||||||
let rng = &mut thread_rng();
|
let rng = &mut thread_rng();
|
||||||
|
|
||||||
//let r = R.unwrap_or(Fr::random(rng));
|
//let r = R.unwrap_or(Fr::random(rng));
|
||||||
let mut c_vec: Vec<G2> = Vec::new();
|
|
||||||
// c = g1^m1 * ... * gn^mn * h^r
|
// c = g1^m1 * ... * gn^mn * h^r
|
||||||
//println!("(commit) index: 0");
|
//println!("(commit) index: 0");
|
||||||
let mut c = (csp.pub_bases[0] * r);
|
let mut c = (csp.pub_bases[0] * r);
|
||||||
c_vec.push(c);
|
|
||||||
for i in 1 .. x.len() {
|
for i in 1 .. x.len() {
|
||||||
//println!("(commit) index: {}", i);
|
//println!("(commit) index: {}", i);
|
||||||
let tmp = (csp.pub_bases[i] * x[i]);
|
c = c + (csp.pub_bases[i] * x[i]);
|
||||||
c_vec.push(tmp);
|
|
||||||
c = c + tmp;
|
|
||||||
}
|
}
|
||||||
// return (c, r) <- r
|
// return (c, r) <- r
|
||||||
let commitment = Commitment { c: c, r: r };
|
let commitment = Commitment { c: c, r: r };
|
||||||
|
|
||||||
// debugging
|
// debugging
|
||||||
//println!("{}", commitment);
|
//println!("{}", commitment);
|
||||||
return (commitment, c_vec);
|
return commitment;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decommit(csp: &CSParams, cm: &Commitment, x: &Vec<Fr>) -> bool {
|
pub fn decommit(csp: &CSParams, cm: &Commitment, x: &Vec<Fr>) -> bool {
|
||||||
|
@ -222,7 +218,7 @@ mod tests {
|
||||||
m.push(Fr::random(rng));
|
m.push(Fr::random(rng));
|
||||||
}
|
}
|
||||||
let r = m[0];
|
let r = m[0];
|
||||||
let (c, _) = commit(&csp, &m, r);
|
let c = commit(&csp, &m, r);
|
||||||
|
|
||||||
assert!(decommit(&csp, &c, &m) == true);
|
assert!(decommit(&csp, &c, &m) == true);
|
||||||
}
|
}
|
||||||
|
|
197
src/lib.rs
197
src/lib.rs
|
@ -468,7 +468,7 @@ pub mod unidirectional {
|
||||||
ck_vec.push(ck);
|
ck_vec.push(ck);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (w_com, _) = commit_scheme::commit(&cm_pk, &msg.hash(), r);
|
let w_com = commit_scheme::commit(&cm_pk, &msg.hash(), r);
|
||||||
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk };
|
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk };
|
||||||
let csk_c = CustSecretKey { sk: keypair.sk, k1: k1, k2: k2, r: r, balance: b0_customer, ck_vec: ck_vec };
|
let csk_c = CustSecretKey { sk: keypair.sk, k1: k1, k2: k2, r: r, balance: b0_customer, ck_vec: ck_vec };
|
||||||
return InitCustomerData { T: t_c, csk: csk_c };
|
return InitCustomerData { T: t_c, csk: csk_c };
|
||||||
|
@ -514,6 +514,7 @@ pub mod bidirectional {
|
||||||
use hash_pub_key_to_fr;
|
use hash_pub_key_to_fr;
|
||||||
use hash_buffer_to_fr;
|
use hash_buffer_to_fr;
|
||||||
use debug_elem_in_hex;
|
use debug_elem_in_hex;
|
||||||
|
use debug_g2_in_hex;
|
||||||
use debug_gt_in_hex;
|
use debug_gt_in_hex;
|
||||||
use convert_to_fr;
|
use convert_to_fr;
|
||||||
use convert_str_to_fr;
|
use convert_str_to_fr;
|
||||||
|
@ -611,6 +612,7 @@ pub mod bidirectional {
|
||||||
pub struct ChannelState {
|
pub struct ChannelState {
|
||||||
keys: HashMap<String, PubKeyMap>,
|
keys: HashMap<String, PubKeyMap>,
|
||||||
R: i32,
|
R: i32,
|
||||||
|
tx_fee: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cid: Fr,
|
pub cid: Fr,
|
||||||
pub pay_init: bool,
|
pub pay_init: bool,
|
||||||
|
@ -623,6 +625,7 @@ pub mod bidirectional {
|
||||||
ChannelState {
|
ChannelState {
|
||||||
keys: HashMap::new(), // store wpks/revoke_tokens
|
keys: HashMap::new(), // store wpks/revoke_tokens
|
||||||
R: 0,
|
R: 0,
|
||||||
|
tx_fee: 0,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
cid: generate_channel_id(),
|
cid: generate_channel_id(),
|
||||||
pay_init: false,
|
pay_init: false,
|
||||||
|
@ -630,6 +633,14 @@ pub mod bidirectional {
|
||||||
third_party: third_party_support
|
third_party: third_party_support
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_channel_fee(&mut self, fee: i32) {
|
||||||
|
self.tx_fee = fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_channel_fee(&self) -> i32 {
|
||||||
|
return self.tx_fee as i32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChannelclosureC {
|
pub struct ChannelclosureC {
|
||||||
|
@ -643,22 +654,33 @@ pub mod bidirectional {
|
||||||
}
|
}
|
||||||
|
|
||||||
// proof of valid balance
|
// proof of valid balance
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ProofVB {
|
pub struct ProofVB {
|
||||||
range_proof: bulletproofs::RangeProof,
|
range_proof: bulletproofs::RangeProof,
|
||||||
value_commitment: RistrettoPoint
|
value_commitment: RistrettoPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BalanceProof {
|
||||||
|
third_party: bool,
|
||||||
|
balance_increment: i32,
|
||||||
|
w_com_pr_pr: G2,
|
||||||
|
old_bal_com: G2,
|
||||||
|
vcom: Option<commit_scheme::Commitment>,
|
||||||
|
proof_vcom: Option<clproto::ProofCV>,
|
||||||
|
proof_vrange: Option<ProofVB>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct PaymentProof {
|
pub struct PaymentProof {
|
||||||
proof2a: clproto::ProofCV, // PoK of committed values in new wallet
|
proof2a: clproto::ProofCV, // PoK of committed values in new wallet
|
||||||
proof2b: clproto::ProofCV, // PoK of committed values in old wallet (minus wpk)
|
proof2b: clproto::ProofCV, // PoK of committed values in old wallet (minus wpk)
|
||||||
proof2c: clproto::ProofVS, // PoK of old wallet signature (that includes wpk)
|
proof2c: clproto::ProofVS, // PoK of old wallet signature (that includes wpk)
|
||||||
proof3: ProofVB, // range proof that balance - balance_inc is between (0, val_max)
|
proof3: ProofVB, // range proof that balance - balance_inc is between (0, val_max)
|
||||||
w_com_pr_pr: G2,
|
|
||||||
balance_inc: i32, // balance increment
|
|
||||||
old_bal_com: G2,
|
|
||||||
old_com_base: G2,
|
old_com_base: G2,
|
||||||
wpk: secp256k1::PublicKey, // verification key for old wallet
|
wpk: secp256k1::PublicKey, // verification key for old wallet
|
||||||
wallet_sig: clsigs::SignatureD // blinded signature for old wallet
|
wallet_sig: clsigs::SignatureD, // blinded signature for old wallet
|
||||||
|
pub bal_proof: BalanceProof
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RevokeToken {
|
pub struct RevokeToken {
|
||||||
|
@ -718,7 +740,7 @@ pub mod bidirectional {
|
||||||
// commitment, channel id, customer balance, hash of wpk (wallet ver/pub key)
|
// commitment, channel id, customer balance, hash of wpk (wallet ver/pub key)
|
||||||
let mut x: Vec<Fr> = vec![r, cid, b0, h_wpk];
|
let mut x: Vec<Fr> = vec![r, cid, b0, h_wpk];
|
||||||
// commitment of wallet values
|
// commitment of wallet values
|
||||||
let (w_com, _) = commit_scheme::commit(&cm_csp, &x, r);
|
let w_com = commit_scheme::commit(&cm_csp, &x, r);
|
||||||
// construct channel token
|
// construct channel token
|
||||||
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk.clone(), third_party_pay: channel.third_party };
|
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk.clone(), third_party_pay: channel.third_party };
|
||||||
// construct customer wallet secret key plus other components
|
// construct customer wallet secret key plus other components
|
||||||
|
@ -827,7 +849,7 @@ pub mod bidirectional {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pay_by_customer_phase1(pp: &PublicParams, T: &ChannelToken, pk_m: &clsigs::PublicKeyD,
|
pub fn pay_by_customer_phase1(pp: &PublicParams, channel: &ChannelState, T: &ChannelToken, pk_m: &clsigs::PublicKeyD,
|
||||||
old_w: &CustomerWallet, balance_increment: i32) -> (ChannelToken, CustomerWallet, PaymentProof) {
|
old_w: &CustomerWallet, balance_increment: i32) -> (ChannelToken, CustomerWallet, PaymentProof) {
|
||||||
//println!("pay_by_customer_phase1 - generate new wallet commit, PoK of commit values, and PoK of old wallet.");
|
//println!("pay_by_customer_phase1 - generate new wallet commit, PoK of commit values, and PoK of old wallet.");
|
||||||
// get balance, keypair, commitment randomness and wallet sig
|
// get balance, keypair, commitment randomness and wallet sig
|
||||||
|
@ -852,18 +874,18 @@ pub mod bidirectional {
|
||||||
// retrieve the current payment channel id
|
// retrieve the current payment channel id
|
||||||
let cid = old_w.cid.clone();
|
let cid = old_w.cid.clone();
|
||||||
// convert balance into Fr (B - e)
|
// convert balance into Fr (B - e)
|
||||||
let updated_balance = bal - balance_increment;
|
let updated_balance = bal - balance_increment - channel.tx_fee;
|
||||||
if updated_balance < 0 {
|
if updated_balance < 0 {
|
||||||
panic!("pay_by_customer_phase1 - insufficient funds to make payment!");
|
panic!("pay_by_customer_phase1 - insufficient funds to make payment!");
|
||||||
}
|
}
|
||||||
// record the potential to payment
|
// record the potential to payment
|
||||||
let merchant_balance = old_w.merchant_balance + balance_increment;
|
let merchant_balance = old_w.merchant_balance + (balance_increment + channel.tx_fee);
|
||||||
|
|
||||||
let updated_balance_pr = convert_int_to_fr(updated_balance);
|
let updated_balance_pr = convert_int_to_fr(updated_balance);
|
||||||
|
|
||||||
let mut new_wallet_sec: Vec<Fr> = vec![r_pr, cid, updated_balance_pr, h_wpk];
|
let mut new_wallet_sec: Vec<Fr> = vec![r_pr, cid, updated_balance_pr, h_wpk];
|
||||||
// commitment of new wallet values
|
// commitment of new wallet values
|
||||||
let (w_com, com_vec) = commit_scheme::commit(&cm_csp, &new_wallet_sec, r_pr);
|
let w_com = commit_scheme::commit(&cm_csp, &new_wallet_sec, r_pr);
|
||||||
let w_com_bytes: Vec<u8> = encode(&w_com.c, Infinite).unwrap();
|
let w_com_bytes: Vec<u8> = encode(&w_com.c, Infinite).unwrap();
|
||||||
|
|
||||||
// generate proof of knowledge for committed values in new wallet
|
// generate proof of knowledge for committed values in new wallet
|
||||||
|
@ -887,8 +909,52 @@ pub mod bidirectional {
|
||||||
|
|
||||||
let proof_rp = ProofVB { range_proof: range_proof, value_commitment: value_cm };
|
let proof_rp = ProofVB { range_proof: range_proof, value_commitment: value_cm };
|
||||||
|
|
||||||
|
let mut bal_proof;
|
||||||
if T.third_party_pay {
|
if T.third_party_pay {
|
||||||
// TODO: add check for third-party payment support
|
let r_inc = Fr::random(rng);
|
||||||
|
let bal_inc_fr = -convert_int_to_fr(balance_increment + channel.tx_fee);
|
||||||
|
let inc_vec: Vec<Fr> = vec![r_inc, bal_inc_fr];
|
||||||
|
let mut v_com = commit_scheme::commit(&cm_csp, &inc_vec, r_inc);
|
||||||
|
//let tx_fee = cm_csp.pub_bases[1] * -convert_int_to_fr(channel.tx_fee);
|
||||||
|
//v_com.c = v_com.c + tx_fee;
|
||||||
|
let proof_vcom = clproto::bs_gen_nizk_proof(&inc_vec, &cm_csp.pub_bases, v_com.c);
|
||||||
|
|
||||||
|
// range proof that pay increment < payment max
|
||||||
|
let v_com_bytes: Vec<u8> = encode(&proof_vcom.C, Infinite).unwrap();
|
||||||
|
|
||||||
|
let mut inc_bal;
|
||||||
|
let final_balance_increment = balance_increment + channel.tx_fee;
|
||||||
|
if final_balance_increment < 0 {
|
||||||
|
// negative value => convert to positive value
|
||||||
|
assert!(final_balance_increment >= -E_MAX);
|
||||||
|
inc_bal = -final_balance_increment as u64
|
||||||
|
} else {
|
||||||
|
// positive value
|
||||||
|
inc_bal = final_balance_increment as u64;
|
||||||
|
}
|
||||||
|
let inc_blinding = Scalar::hash_from_bytes::<Sha512>(&v_com_bytes);
|
||||||
|
let mut osrng1 = OsRng::new().unwrap();
|
||||||
|
let mut transcript1 = ProofTranscript::new(b"Range Proof for Balance Increment");
|
||||||
|
let inc_range_proof = RangeProof::prove_single(&pp.range_proof_gens, &mut transcript1,
|
||||||
|
&mut osrng1, inc_bal, &inc_blinding,
|
||||||
|
pp.range_proof_bits).unwrap();
|
||||||
|
let inc_pg = &pp.range_proof_gens.pedersen_gens;
|
||||||
|
let inc_cm = inc_pg.commit(Scalar::from(inc_bal), inc_blinding);
|
||||||
|
|
||||||
|
let proof_vrange = ProofVB { range_proof: inc_range_proof, value_commitment: inc_cm };
|
||||||
|
bal_proof = BalanceProof { third_party: true, vcom: Some(v_com),
|
||||||
|
proof_vcom: Some(proof_vcom), proof_vrange: Some(proof_vrange),
|
||||||
|
w_com_pr_pr: w_com_pr_pr, balance_increment: 0,
|
||||||
|
old_bal_com: wallet_proof.bal_com,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// balance_increment => // epsilon - payment increment/decrement
|
||||||
|
// wallet_proof.bal_com => // old balance commitment
|
||||||
|
bal_proof = BalanceProof { third_party: false, vcom: None,
|
||||||
|
proof_vcom: None, proof_vrange: None,
|
||||||
|
w_com_pr_pr: w_com_pr_pr, balance_increment: balance_increment,
|
||||||
|
old_bal_com: wallet_proof.bal_com,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// create payment proof which includes params to reveal wpk from old wallet
|
// create payment proof which includes params to reveal wpk from old wallet
|
||||||
|
@ -897,10 +963,7 @@ pub mod bidirectional {
|
||||||
proof2b: wallet_proof.proof_cv, // PoK of committed values (minus h(wpk))
|
proof2b: wallet_proof.proof_cv, // PoK of committed values (minus h(wpk))
|
||||||
proof2c: wallet_proof.proof_vs, // PoK of signature on old wallet
|
proof2c: wallet_proof.proof_vs, // PoK of signature on old wallet
|
||||||
proof3: proof_rp, // range proof that the updated_balance is within a public range
|
proof3: proof_rp, // range proof that the updated_balance is within a public range
|
||||||
// TODO: clean up: balance_inc, old_bal_com, old_com_base, wpk (should be a separate structure?)
|
bal_proof: bal_proof,
|
||||||
w_com_pr_pr: w_com_pr_pr,
|
|
||||||
balance_inc: balance_increment, // epsilon - payment increment/decrement
|
|
||||||
old_bal_com: wallet_proof.bal_com, // old balance commitment
|
|
||||||
old_com_base: cm_csp.pub_bases[wpk_index], // base Z
|
old_com_base: cm_csp.pub_bases[wpk_index], // base Z
|
||||||
wpk: old_w.wpk.clone(), // showing public key for old wallet
|
wpk: old_w.wpk.clone(), // showing public key for old wallet
|
||||||
wallet_sig: wallet_proof.blind_sig // blinded signature for old wallet
|
wallet_sig: wallet_proof.blind_sig // blinded signature for old wallet
|
||||||
|
@ -922,6 +985,7 @@ pub mod bidirectional {
|
||||||
let proof_cv = &proof.proof2a;
|
let proof_cv = &proof.proof2a;
|
||||||
let proof_old_cv = &proof.proof2b;
|
let proof_old_cv = &proof.proof2b;
|
||||||
let proof_vs = &proof.proof2c;
|
let proof_vs = &proof.proof2c;
|
||||||
|
let bal_proof = &proof.bal_proof;
|
||||||
// get merchant keypair
|
// get merchant keypair
|
||||||
let pk_m = &m_data.T;
|
let pk_m = &m_data.T;
|
||||||
let sk_m = &m_data.csk.sk;
|
let sk_m = &m_data.csk.sk;
|
||||||
|
@ -932,7 +996,7 @@ pub mod bidirectional {
|
||||||
|
|
||||||
// add specified wpk to make the proof valid
|
// add specified wpk to make the proof valid
|
||||||
// NOTE: if valid, then wpk is indeed the wallet public key for the wallet
|
// NOTE: if valid, then wpk is indeed the wallet public key for the wallet
|
||||||
let new_C = proof_old_cv.C + proof.old_bal_com + (proof.old_com_base * hash_pub_key_to_fr(&proof.wpk));
|
let new_C = proof_old_cv.C + bal_proof.old_bal_com + (proof.old_com_base * hash_pub_key_to_fr(&proof.wpk));
|
||||||
let new_proof_old_cv = clproto::ProofCV { T: proof_old_cv.T,
|
let new_proof_old_cv = clproto::ProofCV { T: proof_old_cv.T,
|
||||||
C: new_C,
|
C: new_C,
|
||||||
s: proof_old_cv.s.clone(),
|
s: proof_old_cv.s.clone(),
|
||||||
|
@ -944,7 +1008,7 @@ pub mod bidirectional {
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_existing_wpk = exist_in_merchant_state(&state, &proof.wpk, None);
|
let is_existing_wpk = exist_in_merchant_state(&state, &proof.wpk, None);
|
||||||
let bal_inc_within_range = proof.balance_inc >= -E_MAX && proof.balance_inc <= E_MAX;
|
let bal_inc_within_range = bal_proof.balance_increment >= -E_MAX && bal_proof.balance_increment <= E_MAX;
|
||||||
// check the range proof of the updated balance
|
// check the range proof of the updated balance
|
||||||
let mut osrng = OsRng::new().unwrap();
|
let mut osrng = OsRng::new().unwrap();
|
||||||
let mut transcript = ProofTranscript::new(b"BOLT Range Proof");
|
let mut transcript = ProofTranscript::new(b"BOLT Range Proof");
|
||||||
|
@ -958,7 +1022,7 @@ pub mod bidirectional {
|
||||||
// check that the proof of valid signature and then
|
// check that the proof of valid signature and then
|
||||||
if proof_vs_old_wallet && !is_existing_wpk && bal_inc_within_range && is_range_proof_valid {
|
if proof_vs_old_wallet && !is_existing_wpk && bal_inc_within_range && is_range_proof_valid {
|
||||||
println!("Proof of knowledge of signature is valid!");
|
println!("Proof of knowledge of signature is valid!");
|
||||||
if proof.balance_inc < 0 {
|
if bal_proof.balance_increment < 0 {
|
||||||
// negative increment
|
// negative increment
|
||||||
state.R = 1;
|
state.R = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -970,14 +1034,25 @@ pub mod bidirectional {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we can verify the proof of knowledge for committed values in new wallet
|
// now we can verify the proof of knowledge for committed values in new wallet
|
||||||
let bal_index = 2;
|
if !proof.bal_proof.third_party {
|
||||||
let mut bal_inc_fr;
|
let bal_inc_fr = -convert_int_to_fr(bal_proof.balance_increment);
|
||||||
bal_inc_fr = -convert_int_to_fr(proof.balance_inc);
|
|
||||||
// check that the PoK on new wallet commitment is valid and
|
// check that the PoK on new wallet commitment is valid and
|
||||||
// the updated balance differs by the balance increment from the balance
|
// the updated balance differs by the balance increment from the balance
|
||||||
// in previous wallet
|
// in previous wallet
|
||||||
let w_com_pr = proof.w_com_pr_pr + proof.old_bal_com + (proof_old_cv.pub_bases[bal_index] * bal_inc_fr);
|
let bal_index = 2;
|
||||||
if clproto::bs_verify_nizk_proof(&proof_cv) && (proof_cv.C == w_com_pr) {
|
let w_com_pr = bal_proof.w_com_pr_pr + bal_proof.old_bal_com + (proof_old_cv.pub_bases[bal_index] * bal_inc_fr);
|
||||||
|
if proof_cv.C != w_com_pr {
|
||||||
|
panic!("pay_by_merchant_phase1 - Old and new balance does not differ by payment amount!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// in third party case, what we do a PoK for committed payment increment
|
||||||
|
let proof_vcom = proof.bal_proof.proof_vcom.as_ref().unwrap();
|
||||||
|
if !clproto::bs_verify_nizk_proof(&proof_vcom) {
|
||||||
|
panic!("pay_by_merchant_phase1 - Could not verify the NIZK PoK of payment amount");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clproto::bs_verify_nizk_proof(&proof_cv) {
|
||||||
// generate refund token on new wallet
|
// generate refund token on new wallet
|
||||||
let i = pk_m.Z2.len()-1;
|
let i = pk_m.Z2.len()-1;
|
||||||
let c_refund = proof_cv.C + (pk_m.Z2[i] * convert_str_to_fr("refund"));
|
let c_refund = proof_cv.C + (pk_m.Z2[i] * convert_str_to_fr("refund"));
|
||||||
|
@ -993,6 +1068,52 @@ pub mod bidirectional {
|
||||||
panic!("pay_by_merchant_phase1 - NIZK verification failed for new wallet commitment!");
|
panic!("pay_by_merchant_phase1 - NIZK verification failed for new wallet commitment!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Verify third party payment proof from two bi-directional channel payments with intermediary
|
||||||
|
///
|
||||||
|
pub fn verify_third_party_payment(pp: &PublicParams, fee: i32, 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 mut osrng1 = OsRng::new().unwrap();
|
||||||
|
let mut transcript1 = ProofTranscript::new(b"Range Proof for Balance Increment");
|
||||||
|
let range_proof1_valid = rproof1.range_proof.verify(&[rproof1.value_commitment],
|
||||||
|
&pp.range_proof_gens,
|
||||||
|
&mut transcript1,
|
||||||
|
&mut osrng1,
|
||||||
|
pp.range_proof_bits).is_ok();
|
||||||
|
|
||||||
|
let mut osrng2 = OsRng::new().unwrap();
|
||||||
|
let mut transcript2 = ProofTranscript::new(b"Range Proof for Balance Increment");
|
||||||
|
let range_proof2_valid = rproof2.range_proof.verify(&[rproof2.value_commitment],
|
||||||
|
&pp.range_proof_gens,
|
||||||
|
&mut transcript2,
|
||||||
|
&mut osrng2,
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn pay_by_customer_phase2(pp: &PublicParams, old_w: &CustomerWallet, new_w: &CustomerWallet,
|
pub fn pay_by_customer_phase2(pp: &PublicParams, old_w: &CustomerWallet, new_w: &CustomerWallet,
|
||||||
pk_m: &clsigs::PublicKeyD, rt_w: &clsigs::SignatureD) -> RevokeToken {
|
pk_m: &clsigs::PublicKeyD, rt_w: &clsigs::SignatureD) -> RevokeToken {
|
||||||
// (1) verify the refund token (rt_w) against the new wallet contents
|
// (1) verify the refund token (rt_w) against the new wallet contents
|
||||||
|
@ -1030,7 +1151,7 @@ pub mod bidirectional {
|
||||||
// update merchant state with (wpk, sigma_rev)
|
// update merchant state with (wpk, sigma_rev)
|
||||||
update_merchant_state(&mut state, &proof.wpk, Some(rv.signature));
|
update_merchant_state(&mut state, &proof.wpk, Some(rv.signature));
|
||||||
let new_wallet_sig = clproto::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, proof_cv.C, proof_cv.num_secrets);
|
let new_wallet_sig = clproto::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, proof_cv.C, proof_cv.num_secrets);
|
||||||
m_data.csk.balance += proof.balance_inc;
|
m_data.csk.balance += proof.bal_proof.balance_increment + state.tx_fee;
|
||||||
state.R = 2;
|
state.R = 2;
|
||||||
return new_wallet_sig;
|
return new_wallet_sig;
|
||||||
}
|
}
|
||||||
|
@ -1225,6 +1346,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore] // JAA: REMOVE
|
||||||
fn unidirectional_payment_basics_work() {
|
fn unidirectional_payment_basics_work() {
|
||||||
// TODO: finish me
|
// TODO: finish me
|
||||||
assert!(true == true);
|
assert!(true == true);
|
||||||
|
@ -1305,7 +1427,7 @@ mod tests {
|
||||||
// let's test the pay protocol
|
// let's test the pay protocol
|
||||||
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.T, &merch_keys.pk, &mut cust_data.csk));
|
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.T, &merch_keys.pk, &mut cust_data.csk));
|
||||||
|
|
||||||
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &cust_data.T, // channel token
|
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.T, // channel token
|
||||||
&merch_keys.pk, // merchant pub key
|
&merch_keys.pk, // merchant pub key
|
||||||
&cust_data.csk, // wallet
|
&cust_data.csk, // wallet
|
||||||
payment_increment); // balance increment (FUNC INPUT)
|
payment_increment); // balance increment (FUNC INPUT)
|
||||||
|
@ -1416,15 +1538,22 @@ mod tests {
|
||||||
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust1_data.T, &merch_keys.pk, &mut cust1_data.csk));
|
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust1_data.T, &merch_keys.pk, &mut cust1_data.csk));
|
||||||
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust2_data.T, &merch_keys.pk, &mut cust2_data.csk));
|
assert!(bidirectional::pay_by_customer_phase1_precompute(&pp, &cust2_data.T, &merch_keys.pk, &mut cust2_data.csk));
|
||||||
|
|
||||||
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &cust1_data.T, // channel token
|
println!("Channel 1 fee: {}", channel1.get_channel_fee());
|
||||||
|
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel1,
|
||||||
|
&cust1_data.T, // channel token
|
||||||
&merch_keys.pk, // merchant pub key
|
&merch_keys.pk, // merchant pub key
|
||||||
&cust1_data.csk, // wallet
|
&cust1_data.csk, // wallet
|
||||||
payment_increment); // balance increment (FUNC INPUT)
|
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, &cust2_data.T, // channel token
|
let (t_c2, new_wallet2, pay_proof2) = bidirectional::pay_by_customer_phase1(&pp, &channel2,
|
||||||
|
&cust2_data.T, // channel token
|
||||||
&merch_keys.pk, // merchant pub key
|
&merch_keys.pk, // merchant pub key
|
||||||
&cust2_data.csk, // wallet
|
&cust2_data.csk, // wallet
|
||||||
-payment_increment); // balance increment (FUNC INPUT)
|
-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)
|
// get the refund token (rt_w)
|
||||||
let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, channel1, &pay_proof1, &merch1_data);
|
let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, channel1, &pay_proof1, &merch1_data);
|
||||||
|
@ -1458,10 +1587,12 @@ mod tests {
|
||||||
let mut channelA = bidirectional::ChannelState::new(String::from("Channel A -> I"), true);
|
let mut channelA = bidirectional::ChannelState::new(String::from("Channel A -> I"), true);
|
||||||
let mut channelB = bidirectional::ChannelState::new(String::from("Channel B -> I"), true);
|
let mut channelB = bidirectional::ChannelState::new(String::from("Channel B -> I"), true);
|
||||||
|
|
||||||
//
|
let fee = 2;
|
||||||
|
channelA.set_channel_fee(fee);
|
||||||
|
|
||||||
let total_payment = 20;
|
let total_payment = 20;
|
||||||
let b0_alice = 20;
|
let b0_alice = 30;
|
||||||
let b0_bob = 20;
|
let b0_bob = 30;
|
||||||
let b0_merchantA = 40;
|
let b0_merchantA = 40;
|
||||||
let b0_merchantB = 40;
|
let b0_merchantB = 40;
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ pub fn encrypt(key: &SymKey, plaintext: &String) -> SymCT {
|
||||||
pub fn decrypt(key: &SymKey, ciphertext: &SymCT) -> String {
|
pub fn decrypt(key: &SymKey, ciphertext: &SymCT) -> String {
|
||||||
let nonce = ciphertext.nonce;
|
let nonce = ciphertext.nonce;
|
||||||
let pt = secretbox::open(&ciphertext.ciphertext, &nonce, &key.key).unwrap();
|
let pt = secretbox::open(&ciphertext.ciphertext, &nonce, &key.key).unwrap();
|
||||||
// TODO: investigate better error handling here
|
|
||||||
let plaintext = String::from_utf8(pt).expect("Found invalid UTF-8");
|
let plaintext = String::from_utf8(pt).expect("Found invalid UTF-8");
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue