Add wtp logic
This commit is contained in:
parent
e36ad50857
commit
3c0f087ff6
|
@ -21,6 +21,7 @@ libc = "*"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_with = "1.0"
|
serde_with = "1.0"
|
||||||
|
serde_bytes = "0.11.2"
|
||||||
time = "*"
|
time = "*"
|
||||||
secp256k1 = { version = "0.15.0", features = ["rand", "serde"] }
|
secp256k1 = { version = "0.15.0", features = ["rand", "serde"] }
|
||||||
curve25519-dalek = { version = "1", features = ["serde"] }
|
curve25519-dalek = { version = "1", features = ["serde"] }
|
||||||
|
|
|
@ -63,19 +63,16 @@ 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)
|
self.lib.ffishim_bidirectional_merchant_close.argtypes = (c_void_p, 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
|
||||||
|
|
||||||
# ON-CHAIN BOLT LOGIC / WTPs
|
# ON-CHAIN BOLT LOGIC / WTPs
|
||||||
|
|
||||||
self.lib.ffishim_bidirectional_verify_open_channel.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p)
|
self.lib.ffishim_bidirectional_wtp_verify_cust_close_message.argtypes = (c_void_p, c_void_p, c_void_p, c_void_p)
|
||||||
self.lib.ffishim_bidirectional_verify_open_channel.restype = c_void_p
|
self.lib.ffishim_bidirectional_wtp_verify_cust_close_message.restype = c_void_p
|
||||||
|
|
||||||
#self.lib.ffishim_bidirectional_verify_close_channel.argtypes = (c_void_p, c_void_p)
|
self.lib.ffishim_bidirectional_wtp_verify_merch_close_message.argtypes = (c_void_p, c_void_p, c_void_p)
|
||||||
#self.lib.ffishim_bidirectional_verify_close_channel.restype = c_void_p
|
self.lib.ffishim_bidirectional_wtp_verify_merch_close_message.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.restype = c_void_p
|
|
||||||
|
|
||||||
self.lib.ffishim_free_string.argtypes = (c_void_p, )
|
self.lib.ffishim_free_string.argtypes = (c_void_p, )
|
||||||
|
|
||||||
|
@ -163,55 +160,40 @@ class Libbolt(object):
|
||||||
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.get('cust_close')
|
return output_dictionary.get('cust_close')
|
||||||
|
|
||||||
def bidirectional_merchant_close(self, channel_state, channel_token, cust_close, merch_state):
|
def bidirectional_merchant_close(self, channel_state, channel_token, address, cust_close, merch_state):
|
||||||
output_string = self.lib.ffishim_bidirectional_merchant_close(channel_state.encode(), channel_token.encode(),
|
output_string = self.lib.ffishim_bidirectional_merchant_close(channel_state.encode(), channel_token.encode(),
|
||||||
cust_close.encode(), merch_state.encode())
|
address.encode(), cust_close.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.get('wpk'), output_dictionary.get('revoke_token'), output_dictionary.get('error'))
|
return (output_dictionary.get('wpk'), output_dictionary.get('merch_close'), output_dictionary.get('error'))
|
||||||
|
|
||||||
# WTP logic
|
# WTP logic
|
||||||
|
|
||||||
def wtp_get_wallet(self, cust_state):
|
def wtp_get_wallet(self, cust_state):
|
||||||
cust_state_dict = self.interperate_json_string_as_dictionary(cust_state)
|
cust_state_dict = self._interperate_json_string_as_dictionary(cust_state)
|
||||||
return json.dumps(cust_state_dict.get("wpk")), json.dumps(cust_state_dict.get("wallet"))
|
return json.dumps(cust_state_dict.get("wpk")), json.dumps(cust_state_dict.get("wallet"))
|
||||||
|
|
||||||
def wtp_get_close_token(self, cust_close):
|
def wtp_get_close_token(self, cust_close):
|
||||||
cust_close_dict = self.interperate_json_string_as_dictionary(cust_close)
|
cust_close_dict = self._interperate_json_string_as_dictionary(cust_close)
|
||||||
return json.dumps(cust_close_dict.get("signature"))
|
return json.dumps(cust_close_dict.get("signature"))
|
||||||
|
|
||||||
def wtp_verify_open_channel(self, channel_token, wpk, cust_close_wallet, close_token):
|
def wtp_verify_cust_close_message(self, channel_token, wpk, cust_close_wallet, close_token):
|
||||||
output_string = self.lib.ffishim_bidirectional_verify_open_channel(channel_token.encode(), wpk.encode(), cust_close_wallet.encode(), close_token.encode())
|
output_string = self.lib.ffishim_bidirectional_wtp_verify_cust_close_message(channel_token.encode(),
|
||||||
|
wpk.encode(),
|
||||||
|
cust_close_wallet.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.get('result')
|
return output_dictionary.get('result')
|
||||||
|
|
||||||
# def bidirectional_resolve(self, pp, cust_data, merch_data, cust_closure, merch_closure):
|
def wtp_verify_merch_close_message(self, channel_token, wpk, merch_close):
|
||||||
# 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_wtp_verify_merch_close_message(channel_token.encode(),
|
||||||
# output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
|
wpk.encode(),
|
||||||
# return (int(output_dictionary['new_b0_cust']), int(output_dictionary['new_b0_merch']))
|
merch_close.encode())
|
||||||
#
|
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
|
||||||
# # --------------------------------------------
|
return output_dictionary.get('result')
|
||||||
# def commit_scheme_decommit(self, csp, commitment, x):
|
|
||||||
# output_string = self.lib.ffishim_commit_scheme_decommit(csp.encode(), commitment.encode(), x.encode())
|
|
||||||
# output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
|
|
||||||
# if output_dictionary['return_value'] == 'true':
|
|
||||||
# return True
|
|
||||||
# return False
|
|
||||||
|
|
||||||
def interperate_json_string_as_dictionary(self, json_string):
|
def _interperate_json_string_as_dictionary(self, json_string):
|
||||||
return ast.literal_eval(json_string)
|
return ast.literal_eval(json_string)
|
||||||
|
|
||||||
def util_convert_int_list_to_hex_string(self, dictionary):
|
|
||||||
return "".join(["{0:02x}".format(x) for x in dictionary])
|
|
||||||
|
|
||||||
# def util_extract_public_key_from_keypair(self, keypair):
|
|
||||||
# # Interperate the input keypair struct as a dictionary and then extract
|
|
||||||
# dictionary = self.interperate_json_string_as_dictionary(keypair)
|
|
||||||
# return json.dumps(dictionary['pk'])
|
|
||||||
#
|
|
||||||
# def util_extract_pub_bases_from_keypair(self, keypair):
|
|
||||||
# dictionary = self.interperate_json_string_as_dictionary(keypair)
|
|
||||||
# return json.dumps(dictionary['bases'])
|
|
||||||
|
|
||||||
if platform == 'darwin':
|
if platform == 'darwin':
|
||||||
prefix = 'lib'
|
prefix = 'lib'
|
||||||
ext = 'dylib'
|
ext = 'dylib'
|
||||||
|
@ -285,6 +267,8 @@ def run_unit_test():
|
||||||
(cust_state, is_pay_valid) = libbolt.bidirectional_pay_verify_payment_token(channel_state, cust_state, pay_token)
|
(cust_state, is_pay_valid) = libbolt.bidirectional_pay_verify_payment_token(channel_state, cust_state, pay_token)
|
||||||
print("Pay token is valid: ", is_pay_valid)
|
print("Pay token is valid: ", is_pay_valid)
|
||||||
|
|
||||||
|
old_cust_close = libbolt.bidirectional_customer_close(channel_state, cust_state)
|
||||||
|
|
||||||
# make a payment
|
# make a payment
|
||||||
amount = 10
|
amount = 10
|
||||||
(payment_proof2, new_cust_state2) = libbolt.bidirectional_pay_generate_payment_proof(channel_state, cust_state, amount)
|
(payment_proof2, new_cust_state2) = libbolt.bidirectional_pay_generate_payment_proof(channel_state, cust_state, amount)
|
||||||
|
@ -312,8 +296,20 @@ def run_unit_test():
|
||||||
print("Cust close msg: ", cust_close)
|
print("Cust close msg: ", cust_close)
|
||||||
print("<========================================>")
|
print("<========================================>")
|
||||||
|
|
||||||
merch_close_tokens = libbolt.bidirectional_merchant_close(channel_state, channel_token, cust_close, merch_state)
|
# normal case: no action b/c cust close is valid
|
||||||
print("Merch close tokens: ", merch_close_tokens)
|
address = "11" * 32
|
||||||
|
merch_close = libbolt.bidirectional_merchant_close(channel_state, channel_token, address, cust_close, merch_state)
|
||||||
|
print("Customer initiated - Merch close msg: ", merch_close)
|
||||||
|
print("<========================================>")
|
||||||
|
|
||||||
|
# common case: merchant catches customer double spending
|
||||||
|
address = "11" * 32
|
||||||
|
merch_wpk, merch_close_msg, _ = libbolt.bidirectional_merchant_close(channel_state, channel_token, address, old_cust_close, merch_state)
|
||||||
|
print("Double spend - Merch close msg: ", merch_close_msg)
|
||||||
|
merch_close_valid = libbolt.wtp_verify_merch_close_message(channel_token, merch_wpk, merch_close_msg)
|
||||||
|
print("Merchant close msg valid: ", merch_close_valid)
|
||||||
|
print("<========================================>")
|
||||||
|
|
||||||
|
|
||||||
print("<========================================>")
|
print("<========================================>")
|
||||||
wpk, cust_close_wallet = libbolt.wtp_get_wallet(cust_state)
|
wpk, cust_close_wallet = libbolt.wtp_get_wallet(cust_state)
|
||||||
|
@ -321,9 +317,11 @@ def run_unit_test():
|
||||||
print("close-msg wallet = ", cust_close_wallet)
|
print("close-msg wallet = ", cust_close_wallet)
|
||||||
cust_close_token = libbolt.wtp_get_close_token(cust_close)
|
cust_close_token = libbolt.wtp_get_close_token(cust_close)
|
||||||
print("close token: ", cust_close_token)
|
print("close token: ", cust_close_token)
|
||||||
print("Valid channel opening: ", libbolt.wtp_verify_open_channel(channel_token, wpk, cust_close_wallet, cust_close_token))
|
print("Valid channel opening: ", libbolt.wtp_verify_cust_close_message(channel_token, wpk, cust_close_wallet, cust_close_token))
|
||||||
|
# TODO: merch close when cust_close represents correct channel state
|
||||||
|
|
||||||
print("Invalid channel opening: ", libbolt.wtp_verify_open_channel(channel_token, revoked_wpk, cust_close_wallet, cust_close_token))
|
print("Invalid channel opening: ", libbolt.wtp_verify_cust_close_message(channel_token, revoked_wpk, cust_close_wallet, cust_close_token))
|
||||||
|
print("<========================================>")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_unit_test()
|
run_unit_test()
|
||||||
|
|
|
@ -15,7 +15,7 @@ use pairing::bls12_381::{Bls12};
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup};
|
use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup};
|
||||||
use ped92::{CSParams, Commitment, CSMultiParams};
|
use ped92::{CSParams, Commitment, CSMultiParams};
|
||||||
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, RevokedMessage};
|
use util::{hash_pubkey_to_fr, convert_int_to_fr, hash_to_fr, RevokedMessage, hash_to_slice};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -104,7 +104,7 @@ pub struct ChannelState<E: Engine> {
|
||||||
pub struct ChannelToken<E: Engine> {
|
pub struct ChannelToken<E: Engine> {
|
||||||
pub pk_c: Option<secp256k1::PublicKey>, // pk_c
|
pub pk_c: Option<secp256k1::PublicKey>, // pk_c
|
||||||
pub pk_m: secp256k1::PublicKey, // pk_m
|
pub pk_m: secp256k1::PublicKey, // pk_m
|
||||||
pub cl_pk_m: cl::PublicKey<E>, // PK_m
|
pub cl_pk_m: cl::PublicKey<E>, // PK_m (used for verifying blind signatures)
|
||||||
pub mpk: cl::PublicParams<E>, // mpk for PK_m
|
pub mpk: cl::PublicParams<E>, // mpk for PK_m
|
||||||
pub comParams: CSMultiParams<E>,
|
pub comParams: CSMultiParams<E>,
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,6 @@ impl<E: Engine> CustomerState<E> {
|
||||||
let ct_db= HashMap::new();
|
let ct_db= HashMap::new();
|
||||||
let pt_db= HashMap::new();
|
let pt_db= HashMap::new();
|
||||||
|
|
||||||
//println!("Customer wallet formed -> now returning the structure to the caller.");
|
|
||||||
return CustomerState {
|
return CustomerState {
|
||||||
name: name,
|
name: name,
|
||||||
pk_c: pk_c,
|
pk_c: pk_c,
|
||||||
|
@ -290,7 +289,6 @@ impl<E: Engine> CustomerState<E> {
|
||||||
let is_valid = pk.verify(&mpk, &close_wallet, &unblind_close_token);
|
let is_valid = pk.verify(&mpk, &close_wallet, &unblind_close_token);
|
||||||
if is_valid {
|
if is_valid {
|
||||||
// record the unblinded close token
|
// record the unblinded close token
|
||||||
//cp.pub_params.keypair
|
|
||||||
self.close_tokens.insert( self.index, unblind_close_token);
|
self.close_tokens.insert( self.index, unblind_close_token);
|
||||||
}
|
}
|
||||||
return is_valid;
|
return is_valid;
|
||||||
|
@ -417,18 +415,47 @@ impl<E: Engine> CustomerState<E> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub name: String,
|
||||||
|
// pub pk_c: secp256k1::PublicKey,
|
||||||
|
// sk_c: secp256k1::SecretKey,
|
||||||
|
// pub cust_balance: i32, //
|
||||||
|
// pub merch_balance: i32,
|
||||||
|
// pub wpk: secp256k1::PublicKey, // keypair bound to the wallet
|
||||||
|
// wsk: secp256k1::SecretKey,
|
||||||
|
// old_kp: Option<WalletKeyPair>, // old wallet key pair
|
||||||
|
// t: E::Fr, // randomness used to form the commitment
|
||||||
|
// wallet: Wallet<E>, // vector of field elements that represent wallet
|
||||||
|
// pub w_com: Commitment<E>, // commitment to the current state of the wallet
|
||||||
|
// index: i32,
|
||||||
|
// close_tokens: HashMap<i32, Signature<E>>,
|
||||||
|
// pay_tokens: HashMap<i32, Signature<E>>
|
||||||
|
|
||||||
|
|
||||||
impl<E: Engine> fmt::Display for CustomerState<E> {
|
impl<E: Engine> fmt::Display for CustomerState<E> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
content = format!("pk = {}\n", &self.pk_c);
|
content = format!("name = {}\n", &self.name);
|
||||||
|
content = format!("{}pk = {}\n", content, &self.pk_c);
|
||||||
content = format!("{}sk = {}\n", content, &self.sk_c);
|
content = format!("{}sk = {}\n", content, &self.sk_c);
|
||||||
content = format!("{}cust-bal = {}\n", content, &self.cust_balance);
|
content = format!("{}cust-bal = {}\n", content, &self.cust_balance);
|
||||||
content = format!("{}merch-bal = {}\n", content, &self.merch_balance);
|
content = format!("{}merch-bal = {}\n", content, &self.merch_balance);
|
||||||
// add remaining fields
|
content = format!("{}wpk = {}\nwsk = {}\n", content, &self.wpk, &self.wsk);
|
||||||
|
if (!self.old_kp.is_none()) {
|
||||||
|
let old_kp = self.old_kp.unwrap();
|
||||||
|
content = format!("{}revoked: wpk = {}\nrevoked: wsk = {}\n", content, &old_kp.wpk, &old_kp.wsk);
|
||||||
|
}
|
||||||
|
content = format!("{}t = {}\n", content, &self.t);
|
||||||
|
|
||||||
write!(f, "CustomerState : (\n{}\n)", &content)
|
write!(f, "CustomerState : (\n{}\n)", &content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ChannelcloseM {
|
||||||
|
pub address: String,
|
||||||
|
pub revoke: Option<secp256k1::Signature>,
|
||||||
|
pub signature: secp256k1::Signature
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Merchant wallet (NEW)
|
/// Merchant wallet (NEW)
|
||||||
|
@ -562,6 +589,19 @@ impl<E: Engine> MerchantState<E> {
|
||||||
Err(BoltError::new("verify_revoke_token - Failed to verify the revoke token for wpk!"))
|
Err(BoltError::new("verify_revoke_token - Failed to verify the revoke token for wpk!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sign_revoke_message(&self, address: String, revoke_token: &Option<secp256k1::Signature>) -> ChannelcloseM {
|
||||||
|
let secp = secp256k1::Secp256k1::signing_only();
|
||||||
|
let mut msg = Vec::new();
|
||||||
|
msg.extend(address.as_bytes());
|
||||||
|
if !revoke_token.is_none() {
|
||||||
|
let r = revoke_token.unwrap().serialize_der().to_vec();
|
||||||
|
msg.extend(r);
|
||||||
|
}
|
||||||
|
let msg2 = secp256k1::Message::from_slice(&hash_to_slice(&msg) ).unwrap();
|
||||||
|
let merch_sig = secp.sign(&msg2, &self.sk);
|
||||||
|
return ChannelcloseM { address: address.clone(), revoke: revoke_token.clone(), signature: merch_sig };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -612,10 +652,6 @@ mod tests {
|
||||||
let amount = 10;
|
let amount = 10;
|
||||||
let (pay_proof, new_com, old_wpk, new_cw) = cust_state.generate_payment(rng, &channel, amount);
|
let (pay_proof, new_com, old_wpk, new_cw) = cust_state.generate_payment(rng, &channel, amount);
|
||||||
|
|
||||||
// println!("{}", new_com);
|
|
||||||
// println!("wpk => {}", old_wpk);
|
|
||||||
// println!("{}", new_cw);
|
|
||||||
|
|
||||||
// new pay_token is not sent until revoke_token is obtained from the customer
|
// new pay_token is not sent until revoke_token is obtained from the customer
|
||||||
let new_close_token = merch_state.verify_payment(rng, &channel, &pay_proof, &new_com, &old_wpk, amount).unwrap();
|
let new_close_token = merch_state.verify_payment(rng, &channel, &pay_proof, &new_com, &old_wpk, amount).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub mod ffishim {
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use channels::ChannelcloseM;
|
||||||
|
|
||||||
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,8 +325,11 @@ pub mod ffishim {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn ffishim_bidirectional_merchant_close(ser_channel_state: *mut c_char, ser_channel_token: *mut c_char,
|
pub extern fn ffishim_bidirectional_merchant_close(ser_channel_state: *mut c_char,
|
||||||
ser_cust_close: *mut c_char, ser_merch_state: *mut c_char) -> *mut c_char {
|
ser_channel_token: *mut c_char,
|
||||||
|
ser_address: *const c_char,
|
||||||
|
ser_cust_close: *mut c_char,
|
||||||
|
ser_merch_state: *mut c_char) -> *mut c_char {
|
||||||
// Deserialize the channel state
|
// Deserialize the channel state
|
||||||
let channel_state: bidirectional::ChannelState<Bls12> = deserialize_object(ser_channel_state);
|
let channel_state: bidirectional::ChannelState<Bls12> = deserialize_object(ser_channel_state);
|
||||||
// Deserialize the channel token
|
// Deserialize the channel token
|
||||||
|
@ -335,20 +339,26 @@ pub mod ffishim {
|
||||||
// Deserialize the merch wallet
|
// Deserialize the merch wallet
|
||||||
let merch_state: bidirectional::MerchantState<Bls12> = deserialize_object(ser_merch_state);
|
let merch_state: bidirectional::MerchantState<Bls12> = deserialize_object(ser_merch_state);
|
||||||
|
|
||||||
|
// Deserialize the destination address as a string
|
||||||
|
let ser_addr_bytes = unsafe { CStr::from_ptr(ser_address).to_bytes() };
|
||||||
|
let address: &str = str::from_utf8(ser_addr_bytes).unwrap(); // make sure the bytes are UTF-8
|
||||||
|
|
||||||
let option = bidirectional::merchant_close(&channel_state, &channel_token, &cust_close, &merch_state);
|
let option = bidirectional::merchant_close(&channel_state, &channel_token, &cust_close, &merch_state);
|
||||||
let keys = match option {
|
let keys = match option {
|
||||||
Ok(n) => n.unwrap(),
|
Ok(n) => n.unwrap(),
|
||||||
Err(err) => return error_message(err),
|
Err(err) => return error_message(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let merch_close: bidirectional::ChannelcloseM = merch_state.sign_revoke_message(address.to_string(), &keys.revoke_token);
|
||||||
|
|
||||||
let ser = ["{\'wpk\':\'", serde_json::to_string(&keys.wpk).unwrap().as_str(),
|
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();
|
"\', \'merch_close\':\'", serde_json::to_string(&merch_close).unwrap().as_str(), "\'}"].concat();
|
||||||
let cser = CString::new(ser).unwrap();
|
let cser = CString::new(ser).unwrap();
|
||||||
cser.into_raw()
|
cser.into_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn ffishim_bidirectional_verify_open_channel(ser_channel_token: *mut c_char,
|
pub extern fn ffishim_bidirectional_wtp_verify_cust_close_message(ser_channel_token: *mut c_char,
|
||||||
ser_wpk: *mut c_char,
|
ser_wpk: *mut c_char,
|
||||||
ser_close_msg: *mut c_char,
|
ser_close_msg: *mut c_char,
|
||||||
ser_close_token: *mut c_char) -> *mut c_char {
|
ser_close_token: *mut c_char) -> *mut c_char {
|
||||||
|
@ -362,7 +372,26 @@ pub mod ffishim {
|
||||||
// Deserialize the close token
|
// Deserialize the close token
|
||||||
let close_token: bidirectional::Signature<Bls12> = deserialize_object(ser_close_token);
|
let close_token: bidirectional::Signature<Bls12> = deserialize_object(ser_close_token);
|
||||||
// check the signatures
|
// check the signatures
|
||||||
let token_valid = bidirectional::verify_open_channel(&channel_token, &wpk, &close_msg, &close_token);
|
let token_valid = bidirectional::wtp_verify_cust_close_message(&channel_token, &wpk, &close_msg, &close_token);
|
||||||
|
let ser = ["{\'result\':\'", serde_json::to_string(&token_valid).unwrap().as_str(), "\'}"].concat();
|
||||||
|
let cser = CString::new(ser).unwrap();
|
||||||
|
cser.into_raw()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn ffishim_bidirectional_wtp_verify_merch_close_message(ser_channel_token: *mut c_char, ser_wpk: *mut c_char, ser_merch_close: *mut c_char) -> *mut c_char {
|
||||||
|
// Deserialize the channel token
|
||||||
|
let channel_token: bidirectional::ChannelToken<Bls12> = deserialize_object(ser_channel_token);
|
||||||
|
// Deserialize the wpk
|
||||||
|
let wpk: secp256k1::PublicKey = deserialize_object(ser_wpk);
|
||||||
|
// Deserialize the merch close
|
||||||
|
//let revoke_token: secp256k1::Signature = deserialize_object(ser_revoke_token);
|
||||||
|
let merch_close: bidirectional::ChannelcloseM = deserialize_object(ser_merch_close);
|
||||||
|
|
||||||
|
let revoke_token_valid = bidirectional::wtp_verify_revoke_message(&channel_token, &wpk, &merch_close.revoke.unwrap());
|
||||||
|
let merch_close_valid = bidirectional::wtp_verify_merch_close_message(&channel_token, &merch_close);
|
||||||
|
let token_valid = revoke_token_valid && merch_close_valid;
|
||||||
|
|
||||||
let ser = ["{\'result\':\'", serde_json::to_string(&token_valid).unwrap().as_str(), "\'}"].concat();
|
let ser = ["{\'result\':\'", serde_json::to_string(&token_valid).unwrap().as_str(), "\'}"].concat();
|
||||||
let cser = CString::new(ser).unwrap();
|
let cser = CString::new(ser).unwrap();
|
||||||
cser.into_raw()
|
cser.into_raw()
|
||||||
|
|
40
src/lib.rs
40
src/lib.rs
|
@ -124,11 +124,12 @@ pub mod bidirectional {
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use util::RevokedMessage;
|
use util::{RevokedMessage, hash_to_slice};
|
||||||
pub use ped92::Commitment;
|
pub use ped92::Commitment;
|
||||||
pub use cl::{PublicKey, Signature};
|
pub use cl::{PublicKey, Signature};
|
||||||
pub use BoltResult;
|
pub use BoltResult;
|
||||||
pub use channels::{ChannelState, ChannelToken, CustomerState, MerchantState, PubKeyMap, ChannelParams, BoltError, ResultBoltSig};
|
pub use channels::{ChannelState, ChannelToken, CustomerState, MerchantState, ChannelcloseM,
|
||||||
|
PubKeyMap, ChannelParams, BoltError, ResultBoltSig};
|
||||||
pub use nizk::{CommitmentProof, Proof};
|
pub use nizk::{CommitmentProof, Proof};
|
||||||
pub use wallet::Wallet;
|
pub use wallet::Wallet;
|
||||||
pub use cl::PublicParams;
|
pub use cl::PublicParams;
|
||||||
|
@ -430,6 +431,7 @@ pub mod bidirectional {
|
||||||
let msg = secp256k1::Message::from_slice(&revoke_msg.hash_to_slice()).unwrap();
|
let msg = secp256k1::Message::from_slice(&revoke_msg.hash_to_slice()).unwrap();
|
||||||
// verify that the revocation token is valid
|
// verify that the revocation token is valid
|
||||||
if secp.verify(&msg, &revoke_token, &wpk).is_ok() {
|
if secp.verify(&msg, &revoke_token, &wpk).is_ok() {
|
||||||
|
// compute signature on
|
||||||
return Ok(Some(revoked_state.clone()));
|
return Ok(Some(revoked_state.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,10 +442,14 @@ pub mod bidirectional {
|
||||||
Err(String::from("merchant_close - Customer close message not valid!"))
|
Err(String::from("merchant_close - Customer close message not valid!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn wtp_sign_merch_close_message<E: Engine>(address: &Vec<u8>, revoke_token: &Option<secp256k1::Signature>, merch_state: &MerchantState<E>) -> ChannelcloseM {
|
||||||
|
// return merch_state.sign_revoke_message(&address, &revoke_token);
|
||||||
|
// }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// WTP for validating that a close_token was well-formed
|
/// Used in open-channel WTP for validating that a close_token is a valid signature under <
|
||||||
///
|
///
|
||||||
pub fn verify_open_channel<E: Engine>(channel_token: &ChannelToken<E>, wpk: &secp256k1::PublicKey, close_msg: &wallet::Wallet<E>, close_token: &Signature<E>) -> bool {
|
pub fn wtp_verify_cust_close_message<E: Engine>(channel_token: &ChannelToken<E>, wpk: &secp256k1::PublicKey, close_msg: &wallet::Wallet<E>, close_token: &Signature<E>) -> bool {
|
||||||
// close_msg => <pkc> || <wpk> || <balance-cust> || <balance-merch> || CLOSE
|
// close_msg => <pkc> || <wpk> || <balance-cust> || <balance-merch> || CLOSE
|
||||||
// close_token = regular CL signature on close_msg
|
// close_token = regular CL signature on close_msg
|
||||||
// channel_token => <pk_c, CL_PK_m, pk_m, mpk, comParams>
|
// channel_token => <pk_c, CL_PK_m, pk_m, mpk, comParams>
|
||||||
|
@ -459,7 +465,33 @@ pub mod bidirectional {
|
||||||
return pkc_thesame && wpk_thesame && channel_token.cl_pk_m.verify(&channel_token.mpk, &close_msg.as_fr_vec(), &close_token);
|
return pkc_thesame && wpk_thesame && channel_token.cl_pk_m.verify(&channel_token.mpk, &close_msg.as_fr_vec(), &close_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Used in merch-close WTP for validating that revoke_token is a valid signature under <wpk> and the <revoked || wpk> message
|
||||||
|
///
|
||||||
|
pub fn wtp_verify_revoke_message<E: Engine>(channel_token: &ChannelToken<E>, wpk: &secp256k1::PublicKey, revoke_token: &secp256k1::Signature) -> bool {
|
||||||
|
let secp = secp256k1::Secp256k1::verification_only();
|
||||||
|
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 with respect to revoked || wpk
|
||||||
|
return secp.verify(&msg, &revoke_token, &wpk).is_ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Used in merch-close WTP for validating that merch_sig is a valid signature under <merch_pk> on <dest_addr || revoke-token> message
|
||||||
|
///
|
||||||
|
pub fn wtp_verify_merch_close_message<E: Engine>(channel_token: &ChannelToken<E>, merch_close: &ChannelcloseM) -> bool {
|
||||||
|
let secp = secp256k1::Secp256k1::verification_only();
|
||||||
|
let mut msg = Vec::new();
|
||||||
|
msg.extend(merch_close.address.as_bytes());
|
||||||
|
if !merch_close.revoke.is_none() {
|
||||||
|
// serialize signature in DER format
|
||||||
|
let r = merch_close.revoke.unwrap().serialize_der().to_vec();
|
||||||
|
msg.extend(r);
|
||||||
|
}
|
||||||
|
let msg2 = secp256k1::Message::from_slice(&hash_to_slice(&msg)).unwrap();
|
||||||
|
// verify that merch sig is valid with respect to dest_address
|
||||||
|
return secp.verify(&msg2, &merch_close.signature, &channel_token.pk_m).is_ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, feature = "unstable"))]
|
#[cfg(all(test, feature = "unstable"))]
|
||||||
|
|
|
@ -114,6 +114,14 @@ pub fn hash_buffer_to_fr<'a, E: Engine>(prefix: &'a str, buf: &[u8; 64]) -> E::F
|
||||||
return result.unwrap();
|
return result.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hash_to_slice(input_buf: &Vec<u8>) -> [u8; 32] {
|
||||||
|
let sha2_digest = sha512::hash(input_buf.as_slice());
|
||||||
|
let mut hash_buf: [u8; 32] = [0; 32];
|
||||||
|
hash_buf.copy_from_slice(&sha2_digest[0..32]);
|
||||||
|
return hash_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct RevokedMessage {
|
pub struct RevokedMessage {
|
||||||
|
|
Loading…
Reference in New Issue