2018-06-24 22:06:36 -07:00
|
|
|
//! This crate is an experimental implementation of Blind Off-chain
|
|
|
|
//! lightweight transactions (BOLT).
|
|
|
|
//!
|
|
|
|
//! It builds on academic work done by Ian Miers and Matthew Green -
|
|
|
|
//! https://eprint.iacr.org/2016/701.
|
|
|
|
//!
|
|
|
|
//! Libbolt relies on BN curves at 128-bit security, as implemented in
|
|
|
|
//! [`bn module`](https://github.com/zcash-hackworks/bn).
|
|
|
|
//!
|
2018-07-21 21:22:21 -07:00
|
|
|
#![feature(extern_prelude)]
|
2018-06-24 22:06:36 -07:00
|
|
|
|
2018-07-24 18:42:07 -07:00
|
|
|
#![cfg_attr(all(test, feature = "unstable"), feature(test))]
|
|
|
|
#[cfg(all(test, feature = "unstable"))] extern crate test;
|
|
|
|
|
2018-02-24 00:12:58 -08:00
|
|
|
extern crate bn;
|
2018-02-24 23:46:52 -08:00
|
|
|
extern crate rand;
|
2018-07-21 21:22:21 -07:00
|
|
|
extern crate rand_core;
|
2018-02-24 23:46:52 -08:00
|
|
|
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-07-14 18:17:00 -07:00
|
|
|
extern crate time;
|
2018-10-04 11:38:10 -07:00
|
|
|
extern crate merlin;
|
2018-07-21 21:22:21 -07:00
|
|
|
extern crate bulletproofs;
|
|
|
|
extern crate curve25519_dalek;
|
2018-08-10 00:01:50 -07:00
|
|
|
extern crate sha2;
|
2018-03-24 06:44:45 -07:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
extern crate serde;
|
|
|
|
extern crate serde_with;
|
|
|
|
|
|
|
|
extern crate libc;
|
|
|
|
|
|
|
|
|
2018-02-24 23:46:52 -08:00
|
|
|
use std::fmt;
|
2018-03-24 06:44:45 -07:00
|
|
|
use std::str;
|
2018-07-21 21:22:21 -07:00
|
|
|
use bn::{Group, Fr, G1, G2, Gt};
|
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-12-22 12:35:13 -08:00
|
|
|
use sha2::Sha512;
|
2018-06-09 23:00:01 -07:00
|
|
|
use std::collections::HashMap;
|
2018-12-22 12:35:13 -08:00
|
|
|
use curve25519_dalek::digest::*;
|
2018-07-21 21:22:21 -07:00
|
|
|
use curve25519_dalek::scalar::Scalar;
|
2018-10-04 11:38:10 -07:00
|
|
|
use merlin::Transcript;
|
|
|
|
use bulletproofs::{BulletproofGens, PedersenGens, RangeProof};
|
2018-02-24 00:12:58 -08:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
|
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-07-24 21:56:41 -07:00
|
|
|
pub mod clproto;
|
2019-02-19 09:01:51 -08:00
|
|
|
pub mod serialization_wrappers;
|
2018-04-02 07:47:19 -07:00
|
|
|
|
2018-06-14 20:50:00 -07:00
|
|
|
const E_MIN: i32 = 1;
|
2018-07-25 19:59:47 -07:00
|
|
|
const E_MAX: i32 = 255; // TODO: should be 2^32 - 1
|
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-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;
|
|
|
|
}
|
|
|
|
|
2019-02-27 21:35:07 -08:00
|
|
|
pub fn print_length(commit: &commit_scheme::Commitment) {
|
|
|
|
let c_vec: Vec<u8> = encode(&commit.c, Infinite).unwrap();
|
|
|
|
println!("Length of G2: {}", c_vec.len());
|
|
|
|
let r_vec: Vec<u8> = encode(&commit.r, Infinite).unwrap();
|
|
|
|
println!("Length of FR: {}", r_vec.len());
|
|
|
|
}
|
|
|
|
|
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);
|
2018-08-15 00:47:02 -07:00
|
|
|
// // encode the balance as a hex string
|
2018-06-09 23:00:01 -07:00
|
|
|
// 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-24 21:03:59 -07:00
|
|
|
#[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-06-24 22:06:36 -07:00
|
|
|
pub fn hash(&self) -> Vec<Fr> {
|
2018-07-25 19:19:03 -07:00
|
|
|
let input_buf = self.sk.encode();
|
2018-06-24 22:06:36 -07:00
|
|
|
let mut v: Vec<Fr> = Vec::new();
|
|
|
|
|
2018-07-25 12:17:51 -07:00
|
|
|
v.push(convert_to_fr(&input_buf));
|
2018-03-24 21:03:59 -07:00
|
|
|
// encode k1 in the vector
|
2018-06-24 22:06:36 -07:00
|
|
|
v.push(self.k1.clone());
|
|
|
|
v.push(self.k2.clone());
|
|
|
|
// convert the balance into a Fr
|
|
|
|
let bal = Fr::from_str(self.balance.to_string().as_str()).unwrap();
|
|
|
|
v.push(bal);
|
2018-03-24 21:03:59 -07:00
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
return v;
|
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-06-24 20:14:02 -07:00
|
|
|
////////////////////////////////// Utilities //////////////////////////////////
|
2018-05-06 18:50:37 -07:00
|
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
pub fn hash_g1_to_fr(x: &G1) -> Fr {
|
2018-06-05 10:26:16 -07:00
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
pub fn hash_pub_key_to_fr(wpk: &secp256k1::PublicKey) -> Fr {
|
2018-06-08 18:20:15 -07:00
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
pub fn compute_pub_key_fingerprint(wpk: &secp256k1::PublicKey) -> String {
|
2018-06-14 18:07:18 -07:00
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
pub fn hash_buffer_to_fr<'a>(prefix: &'a str, buf: &[u8; 64]) -> Fr {
|
2018-06-13 17:28:37 -07:00
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
fn convert_to_fr(input_buf: &Vec<u8>) -> Fr {
|
2018-06-09 23:00:01 -07:00
|
|
|
// 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-07-25 12:17:51 -07:00
|
|
|
fn convert_str_to_fr<'a>(input: &'a str) -> Fr {
|
2018-06-13 17:28:37 -07:00
|
|
|
let mut input_buf = Vec::new();
|
|
|
|
input_buf.extend_from_slice(input.as_bytes());
|
2018-07-25 12:17:51 -07:00
|
|
|
return convert_to_fr(&input_buf);
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-08-10 00:01:50 -07:00
|
|
|
fn convert_int_to_fr(value: i32) -> Fr {
|
|
|
|
if value > 0 {
|
|
|
|
return Fr::from_str(value.to_string().as_str()).unwrap();
|
|
|
|
} else {
|
|
|
|
// negative value
|
|
|
|
let value2 = value * -1;
|
|
|
|
return -Fr::from_str(value2.to_string().as_str()).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-09 23:00:01 -07:00
|
|
|
// refund message
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-06-14 20:50:00 -07:00
|
|
|
pub struct RefundMessage {
|
|
|
|
pub msgtype: String, // purpose type of message
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_public_key")]
|
2018-06-11 00:31:27 -07:00
|
|
|
pub wpk: secp256k1::PublicKey,
|
|
|
|
pub balance: usize, // the balance
|
2019-02-26 11:52:47 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable_option", deserialize_with = "serialization_wrappers::deserialize_optional_fr")]
|
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-07-25 12:17:51 -07:00
|
|
|
v.push(convert_to_fr(&input_buf));
|
2018-06-09 23:00:01 -07:00
|
|
|
|
2018-07-25 12:17:51 -07:00
|
|
|
v.push(hash_pub_key_to_fr(&self.wpk));
|
2018-06-09 23:00:01 -07:00
|
|
|
|
|
|
|
// 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());
|
2018-07-25 12:17:51 -07:00
|
|
|
v.push(convert_to_fr(&b_buf));
|
2018-06-09 23:00:01 -07:00
|
|
|
|
|
|
|
//let r_vec: Vec<u8> = encode(&self.r, Infinite).unwrap();
|
2018-06-24 22:06:36 -07:00
|
|
|
if !self.r.is_none() {
|
2018-06-09 23:00:01 -07:00
|
|
|
v.push(self.r.unwrap().clone());
|
|
|
|
}
|
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct RevokedMessage {
|
|
|
|
pub msgtype: String,
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_public_key")]
|
2018-06-11 00:31:27 -07:00
|
|
|
pub wpk: secp256k1::PublicKey,
|
2019-02-26 11:52:47 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_fixed_byte_array_option", deserialize_with = "serialization_wrappers::deserialize_optional_fixed_64_byte_array")]
|
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-07-25 12:17:51 -07:00
|
|
|
v.push(convert_to_fr(&input_buf));
|
2018-06-09 23:00:01 -07:00
|
|
|
|
2018-07-25 12:17:51 -07:00
|
|
|
v.push(hash_pub_key_to_fr(&self.wpk));
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
if !self.sig.is_none() {
|
2018-07-25 12:17:51 -07:00
|
|
|
v.push(hash_buffer_to_fr(&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
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
////////////////////////////////// Utilities //////////////////////////////////
|
|
|
|
|
|
|
|
/////////////////////////////// Unidirectional ////////////////////////////////
|
|
|
|
|
|
|
|
pub mod unidirectional {
|
|
|
|
use std::fmt;
|
2018-08-24 00:18:36 -07:00
|
|
|
use std::collections::HashMap;
|
2018-07-21 21:22:21 -07:00
|
|
|
use rand::{Rng, thread_rng};
|
|
|
|
use rand_core::RngCore;
|
2018-08-24 00:18:36 -07:00
|
|
|
use bn::{Group, Fr, G2};
|
2018-06-24 22:06:36 -07:00
|
|
|
use sym;
|
|
|
|
use commit_scheme;
|
|
|
|
use clsigs;
|
2018-08-24 00:18:36 -07:00
|
|
|
use clproto;
|
2018-06-24 22:06:36 -07:00
|
|
|
use Message;
|
|
|
|
use sodiumoxide::randombytes;
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct CustomerWallet {
|
|
|
|
sk: clsigs::SecretKeyD, // the secret key for the signature scheme (Is it possible to make this a generic field?)
|
|
|
|
cid: Fr, // channel Id
|
|
|
|
wpk: secp256k1::PublicKey, // signature verification key
|
|
|
|
wsk: secp256k1::SecretKey // signature signing key
|
|
|
|
}
|
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
pub struct PublicParams {
|
|
|
|
cl_mpk: clsigs::PublicParams,
|
|
|
|
l: usize
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ChannelToken {
|
|
|
|
w_com: commit_scheme::Commitment,
|
|
|
|
pk: clsigs::PublicKey
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CustSecretKey {
|
2018-08-10 00:01:50 -07:00
|
|
|
sk: clsigs::SecretKey, // the secret key for the signature scheme
|
2018-06-24 22:06:36 -07:00
|
|
|
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 {
|
2018-08-16 15:05:01 -07:00
|
|
|
channel_token: ChannelToken,
|
2018-06-24 22:06:36 -07:00
|
|
|
csk: CustSecretKey
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InitMerchantData {
|
2018-08-16 15:05:01 -07:00
|
|
|
channel_token: clsigs::PublicKey,
|
2018-06-24 22:06:36 -07:00
|
|
|
csk: MerchSecretKey
|
|
|
|
}
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
pub struct PubKeyMap {
|
|
|
|
wpk: secp256k1::PublicKey,
|
|
|
|
revoke_token: Option<secp256k1::Signature>
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ChannelState {
|
|
|
|
keys: HashMap<String, PubKeyMap>,
|
|
|
|
R: i32,
|
|
|
|
tx_fee: i32,
|
|
|
|
pub name: String,
|
|
|
|
pub cid: Fr,
|
|
|
|
pub pay_init: bool,
|
|
|
|
pub channel_established: bool,
|
|
|
|
pub third_party: bool
|
|
|
|
}
|
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
pub fn setup() -> PublicParams {
|
2018-07-25 19:19:03 -07:00
|
|
|
let cl_mpk = clsigs::setup_d();
|
2018-06-24 22:06:36 -07:00
|
|
|
let l = 4;
|
|
|
|
let pp = PublicParams { cl_mpk: cl_mpk, l: l };
|
|
|
|
return pp;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn keygen(pp: &PublicParams) -> clsigs::KeyPairD {
|
2018-07-25 19:19:03 -07:00
|
|
|
let keypair = clsigs::keygen_d(&pp.cl_mpk, pp.l);
|
2018-06-24 22:06:36 -07:00
|
|
|
return keypair;
|
|
|
|
}
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
///
|
|
|
|
/// init_customer - takes as input the public params, channel state, commitment params, keypair,
|
|
|
|
/// and initial balance for customer and merchant. Generate initial customer channel token,
|
|
|
|
/// and wallet commitment.
|
|
|
|
///
|
2018-06-24 22:06:36 -07:00
|
|
|
pub fn init_customer(pp: &PublicParams, cm_pk: commit_scheme::CSParams,
|
|
|
|
b0_customer: i32, b0_merchant: i32,
|
|
|
|
keypair: &clsigs::KeyPair) -> InitCustomerData {
|
2018-07-21 21:22:21 -07:00
|
|
|
sym::init_mod();
|
2018-06-24 22:06:36 -07:00
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
let w_com = commit_scheme::commit(&cm_pk, &msg.hash(), r);
|
2018-06-24 22:06:36 -07:00
|
|
|
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 };
|
2018-08-16 15:05:01 -07:00
|
|
|
return InitCustomerData { channel_token: t_c, csk: csk_c };
|
2018-06-24 22:06:36 -07:00
|
|
|
}
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
///
|
|
|
|
/// init_merchant - takes as input the public params, merchant balance and keypair.
|
|
|
|
/// Generates merchant data which consists of channel token and merchant wallet.
|
|
|
|
///
|
2018-06-24 22:06:36 -07:00
|
|
|
pub fn init_merchant(pp: &PublicParams, b0_merchant: i32, keypair: &clsigs::KeyPair) -> InitMerchantData {
|
|
|
|
let csk_m = MerchSecretKey { sk: keypair.sk, balance: b0_merchant };
|
2018-08-16 15:05:01 -07:00
|
|
|
return InitMerchantData { channel_token: keypair.pk, csk: csk_m };
|
2018-06-24 22:06:36 -07:00
|
|
|
}
|
2018-05-06 18:50:37 -07:00
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
///
|
|
|
|
/// establish_customer_phase1 - takes as input the public params, customer wallet and
|
|
|
|
/// common public bases from merchant. Generates a PoK of the committed values in the
|
|
|
|
/// new wallet.
|
|
|
|
///
|
|
|
|
pub fn establish_customer_phase1(pp: &PublicParams, c_data: &InitCustomerData,
|
|
|
|
pub_bases: &Vec<G2>) -> clproto::ProofCV {
|
|
|
|
unimplemented!();
|
2018-05-10 14:08:42 -07:00
|
|
|
// // 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, );
|
2018-08-24 00:18:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// establish_merchant_phase2 - takes as input the public params, channel state, initial
|
|
|
|
/// merchant wallet and PoK of committed values from the customer. Generates a blinded
|
|
|
|
/// signature over the contents of the customer's wallet.
|
|
|
|
///
|
|
|
|
pub fn establish_merchant_phase2(pp: &PublicParams, state: &mut ChannelState, m_data: &InitMerchantData,
|
|
|
|
proof: &clproto::ProofCV) -> clsigs::SignatureD {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// establish_customer_final - takes as input the public params, merchant's verification key,
|
|
|
|
/// customer wallet and blinded signature obtained from merchant. Add the returned
|
|
|
|
/// blinded signature to the wallet.
|
|
|
|
///
|
|
|
|
pub fn establish_customer_final(pp: &PublicParams, pk_m: &clsigs::PublicKeyD,
|
|
|
|
w: &mut CustomerWallet, sig: clsigs::SignatureD) -> bool {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
2018-08-24 00:31:46 -07:00
|
|
|
// TODO: add pay protocol api, channel disput algs, etc
|
2018-06-24 22:06:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////// Unidirectional ////////////////////////////////
|
2018-05-10 14:08:42 -07:00
|
|
|
|
2018-06-24 22:06:36 -07:00
|
|
|
/////////////////////////////// Bidirectional ////////////////////////////////
|
2018-05-10 14:08:42 -07:00
|
|
|
pub mod bidirectional {
|
2018-03-25 20:20:05 -07:00
|
|
|
use std::fmt;
|
2018-07-21 21:22:21 -07:00
|
|
|
use rand::{rngs::OsRng, Rng};
|
|
|
|
use rand_core::RngCore;
|
2018-06-12 11:30:24 -07:00
|
|
|
use bn::{Group, Fr, G1, G2, Gt};
|
2018-03-25 20:20:05 -07:00
|
|
|
use commit_scheme;
|
|
|
|
use clsigs;
|
2018-07-24 21:56:41 -07:00
|
|
|
use clproto;
|
2018-06-18 20:19:53 -07:00
|
|
|
use sodiumoxide;
|
2018-06-24 22:06:36 -07:00
|
|
|
use secp256k1;
|
2018-06-09 23:00:01 -07:00
|
|
|
use RefundMessage;
|
|
|
|
use RevokedMessage;
|
2018-06-14 18:07:18 -07:00
|
|
|
use HashMap;
|
2018-07-25 12:17:51 -07:00
|
|
|
use hash_pub_key_to_fr;
|
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-07-25 12:17:51 -07:00
|
|
|
use convert_str_to_fr;
|
2018-08-10 00:01:50 -07:00
|
|
|
use convert_int_to_fr;
|
2018-07-25 12:17:51 -07:00
|
|
|
use compute_pub_key_fingerprint;
|
2018-06-14 20:50:00 -07:00
|
|
|
use E_MIN;
|
|
|
|
use E_MAX;
|
2018-12-22 12:35:13 -08:00
|
|
|
//use hash_buffer_to_fr;
|
|
|
|
//use debug_g2_in_hex;
|
|
|
|
//use convert_to_fr;
|
2018-07-21 21:22:21 -07:00
|
|
|
use bulletproofs;
|
2019-02-13 06:30:18 -08:00
|
|
|
use sodiumoxide::crypto::hash::sha512;
|
2018-08-10 00:01:50 -07:00
|
|
|
use sha2::Sha512;
|
2018-07-21 21:22:21 -07:00
|
|
|
use curve25519_dalek::scalar::Scalar;
|
|
|
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
2018-10-04 11:38:10 -07:00
|
|
|
use merlin::Transcript;
|
|
|
|
use bulletproofs::{BulletproofGens, PedersenGens, RangeProof};
|
2018-08-10 00:01:50 -07:00
|
|
|
use bincode::rustc_serialize::encode;
|
|
|
|
use bincode::SizeLimit::Infinite;
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
use serialization_wrappers;
|
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
|
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
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
#[derive(Serialize, Deserialize)]
|
2018-03-25 20:20:05 -07:00
|
|
|
pub struct PublicParams {
|
2018-04-05 23:44:31 -07:00
|
|
|
cl_mpk: clsigs::PublicParams,
|
2018-08-15 00:47:02 -07:00
|
|
|
l: usize, // messages for commitment
|
2019-02-19 09:01:51 -08:00
|
|
|
|
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_bullet_proof", deserialize_with = "serialization_wrappers::deserialize_bullet_proof" )]
|
2018-10-04 11:38:10 -07:00
|
|
|
bp_gens: bulletproofs::BulletproofGens,
|
2018-07-21 21:22:21 -07:00
|
|
|
range_proof_bits: usize,
|
2018-06-19 22:14:56 -07:00
|
|
|
extra_verify: bool // extra verification for certain points in the establish/pay protocol
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
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-08-10 00:01:50 -07:00
|
|
|
pk: clsigs::PublicKeyD,
|
|
|
|
third_party_pay: bool
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-07-14 18:17:00 -07:00
|
|
|
// proof of wallet signature, blind signature on wallet and common params for NIZK
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-07-14 18:17:00 -07:00
|
|
|
pub struct CustomerWalletProof {
|
2018-07-24 21:56:41 -07:00
|
|
|
proof_cv: clproto::ProofCV, // proof of knowledge of committed values
|
|
|
|
proof_vs: clproto::ProofVS, // proof of knowledge of valid signature
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_g_two")]
|
2018-08-10 00:01:50 -07:00
|
|
|
bal_com: G2, // old balance commitment
|
2018-07-14 18:17:00 -07:00
|
|
|
blind_sig: clsigs::SignatureD, // a blind signature
|
2018-07-24 21:56:41 -07:00
|
|
|
common_params: clproto::CommonParams, // common params for NIZK
|
2018-07-14 18:17:00 -07:00
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
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?)
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_fr")]
|
2018-05-11 13:21:35 -07:00
|
|
|
cid: Fr, // channel Id
|
2019-03-02 19:17:24 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_public_key")]
|
2018-06-08 18:20:15 -07:00
|
|
|
wpk: secp256k1::PublicKey, // signature verification key
|
2019-03-02 19:17:24 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_secret_key")]
|
2018-06-08 18:20:15 -07:00
|
|
|
wsk: secp256k1::SecretKey, // signature signing key
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_fr")]
|
2018-07-14 18:17:00 -07:00
|
|
|
h_wpk: Fr,
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_fr")]
|
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
|
2018-06-19 22:14:56 -07:00
|
|
|
merchant_balance: i32,
|
2018-06-13 17:28:37 -07:00
|
|
|
signature: Option<clsigs::SignatureD>,
|
2018-08-14 05:28:01 -07:00
|
|
|
// proof of signature on wallet contents in zero-knowledge
|
|
|
|
proof: Option<CustomerWalletProof>,
|
2018-06-13 17:28:37 -07:00
|
|
|
refund_token: Option<clsigs::SignatureD>
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
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
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-03-25 20:20:05 -07:00
|
|
|
pub struct InitCustomerData {
|
2018-08-16 15:05:01 -07:00
|
|
|
pub channel_token: ChannelToken,
|
2018-06-09 00:14:50 -07:00
|
|
|
pub csk: CustomerWallet,
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable_vec", deserialize_with = "serialization_wrappers::deserialize_g_two_vec")]
|
2018-06-13 17:28:37 -07:00
|
|
|
pub bases: Vec<G2>,
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-03-25 20:20:05 -07:00
|
|
|
pub struct InitMerchantData {
|
2018-08-16 15:05:01 -07:00
|
|
|
pub channel_token: clsigs::PublicKeyD,
|
2018-06-11 11:05:24 -07:00
|
|
|
pub csk: MerchSecretKey,
|
2019-02-19 15:02:53 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable_vec", deserialize_with = "serialization_wrappers::deserialize_g_two_vec")]
|
2018-06-11 11:05:24 -07:00
|
|
|
pub bases: Vec<G2>
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-07-29 17:44:08 -07:00
|
|
|
// part of channel state
|
2019-02-19 12:27:39 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct PubKeyMap {
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_public_key")]
|
2018-06-14 18:07:18 -07:00
|
|
|
wpk: secp256k1::PublicKey,
|
|
|
|
revoke_token: Option<secp256k1::Signature>
|
|
|
|
}
|
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct ChannelState {
|
|
|
|
keys: HashMap<String, PubKeyMap>,
|
|
|
|
R: i32,
|
2018-08-13 15:16:02 -07:00
|
|
|
tx_fee: i32,
|
2018-06-14 18:07:18 -07:00
|
|
|
pub name: String,
|
2019-02-19 09:01:51 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_fr")]
|
2018-06-09 23:00:01 -07:00
|
|
|
pub cid: Fr,
|
2018-06-11 00:31:27 -07:00
|
|
|
pub pay_init: bool,
|
2018-07-30 00:06:06 -07:00
|
|
|
pub channel_established: bool,
|
|
|
|
pub third_party: bool
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ChannelState {
|
|
|
|
pub fn new(name: String, third_party_support: bool)-> ChannelState {
|
|
|
|
ChannelState {
|
|
|
|
keys: HashMap::new(), // store wpks/revoke_tokens
|
|
|
|
R: 0,
|
2018-08-13 15:16:02 -07:00
|
|
|
tx_fee: 0,
|
2018-07-30 00:06:06 -07:00
|
|
|
name: name.to_string(),
|
2019-02-13 06:30:18 -08:00
|
|
|
cid: Fr::from_str("0").unwrap(),
|
2018-07-30 00:06:06 -07:00
|
|
|
pay_init: false,
|
|
|
|
channel_established: false,
|
|
|
|
third_party: third_party_support
|
|
|
|
}
|
|
|
|
}
|
2018-08-13 15:16:02 -07:00
|
|
|
|
2019-02-13 06:30:18 -08:00
|
|
|
pub fn generate_channel_id(&mut self, pk: &clsigs::PublicKeyD) {
|
|
|
|
let pk_bytes = pk.encode();
|
|
|
|
let sha2_digest = sha512::hash(&pk_bytes.as_slice());
|
|
|
|
|
|
|
|
let mut hash_buf: [u8; 64] = [0; 64];
|
|
|
|
hash_buf.copy_from_slice(&sha2_digest[0..64]);
|
|
|
|
self.cid = Fr::interpret(&hash_buf);
|
|
|
|
}
|
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
pub fn set_channel_fee(&mut self, fee: i32) {
|
|
|
|
self.tx_fee = fee;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_channel_fee(&self) -> i32 {
|
|
|
|
return self.tx_fee as i32;
|
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-07-25 12:17:51 -07:00
|
|
|
pub struct ChannelclosureC {
|
2018-06-14 22:18:20 -07:00
|
|
|
pub message: RefundMessage,
|
2018-06-09 23:00:01 -07:00
|
|
|
signature: clsigs::SignatureD
|
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-07-25 12:17:51 -07:00
|
|
|
pub struct ChannelclosureM {
|
2018-06-14 18:07:18 -07:00
|
|
|
message: RevokedMessage,
|
2018-06-09 23:00:01 -07:00
|
|
|
signature: clsigs::SignatureD
|
|
|
|
}
|
|
|
|
|
2018-07-21 21:22:21 -07:00
|
|
|
// proof of valid balance
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-07-21 21:22:21 -07:00
|
|
|
pub struct ProofVB {
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_range_proof")]
|
2018-10-04 11:38:10 -07:00
|
|
|
range_proof: (bulletproofs::RangeProof, curve25519_dalek::ristretto::CompressedRistretto),
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_r_point")]
|
2018-07-21 21:22:21 -07:00
|
|
|
value_commitment: RistrettoPoint
|
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-08-13 15:16:02 -07:00
|
|
|
pub struct BalanceProof {
|
|
|
|
third_party: bool,
|
|
|
|
balance_increment: i32,
|
2019-02-26 11:52:47 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_g_two")]
|
2018-08-13 15:16:02 -07:00
|
|
|
w_com_pr_pr: G2,
|
2019-02-26 11:52:47 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_g_two")]
|
2018-08-13 15:16:02 -07:00
|
|
|
old_bal_com: G2,
|
|
|
|
vcom: Option<commit_scheme::Commitment>,
|
|
|
|
proof_vcom: Option<clproto::ProofCV>,
|
|
|
|
proof_vrange: Option<ProofVB>
|
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-06-11 00:31:27 -07:00
|
|
|
pub struct PaymentProof {
|
2018-07-24 21:56:41 -07:00
|
|
|
proof2a: clproto::ProofCV, // PoK of committed values in new wallet
|
2019-02-14 08:55:23 -08:00
|
|
|
//proof2b: clproto::ProofCV, // PoK of committed values in old wallet (minus wpk)
|
2018-07-24 21:56:41 -07:00
|
|
|
proof2c: clproto::ProofVS, // PoK of old wallet signature (that includes wpk)
|
2018-07-21 21:22:21 -07:00
|
|
|
proof3: ProofVB, // range proof that balance - balance_inc is between (0, val_max)
|
2019-02-26 11:52:47 -08:00
|
|
|
#[serde(serialize_with = "serialization_wrappers::serialize_generic_encodable", deserialize_with = "serialization_wrappers::deserialize_g_two")]
|
2018-06-18 11:07:19 -07:00
|
|
|
old_com_base: G2,
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_public_key")]
|
2018-06-23 10:54:01 -07:00
|
|
|
wpk: secp256k1::PublicKey, // verification key for old wallet
|
2018-08-13 15:16:02 -07:00
|
|
|
wallet_sig: clsigs::SignatureD, // blinded signature for old wallet
|
|
|
|
pub bal_proof: BalanceProof
|
2018-06-11 00:31:27 -07:00
|
|
|
}
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[derive(Serialize, Deserialize)]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub struct RevokeToken {
|
|
|
|
message: RevokedMessage,
|
2019-03-03 14:43:20 -08:00
|
|
|
#[serde(deserialize_with = "serialization_wrappers::deserialize_secp_signature")]
|
2018-06-14 18:07:18 -07:00
|
|
|
pub signature: secp256k1::Signature
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
|
|
|
|
2018-06-18 20:19:53 -07:00
|
|
|
pub fn init() {
|
|
|
|
sodiumoxide::init();
|
|
|
|
}
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
///
|
|
|
|
/// setup - generate public parameters for bidirectional payment channels
|
|
|
|
///
|
2018-06-19 22:14:56 -07:00
|
|
|
pub fn setup(_extra_verify: bool) -> PublicParams {
|
2018-07-25 19:19:03 -07:00
|
|
|
let cl_mpk = clsigs::setup_d();
|
2018-06-13 17:28:37 -07:00
|
|
|
let l = 4;
|
2018-07-21 21:22:21 -07:00
|
|
|
let n = 32; // bitsize: 32-bit (0, 2^32-1)
|
|
|
|
let num_rand_values = 1;
|
2018-12-22 12:35:13 -08:00
|
|
|
let generators = BulletproofGens::new(64, num_rand_values); // bitsize
|
2018-07-21 21:22:21 -07:00
|
|
|
|
2018-10-04 11:38:10 -07:00
|
|
|
let pp = PublicParams { cl_mpk: cl_mpk, l: l, bp_gens: generators, range_proof_bits: n, extra_verify: _extra_verify };
|
2018-03-25 20:20:05 -07:00
|
|
|
return pp;
|
|
|
|
}
|
|
|
|
|
2018-08-24 00:18:36 -07:00
|
|
|
///
|
|
|
|
/// keygen - takes as input public parameters and generates a digital signature keypair
|
|
|
|
///
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn keygen(pp: &PublicParams) -> clsigs::KeyPairD {
|
2018-07-25 19:19:03 -07:00
|
|
|
let keypair = clsigs::keygen_d(&pp.cl_mpk, pp.l);
|
2018-03-25 20:20:05 -07:00
|
|
|
return keypair;
|
|
|
|
}
|
|
|
|
|
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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// init_customer - takes as input the public params, channel state, commitment params, keypair,
|
|
|
|
/// and initial balance for customer and merchant. Generate initial customer channel token,
|
|
|
|
/// and wallet commitment.
|
|
|
|
///
|
2019-02-13 06:30:18 -08:00
|
|
|
pub fn init_customer(pp: &PublicParams, channel: &mut ChannelState, b0_customer: i32, b0_merchant: i32,
|
2018-06-13 17:28:37 -07:00
|
|
|
cm_csp: &commit_scheme::CSParams, keypair: &clsigs::KeyPairD) -> InitCustomerData {
|
2018-08-10 00:01:50 -07:00
|
|
|
assert!(b0_customer >= 0);
|
|
|
|
assert!(b0_merchant >= 0);
|
2018-03-25 20:20:05 -07:00
|
|
|
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);
|
2018-07-21 21:22:21 -07:00
|
|
|
let (wsk, wpk) = schnorr.generate_keypair(rng);
|
2018-07-25 12:17:51 -07:00
|
|
|
let h_wpk = hash_pub_key_to_fr(&wpk);
|
2018-06-08 18:20:15 -07:00
|
|
|
// convert balance into Fr
|
2018-08-10 00:01:50 -07:00
|
|
|
let b0 = convert_int_to_fr(b0_customer);
|
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-08-15 00:47:02 -07:00
|
|
|
// retrieve the channel id
|
2019-02-13 06:30:18 -08:00
|
|
|
channel.generate_channel_id(&keypair.pk);
|
2018-08-13 20:57:23 -07:00
|
|
|
let cid = channel.cid;
|
2018-07-29 17:44:08 -07:00
|
|
|
// initial contents of wallet:
|
|
|
|
// commitment, channel id, customer balance, hash of wpk (wallet ver/pub key)
|
|
|
|
let mut x: Vec<Fr> = vec![r, cid, b0, h_wpk];
|
|
|
|
// commitment of wallet values
|
2018-08-13 15:16:02 -07:00
|
|
|
let w_com = commit_scheme::commit(&cm_csp, &x, r);
|
2018-07-29 17:44:08 -07:00
|
|
|
// construct channel token
|
2018-08-10 00:01:50 -07:00
|
|
|
let t_c = ChannelToken { w_com: w_com, pk: keypair.pk.clone(), third_party_pay: channel.third_party };
|
2019-03-02 19:17:24 -08:00
|
|
|
|
2018-07-29 17:44:08 -07:00
|
|
|
// construct customer wallet secret key plus other components
|
2018-07-14 18:17:00 -07:00
|
|
|
let csk_c = CustomerWallet { sk: keypair.sk.clone(), cid: cid, wpk: wpk, wsk: wsk, h_wpk: h_wpk,
|
2018-06-19 22:14:56 -07:00
|
|
|
r: r, balance: b0_customer, merchant_balance: b0_merchant,
|
2018-07-14 18:17:00 -07:00
|
|
|
proof: None, signature: None, refund_token: None };
|
2018-07-29 17:44:08 -07:00
|
|
|
|
2018-08-16 15:05:01 -07:00
|
|
|
return InitCustomerData { channel_token: t_c, csk: csk_c, bases: cm_csp.pub_bases.clone() };
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// init_merchant - takes as input the public params, merchant balance and keypair.
|
|
|
|
/// Generates merchant data which consists of channel token and merchant wallet.
|
|
|
|
///
|
2018-06-05 10:26:16 -07:00
|
|
|
pub fn init_merchant(pp: &PublicParams, b0_merchant: i32, keypair: &clsigs::KeyPairD) -> InitMerchantData {
|
2018-08-10 00:01:50 -07:00
|
|
|
assert!(b0_merchant >= 0);
|
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-08-16 15:05:01 -07:00
|
|
|
return InitMerchantData { channel_token: keypair.pk.clone(), csk: csk_m, bases: cm_csp.pub_bases };
|
2018-03-25 20:20:05 -07:00
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// establish_customer_phase1 - takes as input the public params, customer wallet and
|
|
|
|
/// common public bases from merchant. Generates a PoK of the committed values in the
|
|
|
|
/// new wallet.
|
|
|
|
///
|
2018-06-14 18:07:18 -07:00
|
|
|
pub fn establish_customer_phase1(pp: &PublicParams, c_data: &InitCustomerData,
|
2018-08-15 07:28:46 -07:00
|
|
|
pub_bases: &Vec<G2>) -> clproto::ProofCV {
|
2018-06-08 18:20:15 -07:00
|
|
|
// obtain customer init data
|
2018-08-16 15:05:01 -07:00
|
|
|
let t_c = &c_data.channel_token;
|
2018-06-08 18:20:15 -07:00
|
|
|
let csk_c = &c_data.csk;
|
2018-07-14 18:17:00 -07:00
|
|
|
let h_wpk = csk_c.h_wpk;
|
2018-08-10 00:01:50 -07:00
|
|
|
let b0 = convert_int_to_fr(csk_c.balance);
|
2018-06-08 18:20:15 -07:00
|
|
|
// collect secrets
|
2018-07-29 17:44:08 -07:00
|
|
|
let mut x: Vec<Fr> = vec![t_c.w_com.r, csk_c.cid, b0, h_wpk ];
|
2018-06-11 00:31:27 -07:00
|
|
|
// generate proof of knowledge for committed values
|
2018-07-24 21:56:41 -07:00
|
|
|
let proof_1 = clproto::bs_gen_nizk_proof(&x, &pub_bases, t_c.w_com.c);
|
2018-06-08 18:20:15 -07:00
|
|
|
return proof_1;
|
2018-04-08 00:46:17 -07:00
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// establish_merchant_phase2 - takes as input the public params, channel state, initial
|
|
|
|
/// merchant wallet and PoK of committed values from the customer. Generates a blinded
|
|
|
|
/// signature over the contents of the customer's wallet.
|
|
|
|
///
|
2018-06-11 00:31:27 -07:00
|
|
|
pub fn establish_merchant_phase2(pp: &PublicParams, state: &mut ChannelState, m_data: &InitMerchantData,
|
2018-07-24 21:56:41 -07:00
|
|
|
proof: &clproto::ProofCV) -> clsigs::SignatureD {
|
2019-02-13 19:18:54 -08:00
|
|
|
// verifies proof (\pi_1) and produces signature on the committed values in the initial wallet
|
2018-07-24 21:56:41 -07:00
|
|
|
let wallet_sig = clproto::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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// establish_customer_final - takes as input the public params, merchant's verification key,
|
|
|
|
/// customer wallet and blinded signature obtained from merchant. Add the returned
|
|
|
|
/// blinded signature to the wallet.
|
|
|
|
///
|
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-24 22:06:36 -07:00
|
|
|
if pp.extra_verify {
|
2019-02-13 19:18:54 -08:00
|
|
|
// customer can verify that merchant generated a correct signature on
|
|
|
|
// the expected committed values
|
2018-08-10 00:01:50 -07:00
|
|
|
let bal = convert_int_to_fr(w.balance);
|
2018-07-29 17:44:08 -07:00
|
|
|
let mut x: Vec<Fr> = vec![w.r.clone(), w.cid.clone(), bal, w.h_wpk.clone()];
|
2018-07-25 19:19:03 -07:00
|
|
|
assert!(clsigs::verify_d(&pp.cl_mpk, &pk_m, &x, &sig));
|
2018-06-23 10:54:01 -07:00
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
w.signature = Some(sig);
|
2018-08-15 07:28:46 -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-08-15 07:28:46 -07:00
|
|
|
|
|
|
|
///
|
|
|
|
/// pay_by_customer_phase1_precompute - takes as input the public params, channel token,
|
|
|
|
/// merchant verification key, old customer wallet. Generates PoK of signature on previous wallet.
|
|
|
|
///
|
2018-08-16 15:05:01 -07:00
|
|
|
pub fn pay_by_customer_phase1_precompute(pp: &PublicParams, t: &ChannelToken, pk_m: &clsigs::PublicKeyD, old_w: &mut CustomerWallet) {
|
2018-08-15 07:28:46 -07:00
|
|
|
// generate proof of knowledge of valid signature on previous wallet
|
2018-08-24 00:31:46 -07:00
|
|
|
// get channel id, balance, commitment randomness and wallet sig
|
2018-07-14 18:17:00 -07:00
|
|
|
let cid = old_w.cid.clone();
|
|
|
|
let old_r = &old_w.r;
|
|
|
|
let old_wallet_sig = &old_w.signature;
|
|
|
|
|
|
|
|
let wallet_sig = old_wallet_sig.clone().unwrap();
|
|
|
|
// retrieve old balance
|
2018-08-10 00:01:50 -07:00
|
|
|
let old_balance = convert_int_to_fr(old_w.balance);
|
2018-07-14 18:17:00 -07:00
|
|
|
|
2018-07-24 18:42:07 -07:00
|
|
|
let old_h_wpk = old_w.h_wpk;
|
2018-07-29 17:44:08 -07:00
|
|
|
let mut old_x: Vec<Fr> = vec![old_w.r.clone(), cid, old_balance, old_h_wpk];
|
2018-07-14 18:17:00 -07:00
|
|
|
// retrieve the commitment scheme parameters based on merchant's PK
|
|
|
|
let cm_csp = generate_commit_setup(&pp, &pk_m);
|
2018-08-10 00:01:50 -07:00
|
|
|
// extract the portion of the commitment to the balance of the wallet
|
|
|
|
let bal_index = 2;
|
|
|
|
let old_w_bal_com = cm_csp.pub_bases[bal_index] * old_balance;
|
2018-07-14 18:17:00 -07:00
|
|
|
|
|
|
|
// proof of committed values not including the old wpk since we are revealing it
|
|
|
|
// to the merchant
|
|
|
|
let index = 3;
|
2018-08-16 15:05:01 -07:00
|
|
|
let old_w_com_pr = t.w_com.c - old_w_bal_com - (cm_csp.pub_bases[index] * old_h_wpk);
|
2018-08-10 00:01:50 -07:00
|
|
|
// NOTE: the third argument represents the challenge that is included in the final proof structure
|
2018-07-24 21:56:41 -07:00
|
|
|
let proof_old_cv = clproto::bs_gen_nizk_proof(&old_x, &cm_csp.pub_bases, old_w_com_pr);
|
2018-07-14 18:17:00 -07:00
|
|
|
|
2018-08-15 00:47:02 -07:00
|
|
|
// generate the blind signature for the old wallet signature (we do not want to reveal this
|
2018-08-10 00:01:50 -07:00
|
|
|
// to the merchant)
|
2018-07-24 21:56:41 -07:00
|
|
|
let blind_sig = clproto::prover_generate_blinded_sig(&wallet_sig);
|
2018-08-10 00:01:50 -07:00
|
|
|
// generate the common params necessary to execute the two party NIZK protocol
|
|
|
|
// for verifying the signature
|
2018-07-24 21:56:41 -07:00
|
|
|
let common_params = clproto::gen_common_params(&pp.cl_mpk, &pk_m, &wallet_sig);
|
2018-08-10 00:01:50 -07:00
|
|
|
// generate the NIZK proof of valid signature based on the old wallet
|
2018-07-24 21:56:41 -07:00
|
|
|
let proof_vs = clproto::vs_gen_nizk_proof(&old_x, &common_params, common_params.vs);
|
2018-07-14 18:17:00 -07:00
|
|
|
|
2018-08-10 00:01:50 -07:00
|
|
|
// return the payment proof for the old wallet
|
2018-08-14 05:28:01 -07:00
|
|
|
let old_iou_proof = CustomerWalletProof { proof_cv: proof_old_cv, proof_vs: proof_vs,
|
|
|
|
bal_com: old_w_bal_com, blind_sig: blind_sig, common_params: common_params };
|
|
|
|
old_w.proof = Some(old_iou_proof);
|
2018-07-14 18:17:00 -07:00
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
|
|
|
|
///
|
|
|
|
/// pay_by_customer_phase1 - takes as input the public params, channel state, channel token,
|
|
|
|
/// merchant public keys, old wallet and balance increment. Generate a new wallet commitment
|
|
|
|
/// PoK of the committed values in new wallet and PoK of old wallet. Return new channel token,
|
|
|
|
/// new wallet (minus blind signature and refund token) and payment proof.
|
|
|
|
///
|
2018-08-16 15:05:01 -07:00
|
|
|
pub fn pay_by_customer_phase1(pp: &PublicParams, channel: &ChannelState, t: &ChannelToken, pk_m: &clsigs::PublicKeyD,
|
2018-06-18 11:07:19 -07:00
|
|
|
old_w: &CustomerWallet, balance_increment: i32) -> (ChannelToken, CustomerWallet, PaymentProof) {
|
2018-07-21 21:22:21 -07:00
|
|
|
let mut rng = &mut rand::thread_rng();
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-07-14 18:17:00 -07:00
|
|
|
if old_w.proof.is_none() {
|
|
|
|
panic!("You have not executed the pay_by_customer_phase1_precompute!");
|
|
|
|
}
|
|
|
|
let wallet_proof = old_w.proof.clone().unwrap();
|
2018-06-13 19:24:18 -07:00
|
|
|
let bal = old_w.balance;
|
2018-06-11 00:31:27 -07:00
|
|
|
|
|
|
|
// generate new keypair
|
|
|
|
let mut schnorr = secp256k1::Secp256k1::new();
|
|
|
|
schnorr.randomize(rng);
|
2018-07-21 21:22:21 -07:00
|
|
|
let (wsk, wpk) = schnorr.generate_keypair(rng);
|
2018-07-25 12:17:51 -07:00
|
|
|
let h_wpk = hash_pub_key_to_fr(&wpk);
|
2018-06-11 00:31:27 -07:00
|
|
|
|
|
|
|
// new sample randomness r'
|
2018-06-13 17:28:37 -07:00
|
|
|
let r_pr = Fr::random(rng);
|
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-23 10:54:01 -07:00
|
|
|
// retrieve the current payment channel id
|
2018-06-11 00:31:27 -07:00
|
|
|
let cid = old_w.cid.clone();
|
2018-06-11 11:05:24 -07:00
|
|
|
// convert balance into Fr (B - e)
|
2018-08-13 15:16:02 -07:00
|
|
|
let updated_balance = bal - balance_increment - channel.tx_fee;
|
2018-06-24 22:06:36 -07:00
|
|
|
if updated_balance < 0 {
|
2018-06-14 18:07:18 -07:00
|
|
|
panic!("pay_by_customer_phase1 - insufficient funds to make payment!");
|
|
|
|
}
|
2018-06-23 10:54:01 -07:00
|
|
|
// record the potential to payment
|
2018-08-13 15:16:02 -07:00
|
|
|
let merchant_balance = old_w.merchant_balance + (balance_increment + channel.tx_fee);
|
2018-06-14 18:07:18 -07:00
|
|
|
|
2018-08-10 00:01:50 -07:00
|
|
|
let updated_balance_pr = convert_int_to_fr(updated_balance);
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-07-29 17:44:08 -07:00
|
|
|
let mut new_wallet_sec: Vec<Fr> = vec![r_pr, cid, updated_balance_pr, h_wpk];
|
|
|
|
// commitment of new wallet values
|
2018-08-13 15:16:02 -07:00
|
|
|
let w_com = commit_scheme::commit(&cm_csp, &new_wallet_sec, r_pr);
|
2018-08-10 00:01:50 -07:00
|
|
|
let w_com_bytes: Vec<u8> = encode(&w_com.c, Infinite).unwrap();
|
|
|
|
|
|
|
|
// generate proof of knowledge for committed values in new wallet
|
|
|
|
let mut proof_cv = clproto::bs_gen_nizk_proof(&new_wallet_sec, &cm_csp.pub_bases, w_com.c);
|
|
|
|
let bal_index = 2; // index of balance
|
|
|
|
// sending partial commitment that does not include the balance
|
|
|
|
let w_com_pr_pr = proof_cv.C - (cm_csp.pub_bases[bal_index] * updated_balance_pr);
|
|
|
|
let wpk_index = new_wallet_sec.len() - 1;
|
2018-06-11 00:31:27 -07:00
|
|
|
|
2018-07-21 21:22:21 -07:00
|
|
|
// bullet proof integration here to generate the range proof
|
2018-09-08 10:59:50 -07:00
|
|
|
let mut transcript = Transcript::new(b"BOLT Range Proof");
|
2018-07-21 21:22:21 -07:00
|
|
|
let value = updated_balance as u64;
|
2018-08-10 00:01:50 -07:00
|
|
|
let val_blinding = Scalar::hash_from_bytes::<Sha512>(&w_com_bytes);
|
2018-10-04 11:38:10 -07:00
|
|
|
let pc_gens = PedersenGens::default();
|
|
|
|
let range_proof = RangeProof::prove_single(&pp.bp_gens, &pc_gens, &mut transcript,
|
|
|
|
value, &val_blinding,
|
2018-07-21 21:22:21 -07:00
|
|
|
pp.range_proof_bits).unwrap();
|
2018-10-04 11:38:10 -07:00
|
|
|
//let pg = &pp.range_proof_gens.pedersen_gens;
|
|
|
|
let value_cm = pc_gens.commit(Scalar::from(value), val_blinding);
|
2018-07-21 21:22:21 -07:00
|
|
|
|
|
|
|
let proof_rp = ProofVB { range_proof: range_proof, value_commitment: value_cm };
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
let mut bal_proof;
|
2018-08-16 15:05:01 -07:00
|
|
|
if t.third_party_pay {
|
2018-08-13 15:16:02 -07:00
|
|
|
let r_inc = Fr::random(rng);
|
|
|
|
let bal_inc_fr = -convert_int_to_fr(balance_increment + channel.tx_fee);
|
|
|
|
let inc_vec: Vec<Fr> = vec![r_inc, bal_inc_fr];
|
|
|
|
let mut v_com = commit_scheme::commit(&cm_csp, &inc_vec, r_inc);
|
|
|
|
let proof_vcom = clproto::bs_gen_nizk_proof(&inc_vec, &cm_csp.pub_bases, v_com.c);
|
|
|
|
|
|
|
|
// range proof that pay increment < payment max
|
|
|
|
let v_com_bytes: Vec<u8> = encode(&proof_vcom.C, Infinite).unwrap();
|
|
|
|
|
|
|
|
let mut inc_bal;
|
|
|
|
let final_balance_increment = balance_increment + channel.tx_fee;
|
|
|
|
if final_balance_increment < 0 {
|
|
|
|
// negative value => convert to positive value
|
|
|
|
assert!(final_balance_increment >= -E_MAX);
|
|
|
|
inc_bal = -final_balance_increment as u64
|
|
|
|
} else {
|
|
|
|
// positive value
|
|
|
|
inc_bal = final_balance_increment as u64;
|
|
|
|
}
|
|
|
|
let inc_blinding = Scalar::hash_from_bytes::<Sha512>(&v_com_bytes);
|
2018-09-08 10:59:50 -07:00
|
|
|
let mut transcript1 = Transcript::new(b"Range Proof for Balance Increment");
|
2018-10-04 11:38:10 -07:00
|
|
|
let pc_gens = PedersenGens::default();
|
|
|
|
let inc_range_proof = RangeProof::prove_single(&pp.bp_gens, &pc_gens, &mut transcript1,
|
|
|
|
inc_bal, &inc_blinding,
|
2018-08-13 15:16:02 -07:00
|
|
|
pp.range_proof_bits).unwrap();
|
2018-10-04 11:38:10 -07:00
|
|
|
//let inc_pg = &pp.range_proof_gens.pedersen_gens;
|
|
|
|
let inc_cm = pc_gens.commit(Scalar::from(inc_bal), inc_blinding);
|
2018-08-13 15:16:02 -07:00
|
|
|
|
|
|
|
let proof_vrange = ProofVB { range_proof: inc_range_proof, value_commitment: inc_cm };
|
|
|
|
bal_proof = BalanceProof { third_party: true, vcom: Some(v_com),
|
|
|
|
proof_vcom: Some(proof_vcom), proof_vrange: Some(proof_vrange),
|
|
|
|
w_com_pr_pr: w_com_pr_pr, balance_increment: 0,
|
|
|
|
old_bal_com: wallet_proof.bal_com,
|
|
|
|
};
|
|
|
|
} else {
|
2018-08-15 07:28:46 -07:00
|
|
|
// balance_increment => // epsilon - payment increment/decrement
|
|
|
|
// wallet_proof.bal_com => // old balance commitment
|
2018-08-13 15:16:02 -07:00
|
|
|
bal_proof = BalanceProof { third_party: false, vcom: None,
|
|
|
|
proof_vcom: None, proof_vrange: None,
|
|
|
|
w_com_pr_pr: w_com_pr_pr, balance_increment: balance_increment,
|
|
|
|
old_bal_com: wallet_proof.bal_com,
|
|
|
|
};
|
2018-08-10 00:01:50 -07:00
|
|
|
}
|
|
|
|
|
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 {
|
2018-08-10 00:01:50 -07:00
|
|
|
proof2a: proof_cv, // (1) PoK for committed values, wCom' (in new wallet)
|
2019-02-14 08:55:23 -08:00
|
|
|
//proof2b: wallet_proof.proof_cv, // PoK of committed values (minus h(wpk))
|
2018-07-14 18:17:00 -07:00
|
|
|
proof2c: wallet_proof.proof_vs, // PoK of signature on old wallet
|
2018-07-21 21:22:21 -07:00
|
|
|
proof3: proof_rp, // range proof that the updated_balance is within a public range
|
2018-08-13 15:16:02 -07:00
|
|
|
bal_proof: bal_proof,
|
2018-08-10 00:01:50 -07:00
|
|
|
old_com_base: cm_csp.pub_bases[wpk_index], // base Z
|
2018-07-14 18:17:00 -07:00
|
|
|
wpk: old_w.wpk.clone(), // showing public key for old wallet
|
|
|
|
wallet_sig: wallet_proof.blind_sig // 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-08-16 15:05:01 -07:00
|
|
|
let t_c = ChannelToken { w_com: w_com, pk: t.pk.clone(), third_party_pay: t.third_party_pay };
|
2018-07-14 18:17:00 -07:00
|
|
|
let csk_c = CustomerWallet { sk: old_w.sk.clone(), cid: cid, wpk: wpk, wsk: wsk, h_wpk: h_wpk,
|
2018-06-19 22:14:56 -07:00
|
|
|
r: r_pr, balance: updated_balance, merchant_balance: merchant_balance,
|
2018-07-14 18:17:00 -07:00
|
|
|
proof: None, 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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// pay_by_merchant_phase1 - takes as input the public params, channel state, payment proof
|
|
|
|
/// and merchant keys. If proof is valid, then merchant returns the refund token
|
|
|
|
/// (i.e., partially blind signature on IOU with updated 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-12 11:30:24 -07:00
|
|
|
let proof_cv = &proof.proof2a;
|
2019-02-14 08:55:23 -08:00
|
|
|
//let proof_old_cv = &proof.proof2b;
|
2018-06-23 10:54:01 -07:00
|
|
|
let proof_vs = &proof.proof2c;
|
2018-08-13 15:16:02 -07:00
|
|
|
let bal_proof = &proof.bal_proof;
|
2018-08-15 07:28:46 -07:00
|
|
|
let blinded_sig = &proof.wallet_sig;
|
2018-06-13 17:28:37 -07:00
|
|
|
// get merchant keypair
|
2018-08-16 15:05:01 -07:00
|
|
|
let pk_m = &m_data.channel_token;
|
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
|
2018-08-15 07:28:46 -07:00
|
|
|
let proof_vs_old_wallet = clproto::vs_verify_blind_sig(&pp.cl_mpk, &pk_m, &proof_vs, &blinded_sig);
|
2018-06-23 10:54:01 -07:00
|
|
|
|
2019-02-14 08:55:23 -08:00
|
|
|
// // add specified wpk to make the proof valid
|
|
|
|
// // NOTE: if valid, then wpk is indeed the wallet public key for the wallet
|
|
|
|
// let new_c = proof_old_cv.C + bal_proof.old_bal_com + (proof.old_com_base * hash_pub_key_to_fr(&proof.wpk));
|
|
|
|
// let new_proof_old_cv = clproto::ProofCV { T: proof_old_cv.T,
|
|
|
|
// C: new_c,
|
|
|
|
// s: proof_old_cv.s.clone(),
|
|
|
|
// pub_bases: proof_old_cv.pub_bases.clone(),
|
|
|
|
// num_secrets: proof_old_cv.num_secrets };
|
|
|
|
// let is_wpk_valid_reveal = clproto::bs_verify_nizk_proof(&new_proof_old_cv);
|
|
|
|
// if !is_wpk_valid_reveal {
|
|
|
|
// panic!("pay_by_merchant_phase1 - failed to verify NIZK PoK of committed values that reveals wpk!");
|
|
|
|
// }
|
2018-06-23 10:54:01 -07:00
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
let is_existing_wpk = exist_in_merchant_state(&state, &proof.wpk, None);
|
2018-08-13 15:16:02 -07:00
|
|
|
let bal_inc_within_range = bal_proof.balance_increment >= -E_MAX && bal_proof.balance_increment <= E_MAX;
|
2018-07-21 21:22:21 -07:00
|
|
|
// check the range proof of the updated balance
|
2018-09-08 10:59:50 -07:00
|
|
|
let mut transcript = Transcript::new(b"BOLT Range Proof");
|
2018-10-04 11:38:10 -07:00
|
|
|
let pc_gens = PedersenGens::default();
|
|
|
|
let is_range_proof_valid = proof.proof3.range_proof.0.verify_single(&pp.bp_gens, &pc_gens,
|
|
|
|
&mut transcript, &proof.proof3.range_proof.1,
|
2018-07-21 21:22:21 -07:00
|
|
|
pp.range_proof_bits).is_ok();
|
2018-06-23 10:54:01 -07:00
|
|
|
|
|
|
|
// if above is is_wpk_valid_reveal => true, then we can proceed to
|
|
|
|
// check that the proof of valid signature and then
|
2018-08-10 00:01:50 -07:00
|
|
|
if proof_vs_old_wallet && !is_existing_wpk && bal_inc_within_range && is_range_proof_valid {
|
2018-06-14 18:07:18 -07:00
|
|
|
println!("Proof of knowledge of signature is valid!");
|
2018-08-13 15:16:02 -07:00
|
|
|
if bal_proof.balance_increment < 0 {
|
2018-06-14 18:07:18 -07:00
|
|
|
// 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-23 10:54:01 -07:00
|
|
|
panic!("pay_by_merchant_phase1 - Verification failure for old wallet signature contents!");
|
2018-06-11 00:31:27 -07:00
|
|
|
}
|
2018-06-12 11:30:24 -07:00
|
|
|
|
2018-06-23 10:54:01 -07:00
|
|
|
// now we can verify the proof of knowledge for committed values in new wallet
|
2018-08-13 15:16:02 -07:00
|
|
|
if !proof.bal_proof.third_party {
|
|
|
|
let bal_inc_fr = -convert_int_to_fr(bal_proof.balance_increment);
|
|
|
|
// check that the PoK on new wallet commitment is valid and
|
|
|
|
// the updated balance differs by the balance increment from the balance
|
|
|
|
// in previous wallet
|
|
|
|
let bal_index = 2;
|
2019-02-14 08:55:23 -08:00
|
|
|
let w_com_pr = bal_proof.w_com_pr_pr + bal_proof.old_bal_com + (proof_cv.pub_bases[bal_index] * bal_inc_fr);
|
2018-08-13 15:16:02 -07:00
|
|
|
if proof_cv.C != w_com_pr {
|
|
|
|
panic!("pay_by_merchant_phase1 - Old and new balance does not differ by payment amount!");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// in third party case, what we do a PoK for committed payment increment
|
|
|
|
let proof_vcom = proof.bal_proof.proof_vcom.as_ref().unwrap();
|
|
|
|
if !clproto::bs_verify_nizk_proof(&proof_vcom) {
|
|
|
|
panic!("pay_by_merchant_phase1 - Could not verify the NIZK PoK of payment amount");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if clproto::bs_verify_nizk_proof(&proof_cv) {
|
2018-06-13 17:28:37 -07:00
|
|
|
// generate refund token on new wallet
|
|
|
|
let i = pk_m.Z2.len()-1;
|
2018-07-25 12:17:51 -07:00
|
|
|
let c_refund = proof_cv.C + (pk_m.Z2[i] * convert_str_to_fr("refund"));
|
2018-06-13 17:28:37 -07:00
|
|
|
// generating partially blind signature on refund || wpk' || B - e
|
2018-08-15 07:28:46 -07:00
|
|
|
let rt_w = clproto::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, c_refund, proof_cv.num_secrets + 1);
|
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-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-08-13 15:16:02 -07:00
|
|
|
///
|
|
|
|
/// Verify third party payment proof from two bi-directional channel payments with intermediary
|
|
|
|
///
|
|
|
|
pub fn verify_third_party_payment(pp: &PublicParams, fee: i32, proof1: &BalanceProof, proof2: &BalanceProof) -> bool {
|
|
|
|
if proof1.third_party && proof2.third_party {
|
|
|
|
let vcom1 = &proof1.proof_vcom.as_ref().unwrap();
|
|
|
|
let vcom2 = &proof2.proof_vcom.as_ref().unwrap();
|
|
|
|
let rproof1 = &proof1.proof_vrange.as_ref().unwrap();
|
|
|
|
let rproof2 = &proof2.proof_vrange.as_ref().unwrap();
|
2018-10-04 11:38:10 -07:00
|
|
|
let pc_gens1 = PedersenGens::default();
|
|
|
|
let pc_gens2 = PedersenGens::default();
|
2018-09-08 10:59:50 -07:00
|
|
|
let mut transcript1 = Transcript::new(b"Range Proof for Balance Increment");
|
2018-10-04 11:38:10 -07:00
|
|
|
let range_proof1_valid = rproof1.range_proof.0.verify_single(&pp.bp_gens, &pc_gens1,
|
2018-08-13 15:16:02 -07:00
|
|
|
&mut transcript1,
|
2018-10-04 11:38:10 -07:00
|
|
|
&rproof1.range_proof.1,
|
2018-08-13 15:16:02 -07:00
|
|
|
pp.range_proof_bits).is_ok();
|
|
|
|
|
2018-09-08 10:59:50 -07:00
|
|
|
let mut transcript2 = Transcript::new(b"Range Proof for Balance Increment");
|
2018-10-04 11:38:10 -07:00
|
|
|
let range_proof2_valid = rproof2.range_proof.0.verify_single(&pp.bp_gens, &pc_gens2,
|
2018-08-13 15:16:02 -07:00
|
|
|
&mut transcript2,
|
2018-10-04 11:38:10 -07:00
|
|
|
&rproof2.range_proof.1,
|
2018-08-13 15:16:02 -07:00
|
|
|
pp.range_proof_bits).is_ok();
|
|
|
|
|
|
|
|
let len = vcom1.pub_bases.len();
|
|
|
|
assert!(len >= 2 && vcom1.pub_bases.len() == vcom2.pub_bases.len());
|
|
|
|
|
|
|
|
// g^(e1 + -e2 + fee) * h^(r1 + r2) ==> should be equal to g^(fee) * h^(r1 + r2)
|
|
|
|
// lets add commitments for vcom1 and vcom2 to check
|
|
|
|
let added_commits = vcom1.C + vcom2.C;
|
|
|
|
let tx_fee = vcom1.pub_bases[1] * -convert_int_to_fr(fee);
|
|
|
|
// compute h^r1 + r2
|
|
|
|
let h_r1_r2 = (vcom1.pub_bases[0] * proof1.vcom.unwrap().r) +
|
|
|
|
(vcom2.pub_bases[0] * proof2.vcom.unwrap().r) + tx_fee;
|
2018-08-13 15:18:14 -07:00
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
let is_pay_plus_fee = added_commits == h_r1_r2;
|
|
|
|
return clproto::bs_verify_nizk_proof(&vcom1) &&
|
|
|
|
clproto::bs_verify_nizk_proof(&vcom2) &&
|
|
|
|
range_proof1_valid && range_proof2_valid &&
|
|
|
|
is_pay_plus_fee;
|
|
|
|
}
|
|
|
|
panic!("verify_third_party_payment - third-party payment not enabled for both proofs");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// pay_by_customer_phase2 - takes as input the public params, old wallet, new wallet,
|
|
|
|
/// merchant's verification key and refund token. If the refund token is valid, generate
|
|
|
|
/// a revocation token for the old wallet public key.
|
|
|
|
///
|
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-08-10 00:01:50 -07:00
|
|
|
let bal = convert_int_to_fr(new_w.balance);
|
2018-07-29 17:44:08 -07:00
|
|
|
let h_wpk = hash_pub_key_to_fr(&new_w.wpk);
|
|
|
|
let refund = convert_str_to_fr("refund");
|
|
|
|
let mut x: Vec<Fr> = vec![new_w.r.clone(), new_w.cid.clone(), bal, h_wpk, refund];
|
2018-06-13 17:28:37 -07:00
|
|
|
|
2018-07-25 19:19:03 -07:00
|
|
|
let is_rt_w_valid = clsigs::verify_d(&pp.cl_mpk, &pk_m, &x, &rt_w);
|
2018-06-24 22:06:36 -07:00
|
|
|
if is_rt_w_valid {
|
2018-06-13 17:28:37 -07:00
|
|
|
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
|
2018-07-21 21:22:21 -07:00
|
|
|
return RevokeToken { message: rm, signature: rv_w };
|
2018-06-13 17:28:37 -07:00
|
|
|
}
|
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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// pay_by_merchant_phase2 - takes as input the public params, channel state, proof of payment,
|
|
|
|
/// merchant wallet, and revocation token 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).
|
|
|
|
///
|
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-07-24 21:56:41 -07:00
|
|
|
if clproto::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-07-24 21:56:41 -07:00
|
|
|
let new_wallet_sig = clproto::bs_compute_blind_signature(&pp.cl_mpk, &sk_m, proof_cv.C, proof_cv.num_secrets);
|
2018-08-13 15:16:02 -07:00
|
|
|
m_data.csk.balance += proof.bal_proof.balance_increment + state.tx_fee;
|
2018-06-14 18:07:18 -07:00
|
|
|
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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// pay_by_customer_final - takes as input the public params, merchant's verification key,
|
|
|
|
/// customer's old wallet, new channel token, new wallet and wallet signature (from merchant).
|
|
|
|
/// Update the new wallet accordingly and checks if the signature from merchant is valid.
|
|
|
|
///
|
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() {
|
2018-06-24 22:06:36 -07:00
|
|
|
if pp.extra_verify {
|
2018-08-10 00:01:50 -07:00
|
|
|
let bal = convert_int_to_fr(new_w.balance);
|
2018-07-29 17:44:08 -07:00
|
|
|
let h_wpk = hash_pub_key_to_fr(&new_w.wpk);
|
|
|
|
let mut x: Vec<Fr> = vec![new_w.r.clone(), new_w.cid.clone(), bal, h_wpk];
|
2018-07-25 19:19:03 -07:00
|
|
|
assert!(clsigs::verify_d(&pp.cl_mpk, &pk_m, &x, &sig));
|
2018-06-23 10:54:01 -07:00
|
|
|
}
|
|
|
|
// update signature in new wallet
|
2018-06-13 17:28:37 -07:00
|
|
|
new_w.signature = Some(sig);
|
2018-06-23 10:54:01 -07:00
|
|
|
// update csk in new wallet
|
2018-06-13 17:28:37 -07:00
|
|
|
c_data.csk = new_w;
|
2018-06-23 10:54:01 -07:00
|
|
|
// update the channel token
|
2018-08-16 15:05:01 -07:00
|
|
|
c_data.channel_token = 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-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// customer_refund - takes as input the public params, channel state, merchant's verification
|
|
|
|
/// key, and customer wallet. Generates a channel closure message for customer.
|
|
|
|
///
|
2018-06-14 22:18:20 -07:00
|
|
|
pub fn customer_refund(pp: &PublicParams, state: &ChannelState, pk_m: &clsigs::PublicKeyD,
|
2018-07-25 12:17:51 -07:00
|
|
|
w: &CustomerWallet) -> ChannelclosureC {
|
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-23 10:54:01 -07:00
|
|
|
// pay protocol not invoked so take the balance
|
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-07-25 19:19:03 -07:00
|
|
|
let sigma = clsigs::sign_d(&pp.cl_mpk, &w.sk, &m_vec);
|
2018-07-25 12:17:51 -07:00
|
|
|
return ChannelclosureC { message: m, signature: sigma };
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 18:07:18 -07:00
|
|
|
fn exist_in_merchant_state(state: &ChannelState, wpk: &secp256k1::PublicKey, rev: Option<secp256k1::Signature>) -> bool {
|
2018-06-24 22:06:36 -07:00
|
|
|
if state.keys.is_empty() {
|
2018-06-14 18:07:18 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-25 12:17:51 -07:00
|
|
|
let fingerprint = compute_pub_key_fingerprint(wpk);
|
2018-06-24 22:06:36 -07:00
|
|
|
if state.keys.contains_key(&fingerprint) {
|
2018-06-14 18:07:18 -07:00
|
|
|
let pub_key = state.keys.get(&fingerprint).unwrap();
|
|
|
|
if pub_key.revoke_token.is_none() {
|
|
|
|
// let's just check the public key
|
2018-07-21 21:22:21 -07:00
|
|
|
return pub_key.wpk == *wpk;
|
2018-06-14 18:07:18 -07:00
|
|
|
}
|
2018-06-24 22:06:36 -07:00
|
|
|
if !rev.is_none() {
|
2018-07-21 21:22:21 -07:00
|
|
|
return pub_key.wpk == *wpk && pub_key.revoke_token.unwrap() == rev.unwrap();
|
2018-06-14 18:07:18 -07:00
|
|
|
}
|
2018-07-21 21:22:21 -07:00
|
|
|
return pub_key.wpk == *wpk;
|
2018-06-14 18:07:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2018-07-25 12:17:51 -07:00
|
|
|
let fingerprint = compute_pub_key_fingerprint(wpk);
|
2018-06-14 18:07:18 -07:00
|
|
|
//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;
|
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// merchant_refute - takes as input the public params, channel token, merchant's wallet,
|
|
|
|
/// channels tate, channel closure from customer, and revocation token.
|
|
|
|
/// Generates a channel closure message for merchant and updated merchant internal state.
|
|
|
|
///
|
2018-08-16 15:05:01 -07:00
|
|
|
pub fn merchant_refute(pp: &PublicParams, state: &mut ChannelState, t_c: &ChannelToken, m_data: &InitMerchantData,
|
|
|
|
rc_c: &ChannelclosureC, rv_token: &secp256k1::Signature) -> ChannelclosureM {
|
2018-08-15 07:28:46 -07:00
|
|
|
// 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-08-16 15:05:01 -07:00
|
|
|
let is_valid = clsigs::verify_d(&pp.cl_mpk, &t_c.pk, &rc_c.message.hash(), &rc_c.signature);
|
2018-06-09 23:00:01 -07:00
|
|
|
if is_valid {
|
|
|
|
let wpk = rc_c.message.wpk;
|
|
|
|
let balance = rc_c.message.balance;
|
2018-08-14 10:00:44 -07:00
|
|
|
if !exist_in_merchant_state(&state, &wpk, Some(*rv_token)) {
|
2018-06-09 23:00:01 -07:00
|
|
|
// 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
|
|
|
}
|
2019-02-19 09:01:51 -08:00
|
|
|
let ser_rv_token = rv_token.serialize_compact();
|
2018-08-14 10:00:44 -07:00
|
|
|
let rm = RevokedMessage::new(String::from("revoked"), wpk, Some(ser_rv_token));
|
|
|
|
// sign the revoked message
|
|
|
|
let signature = clsigs::sign_d(&pp.cl_mpk, &m_data.csk.sk, &rm.hash());
|
|
|
|
return ChannelclosureM { message: rm, signature: signature };
|
2018-06-09 23:00:01 -07:00
|
|
|
} else {
|
|
|
|
panic!("Signature on customer closure message is invalid!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-15 07:28:46 -07:00
|
|
|
///
|
|
|
|
/// resolve - on input the customer and merchant channel tokens T_c, T_m, along with
|
|
|
|
/// closure messages rc_c, rc_m.
|
|
|
|
/// this will be executed by the network to make sure the right balance is returned
|
|
|
|
/// to each party based on provided inputs.
|
|
|
|
///
|
2018-08-14 05:28:01 -07:00
|
|
|
pub fn resolve(pp: &PublicParams, c: &InitCustomerData, m: &InitMerchantData,
|
2018-07-25 12:17:51 -07:00
|
|
|
rc_c: Option<ChannelclosureC>, rc_m: Option<ChannelclosureM>,
|
2018-06-14 22:18:20 -07:00
|
|
|
rt_w: Option<clsigs::SignatureD>) -> (i32, i32) {
|
2018-06-11 00:31:27 -07:00
|
|
|
let total_balance = c.csk.balance + m.csk.balance;
|
2018-06-24 22:06:36 -07:00
|
|
|
if rc_c.is_none() && rc_m.is_none() {
|
2018-08-14 10:00:44 -07:00
|
|
|
panic!("resolve1 - 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-08-14 05:28:01 -07:00
|
|
|
// could not find customer's channel closure message.
|
|
|
|
// judgement: give merchant everything
|
2018-06-11 00:31:27 -07:00
|
|
|
return (0, total_balance);
|
2018-06-09 23:00:01 -07:00
|
|
|
}
|
|
|
|
|
2018-08-16 15:05:01 -07:00
|
|
|
let pk_c = &c.channel_token.pk; // get public key for customer
|
|
|
|
let pk_m = &m.channel_token; // get public key for merchant
|
2018-06-09 23:00:01 -07:00
|
|
|
|
|
|
|
let rc_cust = rc_c.unwrap();
|
2018-07-25 19:19:03 -07:00
|
|
|
let rcc_valid = clsigs::verify_d(&pp.cl_mpk, &pk_c, &rc_cust.message.hash(), &rc_cust.signature);
|
2018-06-11 00:31:27 -07:00
|
|
|
if !rcc_valid {
|
2018-08-14 10:00:44 -07:00
|
|
|
panic!("resolve2 - rc_c signature is invalid!");
|
2018-06-11 00:31:27 -07:00
|
|
|
}
|
2018-08-15 07:28:46 -07:00
|
|
|
let msg = &rc_cust.message;
|
2018-08-16 15:05:01 -07:00
|
|
|
let w_com = &c.channel_token.w_com;
|
2018-06-11 00:31:27 -07:00
|
|
|
|
|
|
|
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-07-25 12:17:51 -07:00
|
|
|
let h_wpk = hash_pub_key_to_fr(&c.csk.wpk);
|
2018-06-11 00:31:27 -07:00
|
|
|
// convert balance into Fr
|
2018-08-10 00:01:50 -07:00
|
|
|
let balance = convert_int_to_fr(c.csk.balance);
|
2018-07-29 17:44:08 -07:00
|
|
|
let mut x: Vec<Fr> = vec![w_com.r, c.csk.cid, h_wpk, balance];
|
2018-06-11 00:31:27 -07:00
|
|
|
|
|
|
|
// 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-08-14 10:00:44 -07:00
|
|
|
println!("resolve3 - 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
|
2018-08-14 10:00:44 -07:00
|
|
|
let bal = convert_int_to_fr(msg.balance as i32);
|
|
|
|
let h_wpk = hash_pub_key_to_fr(&msg.wpk);
|
|
|
|
let refund = convert_str_to_fr("refund");
|
|
|
|
let mut x: Vec<Fr> = vec![c.csk.r.clone(), c.csk.cid.clone(), bal, h_wpk, refund];
|
|
|
|
|
|
|
|
let is_rt_valid = clsigs::verify_d(&pp.cl_mpk, &pk_m, &x, &rt_w.unwrap());
|
|
|
|
if !is_rt_valid {
|
2018-06-11 00:31:27 -07:00
|
|
|
// refund token signature not valid, so pay full channel balance to merchant
|
|
|
|
return (0, total_balance)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-14 10:00:44 -07:00
|
|
|
|
2018-06-11 00:31:27 -07:00
|
|
|
if !rc_m.is_none() {
|
|
|
|
let rc_merch = rc_m.unwrap();
|
2018-07-25 19:19:03 -07:00
|
|
|
let refute_valid = clsigs::verify_d(&pp.cl_mpk, &pk_m, &rc_merch.message.hash(), &rc_merch.signature);
|
2018-06-11 00:31:27 -07:00
|
|
|
if !refute_valid {
|
2018-08-14 05:28:01 -07:00
|
|
|
// refute token is invalid, so return customer balance and merchant balance
|
|
|
|
return (c.csk.balance, m.csk.balance);
|
2018-06-11 00:31:27 -07:00
|
|
|
} else {
|
|
|
|
// if refutation is valid
|
|
|
|
return (0, total_balance);
|
|
|
|
}
|
|
|
|
}
|
2018-06-09 23:00:01 -07:00
|
|
|
|
2018-08-14 10:00:44 -07:00
|
|
|
panic!("resolve4 - 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
|
|
|
}
|
2018-07-24 18:42:07 -07:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
#[no_mangle]
|
|
|
|
pub mod ffishim {
|
|
|
|
extern crate libc;
|
|
|
|
|
|
|
|
use bidirectional;
|
|
|
|
use clsigs;
|
2019-02-19 12:27:39 -08:00
|
|
|
use commit_scheme;
|
2019-02-19 15:02:53 -08:00
|
|
|
use clproto;
|
2019-02-19 12:27:39 -08:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
use serde::{Serialize};
|
|
|
|
|
|
|
|
use libc::{c_char};
|
|
|
|
use std::ffi::{CStr, CString};
|
|
|
|
use std::str;
|
|
|
|
use std::mem;
|
|
|
|
|
2019-03-05 17:05:05 -08:00
|
|
|
use bn::Fr;
|
|
|
|
|
|
|
|
use serialization_wrappers;
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_free_string(pointer: *mut c_char) {
|
|
|
|
unsafe{
|
|
|
|
if pointer.is_null() { return }
|
|
|
|
CString::from_raw(pointer)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_setup(extra_verify: u32) -> *mut c_char {
|
|
|
|
let mut ev = false;
|
|
|
|
if extra_verify > 1 {
|
|
|
|
ev = true;
|
|
|
|
}
|
|
|
|
let pp = bidirectional::setup(ev);
|
2019-02-26 17:10:40 -08:00
|
|
|
let ser = ["{\'pp\':\'",serde_json::to_string(&pp).unwrap().as_str(), "\'}"].concat();
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-02-19 15:02:53 -08:00
|
|
|
pub extern fn ffishim_bidirectional_channelstate_new(channel_name: *const c_char, third_party_support: u32) -> *mut c_char {
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
let bytes = unsafe { CStr::from_ptr(channel_name).to_bytes() };
|
|
|
|
let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8
|
2019-02-26 11:52:47 -08:00
|
|
|
|
2019-02-19 09:01:51 -08:00
|
|
|
let mut tps = false;
|
|
|
|
if third_party_support > 1 {
|
|
|
|
tps = true;
|
|
|
|
}
|
2019-02-19 15:02:53 -08:00
|
|
|
let channel = bidirectional::ChannelState::new(name.to_string(), tps);
|
2019-02-26 17:10:40 -08:00
|
|
|
let ser = ["{\'state\':\'",serde_json::to_string(&channel).unwrap().as_str(), "\'}"].concat();;
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_keygen(serialized_pp: *mut c_char) -> *mut c_char {
|
|
|
|
|
|
|
|
let bytes = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name: &str = str::from_utf8(bytes).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name).unwrap();
|
|
|
|
|
|
|
|
let keypair = bidirectional::keygen(&deserialized_pp);
|
2019-02-26 17:10:40 -08:00
|
|
|
let ser = ["{\'keypair\':\'",serde_json::to_string(&keypair).unwrap().as_str(), "\'}"].concat();
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_init_merchant(serialized_pp: *mut c_char, balance_merchant: i32, serialized_merchant_keypair: *mut c_char) -> *mut c_char {
|
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
|
|
|
let bytes_kp = unsafe { CStr::from_ptr(serialized_merchant_keypair).to_bytes() };
|
|
|
|
let name_kp: &str = str::from_utf8(bytes_kp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_keypair: clsigs::KeyPairD = serde_json::from_str(&name_kp).unwrap();
|
|
|
|
|
|
|
|
let init_merchant_data = bidirectional::init_merchant(&deserialized_pp, balance_merchant, &deserialized_merchant_keypair);
|
2019-02-26 17:10:40 -08:00
|
|
|
let ser = ["{\'merchant_data\':\'", serde_json::to_string(&init_merchant_data).unwrap().as_str(), "\'}"].concat();
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-02-26 17:10:40 -08:00
|
|
|
pub extern fn ffishim_bidirectional_generate_commit_setup(serialized_pp: *mut c_char, serialized_merchant_public_key: *mut c_char) -> *mut c_char {
|
2019-02-19 09:01:51 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-02-26 17:10:40 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_public_key: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-26 17:10:40 -08:00
|
|
|
let cm_csp = bidirectional::generate_commit_setup(&deserialized_pp, &deserialized_merchant_public_key);
|
|
|
|
let ser = ["{\'commit_setup\':\'", serde_json::to_string(&cm_csp).unwrap().as_str(), "\'}"].concat();
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-02-26 11:52:47 -08:00
|
|
|
pub extern fn ffishim_bidirectional_init_customer(serialized_pp: *mut c_char, serialized_channel: *mut c_char, balance_customer: i32, balance_merchant: i32, serialized_commitment_setup: *mut c_char, serialized_customer_keypair: *mut c_char) -> *mut c_char {
|
2019-02-19 09:01:51 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
2019-02-19 09:01:51 -08:00
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
2019-02-19 15:10:23 -08:00
|
|
|
let mut deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
2019-02-19 09:01:51 -08:00
|
|
|
|
|
|
|
|
|
|
|
// Deserialize the commitment setup
|
|
|
|
let bytes_commitment_setup = unsafe { CStr::from_ptr(serialized_commitment_setup).to_bytes() };
|
|
|
|
let name_commitment_setup: &str = str::from_utf8(bytes_commitment_setup).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_ccommitment_setup: commit_scheme::CSParams = serde_json::from_str(&name_commitment_setup).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the client keypair
|
|
|
|
let bytes_kp = unsafe { CStr::from_ptr(serialized_customer_keypair).to_bytes() };
|
|
|
|
let name_kp: &str = str::from_utf8(bytes_kp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_customer_keypair: clsigs::KeyPairD = serde_json::from_str(&name_kp).unwrap();
|
|
|
|
|
2019-02-26 17:10:40 -08:00
|
|
|
// We change the channel state
|
2019-02-19 15:10:23 -08:00
|
|
|
let cust_data = bidirectional::init_customer(&deserialized_pp, &mut deserialized_channel_state, balance_customer, balance_merchant, &deserialized_ccommitment_setup, &deserialized_customer_keypair);
|
2019-02-26 17:10:40 -08:00
|
|
|
let ser = ["{\'customer_data\':\'", serde_json::to_string(&cust_data).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str() ,"\'}"].concat();
|
2019-02-19 09:01:51 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_establish_customer_phase1(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_data: *mut c_char) -> *mut c_char {
|
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
let proof1 = bidirectional::establish_customer_phase1(&deserialized_pp, &deserialized_customer_data, &deserialized_merchant_data.bases);
|
2019-03-02 19:17:24 -08:00
|
|
|
let ser = ["{\'proof\':\'", serde_json::to_string(&proof1).unwrap().as_str(), "\'}"].concat();
|
2019-02-19 15:02:53 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
2019-02-19 09:01:51 -08:00
|
|
|
|
2019-02-19 15:02:53 -08:00
|
|
|
#[no_mangle]
|
2019-02-26 11:52:47 -08:00
|
|
|
pub extern fn ffishim_bidirectional_establish_merchant_phase2(serialized_pp: *mut c_char, serialized_channel: *mut c_char, serialized_merchant_data: *mut c_char, serialized_proof1: *mut c_char) -> *mut c_char {
|
2019-02-19 15:02:53 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
2019-02-19 15:02:53 -08:00
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the first proof
|
|
|
|
let bytes_proof_1 = unsafe { CStr::from_ptr(serialized_proof1).to_bytes() };
|
|
|
|
let name_proof_1: &str = str::from_utf8(bytes_proof_1).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_proof_1: clproto::ProofCV = serde_json::from_str(&name_proof_1).unwrap();
|
|
|
|
|
|
|
|
let wallet_sig = bidirectional::establish_merchant_phase2(&deserialized_pp, &mut deserialized_channel_state, &deserialized_merchant_data, &deserialized_proof_1);
|
2019-03-02 19:17:24 -08:00
|
|
|
let ser = ["{\'wallet_sig\':\'", serde_json::to_string(&wallet_sig).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str() ,"\'}"].concat();
|
2019-02-19 15:02:53 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-02 19:48:47 -08:00
|
|
|
pub extern fn ffishim_bidirectional_establish_customer_final(serialized_pp: *mut c_char, serialized_merchant_public_key: *mut c_char, serialized_customer_data: *mut c_char, serialized_wallet_sig: *mut c_char) -> *mut c_char {
|
2019-02-19 15:02:53 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-03-02 19:48:47 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_publickey: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-19 15:02:53 -08:00
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the wallet_sig
|
|
|
|
let bytes_wallet_sig = unsafe { CStr::from_ptr(serialized_wallet_sig).to_bytes() };
|
|
|
|
let name_wallet_sig: &str = str::from_utf8(bytes_wallet_sig).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_wallet_sig: clsigs::SignatureD = serde_json::from_str(&name_wallet_sig).unwrap();
|
|
|
|
|
2019-03-02 19:48:47 -08:00
|
|
|
bidirectional::establish_customer_final(&deserialized_pp, &deserialized_merchant_publickey, &mut deserialized_customer_data.csk, deserialized_wallet_sig);
|
2019-03-02 19:17:24 -08:00
|
|
|
let ser = ["{\'customer_data\':\'", serde_json::to_string(&deserialized_customer_data).unwrap().as_str(), "\'}"].concat();
|
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
2019-02-19 15:02:53 -08:00
|
|
|
}
|
2019-02-26 11:52:47 -08:00
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-02 19:48:47 -08:00
|
|
|
pub extern fn ffishim_bidirectional_pay_by_customer_phase1_precompute(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_public_key: *mut c_char) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-03-02 19:48:47 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_publickey: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-26 11:52:47 -08:00
|
|
|
|
2019-03-02 19:48:47 -08:00
|
|
|
bidirectional::pay_by_customer_phase1_precompute(&deserialized_pp, &deserialized_customer_data.channel_token, &deserialized_merchant_publickey, &mut deserialized_customer_data.csk);
|
|
|
|
let ser = ["{\'customer_data\':\'", serde_json::to_string(&deserialized_customer_data).unwrap().as_str(), "\'}"].concat();
|
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
2019-02-26 11:52:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-02 19:48:47 -08:00
|
|
|
pub extern fn ffishim_bidirectional_pay_by_customer_phase1(serialized_pp: *mut c_char, serialized_channel: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_public_key: *mut c_char, balance_increment: i32) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-03-02 19:48:47 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_public_key: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-26 11:52:47 -08:00
|
|
|
|
2019-03-02 19:48:47 -08:00
|
|
|
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&deserialized_pp, &deserialized_channel_state, &deserialized_customer_data.channel_token, &deserialized_merchant_public_key, &deserialized_customer_data.csk, balance_increment);
|
|
|
|
let ser = ["{\'channel_token\':\'", serde_json::to_string(&t_c).unwrap().as_str(), "\', \'new_wallet\':\'", serde_json::to_string(&new_wallet).unwrap().as_str() , "\', \'pay_proof\':\'", serde_json::to_string(&pay_proof).unwrap().as_str(), "\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_pay_by_merchant_phase1(serialized_pp: *mut c_char, serialized_channel: /*make mut*/ *mut c_char, serialized_pay_proof: *mut c_char, serialized_merchant_data: *mut c_char) -> *mut c_char {
|
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the pay proof
|
|
|
|
let bytes_pay_proof = unsafe { CStr::from_ptr(serialized_pay_proof).to_bytes() };
|
|
|
|
let name_pay_proof: &str = str::from_utf8(bytes_pay_proof).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pay_proof: bidirectional::PaymentProof = serde_json::from_str(&name_pay_proof).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
|
|
|
|
|
|
|
let rt_w = bidirectional::pay_by_merchant_phase1(&deserialized_pp, &mut deserialized_channel_state, &deserialized_pay_proof, &deserialized_merchant_data);
|
2019-03-03 14:43:20 -08:00
|
|
|
let ser = ["{\'rt_w\':\'", serde_json::to_string(&rt_w).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str() ,"\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-03 14:43:20 -08:00
|
|
|
pub extern fn ffishim_bidirectional_pay_by_customer_phase2(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_new_wallet: *mut c_char, serialized_merchant_public_key: *mut c_char, serialized_rt_w: *mut c_char) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the new wallet
|
|
|
|
let bytes_new_wallet = unsafe { CStr::from_ptr(serialized_new_wallet).to_bytes() };
|
|
|
|
let name_new_wallet: &str = str::from_utf8(bytes_new_wallet).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_new_wallet: bidirectional::CustomerWallet = serde_json::from_str(&name_new_wallet).unwrap();
|
|
|
|
|
2019-03-03 14:43:20 -08:00
|
|
|
// Deserialize the merchant public key
|
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_publickey: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-26 11:52:47 -08:00
|
|
|
|
|
|
|
// Deserialize the rt_w
|
|
|
|
let bytes_rt_w = unsafe { CStr::from_ptr(serialized_rt_w).to_bytes() };
|
|
|
|
let name_rt_w: &str = str::from_utf8(bytes_rt_w).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_rt_w: clsigs::SignatureD = serde_json::from_str(&name_rt_w).unwrap();
|
|
|
|
|
|
|
|
// RevokeToken
|
2019-03-03 14:43:20 -08:00
|
|
|
let rv_w = bidirectional::pay_by_customer_phase2(&deserialized_pp, &deserialized_customer_data.csk, &deserialized_new_wallet, &deserialized_merchant_publickey, &deserialized_rt_w);
|
|
|
|
let ser = ["{\'rv_w\':\'", serde_json::to_string(&rv_w).unwrap().as_str(), "\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_pay_by_merchant_phase2(serialized_pp: *mut c_char, serialized_channel: /*make mut*/ *mut c_char, serialized_pay_proof: *mut c_char, serialized_merchant_data: /*make mut*/ *mut c_char, serialized_revoke_token: *mut c_char ) -> *mut c_char {
|
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the pay proof
|
|
|
|
let bytes_pay_proof = unsafe { CStr::from_ptr(serialized_pay_proof).to_bytes() };
|
|
|
|
let name_pay_proof: &str = str::from_utf8(bytes_pay_proof).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pay_proof: bidirectional::PaymentProof = serde_json::from_str(&name_pay_proof).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant revoke token
|
|
|
|
let bytes_revoke_token = unsafe { CStr::from_ptr(serialized_revoke_token).to_bytes() };
|
|
|
|
let name_revoke_token: &str = str::from_utf8(bytes_revoke_token).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_revoke_token: bidirectional::RevokeToken = serde_json::from_str(&name_revoke_token).unwrap();
|
|
|
|
|
|
|
|
let new_wallet_sig = bidirectional::pay_by_merchant_phase2(&deserialized_pp, &mut deserialized_channel_state, &deserialized_pay_proof, &mut deserialized_merchant_data, &deserialized_revoke_token);
|
2019-03-03 14:43:20 -08:00
|
|
|
let ser = ["{\'new_wallet_sig\':\'", serde_json::to_string(&new_wallet_sig).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str() , "\', \'merch_data\':\'", serde_json::to_string(&deserialized_merchant_data).unwrap().as_str(), "\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-03 14:43:20 -08:00
|
|
|
pub extern fn ffishim_bidirectional_pay_by_customer_final(serialized_pp: *mut c_char, serialized_merchant_public_key: *mut c_char, serialized_customer_data: /* make mut */ *mut c_char, serialized_channel_token: *mut c_char, serialized_new_wallet: *mut c_char, serialized_new_wallet_sig: *mut c_char) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-03-03 14:43:20 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_public_key: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-26 11:52:47 -08:00
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel token
|
|
|
|
let bytes_channel_token = unsafe { CStr::from_ptr(serialized_channel_token).to_bytes() };
|
|
|
|
let name_channel_token: &str = str::from_utf8(bytes_channel_token).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_channel_token: bidirectional::ChannelToken = serde_json::from_str(&name_channel_token).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the new wallet
|
|
|
|
let bytes_new_wallet = unsafe { CStr::from_ptr(serialized_new_wallet).to_bytes() };
|
|
|
|
let name_new_wallet: &str = str::from_utf8(bytes_new_wallet).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_new_wallet: bidirectional::CustomerWallet = serde_json::from_str(&name_new_wallet).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the new wallet sig
|
|
|
|
let bytes_new_wallet_sig = unsafe { CStr::from_ptr(serialized_new_wallet_sig).to_bytes() };
|
|
|
|
let name_new_wallet_sig: &str = str::from_utf8(bytes_new_wallet_sig).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_new_wallet_sig: clsigs::SignatureD = serde_json::from_str(&name_new_wallet_sig).unwrap();
|
|
|
|
|
2019-03-03 14:43:20 -08:00
|
|
|
bidirectional::pay_by_customer_final(&deserialized_pp, &deserialized_merchant_public_key, &mut deserialized_customer_data, deserialized_channel_token, deserialized_new_wallet, deserialized_new_wallet_sig);
|
|
|
|
let ser = ["{\'customer_data\':\'", serde_json::to_string(&deserialized_customer_data).unwrap().as_str(), "\'}"].concat();
|
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
2019-02-26 11:52:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2019-03-03 14:43:20 -08:00
|
|
|
pub extern fn ffishim_bidirectional_customer_refund(serialized_pp: *mut c_char, serialized_channel: *mut c_char, serialized_merchant_public_key: *mut c_char, serialized_wallet: *mut c_char) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant keypair
|
2019-03-03 14:43:20 -08:00
|
|
|
let bytes_pk = unsafe { CStr::from_ptr(serialized_merchant_public_key).to_bytes() };
|
|
|
|
let name_pk: &str = str::from_utf8(bytes_pk).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_public_key: clsigs::PublicKeyD = serde_json::from_str(&name_pk).unwrap();
|
2019-02-26 11:52:47 -08:00
|
|
|
|
|
|
|
// Deserialize the new wallet
|
|
|
|
let bytes_wallet = unsafe { CStr::from_ptr(serialized_wallet).to_bytes() };
|
|
|
|
let name_wallet: &str = str::from_utf8(bytes_wallet).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_wallet: bidirectional::CustomerWallet = serde_json::from_str(&name_wallet).unwrap();
|
|
|
|
|
2019-03-03 14:43:20 -08:00
|
|
|
let rc_c = bidirectional::customer_refund(&deserialized_pp, &deserialized_channel_state, &deserialized_merchant_public_key, &deserialized_wallet);
|
|
|
|
let ser = ["{\'rc_c\':\'", serde_json::to_string(&rc_c).unwrap().as_str(), "\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_bidirectional_merchant_refund(serialized_pp: *mut c_char, serialized_channel: *mut c_char, serialized_channel_token: *mut c_char, serialized_merchant_data: *mut c_char, serialized_channel_closure: *mut c_char, serialized_revoke_token: *mut c_char) -> *mut c_char {
|
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel state
|
|
|
|
let bytes_channel = unsafe { CStr::from_ptr(serialized_channel).to_bytes() };
|
|
|
|
let name_channel: &str = str::from_utf8(bytes_channel).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let mut deserialized_channel_state: bidirectional::ChannelState = serde_json::from_str(&name_channel).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the channel token
|
|
|
|
let bytes_channel_token = unsafe { CStr::from_ptr(serialized_channel_token).to_bytes() };
|
|
|
|
let name_channel_token: &str = str::from_utf8(bytes_channel_token).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_channel_token: bidirectional::ChannelToken = serde_json::from_str(&name_channel_token).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the closure
|
|
|
|
let bytes_channel_closure = unsafe { CStr::from_ptr(serialized_channel_closure).to_bytes() };
|
|
|
|
let name_channel_closure: &str = str::from_utf8(bytes_channel_closure).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_channel_closure: bidirectional::ChannelclosureC = serde_json::from_str(&name_channel_closure).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the revoke_token
|
|
|
|
let bytes_revoke_token = unsafe { CStr::from_ptr(serialized_revoke_token).to_bytes() };
|
|
|
|
let name_revoke_token: &str = str::from_utf8(bytes_revoke_token).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_revoke_token: secp256k1::Signature = serde_json::from_str(&name_revoke_token).unwrap();
|
|
|
|
|
|
|
|
let rc_m = bidirectional::merchant_refute(&deserialized_pp, &mut deserialized_channel_state, &deserialized_channel_token, &deserialized_merchant_data, &deserialized_channel_closure, &deserialized_revoke_token);
|
2019-03-03 14:43:20 -08:00
|
|
|
let ser = ["{\'rc_m\':\'", serde_json::to_string(&rc_m).unwrap().as_str(), "\', \'state\':\'", serde_json::to_string(&deserialized_channel_state).unwrap().as_str(), "\'}"].concat();
|
2019-02-26 11:52:47 -08:00
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
|
|
|
|
2019-03-05 17:05:05 -08:00
|
|
|
#[no_mangle]
|
2019-03-03 14:43:20 -08:00
|
|
|
pub extern fn ffishim_bidirectional_resolve(serialized_pp: *mut c_char, serialized_customer_data: *mut c_char, serialized_merchant_data: *mut c_char, serialized_closure_customer: *mut c_char, serialized_closure_merchant: *mut c_char, serialized_revoke_token: *mut c_char) -> *mut c_char {
|
2019-02-26 11:52:47 -08:00
|
|
|
// Deserialize the pp
|
|
|
|
let bytes_pp = unsafe { CStr::from_ptr(serialized_pp).to_bytes() };
|
|
|
|
let name_pp: &str = str::from_utf8(bytes_pp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_pp: bidirectional::PublicParams = serde_json::from_str(&name_pp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the custdata
|
|
|
|
let bytes_customer_data = unsafe { CStr::from_ptr(serialized_customer_data).to_bytes() };
|
|
|
|
let name_customer_data: &str = str::from_utf8(bytes_customer_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_customer_data: bidirectional::InitCustomerData = serde_json::from_str(&name_customer_data).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant data
|
|
|
|
let bytes_merchant_data = unsafe { CStr::from_ptr(serialized_merchant_data).to_bytes() };
|
|
|
|
let name_merchant_data: &str = str::from_utf8(bytes_merchant_data).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_merchant_data: bidirectional::InitMerchantData = serde_json::from_str(&name_merchant_data).unwrap();
|
|
|
|
|
|
|
|
//TODO handle none()
|
|
|
|
|
|
|
|
// Deserialize the client closure
|
|
|
|
let bytes_closure_customer = unsafe { CStr::from_ptr(serialized_closure_customer).to_bytes() };
|
|
|
|
let name_closure_customer: &str = str::from_utf8(bytes_closure_customer).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_closure_customer: bidirectional::ChannelclosureC = serde_json::from_str(&name_closure_customer).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the merchant closure
|
|
|
|
let bytes_closure_merchant = unsafe { CStr::from_ptr(serialized_closure_merchant).to_bytes() };
|
|
|
|
let name_closure_merchant: &str = str::from_utf8(bytes_closure_merchant).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_closure_merchant: bidirectional::ChannelclosureM = serde_json::from_str(&name_closure_merchant).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the revoke_token
|
|
|
|
let bytes_revoke_token = unsafe { CStr::from_ptr(serialized_revoke_token).to_bytes() };
|
|
|
|
let name_revoke_token: &str = str::from_utf8(bytes_revoke_token).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_revoke_token: clsigs::SignatureD = serde_json::from_str(&name_revoke_token).unwrap();
|
|
|
|
|
|
|
|
let (new_b0_cust, new_b0_merch) = bidirectional::resolve(&deserialized_pp, &deserialized_customer_data, &deserialized_merchant_data, Some(deserialized_closure_customer), Some(deserialized_closure_merchant), Some(deserialized_revoke_token));
|
2019-03-03 14:43:20 -08:00
|
|
|
let ser = ["{\'new_b0_cust\':\'", new_b0_cust.to_string().as_str(), "\', \'new_b0_merch\':\'", new_b0_merch.to_string().as_str(), "\'}"].concat();
|
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
2019-02-26 11:52:47 -08:00
|
|
|
}
|
|
|
|
|
2019-03-05 17:05:05 -08:00
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn ffishim_commit_scheme_decommit(serialized_csp: *mut c_char, serialized_commitment: *mut c_char, serialized_x: *mut c_char) -> *mut c_char {
|
|
|
|
// Deserialize the csp
|
|
|
|
let bytes_csp = unsafe { CStr::from_ptr(serialized_csp).to_bytes() };
|
|
|
|
let name_csp: &str = str::from_utf8(bytes_csp).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_csp: commit_scheme::CSParams = serde_json::from_str(&name_csp).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the commit
|
|
|
|
let bytes_commitment = unsafe { CStr::from_ptr(serialized_commitment).to_bytes() };
|
|
|
|
let name_commitment: &str = str::from_utf8(bytes_commitment).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_commitment: commit_scheme::Commitment = serde_json::from_str(&name_commitment).unwrap();
|
|
|
|
|
|
|
|
// Deserialize the vec<fr> x
|
|
|
|
let bytes_x = unsafe { CStr::from_ptr(serialized_x).to_bytes() };
|
|
|
|
let name_x: &str = str::from_utf8(bytes_x).unwrap(); // make sure the bytes are UTF-8
|
|
|
|
let deserialized_x: serialization_wrappers::VecFrWrapper = serde_json::from_str(&name_x).unwrap();
|
|
|
|
// Wrapper struct is required because Serde needs something to annotate
|
|
|
|
|
|
|
|
let ser = match commit_scheme::decommit(&deserialized_csp, &deserialized_commitment, &deserialized_x.0) {
|
|
|
|
false => "{\'return_value\':\'false\'}",
|
|
|
|
true => "{\'return_value\':\'true\'}",
|
|
|
|
};
|
|
|
|
let cser = CString::new(ser).unwrap();
|
|
|
|
cser.into_raw()
|
|
|
|
}
|
2019-02-19 09:01:51 -08:00
|
|
|
}
|
|
|
|
|
2018-07-24 18:42:07 -07:00
|
|
|
#[cfg(all(test, feature = "unstable"))]
|
|
|
|
mod benches {
|
|
|
|
use rand::{Rng, thread_rng};
|
|
|
|
use test::{Bencher, black_box};
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
pub fn bench_one(bh: &mut Bencher) {
|
2018-07-24 21:56:41 -07:00
|
|
|
println!("Run benchmark tests here!");
|
2018-07-24 18:42:07 -07:00
|
|
|
}
|
|
|
|
}
|
2018-07-25 19:19:03 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
2018-08-14 10:00:44 -07:00
|
|
|
#[ignore]
|
2018-07-25 19:19:03 -07:00
|
|
|
fn unidirectional_payment_basics_work() {
|
|
|
|
// TODO: finish me
|
2018-08-14 10:00:44 -07:00
|
|
|
assert!(true);
|
2018-07-25 19:19:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn setup_new_channel_helper(pp: &bidirectional::PublicParams, channel: &mut bidirectional::ChannelState,
|
|
|
|
init_cust_bal: i32, init_merch_bal: i32)
|
|
|
|
-> (clsigs::KeyPairD, bidirectional::InitMerchantData,
|
|
|
|
clsigs::KeyPairD, bidirectional::InitCustomerData) {
|
|
|
|
|
|
|
|
let b0_cust = init_cust_bal;
|
|
|
|
let b0_merch = init_merch_bal;
|
|
|
|
|
|
|
|
// generate long-lived keypair for merchant -- used to identify
|
2018-08-24 00:31:46 -07:00
|
|
|
// merchant to all customers
|
2018-07-25 19:19:03 -07:00
|
|
|
let merch_keys = bidirectional::keygen(&pp);
|
|
|
|
|
2018-08-15 00:47:02 -07:00
|
|
|
// customer generates an ephemeral keypair for use on a single channel
|
2018-07-25 19:19:03 -07:00
|
|
|
let cust_keys = bidirectional::keygen(&pp);
|
|
|
|
|
|
|
|
// each party executes the init algorithm on the agreed initial challenge balance
|
|
|
|
// in order to derive the channel tokens
|
|
|
|
// initialize on the merchant side with balance: b0_merch
|
|
|
|
let merch_data = bidirectional::init_merchant(&pp, b0_merch, &merch_keys);
|
|
|
|
|
|
|
|
// retrieve commitment setup params (using merchant long lived pk params)
|
|
|
|
let cm_csp = bidirectional::generate_commit_setup(&pp, &merch_keys.pk);
|
|
|
|
// initialize on the customer side with balance: b0_cust
|
2019-02-13 06:39:22 -08:00
|
|
|
let cust_data = bidirectional::init_customer(&pp, channel,
|
2018-07-25 19:19:03 -07:00
|
|
|
b0_cust, b0_merch,
|
|
|
|
&cm_csp, &cust_keys);
|
|
|
|
return (merch_keys, merch_data, cust_keys, cust_data);
|
|
|
|
}
|
|
|
|
|
2018-07-30 00:06:06 -07:00
|
|
|
fn setup_new_channel_existing_merchant_helper(pp: &bidirectional::PublicParams, channel: &mut bidirectional::ChannelState,
|
|
|
|
init_cust_bal: i32, init_merch_bal: i32, merch_keys: &clsigs::KeyPairD)
|
|
|
|
-> (bidirectional::InitMerchantData, clsigs::KeyPairD, bidirectional::InitCustomerData) {
|
|
|
|
|
|
|
|
let b0_cust = init_cust_bal;
|
|
|
|
let b0_merch = init_merch_bal;
|
|
|
|
|
2018-08-15 00:47:02 -07:00
|
|
|
// customer generates an ephemeral keypair for use on a single channel
|
2018-07-30 00:06:06 -07:00
|
|
|
let cust_keys = bidirectional::keygen(&pp);
|
|
|
|
|
|
|
|
// each party executes the init algorithm on the agreed initial challenge balance
|
|
|
|
// in order to derive the channel tokens
|
|
|
|
// initialize on the merchant side with balance: b0_merch
|
|
|
|
let merch_data = bidirectional::init_merchant(&pp, b0_merch, &merch_keys);
|
|
|
|
|
|
|
|
// retrieve commitment setup params (using merchant long lived pk params)
|
|
|
|
let cm_csp = bidirectional::generate_commit_setup(&pp, &merch_keys.pk);
|
|
|
|
// initialize on the customer side with balance: b0_cust
|
2019-02-13 06:39:22 -08:00
|
|
|
let cust_data = bidirectional::init_customer(&pp, channel,
|
2018-07-30 00:06:06 -07:00
|
|
|
b0_cust, b0_merch,
|
|
|
|
&cm_csp, &cust_keys);
|
|
|
|
return (merch_data, cust_keys, cust_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn execute_establish_protocol_helper(pp: &bidirectional::PublicParams, channel: &mut bidirectional::ChannelState,
|
|
|
|
merch_keys: &clsigs::KeyPairD, merch_data: &mut bidirectional::InitMerchantData,
|
|
|
|
cust_keys: &clsigs::KeyPairD, cust_data: &mut bidirectional::InitCustomerData) {
|
|
|
|
// entering the establish protocol for the channel
|
2018-08-15 07:28:46 -07:00
|
|
|
let proof = bidirectional::establish_customer_phase1(&pp, &cust_data, &merch_data.bases);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
|
|
|
// obtain the wallet signature from the merchant
|
|
|
|
let wallet_sig = bidirectional::establish_merchant_phase2(&pp, channel, &merch_data, &proof);
|
|
|
|
|
|
|
|
// complete channel establishment
|
|
|
|
assert!(bidirectional::establish_customer_final(&pp, &merch_keys.pk, &mut cust_data.csk, wallet_sig));
|
|
|
|
}
|
|
|
|
|
2018-07-25 19:19:03 -07:00
|
|
|
// pp, channel, merch_keys, merch_data, cust_keys, cust_data, pay_increment
|
|
|
|
fn execute_pay_protocol_helper(pp: &bidirectional::PublicParams, channel: &mut bidirectional::ChannelState,
|
|
|
|
merch_keys: &clsigs::KeyPairD, merch_data: &mut bidirectional::InitMerchantData,
|
|
|
|
cust_keys: &clsigs::KeyPairD, cust_data: &mut bidirectional::InitCustomerData,
|
|
|
|
payment_increment: i32) {
|
|
|
|
// let's test the pay protocol
|
2018-08-16 15:05:01 -07:00
|
|
|
bidirectional::pay_by_customer_phase1_precompute(&pp, &cust_data.channel_token, &merch_keys.pk, &mut cust_data.csk);
|
2018-07-25 19:59:47 -07:00
|
|
|
|
2018-08-16 15:05:01 -07:00
|
|
|
let (t_c, new_wallet, pay_proof) = bidirectional::pay_by_customer_phase1(&pp, &channel, &cust_data.channel_token, // channel token
|
2018-07-25 19:19:03 -07:00
|
|
|
&merch_keys.pk, // merchant pub key
|
|
|
|
&cust_data.csk, // wallet
|
|
|
|
payment_increment); // balance increment (FUNC INPUT)
|
|
|
|
|
|
|
|
// get the refund token (rt_w)
|
|
|
|
let rt_w = bidirectional::pay_by_merchant_phase1(&pp, channel, &pay_proof, &merch_data);
|
|
|
|
|
|
|
|
// get the revocation token (rv_w) on the old public key (wpk)
|
|
|
|
let rv_w = bidirectional::pay_by_customer_phase2(&pp, &cust_data.csk, &new_wallet, &merch_keys.pk, &rt_w);
|
|
|
|
|
|
|
|
// get the new wallet sig (new_wallet_sig) on the new wallet
|
|
|
|
let new_wallet_sig = bidirectional::pay_by_merchant_phase2(&pp, channel, &pay_proof, merch_data, &rv_w);
|
|
|
|
|
|
|
|
assert!(bidirectional::pay_by_customer_final(&pp, &merch_keys.pk, cust_data, t_c, new_wallet, new_wallet_sig));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bidirectional_payment_basics_work() {
|
2018-07-29 17:44:08 -07:00
|
|
|
let pp = bidirectional::setup(true);
|
2018-07-25 19:19:03 -07:00
|
|
|
|
2018-07-30 00:06:06 -07:00
|
|
|
// just bidirectional case (w/o third party)
|
|
|
|
let mut channel = bidirectional::ChannelState::new(String::from("Channel A -> B"), false);
|
2018-07-25 19:19:03 -07:00
|
|
|
let total_owed = 40;
|
|
|
|
let b0_customer = 90;
|
|
|
|
let b0_merchant = 20;
|
|
|
|
let payment_increment = 20;
|
|
|
|
|
|
|
|
//let msg = "Open Channel ID: ";
|
|
|
|
//libbolt::debug_elem_in_hex(msg, &channel.cid);
|
|
|
|
|
|
|
|
let (merch_keys, mut merch_data, cust_keys, mut cust_data) = setup_new_channel_helper(&pp, &mut channel, b0_customer, b0_merchant);
|
|
|
|
|
2018-07-30 00:06:06 -07:00
|
|
|
// run establish protocol for customer and merchant channel
|
|
|
|
execute_establish_protocol_helper(&pp, &mut channel, &merch_keys, &mut merch_data, &cust_keys, &mut cust_data);
|
2018-07-25 19:19:03 -07:00
|
|
|
|
|
|
|
assert!(channel.channel_established);
|
|
|
|
|
|
|
|
{
|
|
|
|
// make multiple payments in a loop
|
|
|
|
let num_payments = total_owed / payment_increment;
|
|
|
|
for i in 0 .. num_payments {
|
|
|
|
execute_pay_protocol_helper(&pp, &mut channel, &merch_keys, &mut merch_data, &cust_keys, &mut cust_data, payment_increment);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// scope localizes the immutable borrow here (for debug purposes only)
|
|
|
|
let cust_wallet = &cust_data.csk;
|
|
|
|
let merch_wallet = &merch_data.csk;
|
|
|
|
println!("Customer balance: {}", cust_wallet.balance);
|
|
|
|
println!("Merchant balance: {}", merch_wallet.balance);
|
|
|
|
assert!(cust_wallet.balance == (b0_customer - total_owed) && merch_wallet.balance == total_owed + b0_merchant);
|
|
|
|
}
|
|
|
|
|
|
|
|
let cust_wallet = &cust_data.csk;
|
|
|
|
// get channel closure message
|
|
|
|
let rc_c = bidirectional::customer_refund(&pp, &channel, &merch_keys.pk, &cust_wallet);
|
|
|
|
println!("Obtained the channel closure message: {}", rc_c.message.msgtype);
|
|
|
|
}
|
2018-07-30 00:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bidirectional_payment_negative_payment_works() {
|
|
|
|
let pp = bidirectional::setup(true);
|
|
|
|
|
|
|
|
// just bidirectional case (w/o third party)
|
2018-08-24 00:31:46 -07:00
|
|
|
let mut channel = bidirectional::ChannelState::new(String::from("Channel A <-> B"), false);
|
2018-07-30 00:06:06 -07:00
|
|
|
let total_owed = -20;
|
|
|
|
let b0_customer = 90;
|
|
|
|
let b0_merchant = 30;
|
|
|
|
let payment_increment = -20;
|
|
|
|
|
|
|
|
//let msg = "Open Channel ID: ";
|
|
|
|
//libbolt::debug_elem_in_hex(msg, &channel.cid);
|
|
|
|
|
|
|
|
let (merch_keys, mut merch_data, cust_keys, mut cust_data) = setup_new_channel_helper(&pp, &mut channel, b0_customer, b0_merchant);
|
|
|
|
|
|
|
|
// run establish protocol for customer and merchant channel
|
|
|
|
execute_establish_protocol_helper(&pp, &mut channel, &merch_keys, &mut merch_data, &cust_keys, &mut cust_data);
|
|
|
|
println!("Initial Customer balance: {}", cust_data.csk.balance);
|
|
|
|
println!("Initial Merchant balance: {}", merch_data.csk.balance);
|
|
|
|
|
|
|
|
assert!(channel.channel_established);
|
|
|
|
|
|
|
|
{
|
|
|
|
// make multiple payments in a loop
|
|
|
|
execute_pay_protocol_helper(&pp, &mut channel, &merch_keys, &mut merch_data, &cust_keys, &mut cust_data, payment_increment);
|
|
|
|
|
|
|
|
{
|
|
|
|
// scope localizes the immutable borrow here (for debug purposes only)
|
|
|
|
let cust_wallet = &cust_data.csk;
|
|
|
|
let merch_wallet = &merch_data.csk;
|
|
|
|
println!("Customer balance: {}", cust_wallet.balance);
|
|
|
|
println!("Merchant balance: {}", merch_wallet.balance);
|
|
|
|
assert!(cust_wallet.balance == (b0_customer - total_owed) && merch_wallet.balance == total_owed + b0_merchant);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute_third_party_pay_protocol_helper(pp: &bidirectional::PublicParams,
|
|
|
|
channel1: &mut bidirectional::ChannelState, channel2: &mut bidirectional::ChannelState,
|
|
|
|
merch_keys: &clsigs::KeyPairD, merch1_data: &mut bidirectional::InitMerchantData,
|
|
|
|
merch2_data: &mut bidirectional::InitMerchantData,
|
|
|
|
cust1_keys: &clsigs::KeyPairD, cust1_data: &mut bidirectional::InitCustomerData,
|
|
|
|
cust2_keys: &clsigs::KeyPairD, cust2_data: &mut bidirectional::InitCustomerData,
|
|
|
|
payment_increment: i32) {
|
|
|
|
// let's test the pay protocol
|
2018-08-16 15:05:01 -07:00
|
|
|
bidirectional::pay_by_customer_phase1_precompute(&pp, &cust1_data.channel_token, &merch_keys.pk, &mut cust1_data.csk);
|
|
|
|
bidirectional::pay_by_customer_phase1_precompute(&pp, &cust2_data.channel_token, &merch_keys.pk, &mut cust2_data.csk);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
println!("Channel 1 fee: {}", channel1.get_channel_fee());
|
|
|
|
let (t_c1, new_wallet1, pay_proof1) = bidirectional::pay_by_customer_phase1(&pp, &channel1,
|
2018-08-16 15:05:01 -07:00
|
|
|
&cust1_data.channel_token, // channel token
|
2018-07-30 00:06:06 -07:00
|
|
|
&merch_keys.pk, // merchant pub key
|
|
|
|
&cust1_data.csk, // wallet
|
2018-08-13 15:16:02 -07:00
|
|
|
payment_increment); // balance increment
|
|
|
|
println!("Channel 2 fee: {}", channel2.get_channel_fee());
|
|
|
|
let (t_c2, new_wallet2, pay_proof2) = bidirectional::pay_by_customer_phase1(&pp, &channel2,
|
2018-08-16 15:05:01 -07:00
|
|
|
&cust2_data.channel_token, // channel token
|
2018-07-30 00:06:06 -07:00
|
|
|
&merch_keys.pk, // merchant pub key
|
|
|
|
&cust2_data.csk, // wallet
|
2018-08-13 15:16:02 -07:00
|
|
|
-payment_increment); // balance decrement
|
|
|
|
|
|
|
|
// validate pay_proof1 and pay_proof2 (and the channel state for the fee paying channel, if fee > 0)
|
|
|
|
let tx_fee = channel1.get_channel_fee() + channel2.get_channel_fee();
|
|
|
|
assert!(bidirectional::verify_third_party_payment(&pp, tx_fee, &pay_proof1.bal_proof, &pay_proof2.bal_proof));
|
2018-07-25 19:19:03 -07:00
|
|
|
|
2018-07-30 00:06:06 -07:00
|
|
|
// get the refund token (rt_w)
|
|
|
|
let rt_w1 = bidirectional::pay_by_merchant_phase1(&pp, channel1, &pay_proof1, &merch1_data);
|
|
|
|
|
|
|
|
// get the refund token (rt_w)
|
|
|
|
let rt_w2 = bidirectional::pay_by_merchant_phase1(&pp, channel2, &pay_proof2, &merch2_data);
|
|
|
|
|
|
|
|
// get the revocation token (rv_w) on the old public key (wpk)
|
|
|
|
let rv_w1 = bidirectional::pay_by_customer_phase2(&pp, &cust1_data.csk, &new_wallet1, &merch_keys.pk, &rt_w1);
|
|
|
|
|
|
|
|
// get the revocation token (rv_w) on the old public key (wpk)
|
|
|
|
let rv_w2 = bidirectional::pay_by_customer_phase2(&pp, &cust2_data.csk, &new_wallet2, &merch_keys.pk, &rt_w2);
|
|
|
|
|
|
|
|
// get the new wallet sig (new_wallet_sig) on the new wallet
|
|
|
|
let new_wallet_sig1 = bidirectional::pay_by_merchant_phase2(&pp, channel1, &pay_proof1, merch1_data, &rv_w1);
|
|
|
|
|
|
|
|
// get the new wallet sig (new_wallet_sig) on the new wallet
|
|
|
|
let new_wallet_sig2 = bidirectional::pay_by_merchant_phase2(&pp, channel2, &pay_proof2, merch2_data, &rv_w2);
|
|
|
|
|
|
|
|
assert!(bidirectional::pay_by_customer_final(&pp, &merch_keys.pk, cust1_data, t_c1, new_wallet1, new_wallet_sig1));
|
|
|
|
|
|
|
|
assert!(bidirectional::pay_by_customer_final(&pp, &merch_keys.pk, cust2_data, t_c2, new_wallet2, new_wallet_sig2));
|
2018-07-25 19:19:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn third_party_payment_basics_work() {
|
2018-07-30 00:06:06 -07:00
|
|
|
let pp = bidirectional::setup(true);
|
|
|
|
|
|
|
|
// third party -- so indicate so in the channel state
|
2018-08-24 00:31:46 -07:00
|
|
|
let mut channel_a = bidirectional::ChannelState::new(String::from("Channel A <-> I"), true);
|
|
|
|
let mut channel_b = bidirectional::ChannelState::new(String::from("Channel B <-> I"), true);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
2018-08-13 15:16:02 -07:00
|
|
|
let fee = 2;
|
2018-08-16 23:00:02 -07:00
|
|
|
channel_a.set_channel_fee(fee);
|
2018-08-13 15:16:02 -07:00
|
|
|
|
2018-07-30 00:06:06 -07:00
|
|
|
let total_payment = 20;
|
2018-08-13 15:16:02 -07:00
|
|
|
let b0_alice = 30;
|
|
|
|
let b0_bob = 30;
|
2018-08-16 23:00:02 -07:00
|
|
|
let b0_merchant_a = 40;
|
|
|
|
let b0_merchant_b = 40;
|
2018-07-30 00:06:06 -07:00
|
|
|
|
2018-08-16 23:00:02 -07:00
|
|
|
let (merch_keys, mut merch_data_a, alice_keys, mut alice_data) = setup_new_channel_helper(&pp, &mut channel_a, b0_alice, b0_merchant_a);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
2018-08-16 23:00:02 -07:00
|
|
|
let (mut merch_data_b, bob_keys, mut bob_data) =
|
|
|
|
setup_new_channel_existing_merchant_helper(&pp, &mut channel_b, b0_bob, b0_merchant_b, &merch_keys);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
|
|
|
// run establish protocol for alice and merchant channel
|
2018-08-16 23:00:02 -07:00
|
|
|
execute_establish_protocol_helper(&pp, &mut channel_a, &merch_keys, &mut merch_data_a, &alice_keys, &mut alice_data);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
|
|
|
// run establish protocol for bob and merchant channel
|
2018-08-16 23:00:02 -07:00
|
|
|
execute_establish_protocol_helper(&pp, &mut channel_b, &merch_keys, &mut merch_data_b, &bob_keys, &mut bob_data);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
2018-08-16 23:00:02 -07:00
|
|
|
assert!(channel_a.channel_established);
|
|
|
|
assert!(channel_b.channel_established);
|
2018-07-30 00:06:06 -07:00
|
|
|
|
|
|
|
// alice can pay bob through the merchant
|
2018-08-16 23:00:02 -07:00
|
|
|
execute_third_party_pay_protocol_helper(&pp, &mut channel_a, &mut channel_b,
|
|
|
|
&merch_keys, &mut merch_data_a, &mut merch_data_b,
|
2018-07-30 00:06:06 -07:00
|
|
|
&alice_keys, &mut alice_data, &bob_keys, &mut bob_data, total_payment);
|
|
|
|
|
|
|
|
println!("Customer alice balance: {}", alice_data.csk.balance);
|
2018-08-16 23:00:02 -07:00
|
|
|
println!("Merchant channel balance with alice: {}", merch_data_a.csk.balance);
|
2018-07-30 00:06:06 -07:00
|
|
|
println!("Customer bob balance: {}", bob_data.csk.balance);
|
2018-08-16 23:00:02 -07:00
|
|
|
println!("Merchant channel balance with bob: {}", merch_data_b.csk.balance);
|
2018-07-25 19:19:03 -07:00
|
|
|
}
|
|
|
|
|
2019-03-05 17:05:05 -08:00
|
|
|
#[test]
|
|
|
|
#[ignore]
|
|
|
|
fn serialization_tests() {
|
|
|
|
// TODO: finish me
|
|
|
|
assert!(true);
|
|
|
|
}
|
|
|
|
|
2018-08-10 00:01:50 -07:00
|
|
|
}
|