Add better error handling for verify_revoke_token() and more tests

This commit is contained in:
J. Ayo Akinyele 2019-09-06 04:45:47 +02:00
parent a526184a74
commit 7d92625c14
5 changed files with 97 additions and 28 deletions

View File

@ -9,6 +9,7 @@ extern crate secp256k1;
use bolt::bidirectional;
use std::time::Instant;
use pairing::bls12_381::{Bls12};
use bolt::handle_bolt_result;
macro_rules! measure_one_arg {
($x: expr) => {
@ -96,10 +97,11 @@ fn main() {
let revoke_token = bidirectional::generate_revoke_token(&channel_state, &mut cust_state, new_cust_state, &new_close_token);
// send revoke token and get pay-token in response
let new_pay_token = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let new_pay_token_result = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let new_pay_token = handle_bolt_result!(new_pay_token_result);
// verify the pay token and update internal state
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token));
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token.unwrap()));
println!("******************************************");
@ -112,10 +114,11 @@ fn main() {
let revoke_token2 = bidirectional::generate_revoke_token(&channel_state, &mut cust_state, new_cust_state2, &new_close_token2);
// send revoke token and get pay-token in response
let new_pay_token2 = bidirectional::verify_revoke_token(&revoke_token2, &mut merch_state);
let new_pay_token_result2 = bidirectional::verify_revoke_token(&revoke_token2, &mut merch_state);
let new_pay_token2 = handle_bolt_result!(new_pay_token_result2);
// verify the pay token and update internal state
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token2));
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token2.unwrap()));
println!("Final Cust state: {}", cust_state);

View File

