Clean up merchant close and more tests
This commit is contained in:
parent
ef3be30ea5
commit
68ed3a0711
115
py/libbolt.py
115
py/libbolt.py
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
216
src/lib.rs
216
src/lib.rs
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue