Clean up merchant close and more tests

This commit is contained in:
J. Ayo Akinyele 2019-08-20 19:09:01 -04:00
parent ef3be30ea5
commit 68ed3a0711
4 changed files with 245 additions and 140 deletions

View File

@ -61,9 +61,9 @@ class Libbolt(object):
self.lib.ffishim_bidirectional_customer_close.argtypes = (c_void_p, c_void_p) self.lib.ffishim_bidirectional_customer_close.argtypes = (c_void_p, c_void_p)
self.lib.ffishim_bidirectional_customer_close.restype = c_void_p self.lib.ffishim_bidirectional_customer_close.restype = c_void_p
# self.lib.ffishim_bidirectional_merchant_close.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p) self.lib.ffishim_bidirectional_merchant_close.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p)
# self.lib.ffishim_bidirectional_merchant_close.restype = c_void_p self.lib.ffishim_bidirectional_merchant_close.restype = c_void_p
#
# self.lib.ffishim_bidirectional_resolve.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p, c_void_p) # self.lib.ffishim_bidirectional_resolve.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p, c_void_p)
# self.lib.ffishim_bidirectional_resolve.restype = c_void_p # self.lib.ffishim_bidirectional_resolve.restype = c_void_p
@ -79,78 +79,80 @@ class Libbolt(object):
def bidirectional_init_merchant(self, channel_state, b0_merch, name): def bidirectional_init_merchant(self, channel_state, b0_merch, name):
output_string = self.lib.ffishim_bidirectional_init_merchant(channel_state.encode(), b0_merch, name.encode()) output_string = self.lib.ffishim_bidirectional_init_merchant(channel_state.encode(), b0_merch, name.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['channel_token'], output_dictionary['merch_wallet'] return output_dictionary['channel_token'], output_dictionary['merch_state']
def bidirectional_init_customer(self, channel_state, channel_token, b0_cust, b0_merch, name): def bidirectional_init_customer(self, channel_state, channel_token, b0_cust, b0_merch, name):
output_string = self.lib.ffishim_bidirectional_init_customer(channel_state.encode(), channel_token.encode(), b0_cust, b0_merch, name.encode()) output_string = self.lib.ffishim_bidirectional_init_customer(channel_state.encode(), channel_token.encode(), b0_cust, b0_merch, name.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return (output_dictionary['channel_token'], output_dictionary['cust_wallet']) return (output_dictionary['channel_token'], output_dictionary['cust_state'])
# ESTABLISH PROTOCOL # ESTABLISH PROTOCOL
def bidirectional_establish_customer_generate_proof(self, channel_token, cust_wallet): def bidirectional_establish_customer_generate_proof(self, channel_token, cust_state):
output_string = self.lib.ffishim_bidirectional_establish_customer_generate_proof(channel_token.encode(), cust_wallet.encode()) output_string = self.lib.ffishim_bidirectional_establish_customer_generate_proof(channel_token.encode(), cust_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['channel_token'], output_dictionary['cust_wallet'], output_dictionary['com'], output_dictionary['com_proof'] return output_dictionary['channel_token'], output_dictionary['cust_state'], output_dictionary['com'], output_dictionary['com_proof']
def bidirectional_establish_merchant_issue_close_token(self, channel_state, com, com_proof, merch_wallet): def bidirectional_establish_merchant_issue_close_token(self, channel_state, com, com_proof, merch_state):
output_string = self.lib.ffishim_bidirectional_establish_merchant_issue_close_token(channel_state.encode(), com.encode(), com_proof.encode(), merch_wallet.encode()) output_string = self.lib.ffishim_bidirectional_establish_merchant_issue_close_token(channel_state.encode(), com.encode(), com_proof.encode(), merch_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['close_token'] return output_dictionary['close_token']
def bidirectional_establish_merchant_issue_pay_token(self, channel_state, com, merch_wallet): def bidirectional_establish_merchant_issue_pay_token(self, channel_state, com, merch_state):
output_string = self.lib.ffishim_bidirectional_establish_merchant_issue_pay_token(channel_state.encode(), com.encode(), merch_wallet.encode()) output_string = self.lib.ffishim_bidirectional_establish_merchant_issue_pay_token(channel_state.encode(), com.encode(), merch_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['pay_token'] return output_dictionary['pay_token']
def bidirectional_establish_customer_verify_close_token(self, channel_state, cust_wallet, close_token): def bidirectional_establish_customer_verify_close_token(self, channel_state, cust_state, close_token):
output_string = self.lib.ffishim_bidirectional_verify_close_token(channel_state.encode(), cust_wallet.encode(), close_token.encode()) output_string = self.lib.ffishim_bidirectional_verify_close_token(channel_state.encode(), cust_state.encode(), close_token.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['is_token_valid'], output_dictionary['channel_state'], output_dictionary['cust_wallet'] return output_dictionary['is_token_valid'], output_dictionary['channel_state'], output_dictionary['cust_state']
def bidirectional_establish_customer_final(self, channel_state, cust_wallet, pay_token): def bidirectional_establish_customer_final(self, channel_state, cust_state, pay_token):
output_string = self.lib.ffishim_bidirectional_establish_customer_final(channel_state.encode(), cust_wallet.encode(), pay_token.encode()) output_string = self.lib.ffishim_bidirectional_establish_customer_final(channel_state.encode(), cust_state.encode(), pay_token.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['is_established'], output_dictionary['channel_state'], output_dictionary['cust_wallet'] return output_dictionary['is_established'], output_dictionary['channel_state'], output_dictionary['cust_state']
# PAY PROTOCOL # PAY PROTOCOL
# generate payment proof # generate payment proof
def bidirectional_pay_generate_payment_proof(self, channel_state, cust_wallet, amount): def bidirectional_pay_generate_payment_proof(self, channel_state, cust_state, amount):
output_string = self.lib.ffishim_bidirectional_pay_generate_payment_proof(channel_state.encode(), cust_wallet.encode(), amount) output_string = self.lib.ffishim_bidirectional_pay_generate_payment_proof(channel_state.encode(), cust_state.encode(), amount)
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['payment'], output_dictionary['cust_wallet'] return output_dictionary['payment'], output_dictionary['cust_state']
# verify payment proof # verify payment proof
def bidirectional_pay_verify_payment_proof(self, channel_state, pay_proof, merch_wallet): def bidirectional_pay_verify_payment_proof(self, channel_state, pay_proof, merch_state):
output_string = self.lib.ffishim_bidirectional_pay_verify_payment_proof(channel_state.encode(), pay_proof.encode(), merch_wallet.encode()) output_string = self.lib.ffishim_bidirectional_pay_verify_payment_proof(channel_state.encode(), pay_proof.encode(), merch_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return (output_dictionary['close_token'], output_dictionary['merch_wallet']) return (output_dictionary['close_token'], output_dictionary['merch_state'])
# generate revoke token # generate revoke token
def bidirectional_pay_generate_revoke_token(self, channel_state, cust_wallet, new_cust_wallet, close_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_wallet.encode(), output_string = self.lib.ffishim_bidirectional_pay_generate_revoke_token(channel_state.encode(), cust_state.encode(),
new_cust_wallet.encode(), close_token.encode()) new_cust_state.encode(), close_token.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['revoke_token'], output_dictionary['cust_wallet'] return output_dictionary['revoke_token'], output_dictionary['cust_state']
# verify revoke token # verify revoke token
def bidirectional_pay_verify_revoke_token(self, revoke_token, merch_wallet): def bidirectional_pay_verify_revoke_token(self, revoke_token, merch_state):
output_string = self.lib.ffishim_bidirectional_pay_verify_revoke_token(revoke_token.encode(), merch_wallet.encode()) output_string = self.lib.ffishim_bidirectional_pay_verify_revoke_token(revoke_token.encode(), merch_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return (output_dictionary['pay_token'], output_dictionary['merch_wallet']) return (output_dictionary['pay_token'], output_dictionary['merch_state'])
# CLOSE # CLOSE
def bidirectional_customer_close(self, channel_state, cust_wallet): def bidirectional_customer_close(self, channel_state, cust_state):
output_string = self.lib.ffishim_bidirectional_customer_close(channel_state.encode(), cust_wallet.encode()) output_string = self.lib.ffishim_bidirectional_customer_close(channel_state.encode(), cust_state.encode())
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8')) output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['cust_close'] return output_dictionary.get('cust_close')
def bidirectional_merchant_close(self, channel_state, channel_token, cust_close, merch_state):
output_string = self.lib.ffishim_bidirectional_merchant_close(channel_state.encode(), channel_token.encode(),
cust_close.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('wpk'), output_dictionary.get('revoke_token'), output_dictionary.get('error'))
# def bidirectional_merchant_refund(self, pp, channel, channel_token, merch_data, channel_closure, revoke_token):
# output_string = self.lib.ffishim_bidirectional_merchant_refund(pp.encode(), channel.encode(), channel_token.encode(), merch_data.encode(), channel_closure.encode(), revoke_token.encode())
# output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
# return (output_dictionary['rc_m'], output_dictionary['state'])
# #
# def bidirectional_resolve(self, pp, cust_data, merch_data, cust_closure, merch_closure): # def bidirectional_resolve(self, pp, cust_data, merch_data, cust_closure, merch_closure):
# output_string = self.lib.ffishim_bidirectional_resolve( pp.encode(), cust_data.encode(), merch_data.encode(), cust_closure.encode(), merch_closure.encode()) # output_string = self.lib.ffishim_bidirectional_resolve( pp.encode(), cust_data.encode(), merch_data.encode(), cust_closure.encode(), merch_closure.encode())
@ -203,28 +205,28 @@ channel_state = libbolt.channel_setup("My New Channel A")
print("channel state new: ", channel_state) print("channel state new: ", channel_state)
(channel_token, merch_wallet) = libbolt.bidirectional_init_merchant(channel_state, b0_merch, "Bob") (channel_token, merch_state) = libbolt.bidirectional_init_merchant(channel_state, b0_merch, "Bob")
print("merch_wallet: ", len(merch_wallet)) print("merch_state: ", len(merch_state))
#print("channel_token: ", type(_channel_token)) #print("channel_token: ", type(_channel_token))
(channel_token, cust_wallet) = libbolt.bidirectional_init_customer(channel_state, channel_token, b0_cust, b0_merch, "Alice") (channel_token, cust_state) = libbolt.bidirectional_init_customer(channel_state, channel_token, b0_cust, b0_merch, "Alice")
print("cust_wallet: ", len(cust_wallet)) print("cust_state: ", len(cust_state))
(channel_token, cust_wallet, com, com_proof) = libbolt.bidirectional_establish_customer_generate_proof(channel_token, cust_wallet) (channel_token, cust_state, com, com_proof) = libbolt.bidirectional_establish_customer_generate_proof(channel_token, cust_state)
print("com: ", com) print("com: ", com)
close_token = libbolt.bidirectional_establish_merchant_issue_close_token(channel_state, com, com_proof, merch_wallet) close_token = libbolt.bidirectional_establish_merchant_issue_close_token(channel_state, com, com_proof, merch_state)
print("close token: ", close_token) print("close token: ", close_token)
(is_token_valid, channel_state, cust_wallet) = libbolt.bidirectional_establish_customer_verify_close_token(channel_state, cust_wallet, close_token) (is_token_valid, channel_state, cust_state) = libbolt.bidirectional_establish_customer_verify_close_token(channel_state, cust_state, close_token)
pay_token = libbolt.bidirectional_establish_merchant_issue_pay_token(channel_state, com, merch_wallet) pay_token = libbolt.bidirectional_establish_merchant_issue_pay_token(channel_state, com, merch_state)
print("pay token: ", pay_token) print("pay token: ", pay_token)
(is_channel_established, channel_state, cust_wallet) = libbolt.bidirectional_establish_customer_final(channel_state, cust_wallet, pay_token) (is_channel_established, channel_state, cust_state) = libbolt.bidirectional_establish_customer_final(channel_state, cust_state, pay_token)
if is_channel_established: if is_channel_established:
print("updated cust_wallet: ", cust_wallet) print("updated cust_state: ", cust_state)
else: else:
print("channel still not established. did you verify close token?") print("channel still not established. did you verify close token?")
@ -232,21 +234,24 @@ else:
print("Pay protocol...") print("Pay protocol...")
amount = 5 amount = 5
(payment_proof, new_cust_wallet) = libbolt.bidirectional_pay_generate_payment_proof(channel_state, cust_wallet, amount) (payment_proof, new_cust_state) = libbolt.bidirectional_pay_generate_payment_proof(channel_state, cust_state, amount)
print("Pay proof: ", len(payment_proof)) print("Pay proof: ", len(payment_proof))
print("new cust wallet: ", new_cust_wallet) print("new cust wallet: ", new_cust_state)
print("<========================================>") print("<========================================>")
(new_close_token, merch_wallet) = libbolt.bidirectional_pay_verify_payment_proof(channel_state, payment_proof, merch_wallet) (new_close_token, merch_state) = libbolt.bidirectional_pay_verify_payment_proof(channel_state, payment_proof, merch_state)
print("Close token: ", new_close_token) print("Close token: ", new_close_token)
print("<========================================>") print("<========================================>")
(revoke_token, cust_wallet) = libbolt.bidirectional_pay_generate_revoke_token(channel_state, cust_wallet, new_cust_wallet, new_close_token) (revoke_token, cust_state) = libbolt.bidirectional_pay_generate_revoke_token(channel_state, cust_state, new_cust_state, new_close_token)
print("Revoke token: ", revoke_token) print("Revoke token: ", revoke_token)
(pay_token, merch_wallet) = libbolt.bidirectional_pay_verify_revoke_token(revoke_token, merch_wallet) (pay_token, merch_state) = libbolt.bidirectional_pay_verify_revoke_token(revoke_token, merch_state)
print("Pay token: ", pay_token) print("Pay token: ", pay_token)
cust_close_msg = libbolt.bidirectional_customer_close(channel_state, cust_wallet) cust_close = libbolt.bidirectional_customer_close(channel_state, cust_state)
print("Cust close msg: ", cust_close_msg) print("Cust close msg: ", cust_close)
print("<========================================>") print("<========================================>")
merch_close_tokens = libbolt.bidirectional_merchant_close(channel_state, channel_token, cust_close, merch_state)
print("Merch close tokens: ", merch_close_tokens)

View File

@ -12,6 +12,7 @@ pub mod ffishim {
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::str; use std::str;
use std::mem; use std::mem;
use bidirectional::ChannelcloseC;
fn error_message(s: String) -> *mut c_char { fn error_message(s: String) -> *mut c_char {
let ser = ["{\'error\':\'", serde_json::to_string(&s).unwrap().as_str(), "\'}"].concat(); let ser = ["{\'error\':\'", serde_json::to_string(&s).unwrap().as_str(), "\'}"].concat();
@ -324,34 +325,32 @@ pub mod ffishim {
cser.into_raw() cser.into_raw()
} }
#[no_mangle]
pub extern fn ffishim_bidirectional_merchant_close(ser_channel_state: *mut c_char, ser_channel_token: *mut c_char,
ser_cust_close: *mut c_char, ser_merch_state: *mut c_char) -> *mut c_char {
// Deserialize the channel state
let channel_state: bidirectional::ChannelState<Bls12> = deserialize_object(ser_channel_state);
// Deserialize the channel token
let mut channel_token: bidirectional::ChannelToken<Bls12> = deserialize_object(ser_channel_token);
// Deserialize the customer close structure
let cust_close: bidirectional::ChannelcloseC<Bls12> = deserialize_object(ser_cust_close);
// Deserialize the merch wallet
let mut merch_state: bidirectional::MerchantState<Bls12> = deserialize_object(ser_merch_state);
let option = bidirectional::merchant_close(&channel_state, &channel_token, &cust_close, &merch_state);
let keys = match option {
Ok(n) => n.unwrap(),
Err(err) => return error_message(err),
};
let ser = ["{\'wpk\':\'", serde_json::to_string(&keys.wpk).unwrap().as_str(),
"\', \'revoke_token\':\'", serde_json::to_string(&keys.revoke_token).unwrap().as_str(), "\'}"].concat();
let cser = CString::new(ser).unwrap();
cser.into_raw()
}
} }
// #[no_mangle]
// pub extern fn ffishim_bidirectional_merchant_refund(serialized_pp: *mut c_char, serialized_channel: *mut c_char, serialized_channel_token: *mut c_char, serialized_merchant_data: *mut c_char, serialized_channel_closure: *mut c_char, serialized_revoke_token: *mut c_char) -> *mut c_char {
// // Deserialize the pp
// let deserialized_pp: bidirectional::PublicParams = deserialize_object(serialized_pp);
//
// // Deserialize the channel state
// let mut deserialized_channel_state: bidirectional::ChannelState = deserialize_object(serialized_channel);
//
// // Deserialize the channel token
// let deserialized_channel_token: bidirectional::ChannelToken = deserialize_object(serialized_channel_token);
//
// // Deserialize the merchant data
// let deserialized_merchant_data: bidirectional::InitMerchantData = deserialize_object(serialized_merchant_data);
//
// // Deserialize the closure
// let deserialized_channel_closure: bidirectional::ChannelclosureC = deserialize_object(serialized_channel_closure);
//
// // Deserialize the revoke_token
// let deserialized_revoke_token: secp256k1::Signature = deserialize_object(serialized_revoke_token);
//
// let rc_m = bidirectional::merchant_refute(&deserialized_pp, &mut deserialized_channel_state, &deserialized_channel_token, &deserialized_merchant_data, &deserialized_channel_closure, &deserialized_revoke_token);
// let ser = ["{\'rc_m\':\'", serde_json::to_string(&rc_m).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str(), "\'}"].concat();
// let cser = CString::new(ser).unwrap();
// cser.into_raw()
// }
//
// #[no_mangle] // #[no_mangle]
// pub extern fn ffishim_bidirectional_resolve(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_data: *mut c_char, serialized_closure_customer: *mut c_char, serialized_closure_merchant: *mut c_char) -> *mut c_char { // pub extern fn ffishim_bidirectional_resolve(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_data: *mut c_char, serialized_closure_customer: *mut c_char, serialized_closure_merchant: *mut c_char) -> *mut c_char {
// // Deserialize the pp // // Deserialize the pp

View File

@ -140,16 +140,11 @@ pub mod bidirectional {
#[serde(bound(deserialize = "<E as ff::ScalarEngine>::Fr: serde::Deserialize<'de>, \ #[serde(bound(deserialize = "<E as ff::ScalarEngine>::Fr: serde::Deserialize<'de>, \
<E as pairing::Engine>::G1: serde::Deserialize<'de>"))] <E as pairing::Engine>::G1: serde::Deserialize<'de>"))]
pub struct ChannelcloseC<E: Engine> { pub struct ChannelcloseC<E: Engine> {
pub wpk: secp256k1::PublicKey,
pub message: wallet::Wallet<E>, pub message: wallet::Wallet<E>,
pub signature: cl::Signature<E> pub signature: cl::Signature<E>
} }
#[derive(Clone)]
pub struct ChannelcloseM<E: Engine> {
pub message: util::RevokedMessage,
pub signature: cl::Signature<E>
}
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \ #[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \
<E as pairing::Engine>::G1: serde::Serialize, \ <E as pairing::Engine>::G1: serde::Serialize, \
@ -288,6 +283,8 @@ pub mod bidirectional {
// if valid revoke_token is provided later for wpk, then release pay-token // if valid revoke_token is provided later for wpk, then release pay-token
let new_close_token = merch_state.verify_payment(csprng, &channel_state, let new_close_token = merch_state.verify_payment(csprng, &channel_state,
&payment.proof, &payment.com, &payment.wpk, payment.amount).unwrap(); &payment.proof, &payment.com, &payment.wpk, payment.amount).unwrap();
// store the wpk since it has been revealed
update_merchant_state(&mut merch_state.keys, &payment.wpk, None);
return new_close_token; return new_close_token;
} }
@ -384,29 +381,32 @@ pub mod bidirectional {
let close_wallet = wallet.with_close(String::from("close")); let close_wallet = wallet.with_close(String::from("close"));
assert!(pk.verify(&cp.pub_params.mpk, &close_wallet, &close_token)); assert!(pk.verify(&cp.pub_params.mpk, &close_wallet, &close_token));
ChannelcloseC { message: wallet, signature: close_token } ChannelcloseC { wpk: cust_state.wpk, message: wallet, signature: close_token }
} }
fn exist_in_merchant_state<E: Engine>(db: &mut HashMap<String, PubKeyMap>, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) -> bool { // fn exist_in_merchant_state<E: Engine>(db: &HashMap<String, PubKeyMap>, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) -> (bool, Option<PubKeyMap>) {
if db.is_empty() { // if db.is_empty() {
return false; // return (false, None);
} // }
//
let fingerprint = util::compute_pub_key_fingerprint(wpk); // let fingerprint = util::compute_pub_key_fingerprint(wpk);
if db.contains_key(&fingerprint) { // if db.contains_key(&fingerprint) {
let pub_key = db.get(&fingerprint).unwrap(); // let revoked_state = db.get(&fingerprint).unwrap();
if pub_key.revoke_token.is_none() { //
// let's just check the public key //
return pub_key.wpk == *wpk; //
} // if revoked_state.revoke_token.is_none() {
if !rev.is_none() { // // let's just check the public key
return pub_key.wpk == *wpk && pub_key.revoke_token.unwrap() == rev.unwrap(); // return (revoked_state.wpk == *wpk, None);
} // }
return pub_key.wpk == *wpk; // if !rev.is_none() {
} // return (revoked_state.wpk == *wpk && pub_key.revoke_token.unwrap() == rev.unwrap(), None);
// }
return false; // return (pub_key.wpk == *wpk, Some(pub_key));
} // }
//
// return false;
// }
fn update_merchant_state(db: &mut HashMap<String, PubKeyMap>, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) { fn update_merchant_state(db: &mut HashMap<String, PubKeyMap>, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) {
let fingerprint = util::compute_pub_key_fingerprint(wpk); let fingerprint = util::compute_pub_key_fingerprint(wpk);
@ -421,35 +421,49 @@ pub mod bidirectional {
} }
/// ///
/// merchant_refute - takes as input the public params, channel token, merchant's wallet, /// merchant_close - takes as input the channel state, channel token, customer close msg/sig,
/// channels tate, channel closure from customer, and revocation token. /// Returns tokens for merchant close transaction (only if customer close message is found to be a
/// Generates a channel closure message for merchant and updated merchant internal state. /// double spend). If not, then None is returned.
/// ///
pub fn merchant_refute<E: Engine>(channel_state: &mut ChannelState<E>, pub fn merchant_close<E: Engine>(channel_state: &ChannelState<E>,
channel_token: &ChannelToken<E>, channel_token: &ChannelToken<E>,
rc_c: &ChannelcloseC<E>, rv_token: &secp256k1::Signature) -> bool { cust_close: &ChannelcloseC<E>,
return true; merch_state: &MerchantState<E>) -> BoltResult<PubKeyMap> {
if (!channel_state.channel_established) {
return Err(String::from("merchant_close - Channel not established! Cannot generate channel closure message."));
}
let cp = channel_state.cp.as_ref().unwrap();
let pk = cp.pub_params.keypair.get_public_key(&cp.pub_params.mpk);
let mut wallet = cust_close.message.clone();
let close_wallet = wallet.with_close(String::from("close")).clone();
let close_token = cust_close.signature.clone();
let is_valid = pk.verify(&cp.pub_params.mpk, &close_wallet, &close_token);
if is_valid {
let wpk = cust_close.wpk;
// found the wpk, which means old close token
let fingerprint = util::compute_pub_key_fingerprint(&wpk);
if merch_state.keys.contains_key(&fingerprint) {
let revoked_state = merch_state.keys.get(&fingerprint).unwrap();
if !revoked_state.revoke_token.is_none() {
let revoke_token = revoked_state.revoke_token.unwrap().clone();
// verify the revoked state first before returning
let secp = secp256k1::Secp256k1::new();
let revoke_msg = RevokedMessage::new(String::from("revoked"), wpk.clone());
let msg = secp256k1::Message::from_slice(&revoke_msg.hash_to_slice()).unwrap();
// verify that the revocation token is valid
if secp.verify(&msg, &revoke_token, &wpk).is_ok() {
return Ok(Some(revoked_state.clone()));
}
}
return Err(String::from("merchant_close - Found wpk but could not find the revoke token. Merchant abort detected."));
}
return Err(String::from("merchant_close - Could not find entry for wpk & revoke token pair. Valid close!"));
}
Err(String::from("merchant_close - Customer close message not valid!"))
} }
// rc_c: &ChannelclosureC, rv_token: &secp256k1::Signature) // -> ChannelclosureM {
// // for merchant => on input the merchant's current state S_old and a customer channel closure message,
// // outputs a merchant channel closure message rc_m and updated merchant state S_new
// let is_valid = cl::verify_d(&pp.cl_mpk, &t_c.pk, &rc_c.message.hash(), &rc_c.signature);
// if is_valid {
// let wpk = rc_c.message.wpk;
// let balance = rc_c.message.balance;
// if !exist_in_merchant_state(&state, &wpk, Some(*rv_token)) {
// // update state to include the user's wallet key
// assert!(update_merchant_state(state, &wpk, Some(*rv_token)));
// }
// let ser_rv_token = rv_token.serialize_compact();
// let rm = RevokedMessage::new(String::from("revoked"), wpk, Some(ser_rv_token));
// // sign the revoked message
// let signature = cl::sign_d(&pp.cl_mpk, &m_data.csk.sk, &rm.hash());
// return ChannelclosureM { message: rm, signature: signature };
// } else {
// panic!("Signature on customer closure message is invalid!");
// }
// }
} }
#[cfg(all(test, feature = "unstable"))] #[cfg(all(test, feature = "unstable"))]
@ -468,6 +482,7 @@ mod tests {
use super::*; use super::*;
use ff::Rand; use ff::Rand;
use pairing::bls12_381::{Bls12}; use pairing::bls12_381::{Bls12};
use rand::Rng;
fn setup_new_channel_helper(channel_state: &mut bidirectional::ChannelState<Bls12>, fn setup_new_channel_helper(channel_state: &mut bidirectional::ChannelState<Bls12>,
init_cust_bal: i32, init_merch_bal: i32) init_cust_bal: i32, init_merch_bal: i32)
@ -636,10 +651,10 @@ mod tests {
assert!(cust_state.cust_balance == (b0_customer - total_owed) && cust_state.merch_balance == total_owed + b0_merchant); assert!(cust_state.cust_balance == (b0_customer - total_owed) && cust_state.merch_balance == total_owed + b0_merchant);
} }
let cust_close = bidirectional::customer_close(&channel_state, &cust_state); let cust_close_msg = bidirectional::customer_close(&channel_state, &cust_state);
println!("Obtained the channel close message"); println!("Obtained the channel close message");
println!("{}", cust_close.message); println!("{}", cust_close_msg.message);
println!("{}", cust_close.signature); println!("{}", cust_close_msg.signature);
} }
} }
@ -664,7 +679,6 @@ mod tests {
assert!(channel_state.channel_established); assert!(channel_state.channel_established);
{ {
// make multiple payments in a loop
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, payment_increment); execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, payment_increment);
{ {
@ -676,6 +690,94 @@ mod tests {
} }
} }
#[test]
fn bidirectional_merchant_close_detects_double_spends() {
let mut rng = &mut rand::thread_rng();
let b0_customer = rng.gen_range(100, 1000);
let b0_merchant = 10;
let pay_increment = 20;
let mut channel_state = bidirectional::ChannelState::<Bls12>::new(String::from("Channel A -> B"), false);
channel_state.setup(&mut rng); // or load_setup params
let (mut channel_token, mut merch_state, mut cust_state) = setup_new_channel_helper( &mut channel_state, b0_customer, b0_merchant);
// run establish protocol for customer and merchant channel
execute_establish_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state);
assert!(channel_state.channel_established);
// let's make a few payments then exit channel (will post an old channel state
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
// let's close then move state forward
let old_cust_close_msg = bidirectional::customer_close(&channel_state, &cust_state);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
let cur_cust_close_msg = bidirectional::customer_close(&channel_state, &cust_state);
let merch_close_result = bidirectional::merchant_close(&channel_state,
&channel_token,
&old_cust_close_msg,
&merch_state);
let merch_close_msg = match merch_close_result {
Ok(n) => n.unwrap(),
Err(err) => panic!("Merchant close msg: {}", err)
};
println!("Double spend attempt by customer! Evidence below...");
println!("Merchant close: wpk = {}", merch_close_msg.wpk);
println!("Merchant close: revoke_token = {}", merch_close_msg.revoke_token.unwrap());
}
#[test]
#[should_panic]
fn bidirectional_merchant_close_works() {
let mut rng = &mut rand::thread_rng();
let b0_customer = rng.gen_range(100, 1000);
let b0_merchant = 10;
let pay_increment = 20;
let mut channel_state = bidirectional::ChannelState::<Bls12>::new(String::from("Channel A -> B"), false);
channel_state.setup(&mut rng); // or load_setup params
let (mut channel_token, mut merch_state, mut cust_state) = setup_new_channel_helper( &mut channel_state, b0_customer, b0_merchant);
// run establish protocol for customer and merchant channel
execute_establish_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state);
assert!(channel_state.channel_established);
// let's make a few payments then exit channel (will post an old channel state
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
execute_payment_protocol_helper(&mut channel_state, &mut channel_token, &mut merch_state, &mut cust_state, pay_increment);
let cust_close_msg = bidirectional::customer_close(&channel_state, &cust_state);
let merch_close_result = bidirectional::merchant_close(&channel_state,
&channel_token,
&cust_close_msg,
&merch_state);
let merch_close_msg = match merch_close_result {
Ok(n) => n.unwrap(),
Err(err) => panic!("Merchant close msg: {}", err)
};
}
// fn execute_third_party_pay_protocol_helper(pp: &bidirectional::PublicParams, // fn execute_third_party_pay_protocol_helper(pp: &bidirectional::PublicParams,
// channel1: &mut bidirectional::ChannelState, channel2: &mut bidirectional::ChannelState, // channel1: &mut bidirectional::ChannelState, channel2: &mut bidirectional::ChannelState,
// merch_keys: &cl::KeyPairD, merch1_data: &mut bidirectional::InitMerchantData, // merch_keys: &cl::KeyPairD, merch1_data: &mut bidirectional::InitMerchantData,

View File

@ -119,7 +119,6 @@ pub fn hash_buffer_to_fr<'a, E: Engine>(prefix: &'a str, buf: &[u8; 64]) -> E::F
pub struct RevokedMessage { pub struct RevokedMessage {
pub msgtype: String, pub msgtype: String,
pub wpk: secp256k1::PublicKey pub wpk: secp256k1::PublicKey
//pub sig: Option<[u8; 64]> // represents revocation token serialized compact bytes
} }
impl RevokedMessage { impl RevokedMessage {