@ -128,7 +128,7 @@ class Libbolt(object):
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_state.encode(), amount)
output_dictionary = ast.literal_eval(ctypes.cast(output_string, ctypes.c_char_p).value.decode('utf-8'))
return output_dictionary['payment'], output_dictionary['cust_state']
return output_dictionary.get('payment'), output_dictionary.get('cust_state')
# verify payment proof
def bidirectional_pay_verify_payment_proof(self, channel_state, pay_proof, merch_state):
@ -141,20 +141,20 @@ class Libbolt(object):
output_string = self.lib.ffishim_bidirectional_pay_generate_revoke_token(channel_state.encode(), cust_state.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'))
return output_dictionary['revoke_token'], output_dictionary['cust_state']
return output_dictionary.get('revoke_token'), output_dictionary.get('cust_state')
# verify revoke token
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_state.encode())
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_state'])
return (output_dictionary.get('pay_token'), output_dictionary.get('merch_state'))
# verify payment token
def bidirectional_pay_verify_payment_token(self, channel_state, cust_state, pay_token):
output_string = self.lib.ffishim_bidirectional_pay_verify_payment_token(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'))
is_pay_valid = self._convert_boolean(output_dictionary.get('is_pay_valid'))
return (output_dictionary['cust_state'], is_pay_valid)
return (output_dictionary.get('cust_state'), is_pay_valid)
# CLOSE

View File

@ -11,7 +11,10 @@ def malformed_token(token):
token_dict = ast.literal_eval(token)
updated_token = {}
for k,v in token_dict.items():
updated_token[k] = v[:-4] + rand_hex(4)
if type(v) == str:
updated_token[k] = v[:-4] + rand_hex(4)
else:
updated_token[k] = v
return json.dumps(updated_token)
def malformed_proof(proof):
@ -181,20 +184,71 @@ class BoltPayTests(unittest.TestCase):
(self.cust_state, is_pay_valid) = self.bolt.bidirectional_pay_verify_payment_token(self.channel_state, self.cust_state, pay_token)
self.assertTrue(is_pay_valid)
def test_pay_protocol_bad_payment_proof_fails(self):
amount = 10
def test_pay_protocol_bad_payment_proof_fail_handled(self):
"""
Payment protocol fails as expected when customer sends a bad payment proof
:return:
"""
amount = 15
(payment_proof, new_cust_state) = self.bolt.bidirectional_pay_generate_payment_proof(self.channel_state, self.cust_state, amount)
bad_payment_proof = malformed_proof(payment_proof)
(new_close_token, self.merch_state) = self.bolt.bidirectional_pay_verify_payment_proof(self.channel_state, bad_payment_proof, self.merch_state)
self.assertTrue(new_close_token is None)
def test_pay_protocol_bad_revoke_token_fails(self):
pass
def test_pay_protocol_bad_close_token_fail_handled(self):
"""
Payment protocol fails as expected when merchant returns a malformed/bad close token
:return:
"""
amount = 10
(payment_proof, new_cust_state) = self.bolt.bidirectional_pay_generate_payment_proof(self.channel_state, self.cust_state, amount)
def test_pay_protocol_bad_payment_token_fails(self):
pass
(new_close_token, self.merch_state) = self.bolt.bidirectional_pay_verify_payment_proof(self.channel_state, payment_proof, self.merch_state)
bad_close_token = malformed_token(new_close_token)
(revoke_token, self.cust_state) = self.bolt.bidirectional_pay_generate_revoke_token(self.channel_state, self.cust_state, new_cust_state, bad_close_token)
self.assertTrue(revoke_token is None)
def test_pay_protocol_bad_revoke_token_fail_handled(self):
"""
Payment protocol fails as expected when customer sends a bad revoke token
:return:
"""
amount = 20
(payment_proof, new_cust_state) = self.bolt.bidirectional_pay_generate_payment_proof(self.channel_state, self.cust_state, amount)
(new_close_token, self.merch_state) = self.bolt.bidirectional_pay_verify_payment_proof(self.channel_state, payment_proof, self.merch_state)
(revoke_token, self.cust_state) = self.bolt.bidirectional_pay_generate_revoke_token(self.channel_state, self.cust_state, new_cust_state, new_close_token)
bad_revoke_token = malformed_token(revoke_token)
(pay_token, merch_state) = self.bolt.bidirectional_pay_verify_revoke_token(bad_revoke_token, self.merch_state)
self.assertTrue(pay_token is None)
def test_pay_protocol_bad_payment_token_fail_handled(self):
"""
Payment protocol fails as expected when merchant returns a malformed pay token
:return:
"""
amount = 25
(payment_proof, new_cust_state) = self.bolt.bidirectional_pay_generate_payment_proof(self.channel_state, self.cust_state, amount)
(new_close_token, self.merch_state) = self.bolt.bidirectional_pay_verify_payment_proof(self.channel_state, payment_proof, self.merch_state)
(revoke_token, self.cust_state) = self.bolt.bidirectional_pay_generate_revoke_token(self.channel_state, self.cust_state, new_cust_state, new_close_token)
(pay_token, self.merch_state) = self.bolt.bidirectional_pay_verify_revoke_token(revoke_token, self.merch_state)
bad_pay_token = malformed_token(pay_token)
(cust_state, is_pay_valid) = self.bolt.bidirectional_pay_verify_payment_token(self.channel_state, self.cust_state, bad_pay_token)
self.assertTrue(is_pay_valid is None)
class BoltMultiChannelTests(unittest.TestCase):
pass
class BoltIntermediaryTests(unittest.TestCase):
pass
if __name__ == '__main__':
unittest.main()

View File

@ -343,8 +343,10 @@ pub mod ffishim {
let mut merch_state = handle_errors!(merch_state_result);
// send revoke token and get pay-token in response
let pay_token = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let ser = ["{\'pay_token\':\'", serde_json::to_string(&pay_token).unwrap().as_str(),
let pay_token_result = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let pay_token = handle_errors!(pay_token_result);
let ser = ["{\'pay_token\':\'", serde_json::to_string(&pay_token.unwrap()).unwrap().as_str(),
"\', \'merch_state\':\'", serde_json::to_string(&merch_state).unwrap().as_str() ,"\'}"].concat();
let cser = CString::new(ser).unwrap();
cser.into_raw()

View File

@ -106,6 +106,14 @@ impl<'a> fmt::UpperHex for HexSlice<'a> {
pub type BoltResult<T> = Result<Option<T>, String>;
#[macro_export]
macro_rules! handle_bolt_result {
($e:expr) => (match $e {
Ok(val) => val,
Err(_) => None,
});
}
////////////////////////////////// Utilities //////////////////////////////////
/////////////////////////////// Bidirectional ////////////////////////////////
@ -358,10 +366,14 @@ pub mod bidirectional {
/// merchant state, from the customer. If the revocation token is valid,
/// generate a new signature for the new wallet (from the PoK of committed values in new wallet).
///
pub fn verify_revoke_token<E: Engine>(rt: &RevokeToken, merch_state: &mut MerchantState<E>) -> cl::Signature<E> {
let new_pay_token = merch_state.verify_revoke_token(&rt.signature, &rt.message, &rt.message.wpk).unwrap();
pub fn verify_revoke_token<E: Engine>(rt: &RevokeToken, merch_state: &mut MerchantState<E>) -> BoltResult<cl::Signature<E>> {
let pay_token_result = merch_state.verify_revoke_token(&rt.signature, &rt.message, &rt.message.wpk);
let new_pay_token = match pay_token_result {
Ok(n) => n,
Err(err) => return Err(String::from(err.to_string()))
};
update_merchant_state(&mut merch_state.keys, &rt.message.wpk, Some(rt.signature.clone()));
return new_pay_token;
Ok(Some(new_pay_token))
}
///// end of pay protocol
@ -445,10 +457,6 @@ pub mod bidirectional {
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);
// }
///
/// Used in open-channel WTP for validating that a close_token is a valid signature under <
///
@ -583,10 +591,11 @@ mod tests {
let revoke_token = bidirectional::generate_revoke_token(&channel_state, cust_state, new_cust_state, &new_close_token);
// send revoke token and get pay-token in response
let new_pay_token = bidirectional::verify_revoke_token(&revoke_token, merch_state);
let new_pay_token_result: BoltResult<cl::Signature<Bls12>> = bidirectional::verify_revoke_token(&revoke_token, merch_state);
let new_pay_token = handle_bolt_result!(new_pay_token_result);
// verify the pay token and update internal state
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token));
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token.unwrap()));
}
#[test]
@ -638,10 +647,11 @@ mod tests {
let revoke_token = bidirectional::generate_revoke_token(&channel_state, &mut cust_state, new_cust_state, &new_close_token);
// send revoke token and get pay-token in response
let new_pay_token = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let new_pay_token_result: BoltResult<cl::Signature<Bls12>> = bidirectional::verify_revoke_token(&revoke_token, &mut merch_state);
let new_pay_token = handle_bolt_result!(new_pay_token_result);
// verify the pay token and update internal state
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token));
assert!(cust_state.verify_pay_token(&channel_state, &new_pay_token.unwrap()));
println!("Successful payment!");