2018-02-24 00:12:58 -08:00
|
|
|
extern crate bn;
|
2018-02-24 23:46:52 -08:00
|
|
|
extern crate rand;
|
|
|
|
extern crate bincode;
|
|
|
|
extern crate sodiumoxide;
|
2018-06-07 23:57:46 -07:00
|
|
|
extern crate rustc_serialize;
|
2018-06-08 18:20:15 -07:00
|
|
|
extern crate secp256k1;
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-02-24 23:46:52 -08:00
|
|
|
use std::fmt;
|
2018-03-24 06:44:45 -07:00
|
|
|
use std::str;
|
|
|
|
use std::default;
|
2018-06-13 17:28:37 -07:00
|
|
|
use std::result;
|
2018-06-05 10:26:16 -07:00
|
|
|
use bn::{Group, Fr, G1, G2, Gt, pairing};
|
2018-02-24 23:46:52 -08:00
|
|
|
use bincode::SizeLimit::Infinite;
|
|
|
|
use bincode::rustc_serialize::{encode, decode};
|
2018-04-08 00:46:17 -07:00
|
|
|
use sodiumoxide::randombytes;
|
2018-03-24 06:44:45 -07:00
|
|
|
use sodiumoxide::crypto::hash::sha512;
|
2018-06-09 23:00:01 -07:00
|
|
|
use std::collections::HashMap;
|
2018-02-24 00:12:58 -08:00
|
|
|
|
2018-04-07 12:01:27 -07:00
|
|
|
pub mod prf;
|
2018-04-02 07:47:19 -07:00
|
|
|
pub mod sym;
|
2018-04-07 12:01:27 -07:00
|
|
|
pub mod ote;
|
2018-04-02 07:47:19 -07:00
|
|
|
pub mod clsigs;
|
|
|
|
pub mod commit_scheme;
|
|
|
|
|
2018-06-14 20:50:00 -07:00
|
|
|
const E_MIN: i32 = 1;
|
|
|
|
const E_MAX: i32 = 255;
|
|
|
|
|
2018-03-24 06:44:45 -07:00
|
|
|
//pub fn hash_string(s: &str) -> String {
|
|
|
|
// let digest = sha256::hash(s.as_bytes());
|
|
|
|
// format!("{:X}", HexSlice::new(&digest))
|
|
|
|
//}
|
2018-02-24 23:46:52 -08:00
|
|
|
|
2018-03-24 06:44:45 -07:00
|
|
|
pub fn debug_elem_in_hex(prefix: &str, r: &Fr) {
|
|
|
|
let encoded: Vec<u8> = encode(&r, Infinite).unwrap();
|
|
|
|
print!("{} (hex) = 0x", prefix);
|
|
|
|
for e in encoded.iter() {
|
|
|
|
print!("{:x}", e);
|
|
|
|
}
|
|
|
|
print!("\n");
|
2018-02-24 00:12:58 -08:00
|
|
|
}
|
|
|
|
|
2018-06-05 19:57:44 -07:00
|
|
|
pub fn debug_g1_in_hex(prefix: &str, g: &G1) {
|
|
|
|
let encoded: Vec<u8> = encode(&g, Infinite).unwrap();
|
|
|
|
print!("{} (hex) = 0x", prefix);
|
|
|
|
for e in encoded.iter() {
|
|
|
|
print!("{:x}", e);
|
|
|
|
}
|
|
|
|
print!("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn debug_g2_in_hex(prefix: &str, g: &G2) {
|
|
|
|
let encoded: Vec<u8> = encode(&g, Infinite).unwrap();
|
|
|
|
print!("{} (hex) = 0x", prefix);
|
|
|
|
for e in encoded.iter() {
|
|
|
|
print!("{:x}", e);
|
|
|
|
}
|
|
|
|
print!("\n");
|
|
|
|
}
|
|
|
|
|
2018-06-07 23:57:46 -07:00
|
|
|
pub fn debug_gt_in_hex(prefix: &str, g: &Gt) {
|
|
|
|
let encoded: Vec<u8> = encode(&g, Infinite).unwrap();
|
|
|
|
print!("{} (hex) = 0x", prefix);
|
|
|
|
for e in encoded.iter() {
|
|
|
|
print!("{:x}", e);
|
|
|
|
}
|
|
|
|
print!("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-24 06:44:45 -07:00
|
|
|
struct HexSlice<'a>(&'a [u8]);
|
|
|
|
|
|
|
|
impl<'a> HexSlice<'a> {
|
|
|
|
fn new<T>(data: &'a T) -> HexSlice<'a>
|
|
|
|
where T: ?Sized + AsRef<[u8]> + 'a
|
|
|
|
{
|
|
|
|
HexSlice(data.as_ref())
|
2018-02-24 23:46:52 -08:00
|
|
|
}
|
|
|
|
}
|
2018-02-24 00:12:58 -08:00
|
|
|
|
2018-03-24 06:44:45 -07:00
|
|
|
impl<'a> fmt::LowerHex for HexSlice<'a> {
|
2018-02-24 23:46:52 -08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2018-03-24 06:44:45 -07:00
|
|
|
for byte in self.0 {
|
|
|
|
// Decide if you want upper- or lowercase results,
|
|
|
|
// padding the values to two characters, spaces
|
|
|
|
// between bytes, etc.
|
|
|
|
write!(f, "{:x}", byte)?;
|
2018-02-24 23:46:52 -08:00
|
|
|
}
|
2018-03-24 06:44:45 -07:00
|
|
|
Ok(())
|
2018-02-24 23:46:52 -08:00
|
|
|
}
|
2018-02-24 00:12:58 -08:00
|
|
|
}
|
|
|
|
|
2018-03-24 06:44:45 -07:00
|
|
|
impl<'a> fmt::UpperHex for HexSlice<'a> {
|
2018-02-24 23:46:52 -08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2018-03-24 06:44:45 -07:00
|
|
|
for byte in self.0 {
|
|
|
|
// Decide if you want upper- or lowercase results,
|
|
|
|
// padding the values to two characters, spaces
|
|
|
|
// between bytes, etc.
|
|
|
|
write!(f, "{:X}", byte)?;
|
2018-02-24 23:46:52 -08:00
|
|
|
}
|
2018-03-24 06:44:45 -07:00
|
|
|
Ok(())
|
2018-02-24 23:46:52 -08:00
|
|
|
}
|
2018-02-24 00:12:58 -08:00
|
|
|
}
|
2018-03-24 06:44:45 -07:00
|
|
|
// To hash this message structure, encode each element in the tuple
|
|
|
|
// as a byte stream, then apply a hash on it. Then, convert the output value into
|
|
|
|
// a Fr element.
|
2018-02-24 00:12:58 -08:00
|
|
|
|
2018-02-24 23:46:52 -08:00
|
|
|
pub fn misc_tests() {
|
|
|
|
let rng = &mut rand::thread_rng();
|
|
|
|
let a = Fr::random(rng);
|
|
|
|
// println!("crs = {}", stringify!(a));
|
|
|
|
// let limit = bincode::SizeLimit::Bounded(256);
|
|
|
|
let encoded: Vec<u8> = encode(&a, Infinite).unwrap();
|
|
|
|
println!("a length = {}", encoded.len());
|
|
|
|
println!("a = {:?}", encoded);
|
|
|
|
print!("a (hex) = 0x");
|
|
|
|
for x in encoded.iter() {
|
|
|
|
print!("{:x}", x);
|
|
|
|
}
|
|
|
|
print!("\n");
|
2018-02-24 00:12:58 -08:00
|
|
|
|
|
|
|
}
|
2018-02-24 23:46:52 -08:00
|
|
|
|
2018-04-07 12:01:27 -07:00
|
|
|
pub fn print(g: &G1) -> String {
|
|
|
|
let c_vec: Vec<u8> = encode(g, Infinite).unwrap();
|
|
|
|
let mut c_s = String::new();
|
|
|
|
for x in c_vec.iter() {
|
|
|
|
c_s = format!("{}{:x}", c_s, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
return c_s;
|
|
|
|
}
|
|
|
|
|
2018-04-02 07:47:19 -07:00
|
|
|
////////////////////////////////// ZK proof compiler ///////////////////////////////////
|
|
|
|
|
|
|
|
//pub mod zkp {
|
|
|
|
//
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! log {
|
|
|
|
// ($msg:expr) => {{
|
|
|
|
// let state: i32 = get_log_state();
|
|
|
|
// if state > 0 {
|
|
|
|
// println!("log({}): {}", state, $msg);
|
|
|
|
// }
|
|
|
|
// }};
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//#[doc(hidden)]
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! __compute_formula_scalarlist {
|
|
|
|
// // Unbracket a statement
|
|
|
|
// (($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
|
|
|
// // Add a trailing +
|
|
|
|
// __compute_formula_scalarlist!(($publics,$scalars) $($x)* +)
|
|
|
|
// };
|
|
|
|
// // Inner part of the formula: give a list of &Scalars
|
|
|
|
// // Since there's a trailing +, we can just generate the list as normal...
|
|
|
|
// (($publics:ident, $scalars:ident)
|
|
|
|
// $( $point:ident * $scalar:ident +)+ ) => {
|
|
|
|
// &[ $( $scalars.$scalar ,)* ]
|
|
|
|
// };
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//#[doc(hidden)]
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! __compute_formula_pointlist {
|
|
|
|
// // Unbracket a statement
|
|
|
|
// (($publics:ident, $scalars:ident) ($($x:tt)*)) => {
|
|
|
|
// // Add a trailing +
|
|
|
|
// __compute_formula_pointlist!(($publics,$scalars) $($x)* +)
|
|
|
|
// };
|
|
|
|
// // Inner part of the formula: give a list of &Scalars
|
|
|
|
// // Since there's a trailing +, we can just generate the list as normal...
|
|
|
|
// (($publics:ident, $scalars:ident)
|
|
|
|
// $( $point:ident * $scalar:ident +)* ) => {
|
|
|
|
// &[ $( *($publics.$point) ,)* ]
|
|
|
|
// };
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//#[doc(hidden)]
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! __compute_commitments_consttime {
|
|
|
|
// (($publics:ident, $scalars:ident) $($lhs:ident = $statement:tt),+) => {
|
|
|
|
// Commitments {
|
|
|
|
// $( $lhs :
|
|
|
|
// multiscalar_mult(
|
|
|
|
// __compute_formula_scalarlist!(($publics, $scalars) $statement),
|
|
|
|
// __compute_formula_pointlist!(($publics, $scalars) $statement),
|
|
|
|
// )
|
|
|
|
// ),+
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//#[doc(hidden)]
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! __recompute_commitments_vartime {
|
|
|
|
// (($publics:ident, $scalars:ident, $minus_c:ident) $($lhs:ident = $statement:tt),+) => {
|
|
|
|
// Commitments {
|
|
|
|
// $( $lhs :
|
|
|
|
// vartime::multiscalar_mult(
|
|
|
|
// __compute_formula_scalarlist!(($publics, $scalars) $statement)
|
|
|
|
// .into_iter()
|
|
|
|
// .chain(iter::once(&($minus_c)))
|
|
|
|
// ,
|
|
|
|
// __compute_formula_pointlist!(($publics, $scalars) $statement)
|
|
|
|
// .into_iter()
|
|
|
|
// .chain(iter::once($publics.$lhs))
|
|
|
|
// )
|
|
|
|
// ),+
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//#[macro_export]
|
|
|
|
//macro_rules! create_nipk {
|
|
|
|
//(
|
|
|
|
// $proof_module_name:ident // Name of the module to create
|
|
|
|
// ,
|
|
|
|
// ( $($secret:ident),+ ) // Secret variables, sep by commas
|
|
|
|
// ,
|
|
|
|
// ( $($public:ident),+ ) // Public variables, sep by commas
|
|
|
|
// :
|
|
|
|
// // List of statements to prove
|
|
|
|
// // Format: LHS = ( ... RHS expr ... ),
|
|
|
|
// $($lhs:ident = $statement:tt),+
|
|
|
|
//) => {
|
|
|
|
// mod $proof_module_name {
|
|
|
|
// use $crate::{Group, Fr, G1}
|
|
|
|
// use $crate::sodiumoxide::crypto::hash;
|
|
|
|
// // use $crate::sha2::{Digest, Sha512};
|
|
|
|
// use $crate::rand::Rng;
|
|
|
|
//
|
|
|
|
// use std::iter;
|
|
|
|
//
|
|
|
|
// #[derive(Copy, Clone)]
|
|
|
|
// pub struct Secrets<'a> {
|
|
|
|
// // Create a parameter for each secret value
|
|
|
|
// $(
|
|
|
|
// pub $secret : &'a Fr,
|
|
|
|
// )+
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// #[derive(Copy, Clone)]
|
|
|
|
// pub struct Publics<'a> {
|
|
|
|
// // Create a parameter for each public value
|
|
|
|
// $(
|
|
|
|
// pub $public : &'a G1,
|
|
|
|
// )+
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // Hack because we can't concat identifiers,
|
|
|
|
// // so do responses.x instead of responses_x
|
|
|
|
// // rand.x instead of rand_x, etc.
|
|
|
|
//
|
|
|
|
// struct Commitments {$($lhs: G1,)+ }
|
|
|
|
// struct Randomnesses {$($secret : Scalar,)+}
|
|
|
|
// #[derive(Serialize, Deserialize)]
|
|
|
|
// struct Responses {$($secret : Scalar,)+}
|
|
|
|
//
|
|
|
|
// #[derive(Serialize, Deserialize)]
|
|
|
|
// pub struct Proof {
|
|
|
|
// challenge: Fr,
|
|
|
|
// responses: Responses,
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// impl Proof {
|
|
|
|
// /// Create a `Proof`, in constant time, from the given
|
|
|
|
// /// `Publics` and `Secrets`.
|
|
|
|
// #[allow(dead_code)]
|
|
|
|
// pub fn create<R: Rng>(
|
|
|
|
// rng: &mut R,
|
|
|
|
// publics: Publics,
|
|
|
|
// secrets: Secrets,
|
|
|
|
// ) -> Proof {
|
|
|
|
// let rand = Randomnesses{
|
|
|
|
// $(
|
|
|
|
// $secret : Fr::random(rng),
|
|
|
|
// )+
|
|
|
|
// };
|
|
|
|
// // $statement_rhs = `X * x + Y * y + Z * z`
|
|
|
|
// // should become
|
|
|
|
// // `publics.X * rand.x + publics.Y * rand.y + publics.Z * rand.z`
|
|
|
|
// let commitments: Commitments;
|
|
|
|
// commitments = __compute_commitments_consttime!(
|
|
|
|
// (publics, rand) $($lhs = $statement),*
|
|
|
|
// );
|
|
|
|
//
|
|
|
|
// let mut hash_state = hash::State::new();
|
|
|
|
//
|
|
|
|
// $(
|
|
|
|
// hash_state.update(publics.$public.as_bytes());
|
|
|
|
// )+
|
|
|
|
// $(
|
|
|
|
// hash_state.update(commitments.$lhs.as_bytes());
|
|
|
|
// )+
|
|
|
|
//
|
|
|
|
// let digest = hash_state.finalize();
|
|
|
|
// let mut digest_buf: [u8; 64] = [0; 64];
|
|
|
|
// digest_buf.copy_from_slice(&digest[0..64]);
|
|
|
|
// let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
|
|
|
//
|
|
|
|
// let responses = Responses{
|
|
|
|
// $(
|
|
|
|
// $secret : &(&challenge * secrets.$secret) + &rand.$secret,
|
|
|
|
// )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// Proof{ challenge: challenge, responses: responses }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// /// Verify the `Proof` using the public parameters `Publics`.
|
|
|
|
// #[allow(dead_code)]
|
|
|
|
// pub fn verify(&self, publics: Publics) -> Result<(),()> {
|
|
|
|
// // `A = X * x + Y * y`
|
|
|
|
// // should become
|
|
|
|
// // `publics.X * responses.x + publics.Y * responses.y - publics.A * self.challenge`
|
|
|
|
// let responses = &self.responses;
|
|
|
|
// let minus_c = -&self.challenge;
|
|
|
|
// let commitments = __recompute_commitments_vartime!(
|
|
|
|
// (publics, responses, minus_c) $($lhs = $statement),*
|
|
|
|
// );
|
|
|
|
//
|
|
|
|
// let mut hash_state = hash::State::new();
|
|
|
|
// // Add each public point into the hash
|
|
|
|
// $(
|
|
|
|
// hash_state.update(publics.$public.as_bytes());
|
|
|
|
// )+
|
|
|
|
// // Add each (recomputed) commitment into the hash
|
|
|
|
// $(
|
|
|
|
// hash_state.update(commitments.$lhs.as_bytes());
|
|
|
|
// )*
|
|
|
|
//
|
|
|
|
// let digest = hash_state.finalize();
|
|
|
|
// let mut digest_buf: [u8; 64] = [0; 64];
|
|
|
|
// digest_buf.copy_from_slice(&digest[0..64]);
|
|
|
|
// // Recompute challenge
|
|
|
|
// let challenge = Fr::interpret(&digest_buf); // Scalar::from_hash(hash);
|
|
|
|
//
|
|
|
|
// if challenge == self.challenge { Ok(()) } else { Err(()) }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// #[cfg(test)]
|
|
|
|
// mod bench {
|
|
|
|
// extern crate test;
|
|
|
|
//
|
|
|
|
// use $crate::rand;
|
|
|
|
//
|
|
|
|
// use super::*;
|
|
|
|
//
|
|
|
|
// use self::test::Bencher;
|
|
|
|
//
|
|
|
|
// #[bench]
|
|
|
|
// #[allow(dead_code)]
|
|
|
|
// fn create(b: &mut Bencher) {
|
|
|
|
// let rng = &mut rand::thread_rng();
|
|
|
|
// //let mut rng = OsRng::new().unwrap();
|
|
|
|
//
|
|
|
|
// // Need somewhere to actually put the public points
|
|
|
|
// struct DummyPublics { $( pub $public : G1, )+ }
|
|
|
|
// let dummy_publics = DummyPublics {
|
|
|
|
// $( $public : G1::random(&mut rng) , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// let publics = Publics {
|
|
|
|
// $( $public : &dummy_publics.$public , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// struct DummySecrets { $( pub $secret : Fr, )+ }
|
|
|
|
// let dummy_secrets = DummySecrets {
|
|
|
|
// $( $secret : Fr::random(&mut rng) , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// let secrets = Secrets {
|
|
|
|
// $( $secret : &dummy_secrets.$secret , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// b.iter(|| Proof::create(&mut rng, publics, secrets));
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// #[bench]
|
|
|
|
// #[allow(dead_code)]
|
|
|
|
// fn verify(b: &mut Bencher) {
|
|
|
|
// let mut rng = OsRng::new().unwrap();
|
|
|
|
//
|
|
|
|
// // Need somewhere to actually put the public points
|
|
|
|
// struct DummyPublics { $( pub $public : G1, )+ }
|
|
|
|
// let dummy_publics = DummyPublics {
|
|
|
|
// $( $public : G1::random(&mut rng) , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// let publics = Publics {
|
|
|
|
// $( $public : &dummy_publics.$public , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// struct DummySecrets { $( pub $secret : Fr, )+ }
|
|
|
|
// let dummy_secrets = DummySecrets {
|
|
|
|
// $( $secret : Fr::random(&mut rng) , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// let secrets = Secrets {
|
|
|
|
// $( $secret : &dummy_secrets.$secret , )+
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// let p = Proof::create(&mut rng, publics, secrets);
|
|
|
|
//
|
|
|
|
// b.iter(|| p.verify(publics));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//}
|
|
|
|
////////////////////////////////// ZK proof compiler ///////////////////////////////////
|
|
|
|
|
2018-03-24 21:03:59 -07:00
|
|
|
////////////////////////////////// SymKeyEnc ///////////////////////////////////
|
|
|
|
/*
|
|
|
|
Symmetric Key Encryption Scheme.
|
|
|
|
*/
|
2018-03-25 20:20:05 -07:00
|
|
|
//pub mod sym {
|
2018-03-24 21:03:59 -07:00
|
|
|
// use std::fmt;
|
2018-03-25 20:20:05 -07:00
|
|
|
// use sodiumoxide;
|
|
|
|
// use sodiumoxide::crypto::secretbox;
|
2018-03-24 21:03:59 -07:00
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub struct SymCT {
|
|
|
|
// nonce: secretbox::Nonce,
|
|
|
|
// ciphertext: Vec<u8>
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
//
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// impl fmt::Display for SymCT {
|
2018-03-24 21:03:59 -07:00
|
|
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// let mut y_s = String::new();
|
2018-03-25 20:20:05 -07:00
|
|
|
// for y in self.ciphertext.iter() {
|
2018-03-24 21:03:59 -07:00
|
|
|
// y_s = format!("{}{:x}", y_s, y);
|
|
|
|
// }
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// write!(f, "CT : (ct=0x{})", y_s)
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// #[derive(Clone)]
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub struct SymKey {
|
|
|
|
// key: secretbox::Key,
|
|
|
|
// l: i32
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub fn init() {
|
|
|
|
// sodiumoxide::init();
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub fn keygen(l: i32) -> SymKey {
|
|
|
|
// // TODO: make sure key is a l-bit key
|
|
|
|
// return SymKey { key: secretbox::gen_key(), l: l };
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub fn encrypt(key: &SymKey, plaintext: &String) -> SymCT {
|
|
|
|
// let nonce = secretbox::gen_nonce();
|
|
|
|
// let pt = plaintext.as_bytes();
|
|
|
|
// let ct = secretbox::seal(pt, &nonce, &key.key);
|
|
|
|
// return SymCT { nonce: nonce, ciphertext: ct };
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
|
|
|
//
|
2018-03-25 20:20:05 -07:00
|
|
|
// pub fn decrypt(key: &SymKey, ciphertext: &SymCT) -> String {
|
|
|
|
// let nonce = ciphertext.nonce;
|
|
|
|
// let pt = secretbox::open(&ciphertext.ciphertext, &nonce, &key.key).unwrap();
|
|
|
|
// // TODO: investigate better error handling here
|
|
|
|
// let plaintext = String::from_utf8(pt).expect("Found invalid UTF-8");
|
|
|
|
// return plaintext;
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
2018-03-25 20:20:05 -07:00
|
|
|
//}
|
|
|
|
|
|
|
|
////////////////////////////////// SymKeyEnc ///////////////////////////////////
|
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// OLD RefundMessage
|
|
|
|
//impl<'a> RefundMessage<'a> {
|
|
|
|
// pub fn new(_c_id: Fr, _index: i32) -> RefundMessage<'a> {
|
|
|
|
// RefundMessage {
|
|
|
|
// prefix: "refund", c_id: _c_id, index: _index,
|
2018-03-24 21:03:59 -07:00
|
|
|
// }
|
2018-06-09 23:00:01 -07:00
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn hash(&self) -> Fr {
|
|
|
|
// let mut input_buf = Vec::new();
|
|
|
|
// input_buf.extend_from_slice(self.prefix.as_bytes());
|
|
|
|
// let c_id_vec: Vec<u8> = encode(&self.c_id, Infinite).unwrap();
|
|
|
|
// // encode cId in the vector
|
|
|
|
// input_buf.extend(c_id_vec);
|
|
|
|
// // encoee the balance as a hex string
|
|
|
|
// let b = format!("{:x}", self.index);
|
|
|
|
// input_buf.extend_from_slice(b.as_bytes());
|
|
|
|
// // TODO: add the ck vector (l-bit key)
|
|
|
|
//// let mut in_str = String::new();
|
|
|
|
//// for y in input_buf.iter() {
|
|
|
|
//// in_str = format!("{}{:x}", in_str, y);
|
|
|
|
//// }
|
|
|
|
//// println!("input_buf: {}", in_str);
|
|
|
|
//
|
|
|
|
// // hash the inputs via SHA256
|
|
|
|
// let sha2_digest = sha512::hash(input_buf.as_slice());
|
|
|
|
// // println!("hash: {:?}", sha2_digest);
|
|
|
|
// // let h = format!("{:x}", HexSlice::new(&sha2_digest));
|
|
|
|
// let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
// hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
// return Fr::interpret(&hash_buf);
|
|
|
|
// }
|
|
|
|
//}
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// spend message (for unidirectional scheme)
|
2018-05-06 18:50:37 -07:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SpendMessage<'a> {
|
|
|
|
prefix: &'a str,
|
|
|
|
j: i32,
|
|
|
|
s: G1,
|
|
|
|
u: G1,
|
|
|
|
pi: Proof,
|
2018-06-05 10:26:16 -07:00
|
|
|
ck: sym::SymKey
|
2018-05-06 18:50:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> SpendMessage<'a> {
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn new(_j: i32, _s: G1, _u: G1, _pi: Proof, _ck: sym::SymKey) -> SpendMessage<'a> {
|
2018-05-06 18:50:37 -07:00
|
|
|
SpendMessage {
|
|
|
|
prefix: "spend", j: _j, s: _s, u: _u, pi: _pi, ck: _ck,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn hash(&self) -> Fr {
|
|
|
|
// hash into a Fr element
|
2018-06-05 10:26:16 -07:00
|
|
|
let rng = &mut rand::thread_rng();
|
|
|
|
return Fr::random(rng);
|
2018-05-06 18:50:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// coin message
|
|
|
|
|
|
|
|
|
2018-03-24 21:03:59 -07:00
|
|
|
////////////////////////////////// CL Sigs /////////////////////////////////////
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-03-24 21:03:59 -07:00
|
|
|
////////////////////////////////// COMMITMENT //////////////////////////////////
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct Message {
|
|
|
|
sk: clsigs::SecretKey, // the secret key for the signature scheme (Is it possible to make this a generic field?)
|
|
|
|
k1: Fr, // seed 1 for PRF
|
|
|
|
k2: Fr, // seed 2 for PRF
|
|
|
|
balance: i32 // the balance for the user
|
|
|
|
}
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-03-24 21:03:59 -07:00
|
|
|
impl Message {
|
|
|
|
pub fn new(_sk: clsigs::SecretKey, _k1: Fr, _k2: Fr, _balance: i32) -> Message {
|
|
|
|
Message {
|
|
|
|
sk: _sk, k1: _k1, k2: _k2, balance: _balance,
|
2018-03-24 06:44:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-24 21:13:12 -07:00
|
|
|
pub fn hash(&self) -> Fr {
|
2018-03-24 21:03:59 -07:00
|
|
|
let mut input_buf = self.sk.encode();
|
|
|
|
// TODO: add sk_sigs to encode it
|
|
|
|
let k1_vec: Vec<u8> = encode(&self.k1, Infinite).unwrap();
|
|
|
|
let k2_vec: Vec<u8> = encode(&self.k2, Infinite).unwrap();
|
|
|
|
// encode k1 in the vector
|
|
|
|
input_buf.extend(k1_vec);
|
|
|
|
// encode k2 in the vector
|
|
|
|
input_buf.extend(k2_vec);
|
|
|
|
// encoee the balance as a hex string
|
|
|
|
let b = format!("{:x}", self.balance);
|
|
|
|
// println!("Balance: {}", b);
|
|
|
|
input_buf.extend_from_slice(b.as_bytes());
|
|
|
|
// let mut in_str = String::new();
|
|
|
|
// for y in input_buf.iter() {
|
|
|
|
// in_str = format!("{}{:x}", in_str, y);
|
|
|
|
// }
|
|
|
|
// println!("input_buf: {}", in_str);
|
|
|
|
|
|
|
|
// hash the inputs via SHA256
|
|
|
|
let sha2_digest = sha512::hash(input_buf.as_slice());
|
|
|
|
// println!("hash: {:?}", sha2_digest);
|
|
|
|
// let h = format!("{:x}", HexSlice::new(&sha2_digest));
|
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
return Fr::interpret(&hash_buf);
|
2018-03-24 06:44:45 -07:00
|
|
|
}
|
2018-03-24 21:03:59 -07:00
|
|
|
}
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-03-25 20:20:05 -07:00
|
|
|
////////////////////////////////// COMMITMENT //////////////////////////////////
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2018-05-06 18:50:37 -07:00
|
|
|
////////////////////////////////// NIZKP //////////////////////////////////
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
pub fn concat_to_vector(output: &mut Vec<u8>, t: &G2) {
|
|
|
|
let t_vec: Vec<u8> = encode(t, Infinite).unwrap();
|
|
|
|
output.extend(t_vec);
|
|
|
|
}
|
|
|
|
|
2018-05-06 18:50:37 -07:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct Proof {
|
|
|
|
T: G1,
|
|
|
|
c: Fr,
|
|
|
|
s1: Fr,
|
|
|
|
s2: Fr
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
//pub fn hash(g: &G1, h: &G1, X: &G1, Y: &G1, T: &Gt) -> Fr {
|
|
|
|
// let g_vec: Vec<u8> = encode(&g, Infinite).unwrap();
|
|
|
|
//
|
|
|
|
// // TODO: fix this
|
|
|
|
// return Fr::from_str("1234567890").unwrap();
|
|
|
|
//}
|
2018-05-06 18:50:37 -07:00
|
|
|
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn hashG1ToFr(x: &G1) -> Fr {
|
|
|
|
// TODO: change to serde (instead of rustc_serialize)
|
|
|
|
let x_vec: Vec<u8> = encode(&x, Infinite).unwrap();
|
|
|
|
let sha2_digest = sha512::hash(x_vec.as_slice());
|
2018-05-06 18:50:37 -07:00
|
|
|
|
2018-06-05 10:26:16 -07:00
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
return Fr::interpret(&hash_buf);
|
|
|
|
}
|
2018-05-06 18:50:37 -07:00
|
|
|
|
2018-06-08 18:20:15 -07:00
|
|
|
pub fn hashPubKeyToFr(wpk: &secp256k1::PublicKey) -> Fr {
|
|
|
|
let x_slice = wpk.serialize_uncompressed();
|
|
|
|
let sha2_digest = sha512::hash(&x_slice);
|
|
|
|
|
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
return Fr::interpret(&hash_buf);
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn computePubKeyFingerprint(wpk: &secp256k1::PublicKey) -> String {
|
|
|
|
let x_slice = wpk.serialize();
|
|
|
|
let sha2_digest = sha512::hash(&x_slice);
|
|
|
|
let h = format!("{:x}", HexSlice::new(&sha2_digest[0..16]));
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
pub fn hashBufferToFr<'a>(prefix: &'a str, buf: &[u8; 64]) -> Fr {
|
|
|
|
let mut input_buf = Vec::new();
|
|
|
|
input_buf.extend_from_slice(prefix.as_bytes());
|
|
|
|
input_buf.extend_from_slice(buf);
|
|
|
|
|
|
|
|
let sha2_digest = sha512::hash(&input_buf.as_slice());
|
|
|
|
|
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
return Fr::interpret(&hash_buf);
|
|
|
|
}
|
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
fn convertToFr(input_buf: &Vec<u8>) -> Fr {
|
|
|
|
// hash the inputs via SHA256
|
|
|
|
let sha2_digest = sha512::hash(input_buf.as_slice());
|
|
|
|
// println!("hash: {:?}", sha2_digest);
|
|
|
|
// let h = format!("{:x}", HexSlice::new(&sha2_digest));
|
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
return Fr::interpret(&hash_buf);
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
fn convertStrToFr<'a>(input: &'a str) -> Fr {
|
|
|
|
let mut input_buf = Vec::new();
|
|
|
|
input_buf.extend_from_slice(input.as_bytes());
|
|
|
|
return convertToFr(&input_buf);
|
|
|
|
}
|
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// refund message
|
|
|
|
#[derive(Clone)]
|
2018-06-14 20:50:00 -07:00
|
|
|
pub struct RefundMessage {
|
|
|
|
pub msgtype: String, // purpose type of message
|
2018-06-11 00:31:27 -07:00
|
|
|
pub wpk: secp256k1::PublicKey,
|
|
|
|
pub balance: usize, // the balance
|
2018-06-14 20:50:00 -07:00
|
|
|
pub r: Option<Fr>, // randomness from customer wallet
|
|
|
|
pub rt: Option<clsigs::SignatureD> // refund token
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 20:50:00 -07:00
|
|
|
impl RefundMessage {
|
2018-06-14 22:18:20 -07:00
|
|
|
pub fn new(_msgtype: String, _wpk: secp256k1::PublicKey,
|
2018-06-14 20:50:00 -07:00
|
|
|
_balance: usize, _r: Option<Fr>, _rt: Option<clsigs::SignatureD>) -> RefundMessage {
|
2018-06-09 23:00:01 -07:00
|
|
|
RefundMessage {
|
2018-06-14 22:18:20 -07:00
|
|
|
msgtype: _msgtype, wpk: _wpk, balance: _balance, r: _r, rt: _rt
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn hash(&self) -> Vec<Fr> {
|
|
|
|
let mut v: Vec<Fr> = Vec::new();
|
|
|
|
let mut input_buf = Vec::new();
|
2018-06-11 00:31:27 -07:00
|
|
|
input_buf.extend_from_slice(self.msgtype.as_bytes());
|
2018-06-09 23:00:01 -07:00
|
|
|
v.push(convertToFr(&input_buf));
|
|
|
|
|
|
|
|
v.push(hashPubKeyToFr(&self.wpk));
|
|
|
|
|
|
|
|
// encoee the balance as a hex string
|
|
|
|
let b = format!("{:x}", self.balance);
|
|
|
|
let mut b_buf = Vec::new();
|
|
|
|
b_buf.extend_from_slice(b.as_bytes());
|
|
|
|
v.push(convertToFr(&b_buf));
|
|
|
|
|
|
|
|
//let r_vec: Vec<u8> = encode(&self.r, Infinite).unwrap();
|
|
|
|
if (!self.r.is_none()) {
|
|
|
|
v.push(self.r.unwrap().clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!self.rt.is_none()) {
|
2018-06-14 20:50:00 -07:00
|
|
|
let rt = {
|
|
|
|
&self.rt.clone()
|
|
|
|
};
|
|
|
|
let rt_ref = rt.as_ref();
|
|
|
|
v.push(rt_ref.unwrap().hash(&self.msgtype));
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct RevokedMessage {
|
|
|
|
pub msgtype: String,
|
2018-06-11 00:31:27 -07:00
|
|
|
pub wpk: secp256k1::PublicKey,
|
2018-06-14 22:18:20 -07:00
|
|
|
pub sig: Option<[u8; 64]> // represents revocation token serialized compact bytes
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
impl RevokedMessage {
|
2018-06-14 22:18:20 -07:00
|
|
|
pub fn new(_msgtype: String, _wpk: secp256k1::PublicKey, _sig: Option<[u8; 64]>) -> RevokedMessage {
|
2018-06-09 23:00:01 -07:00
|
|
|
RevokedMessage {
|
2018-06-11 00:31:27 -07:00
|
|
|
msgtype: _msgtype, wpk: _wpk, sig: _sig
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn hash(&self) -> Vec<Fr> {
|
|
|
|
let mut v: Vec<Fr> = Vec::new();
|
|
|
|
let mut input_buf = Vec::new();
|
2018-06-11 00:31:27 -07:00
|
|
|
input_buf.extend_from_slice(self.msgtype.as_bytes());
|
2018-06-09 23:00:01 -07:00
|
|
|
v.push(convertToFr(&input_buf));
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
v.push(hashPubKeyToFr(&self.wpk));
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
if (!self.sig.is_none()) {
|
|
|
|
// TODO: make sure we can call hashBufferToFr with sig
|
2018-06-14 22:18:20 -07:00
|
|
|
v.push(hashBufferToFr(&self.msgtype, &self.sig.unwrap()));
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
return v;
|
|
|
|
}
|
2018-05-06 18:50:37 -07:00
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// return a message digest (32-bytes)
|
|
|
|
pub fn hash_to_slice(&self) -> [u8; 32] {
|
|
|
|
let mut input_buf = Vec::new();
|
|
|
|
input_buf.extend_from_slice(self.msgtype.as_bytes());
|
|
|
|
input_buf.extend_from_slice(&self.wpk.serialize_uncompressed());
|
|
|
|
let sha2_digest = sha512::hash(input_buf.as_slice());
|
|
|
|
// println!("hash: {:?}", sha2_digest);
|
|
|
|
// let h = format!("{:x}", HexSlice::new(&sha2_digest));
|
|
|
|
let mut hash_buf: [u8; 32] = [0; 32];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..32]);
|
|
|
|
return hash_buf;
|
|
|
|
}
|
|
|
|
}
|
2018-05-06 18:50:37 -07:00
|
|
|
|
|
|
|
////////////////////////////////// NIZKP //////////////////////////////////
|
|
|
|
|
2018-05-10 14:08:42 -07:00
|
|
|
//pub mod unidirectional {
|
|
|
|
// use std::fmt;
|
|
|
|
// use rand;
|
|
|
|
// use bn::{Group, Fr};
|
|
|
|
// use sym;
|
|
|
|
// use commit_scheme;
|
|
|
|
// use clsigs;
|
|
|
|
// use Message;
|
|
|
|
// use sodiumoxide::randombytes;
|
|
|
|
//
|
|
|
|
// pub struct PublicParams {
|
|
|
|
// cm_mpk: commit_scheme::PublicKey,
|
|
|
|
// cl_mpk: clsigs::PublicParams,
|
|
|
|
// l_bits: i32
|
|
|
|
// // TODO: add NIZK proof system pub params
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub struct ChannelToken {
|
|
|
|
// w_com: commit_scheme::Commitment,
|
|
|
|
// pk: clsigs::PublicKey
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub struct CustSecretKey {
|
|
|
|
// sk: clsigs::SecretKey, // the secret key for the signature scheme (Is it possible to make this a generic field?)
|
|
|
|
// k1: Fr, // seed 1 for PRF
|
|
|
|
// k2: Fr, // seed 2 for PRF
|
|
|
|
// r: Fr, // random coins for commitment scheme
|
|
|
|
// balance: i32, // the balance for the user
|
|
|
|
// ck_vec: Vec<sym::SymKey>
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub struct MerchSecretKey {
|
|
|
|
// sk: clsigs::SecretKey,
|
|
|
|
// balance: i32
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub struct InitCustomerData {
|
|
|
|
// T: ChannelToken,
|
|
|
|
// csk: CustSecretKey
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub struct InitMerchantData {
|
|
|
|
// T: clsigs::PublicKey,
|
|
|
|
// csk: MerchSecretKey
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn setup() -> PublicParams {
|
|
|
|
// // TODO: provide option for generating CRS parameters
|
|
|
|
// let cm_pk = commit_scheme::setup();
|
|
|
|
// let cl_mpk = clsigs::setup();
|
|
|
|
// let l = 256;
|
|
|
|
// // let nizk = "nizk proof system";
|
|
|
|
// let pp = PublicParams { cm_mpk: cm_pk, cl_mpk: cl_mpk, l_bits: l };
|
|
|
|
// return pp;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn keygen(pp: &PublicParams) -> clsigs::KeyPair {
|
|
|
|
// // TODO: figure out what we need from public params to generate keys
|
|
|
|
// println!("Run Keygen...");
|
|
|
|
// let keypair = clsigs::keygen(&pp.cl_mpk);
|
|
|
|
// return keypair;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn init_customer(pp: &PublicParams, b0_customer: i32, keypair: &clsigs::KeyPair) -> InitCustomerData {
|
|
|
|
// println!("Run Init customer...");
|
|
|
|
// sym::init();
|
|
|
|
// let rng = &mut rand::thread_rng();
|
|
|
|
// // pick two distinct seeds
|
|
|
|
// let l = 256;
|
|
|
|
// let k1 = Fr::random(rng);
|
|
|
|
// let k2 = Fr::random(rng);
|
|
|
|
// let r = Fr::random(rng);
|
|
|
|
// let msg = Message::new(keypair.sk, k1, k2, b0_customer).hash();
|
|
|
|
//
|
|
|
|
// let mut ck_vec: Vec<sym::SymKey> = Vec::new();
|
|
|
|
// // generate the vector ck of sym keys
|
|
|
|
// for i in 1 .. b0_customer {
|
|
|
|
// let ck = sym::keygen(l);
|
|
|
|
// ck_vec.push(ck);
|
|
|
|
// }
|
|
|
|
// let w_com = commit_scheme::commit(&pp.cm_mpk, msg, Some(r));
|
|
|
|
// let t_c = ChannelToken { w_com: w_com, pk: keypair.pk };
|
|
|
|
// let csk_c = CustSecretKey { sk: keypair.sk, k1: k1, k2: k2, r: r, balance: b0_customer, ck_vec: ck_vec };
|
|
|
|
// return InitCustomerData { T: t_c, csk: csk_c };
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn init_merchant(pp: &PublicParams, b0_merchant: i32, keypair: &clsigs::KeyPair) -> InitMerchantData {
|
|
|
|
// println!("Run Init merchant...");
|
|
|
|
// let csk_m = MerchSecretKey { sk: keypair.sk, balance: b0_merchant };
|
|
|
|
// return InitMerchantData { T: keypair.pk, csk: csk_m };
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// // TODO: requires NIZK proof system
|
|
|
|
// pub fn establish_customer(pp: &PublicParams, t_m: &clsigs::PublicKey, csk_c: &CustSecretKey) {
|
|
|
|
// println ! ("Run establish_customer algorithm...");
|
|
|
|
// // set sk_0 to random bytes of length l
|
|
|
|
// // let sk_0 = random_bytes(pp.l);
|
|
|
|
// let buf_len: usize = pp.l_bits as usize;
|
|
|
|
// let mut sk0 = vec![0; buf_len];
|
|
|
|
// randombytes::randombytes_into(&mut sk0);
|
|
|
|
//
|
|
|
|
// let pi1 = create_nizk_proof_one(csk_c.sk, csk_c.k1, csk_c.k2, );
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
pub mod bidirectional {
|
2018-03-25 20:20:05 -07:00
|
|
|
use std::fmt;
|
|
|
|
use rand;
|
2018-06-12 11:30:24 -07:00
|
|
|
use bn::{Group, Fr, G1, G2, Gt};
|
2018-04-05 23:44:31 -07:00
|
|
|
use sym;
|
2018-03-25 20:20:05 -07:00
|
|
|
use commit_scheme;
|
|
|
|
use clsigs;
|
|
|
|
use Message;
|
2018-04-08 00:46:17 -07:00
|
|
|
use sodiumoxide::randombytes;
|
2018-06-08 18:20:15 -07:00
|
|
|
use secp256k1; // ::{Secp256k1, PublicKey, SecretKey};
|
2018-06-09 23:00:01 -07:00
|
|
|
use RefundMessage;
|
|
|
|
use RevokedMessage;
|
2018-06-14 18:07:18 -07:00
|
|
|
use HashMap;
|
2018-06-13 17:28:37 -07:00
|
|
|
use hashPubKeyToFr;
|
|
|
|
use hashBufferToFr;
|
2018-06-11 11:05:24 -07:00
|
|
|
use debug_elem_in_hex;
|
2018-06-12 11:30:24 -07:00
|
|
|
use debug_gt_in_hex;
|
2018-06-13 17:28:37 -07:00
|
|
|
use convertToFr;
|
|
|
|
use convertStrToFr;
|
2018-06-14 18:07:18 -07:00
|
|
|
use computePubKeyFingerprint;
|
2018-06-14 20:50:00 -07:00
|
|
|
use E_MIN;
|
|
|
|
use E_MAX;
|
2018-06-12 11:30:24 -07:00
|
|
|
|
|
|
|
fn print_secret_vector(x: &Vec<Fr>) {
|
|
|
|
for i in 0 .. x.len() {
|
|
|
|
let msg = format!("x[{}] => ", i);
|
|
|
|
debug_elem_in_hex(&msg, &x[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_public_bases_vector(g: &Vec<Gt>) {
|
|
|
|
for i in 0 .. g.len() {
|
|
|
|
let msg = format!("g[{}] => ", i);
|
|
|
|
debug_gt_in_hex(&msg, &g[i]);
|
|
|
|
}
|
|
|
|
}
|
2018-03-25 20:20:05 -07:00
|
|
|
|
|
|
|
pub struct PublicParams {
|
2018-04-05 23:44:31 -07:00
|
|
|
cl_mpk: clsigs::PublicParams,
|
2018-06-09 00:14:50 -07:00
|
|
|
l: usize // messages for committment
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-04-05 23:44:31 -07:00
|
|
|
pub struct ChannelToken {
|
2018-03-25 20:20:05 -07:00
|
|
|
w_com: commit_scheme::Commitment,
|
2018-06-05 10:26:16 -07:00
|
|
|
pk: clsigs::PublicKeyD
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// TODO: add display method to print structure (similar to Commitment)
|
2018-06-09 00:14:50 -07:00
|
|
|
pub struct CustomerWallet {
|
2018-06-05 10:26:16 -07:00
|
|
|
sk: clsigs::SecretKeyD, // the secret key for the signature scheme (Is it possible to make this a generic field?)
|
2018-05-11 13:21:35 -07:00
|
|
|
cid: Fr, // channel Id
|
2018-06-08 18:20:15 -07:00
|
|
|
wpk: secp256k1::PublicKey, // signature verification key
|
|
|
|
wsk: secp256k1::SecretKey, // signature signing key
|
2018-03-25 20:20:05 -07:00
|
|
|
r: Fr, // random coins for commitment scheme
|
2018-06-13 17:28:37 -07:00
|
|
|
pub balance: i32, // the balance for the user
|
|
|
|
signature: Option<clsigs::SignatureD>,
|
|
|
|
refund_token: Option<clsigs::SignatureD>
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// TODO: add display method to print structure (similar to Commitment)
|
2018-03-25 20:20:05 -07:00
|
|
|
pub struct MerchSecretKey {
|
2018-06-09 23:00:01 -07:00
|
|
|
sk: clsigs::SecretKeyD, // merchant signing key
|
2018-06-13 17:28:37 -07:00
|
|
|
pub balance: i32
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InitCustomerData {
|
2018-06-09 00:14:50 -07:00
|
|
|
pub T: ChannelToken,
|
|
|
|
pub csk: CustomerWallet,
|
2018-06-13 17:28:37 -07:00
|
|
|
pub bases: Vec<G2>,
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InitMerchantData {
|
2018-06-09 00:14:50 -07:00
|
|
|
pub T: clsigs::PublicKeyD,
|
2018-06-11 11:05:24 -07:00
|
|
|
pub csk: MerchSecretKey,
|
|
|
|
pub bases: Vec<G2>
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
// TODO: add method to display contents of the channel state
|
|
|
|
// should include contents of the channel state
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct PubKeyMap {
|
|
|
|
wpk: secp256k1::PublicKey,
|
|
|
|
revoke_token: Option<secp256k1::Signature>
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ChannelState {
|
|
|
|
keys: HashMap<String, PubKeyMap>,
|
|
|
|
R: i32,
|
|
|
|
pub name: String,
|
2018-06-09 23:00:01 -07:00
|
|
|
pub cid: Fr,
|
2018-06-11 00:31:27 -07:00
|
|
|
pub pay_init: bool,
|
|
|
|
pub channel_established: bool
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 20:50:00 -07:00
|
|
|
pub struct ChannelClosure_C {
|
2018-06-14 22:18:20 -07:00
|
|
|
pub message: RefundMessage,
|
2018-06-09 23:00:01 -07:00
|
|
|
signature: clsigs::SignatureD
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct ChannelClosure_M {
|
|
|
|
message: RevokedMessage,
|
2018-06-09 23:00:01 -07:00
|
|
|
signature: clsigs::SignatureD
|
|
|
|
}
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
pub struct PaymentProof {
|
|
|
|
proof2a: clsigs::ProofCV, // proof of committed values in new wallet
|
|
|
|
proof2b: clsigs::ProofVS, // proof of knowledge of wallet signature
|
2018-06-13 19:24:18 -07:00
|
|
|
// TODO: add proof2c: range proof that balance - balance_inc is between (0, val_max)
|
2018-06-14 18:07:18 -07:00
|
|
|
balance_inc: i32, // balance increment
|
2018-06-13 17:28:37 -07:00
|
|
|
w_com: commit_scheme::Commitment, // commitment for new wallet
|
2018-06-18 11:07:19 -07:00
|
|
|
old_w_com: G2, // old commitment
|
|
|
|
old_w_com_pr: G2, // old commitment minus Z^wpk
|
|
|
|
old_com_base: G2,
|
2018-06-14 18:07:18 -07:00
|
|
|
pub wpk: secp256k1::PublicKey, // verification key for old wallet (TODO:: remove pub)
|
2018-06-11 00:31:27 -07:00
|
|
|
wallet_sig: clsigs::SignatureD // blinded signature for old wallet
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct RevokeToken {
|
|
|
|
message: RevokedMessage,
|
|
|
|
pub signature: secp256k1::Signature
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-03-25 20:20:05 -07:00
|
|
|
pub fn setup() -> PublicParams {
|
|
|
|
// TODO: provide option for generating CRS parameters
|
2018-06-05 10:26:16 -07:00
|
|
|
let cl_mpk = clsigs::setupD();
|
2018-06-13 17:28:37 -07:00
|
|
|
let l = 4;
|
2018-03-25 20:20:05 -07:00
|
|
|
// let nizk = "nizk proof system";
|
2018-06-13 17:28:37 -07:00
|
|
|
let pp = PublicParams { cl_mpk: cl_mpk, l: l };
|
2018-03-25 20:20:05 -07:00
|
|
|
return pp;
|
|
|
|
}
|
|
|
|
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn keygen(pp: &PublicParams) -> clsigs::KeyPairD {
|
2018-03-25 20:20:05 -07:00
|
|
|
// TODO: figure out what we need from public params to generate keys
|
|
|
|
println!("Run Keygen...");
|
2018-06-09 00:14:50 -07:00
|
|
|
let keypair = clsigs::keygenD(&pp.cl_mpk, pp.l);
|
2018-03-25 20:20:05 -07:00
|
|
|
return keypair;
|
|
|
|
}
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
fn generate_channel_id() -> Fr {
|
2018-06-09 00:14:50 -07:00
|
|
|
let rng = &mut rand::thread_rng();
|
|
|
|
return Fr::random(rng);
|
|
|
|
}
|
|
|
|
|
2018-06-11 11:05:24 -07:00
|
|
|
pub fn generate_commit_setup(pp: &PublicParams, pk: &clsigs::PublicKeyD) -> commit_scheme::CSParams {
|
|
|
|
let g2 = pp.cl_mpk.g2.clone();
|
|
|
|
let bases = pk.Z2.clone();
|
|
|
|
let cm_csp = commit_scheme::setup(pp.l, bases, g2);
|
|
|
|
return cm_csp;
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn init_customer(pp: &PublicParams, channel: &ChannelState, b0_customer: i32,
|
2018-06-13 17:28:37 -07:00
|
|
|
cm_csp: &commit_scheme::CSParams, keypair: &clsigs::KeyPairD) -> InitCustomerData {
|
2018-03-25 20:20:05 -07:00
|
|
|
println!("Run Init customer...");
|
|
|
|
let rng = &mut rand::thread_rng();
|
2018-06-08 18:20:15 -07:00
|
|
|
// generate verification key and signing key (for wallet)
|
|
|
|
let mut schnorr = secp256k1::Secp256k1::new();
|
|
|
|
schnorr.randomize(rng);
|
|
|
|
let (wsk, wpk) = schnorr.generate_keypair(rng).unwrap();
|
|
|
|
let h_wpk = hashPubKeyToFr(&wpk);
|
|
|
|
// convert balance into Fr
|
2018-06-05 10:26:16 -07:00
|
|
|
let b0 = Fr::from_str(b0_customer.to_string().as_str()).unwrap();
|
2018-06-08 18:20:15 -07:00
|
|
|
// randomness for commitment
|
2018-03-25 20:20:05 -07:00
|
|
|
let r = Fr::random(rng);
|
2018-06-11 11:05:24 -07:00
|
|
|
// retreive the channel id
|
2018-06-11 00:31:27 -07:00
|
|
|
let cid = channel.cid.clone();
|
2018-06-05 10:26:16 -07:00
|
|
|
|
2018-06-08 18:20:15 -07:00
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
2018-06-09 00:14:50 -07:00
|
|
|
x.push(r); // set randomness for commitment
|
2018-06-11 00:31:27 -07:00
|
|
|
x.push(cid);
|
2018-06-08 18:20:15 -07:00
|
|
|
x.push(h_wpk);
|
|
|
|
x.push(b0);
|
|
|
|
|
2018-06-09 00:14:50 -07:00
|
|
|
let w_com = commit_scheme::commit(&cm_csp, &x, r);
|
2018-06-05 10:26:16 -07:00
|
|
|
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk.clone() };
|
2018-06-11 00:31:27 -07:00
|
|
|
let csk_c = CustomerWallet { sk: keypair.sk.clone(), cid: cid, wpk: wpk, wsk: wsk,
|
2018-06-13 17:28:37 -07:00
|
|
|
r: r, balance: b0_customer, signature: None,
|
|
|
|
refund_token: None };
|
2018-06-11 11:05:24 -07:00
|
|
|
return InitCustomerData { T: t_c, csk: csk_c, bases: cm_csp.pub_bases.clone() };
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn init_merchant(pp: &PublicParams, b0_merchant: i32, keypair: &clsigs::KeyPairD) -> InitMerchantData {
|
2018-03-25 20:20:05 -07:00
|
|
|
println!("Run Init merchant...");
|
2018-06-11 11:05:24 -07:00
|
|
|
let cm_csp = generate_commit_setup(&pp, &keypair.pk);
|
2018-06-05 10:26:16 -07:00
|
|
|
let csk_m = MerchSecretKey { sk: keypair.sk.clone(), balance: b0_merchant };
|
2018-06-11 11:05:24 -07:00
|
|
|
return InitMerchantData { T: keypair.pk.clone(), csk: csk_m, bases: cm_csp.pub_bases };
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn init_channel(name: String) -> ChannelState {
|
2018-06-11 00:31:27 -07:00
|
|
|
let cid = generate_channel_id();
|
2018-06-14 18:07:18 -07:00
|
|
|
let keys = HashMap::new(); // will store wpks/revoke_tokens
|
|
|
|
return ChannelState { keys: keys, R: 0, name: name, cid: cid, channel_established: false, pay_init: false }
|
2018-06-11 00:31:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//// begin of establish channel protocol
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn establish_customer_phase1(pp: &PublicParams, c_data: &InitCustomerData,
|
|
|
|
m_data: &InitMerchantData) -> clsigs::ProofCV {
|
2018-06-12 11:30:24 -07:00
|
|
|
println!("Run establish_customer algorithm...");
|
2018-06-08 18:20:15 -07:00
|
|
|
// obtain customer init data
|
|
|
|
let t_c = &c_data.T;
|
|
|
|
let csk_c = &c_data.csk;
|
2018-06-11 11:05:24 -07:00
|
|
|
let pub_bases = &m_data.bases;
|
2018-06-08 18:20:15 -07:00
|
|
|
|
|
|
|
let h_wpk = hashPubKeyToFr(&csk_c.wpk);
|
|
|
|
let b0 = Fr::from_str(csk_c.balance.to_string().as_str()).unwrap();
|
|
|
|
// collect secrets
|
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
2018-06-09 00:14:50 -07:00
|
|
|
x.push(t_c.w_com.r); // set randomness used to generate commitment
|
2018-06-08 18:20:15 -07:00
|
|
|
x.push(csk_c.cid);
|
|
|
|
x.push(h_wpk);
|
|
|
|
x.push(b0);
|
2018-06-13 19:24:18 -07:00
|
|
|
//println!("establish_customer_phase1 - secrets for original wallet");
|
|
|
|
//print_secret_vector(&x);
|
2018-06-08 18:20:15 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
// generate proof of knowledge for committed values
|
2018-06-08 18:20:15 -07:00
|
|
|
let proof_1 = clsigs::bs_gen_nizk_proof(&x, &pub_bases, t_c.w_com.c);
|
|
|
|
return proof_1;
|
2018-04-08 00:46:17 -07:00
|
|
|
}
|
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// the merchant calls this method after obtaining proof from the customer
|
2018-06-11 00:31:27 -07:00
|
|
|
pub fn establish_merchant_phase2(pp: &PublicParams, state: &mut ChannelState, m_data: &InitMerchantData,
|
2018-06-09 23:00:01 -07:00
|
|
|
proof: &clsigs::ProofCV) -> clsigs::SignatureD {
|
2018-06-09 00:14:50 -07:00
|
|
|
// verifies proof and produces
|
2018-06-13 17:28:37 -07:00
|
|
|
let wallet_sig = clsigs::bs_check_proof_and_gen_signature(&pp.cl_mpk, &m_data.csk.sk, &proof);
|
2018-06-11 00:31:27 -07:00
|
|
|
state.channel_established = true;
|
2018-06-09 00:14:50 -07:00
|
|
|
return wallet_sig;
|
|
|
|
}
|
2018-03-25 20:20:05 -07:00
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn establish_customer_final(pp: &PublicParams, pk_m: &clsigs::PublicKeyD,
|
|
|
|
w: &mut CustomerWallet, sig: clsigs::SignatureD) -> bool {
|
2018-06-09 23:00:01 -07:00
|
|
|
if w.signature.is_none() {
|
2018-06-11 11:05:24 -07:00
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
|
|
|
x.push(w.r.clone());
|
|
|
|
x.push(w.cid.clone());
|
|
|
|
x.push(hashPubKeyToFr(&w.wpk));
|
|
|
|
x.push(Fr::from_str(w.balance.to_string().as_str()).unwrap());
|
|
|
|
|
2018-06-13 19:24:18 -07:00
|
|
|
//println!("establish_customer_final - print secrets");
|
|
|
|
//print_secret_vector(&x);
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2018-06-11 11:05:24 -07:00
|
|
|
assert!(clsigs::verifyD(&pp.cl_mpk, &pk_m, &x, &sig));
|
2018-06-09 23:00:01 -07:00
|
|
|
w.signature = Some(sig);
|
2018-06-13 19:24:18 -07:00
|
|
|
println!("establish_customer_final - verified merchant signature on initial wallet with {}", w.balance);
|
2018-06-09 00:14:50 -07:00
|
|
|
return true;
|
|
|
|
}
|
2018-06-11 00:31:27 -07:00
|
|
|
// must be an old wallet
|
2018-06-09 00:14:50 -07:00
|
|
|
return false;
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
2018-06-11 00:31:27 -07:00
|
|
|
///// end of establish channel protocol
|
2018-03-25 20:20:05 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
///// begin of pay protocol
|
2018-06-13 19:24:18 -07:00
|
|
|
pub fn pay_by_customer_phase1(pp: &PublicParams, T: &ChannelToken, pk_m: &clsigs::PublicKeyD,
|
2018-06-18 11:07:19 -07:00
|
|
|
old_w: &CustomerWallet, balance_increment: i32) -> (ChannelToken, CustomerWallet, PaymentProof) {
|
2018-06-13 19:24:18 -07:00
|
|
|
println!("pay_by_customer_phase1 - generate new wallet commit, PoK of commit values, and PoK of old wallet.");
|
2018-06-11 00:31:27 -07:00
|
|
|
// get balance, keypair, commitment randomness and wallet sig
|
|
|
|
let rng = &mut rand::thread_rng();
|
|
|
|
|
2018-06-13 19:24:18 -07:00
|
|
|
let bal = old_w.balance;
|
2018-06-11 00:31:27 -07:00
|
|
|
let old_wpk = &old_w.wpk;
|
|
|
|
let old_wsk = &old_w.wsk;
|
|
|
|
let old_r = &old_w.r;
|
|
|
|
let old_wallet_sig = &old_w.signature;
|
|
|
|
|
|
|
|
// generate new keypair
|
|
|
|
let mut schnorr = secp256k1::Secp256k1::new();
|
|
|
|
schnorr.randomize(rng);
|
|
|
|
let (wsk, wpk) = schnorr.generate_keypair(rng).unwrap();
|
|
|
|
let h_wpk = hashPubKeyToFr(&wpk);
|
|
|
|
|
|
|
|
// new sample randomness r'
|
2018-06-13 17:28:37 -07:00
|
|
|
let r_pr = Fr::random(rng);
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-06-12 11:30:24 -07:00
|
|
|
// retrieve the commitment scheme parameters based on merchant's PK
|
|
|
|
let cm_csp = generate_commit_setup(&pp, &pk_m);
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
let cid = old_w.cid.clone();
|
2018-06-11 11:05:24 -07:00
|
|
|
// retrieve old balance
|
2018-06-13 19:24:18 -07:00
|
|
|
let old_balance = Fr::from_str(bal.to_string().as_str()).unwrap();
|
2018-06-11 11:05:24 -07:00
|
|
|
// convert balance into Fr (B - e)
|
2018-06-13 19:24:18 -07:00
|
|
|
let updated_balance = bal - balance_increment;
|
2018-06-14 18:07:18 -07:00
|
|
|
if (updated_balance < 0) {
|
|
|
|
panic!("pay_by_customer_phase1 - insufficient funds to make payment!");
|
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
let updated_balance_pr = Fr::from_str(updated_balance.to_string().as_str()).unwrap();
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
let mut new_wallet_sec: Vec<Fr> = Vec::new();
|
|
|
|
new_wallet_sec.push(r_pr); // set randomness for commitment
|
|
|
|
new_wallet_sec.push(cid);
|
|
|
|
new_wallet_sec.push(h_wpk);
|
|
|
|
new_wallet_sec.push(updated_balance_pr);
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
let w_com = commit_scheme::commit(&cm_csp, &new_wallet_sec, r_pr);
|
2018-06-09 00:14:50 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
// generate proof of knowledge for committed values
|
2018-06-13 17:28:37 -07:00
|
|
|
let proof_cv = clsigs::bs_gen_nizk_proof(&new_wallet_sec, &cm_csp.pub_bases, w_com.c);
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-06-12 11:30:24 -07:00
|
|
|
// generate proof of knowledge of valid signature on previous wallet signature
|
2018-06-11 00:31:27 -07:00
|
|
|
let wallet_sig = old_wallet_sig.clone().unwrap();
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2018-06-11 11:05:24 -07:00
|
|
|
let old_h_wpk = hashPubKeyToFr(&old_wpk);
|
2018-06-18 11:07:19 -07:00
|
|
|
let index = 2;
|
|
|
|
let old_w_com_pr = T.w_com.c - (cm_csp.pub_bases[index] * old_h_wpk);
|
2018-06-11 11:05:24 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
// added the blinding factor to list of secrets
|
2018-06-11 11:05:24 -07:00
|
|
|
let mut old_x: Vec<Fr> = Vec::new();
|
2018-06-12 11:30:24 -07:00
|
|
|
old_x.push(old_r.clone()); // set randomness for commitment
|
|
|
|
old_x.push(cid);
|
|
|
|
old_x.push(old_h_wpk);
|
|
|
|
old_x.push(old_balance);
|
2018-06-11 11:05:24 -07:00
|
|
|
|
2018-06-12 11:30:24 -07:00
|
|
|
let blind_sigs = clsigs::prover_generate_blinded_sig(&wallet_sig);
|
|
|
|
let common_params = clsigs::gen_common_params(&pp.cl_mpk, &pk_m, &wallet_sig);
|
|
|
|
|
|
|
|
//println!("payment_by_customer_phase1 - secrets for old wallet");
|
|
|
|
//print_secret_vector(&old_x);
|
|
|
|
|
|
|
|
let proof_vs = clsigs::vs_gen_nizk_proof(&old_x, &common_params, common_params.vs);
|
2018-06-13 19:24:18 -07:00
|
|
|
// create payment proof which includes params to reveal wpk from old wallet
|
2018-06-13 17:28:37 -07:00
|
|
|
let payment_proof = PaymentProof {
|
|
|
|
proof2a: proof_cv, // proof of knowledge for committed values
|
|
|
|
proof2b: proof_vs, // proof of knowledge of signature on old wallet
|
|
|
|
w_com: w_com,
|
2018-06-14 18:07:18 -07:00
|
|
|
balance_inc: balance_increment, // epsilon - increment/decrement
|
2018-06-18 11:07:19 -07:00
|
|
|
old_w_com: T.w_com.c, // old commitment
|
|
|
|
old_w_com_pr: old_w_com_pr, // old commitment minus Z^wpk
|
|
|
|
old_com_base: cm_csp.pub_bases[index], // base Z
|
2018-06-13 17:28:37 -07:00
|
|
|
wpk: old_wpk.clone(), // showing public key for old wallet
|
|
|
|
wallet_sig: blind_sigs // blinded signature for old wallet
|
2018-06-12 11:30:24 -07:00
|
|
|
};
|
2018-06-13 19:24:18 -07:00
|
|
|
// create new wallet structure (w/o signature or refund token)
|
2018-06-18 11:07:19 -07:00
|
|
|
let t_c = ChannelToken { w_com: w_com, pk: T.pk.clone() };
|
2018-06-13 17:28:37 -07:00
|
|
|
let csk_c = CustomerWallet { sk: old_w.sk.clone(), cid: cid, wpk: wpk, wsk: wsk,
|
|
|
|
r: r_pr, balance: updated_balance, signature: None,
|
|
|
|
refund_token: None };
|
2018-06-18 11:07:19 -07:00
|
|
|
return (t_c, csk_c, payment_proof);
|
2018-06-05 10:26:16 -07:00
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// NOTE regarding balance increments
|
|
|
|
// a positive increment => increment merchant balance, and decrement customer balance
|
|
|
|
// a negative increment => decrement merchant balance, and increment customer balance
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn pay_by_merchant_phase1(pp: &PublicParams, mut state: &mut ChannelState, proof: &PaymentProof,
|
|
|
|
m_data: &InitMerchantData) -> clsigs::SignatureD {
|
2018-06-09 00:14:50 -07:00
|
|
|
println!("Run pay algorithm by Merchant - phase 2");
|
2018-06-11 00:31:27 -07:00
|
|
|
let blind_sigs = &proof.wallet_sig;
|
2018-06-12 11:30:24 -07:00
|
|
|
let proof_cv = &proof.proof2a;
|
2018-06-11 00:31:27 -07:00
|
|
|
let proof_vs = &proof.proof2b;
|
2018-06-13 17:28:37 -07:00
|
|
|
// get merchant keypair
|
2018-06-12 11:30:24 -07:00
|
|
|
let pk_m = &m_data.T;
|
2018-06-13 17:28:37 -07:00
|
|
|
let sk_m = &m_data.csk.sk;
|
|
|
|
|
|
|
|
// let's first confirm that proof of knowledge of signature on old wallet is valid
|
|
|
|
let proof_vs_old_wallet = clsigs::vs_verify_blind_sig(&pp.cl_mpk, &pk_m, &proof_vs, &blind_sigs);
|
2018-06-14 18:07:18 -07:00
|
|
|
let is_existing_wpk = exist_in_merchant_state(&state, &proof.wpk, None);
|
2018-06-14 20:50:00 -07:00
|
|
|
let is_within_range = (proof.balance_inc >= E_MIN && proof.balance_inc <= E_MAX);
|
2018-06-18 11:07:19 -07:00
|
|
|
// TODO: verify correctness
|
|
|
|
let is_wpk_valid_reveal = clsigs::vs_partial_commitment_open(proof.old_w_com,
|
|
|
|
proof.old_w_com_pr,
|
|
|
|
proof.old_com_base,
|
|
|
|
hashPubKeyToFr(&proof.wpk));
|
|
|
|
if proof_vs_old_wallet && !is_existing_wpk && is_within_range && is_wpk_valid_reveal {
|
2018-06-14 18:07:18 -07:00
|
|
|
println!("Proof of knowledge of signature is valid!");
|
|
|
|
if (proof.balance_inc < 0) {
|
|
|
|
// negative increment
|
|
|
|
state.R = 1;
|
|
|
|
} else {
|
|
|
|
// postiive increment
|
|
|
|
state.R = -1; // -1 denotes \bot here
|
|
|
|
}
|
2018-06-11 00:31:27 -07:00
|
|
|
} else {
|
2018-06-14 18:07:18 -07:00
|
|
|
panic!("pay_by_merchant_phase1 - Verification failure for old wallet signature !");
|
2018-06-11 00:31:27 -07:00
|
|
|
}
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// verify the proof of knowledge for committed values in new wallet
|
|
|
|
if clsigs::bs_verify_nizk_proof(&proof_cv) {
|
|
|
|
// generate refund token on new wallet
|
|
|
|
let i = pk_m.Z2.len()-1;
|
2018-06-13 19:24:18 -07:00
|
|
|
let c_refund = proof_cv.C + (pk_m.Z2[i] * convertStrToFr("refund"));
|
2018-06-13 17:28:37 -07:00
|
|
|
// generating partially blind signature on refund || wpk' || B - e
|
2018-06-13 19:24:18 -07:00
|
|
|
let rt_w = clsigs::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, c_refund, proof_cv.num_secrets + 1); // proof_cv.C
|
2018-06-14 18:07:18 -07:00
|
|
|
println!("pay_by_merchant_phase1 - Proof of knowledge of commitment on new wallet is valid");
|
|
|
|
update_merchant_state(&mut state, &proof.wpk, None);
|
2018-06-14 22:18:20 -07:00
|
|
|
state.pay_init = true;
|
2018-06-13 17:28:37 -07:00
|
|
|
return rt_w;
|
2018-06-12 11:30:24 -07:00
|
|
|
}
|
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
// let's update the merchant's wallet balance now
|
2018-06-14 18:07:18 -07:00
|
|
|
panic!("pay_by_merchant_phase1 - NIZK verification failed for new wallet commitment!");
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn pay_by_customer_phase2(pp: &PublicParams, old_w: &CustomerWallet, new_w: &CustomerWallet,
|
|
|
|
pk_m: &clsigs::PublicKeyD, rt_w: &clsigs::SignatureD) -> RevokeToken {
|
2018-06-13 19:24:18 -07:00
|
|
|
// (1) verify the refund token (rt_w) against the new wallet contents
|
2018-06-13 17:28:37 -07:00
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
|
|
|
x.push(new_w.r.clone());
|
|
|
|
x.push(new_w.cid.clone());
|
|
|
|
x.push(hashPubKeyToFr(&new_w.wpk));
|
|
|
|
x.push(Fr::from_str(new_w.balance.to_string().as_str()).unwrap());
|
|
|
|
x.push(convertStrToFr("refund"));
|
|
|
|
|
|
|
|
let is_rt_w_valid = clsigs::verifyD(&pp.cl_mpk, &pk_m, &x, &rt_w);
|
|
|
|
|
|
|
|
if (is_rt_w_valid) {
|
|
|
|
println!("Refund token is valid against the new wallet!");
|
2018-06-14 20:50:00 -07:00
|
|
|
let schnorr = secp256k1::Secp256k1::new();
|
2018-06-14 18:07:18 -07:00
|
|
|
let rm = RevokedMessage::new(String::from("revoked"), old_w.wpk, None);
|
2018-06-13 17:28:37 -07:00
|
|
|
let msg = secp256k1::Message::from_slice(&rm.hash_to_slice()).unwrap();
|
|
|
|
// msg = "revoked"|| old_wpk (for old wallet)
|
|
|
|
let rv_w = schnorr.sign(&msg, &old_w.wsk);
|
|
|
|
// return the revocation token
|
|
|
|
return RevokeToken { message: rm, signature: rv_w.unwrap() };
|
|
|
|
}
|
2018-06-14 18:07:18 -07:00
|
|
|
panic!("pay_by_customer_phase2 - Merchant did not provide a valid refund token!");
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn pay_by_merchant_phase2(pp: &PublicParams, mut state: &mut ChannelState,
|
|
|
|
proof: &PaymentProof, m_data: &mut InitMerchantData,
|
|
|
|
rv: &RevokeToken) -> clsigs::SignatureD {
|
2018-06-13 17:28:37 -07:00
|
|
|
let proof_cv = &proof.proof2a;
|
|
|
|
let sk_m = &m_data.csk.sk;
|
|
|
|
let schnorr = secp256k1::Secp256k1::new();
|
|
|
|
let msg = secp256k1::Message::from_slice(&rv.message.hash_to_slice()).unwrap();
|
|
|
|
// verify that the revocation token is valid
|
|
|
|
let is_rv_valid = schnorr.verify(&msg, &rv.signature, &proof.wpk).is_ok();
|
2018-06-14 18:07:18 -07:00
|
|
|
|
2018-06-13 17:28:37 -07:00
|
|
|
if clsigs::bs_verify_nizk_proof(&proof_cv) && is_rv_valid {
|
2018-06-14 18:07:18 -07:00
|
|
|
// update merchant state with (wpk, sigma_rev)
|
|
|
|
update_merchant_state(&mut state, &proof.wpk, Some(rv.signature));
|
2018-06-13 17:28:37 -07:00
|
|
|
let new_wallet_sig = clsigs::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, proof_cv.C, proof_cv.num_secrets);
|
2018-06-14 18:07:18 -07:00
|
|
|
m_data.csk.balance += proof.balance_inc;
|
|
|
|
state.R = 2;
|
2018-06-13 17:28:37 -07:00
|
|
|
return new_wallet_sig;
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
panic!("pay_by_merchant_phase2 - Customer did not provide valid revocation token!");
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-06-13 19:24:18 -07:00
|
|
|
pub fn pay_by_customer_final(pp: &PublicParams, pk_m: &clsigs::PublicKeyD,
|
2018-06-18 11:07:19 -07:00
|
|
|
c_data: &mut InitCustomerData, mut new_t: ChannelToken,
|
2018-06-13 17:28:37 -07:00
|
|
|
mut new_w: CustomerWallet, sig: clsigs::SignatureD) -> bool {
|
|
|
|
if new_w.signature.is_none() {
|
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
|
|
|
x.push(new_w.r.clone());
|
|
|
|
x.push(new_w.cid.clone());
|
|
|
|
x.push(hashPubKeyToFr(&new_w.wpk));
|
|
|
|
x.push(Fr::from_str(new_w.balance.to_string().as_str()).unwrap());
|
|
|
|
|
2018-06-13 19:24:18 -07:00
|
|
|
//println!("payment_by_customer_final - print secrets");
|
|
|
|
//print_secret_vector(&x);
|
2018-06-13 17:28:37 -07:00
|
|
|
|
|
|
|
assert!(clsigs::verifyD(&pp.cl_mpk, &pk_m, &x, &sig));
|
|
|
|
new_w.signature = Some(sig);
|
|
|
|
c_data.csk = new_w;
|
2018-06-18 11:07:19 -07:00
|
|
|
c_data.T = new_t;
|
2018-06-13 17:28:37 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// must be an old wallet
|
|
|
|
return false;
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
2018-06-13 17:28:37 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
///// end of pay protocol
|
2018-03-25 20:20:05 -07:00
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// for customer => on input a wallet w, it outputs a customer channel closure message rc_c
|
2018-06-14 22:18:20 -07:00
|
|
|
pub fn customer_refund(pp: &PublicParams, state: &ChannelState, pk_m: &clsigs::PublicKeyD,
|
|
|
|
w: &CustomerWallet) -> ChannelClosure_C {
|
2018-06-09 23:00:01 -07:00
|
|
|
println!("Run Refund...");
|
2018-06-11 00:31:27 -07:00
|
|
|
let m;
|
2018-06-09 23:00:01 -07:00
|
|
|
let balance = w.balance as usize;
|
2018-06-11 00:31:27 -07:00
|
|
|
if !state.pay_init {
|
2018-06-09 23:00:01 -07:00
|
|
|
// pay protocol not invoked so take the balane
|
2018-06-14 22:18:20 -07:00
|
|
|
m = RefundMessage::new(String::from("refundUnsigned"), w.wpk, balance, Some(w.r), None);
|
2018-06-11 00:31:27 -07:00
|
|
|
} else {
|
|
|
|
// if channel has already been activated, then take unspent funds
|
2018-06-14 22:18:20 -07:00
|
|
|
m = RefundMessage::new(String::from("refundToken"), w.wpk, balance, None, w.refund_token.clone());
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// generate signature on the balance/channel id, etc to obtain funds back
|
|
|
|
let m_vec = m.hash();
|
2018-06-11 11:05:24 -07:00
|
|
|
let sigma = clsigs::signD(&pp.cl_mpk, &w.sk, &m_vec);
|
2018-06-09 23:00:01 -07:00
|
|
|
return ChannelClosure_C { message: m, signature: sigma };
|
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
fn exist_in_merchant_state(state: &ChannelState, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) -> bool {
|
|
|
|
if (state.keys.is_empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let fingerprint = computePubKeyFingerprint(wpk);
|
|
|
|
if (state.keys.contains_key(&fingerprint)) {
|
|
|
|
let pub_key = state.keys.get(&fingerprint).unwrap();
|
|
|
|
if pub_key.revoke_token.is_none() {
|
|
|
|
// let's just check the public key
|
|
|
|
return (pub_key.wpk == *wpk);
|
|
|
|
}
|
|
|
|
if (!rev.is_none()) {
|
|
|
|
return (pub_key.wpk == *wpk && pub_key.revoke_token.unwrap() == rev.unwrap());
|
|
|
|
}
|
|
|
|
return (pub_key.wpk == *wpk);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
fn update_merchant_state(state: &mut ChannelState, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) -> bool {
|
|
|
|
let fingerprint = computePubKeyFingerprint(wpk);
|
|
|
|
//println!("Print fingerprint: {}", fingerprint);
|
|
|
|
if !rev.is_none() {
|
|
|
|
let cust_pub_key = PubKeyMap { wpk: wpk.clone(), revoke_token: Some(rev.unwrap().clone()) };
|
|
|
|
state.keys.insert(fingerprint, cust_pub_key);
|
|
|
|
} else {
|
|
|
|
let cust_pub_key = PubKeyMap { wpk: wpk.clone(), revoke_token: None };
|
|
|
|
state.keys.insert(fingerprint, cust_pub_key);
|
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2018-06-14 20:50:00 -07:00
|
|
|
pub fn merchant_refute(pp: &PublicParams, T_c: &ChannelToken, m_data: &InitMerchantData,
|
2018-06-14 22:18:20 -07:00
|
|
|
state: &mut ChannelState, rc_c: &ChannelClosure_C, rv_token: &secp256k1::Signature) -> Option<ChannelClosure_M> {
|
2018-06-09 23:00:01 -07:00
|
|
|
println!("Run Refute...");
|
|
|
|
|
|
|
|
let is_valid = clsigs::verifyD(&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;
|
2018-06-14 18:07:18 -07:00
|
|
|
if exist_in_merchant_state(&state, &wpk, Some(*rv_token)) {
|
2018-06-14 22:18:20 -07:00
|
|
|
let mut s = secp256k1::Secp256k1::new();
|
|
|
|
let ser_rv_token = rv_token.serialize_compact(&s);
|
|
|
|
let rm = RevokedMessage::new(String::from("revoked"), wpk, Some(ser_rv_token));
|
2018-06-11 00:31:27 -07:00
|
|
|
// sign the revoked message
|
2018-06-11 11:05:24 -07:00
|
|
|
let signature = clsigs::signD(&pp.cl_mpk, &m_data.csk.sk, &rm.hash());
|
2018-06-09 23:00:01 -07:00
|
|
|
return Some(ChannelClosure_M { message: rm, signature: signature });
|
|
|
|
} else {
|
|
|
|
// update state to include the user's wallet key
|
2018-06-14 18:07:18 -07:00
|
|
|
assert!(update_merchant_state(state, &wpk, Some(*rv_token)));
|
2018-06-09 23:00:01 -07:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("Signature on customer closure message is invalid!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// on input th ecustmomer and merchant channel tokens T_c, T_m
|
|
|
|
// along with closure messages rc_c, rc_m
|
2018-06-14 22:18:20 -07:00
|
|
|
pub fn resolve(pp: &PublicParams, c: &InitCustomerData, m: &InitMerchantData, // cust and merch
|
|
|
|
rc_c: Option<ChannelClosure_C>, rc_m: Option<ChannelClosure_M>,
|
|
|
|
rt_w: Option<clsigs::SignatureD>) -> (i32, i32) {
|
2018-06-09 23:00:01 -07:00
|
|
|
println!("Run Resolve...");
|
2018-06-11 00:31:27 -07:00
|
|
|
let total_balance = c.csk.balance + m.csk.balance;
|
2018-06-09 23:00:01 -07:00
|
|
|
if (rc_c.is_none() && rc_m.is_none()) {
|
2018-06-11 00:31:27 -07:00
|
|
|
panic!("resolve - Did not specify channel closure messages for either customer or merchant!");
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if rc_c.is_none() {
|
2018-06-11 00:31:27 -07:00
|
|
|
// customer did not specify channel closure message
|
|
|
|
return (0, total_balance);
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
// TODO: use matching instead
|
|
|
|
// match rc_c.unwrap() {
|
|
|
|
// Some(v) => foo,
|
|
|
|
// _ => return (0, 0);
|
|
|
|
// }
|
2018-06-09 23:00:01 -07:00
|
|
|
|
2018-06-14 22:18:20 -07:00
|
|
|
let pk_c = &c.T.pk; // get public key for customer
|
|
|
|
let pk_m = &m.T; // get public key for merchant
|
2018-06-09 23:00:01 -07:00
|
|
|
|
|
|
|
let rc_cust = rc_c.unwrap();
|
2018-06-11 00:31:27 -07:00
|
|
|
let rcc_valid = clsigs::verifyD(&pp.cl_mpk, &pk_c, &rc_cust.message.hash(), &rc_cust.signature);
|
|
|
|
if !rcc_valid {
|
|
|
|
panic!("resolve - rc_c signature is invalid!");
|
|
|
|
}
|
|
|
|
let msg = &rc_cust.message;
|
|
|
|
let w_com = &c.T.w_com;
|
|
|
|
|
|
|
|
if msg.msgtype == "refundUnsigned" {
|
|
|
|
// assert the validity of the w_com
|
2018-06-14 22:18:20 -07:00
|
|
|
let cm_csp = generate_commit_setup(&pp, &pk_m);
|
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
let h_wpk = hashPubKeyToFr(&c.csk.wpk);
|
|
|
|
// convert balance into Fr
|
|
|
|
let balance = Fr::from_str(c.csk.balance.to_string().as_str()).unwrap();
|
|
|
|
|
|
|
|
let mut x: Vec<Fr> = Vec::new();
|
|
|
|
x.push(w_com.r); // Token if decommit is valid
|
|
|
|
x.push(c.csk.cid);
|
|
|
|
x.push(h_wpk);
|
|
|
|
x.push(balance);
|
|
|
|
|
|
|
|
// check that w_com is a valid commitment
|
|
|
|
if !commit_scheme::decommit(&cm_csp, &w_com, &x) {
|
|
|
|
// if this fails, then customer gets 0 and merchant gets full channel balance
|
2018-06-14 22:18:20 -07:00
|
|
|
println!("resolve - failed verify commitment on wallet");
|
2018-06-11 00:31:27 -07:00
|
|
|
return (0, total_balance);
|
|
|
|
}
|
|
|
|
} else if msg.msgtype == "refundToken" {
|
2018-06-14 22:18:20 -07:00
|
|
|
// check that the refund token for specified wallet is valid
|
|
|
|
let rt_valid = clsigs::verifyD(&pp.cl_mpk, &pk_c, &msg.hash(), &rt_w.unwrap());
|
2018-06-11 00:31:27 -07:00
|
|
|
if !rt_valid {
|
|
|
|
// refund token signature not valid, so pay full channel balance to merchant
|
|
|
|
return (0, total_balance)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !rc_m.is_none() {
|
|
|
|
let rc_merch = rc_m.unwrap();
|
|
|
|
let refute_valid = clsigs::verifyD(&pp.cl_mpk, &pk_m, &rc_merch.message.hash(), &rc_merch.signature);
|
|
|
|
if !refute_valid {
|
|
|
|
// refutation si invalid, so return customer balance and merchant balanace - claimed value
|
|
|
|
let claimed_value = 0; // TODO: figure out where this value comes from
|
|
|
|
return (c.csk.balance, m.csk.balance - claimed_value); // TODO: ensure merchant balance > 0
|
|
|
|
} else {
|
|
|
|
// if refutation is valid
|
|
|
|
return (0, total_balance);
|
|
|
|
}
|
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
panic!("resolve - Did not specify channel closure messages for either customer or merchant!");
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|