reimplementing channel guts - almost done

This commit is contained in:
J. Ayo Akinyele 2019-07-19 16:26:05 -04:00
parent 7c26f40685
commit 79d1e25b4d
11 changed files with 363 additions and 6 deletions

292
src/channels.rs Normal file
View File

@ -0,0 +1,292 @@
/*
* Implement for Bolt protocols:
* - initializing channel state and generating cust/merch wallets (almost done)
* - establish protocol (WIP)
* - pay protocol (WIP)
* - channel close algorithms (WIP)
*/
extern crate pairing;
extern crate rand;
use super::*;
use pairing::{Engine, CurveProjective};
use pairing::bls12_381::{Bls12};
use cl::{BlindKeyPair, KeyPair, Signature, PublicParams, setup};
use ped92::{CSParams, Commitment, CSMultiParams};
use util::{hash_pubkey_to_fr, convert_int_to_fr};
use rand::Rng;
use std::collections::HashMap;
use std::fmt::Display;
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize)]
struct PubKeyMap {
wpk: secp256k1::PublicKey,
revoke_token: Option<secp256k1::Signature>
}
//#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone)]
pub struct ChannelParams<E: Engine> {
pub cl_mpk: cl::PublicParams<E>,
l: usize, // messages for commitment
range_proof_bits: usize,
extra_verify: bool // extra verification for certain points in the establish/pay protocol
}
//#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone)]
pub struct ChannelState<E: Engine> {
keys: HashMap<String, PubKeyMap>,
R: i32,
tx_fee: i32,
pub cp: Option<ChannelParams<E>>,
pub name: String,
pub pay_init: bool,
pub channel_established: bool,
pub third_party: bool
}
#[derive(Clone)]
pub struct ChannelToken<E: Engine> {
pub pk_c: Option<secp256k1::PublicKey>, // pk_c
pub blind_pk_m: cl::BlindPublicKey<E>, // PK_m
pub pk_m: secp256k1::PublicKey, // pk_m
pub comParams: CSMultiParams<E>,
is_initialized: bool
}
impl<E: Engine> ChannelToken<E> {
pub fn is_init(&mut self) -> bool {
return self.is_initialized
}
pub fn set_customer_pk(&mut self, pk_c: &secp256k1::PublicKey) {
self.pk_c = Some(pk_c.clone());
self.is_initialized = true;
}
}
// add methods to check if channel token is initialized
// (only if
///
/// Channel state for generating/loading channel parameters and generating keypairs
///
impl<E: Engine> ChannelState<E> {
pub fn new(name: String, third_party_support: bool) -> ChannelState<E> {
ChannelState {
keys: HashMap::new(), // store wpks/revoke_tokens
R: 0,
tx_fee: 0,
cp: None,
name: name.to_string(),
pay_init: false,
channel_established: false,
third_party: third_party_support
}
}
pub fn init() {
sodiumoxide::init();
}
///
/// setup - generate public parameters for bidirectional payment channels
///
pub fn setup<R: Rng>(&mut self, csprng: &mut R) {
let cl_mpk = cl::setup(csprng);
let l = 4;
let n = 32; // bitsize: 32-bit (0, 2^32-1)
let num_rand_values = 1;
let cp = ChannelParams { cl_mpk: cl_mpk, l: l, range_proof_bits: n, extra_verify: true };
self.cp = Some(cp);
}
///
/// keygen - takes as input public parameters and generates a digital signature keypair
///
pub fn keygen<R: Rng>(&mut self, csprng: &mut R, id: String) -> cl::BlindKeyPair<E> {
let cp = self.cp.as_ref();
let keypair = BlindKeyPair::<E>::generate(csprng, &cp.unwrap().cl_mpk, cp.unwrap().l);
println!("Generating keypair for '{}'", id);
// print the keypair as well
return keypair;
}
pub fn load_params(&mut self, cp: &ChannelParams<E>) {
// load external params
}
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;
}
}
///
/// Customer wallet consists of a keypair (NEW)
///
pub struct CustomerWallet<E: Engine> {
pk_c: secp256k1::PublicKey,
sk_c: secp256k1::SecretKey,
cust_balance: i32, //
merch_balance: i32,
wpk: secp256k1::PublicKey, // keypair bound to the wallet
wsk: secp256k1::SecretKey,
r: E::Fr, // randomness used to form the commitment
w_com: Commitment<E> // commitment to the current state of the wallet
}
impl<E: Engine> CustomerWallet<E> {
pub fn new<R: Rng>(csprng: &mut R, channel: &mut ChannelState<E>, channel_token: &mut ChannelToken<E>, cust_bal: i32, merch_bal: i32) -> Self {
assert!(!channel_token.is_init());
let mut kp = secp256k1::Secp256k1::new();
kp.randomize(csprng);
// generate the keypair for the channel
let (sk_c, pk_c) = kp.generate_keypair(csprng);
// generate the keypair for the initial wallet
let (wsk, wpk) = kp.generate_keypair(csprng);
// hash the wallet pub key
let wpk_h = hash_pubkey_to_fr::<E>(&wpk);
// hash the channel pub key
let pk_h = hash_pubkey_to_fr::<E>(&pk_c);
// convert balance into Fr
let cust_b0 = convert_int_to_fr::<E>(cust_bal);
let merch_b0 = convert_int_to_fr::<E>(merch_bal);
// randomness for commitment
let r = E::Fr::rand(csprng);
// initialize wallet vector
let wallet: Vec<E::Fr> = vec! {pk_h, wpk_h, cust_b0, merch_b0};
let w_com = channel_token.comParams.commit(&wallet, &r);
channel_token.set_customer_pk(&pk_c);
assert!(channel_token.is_init());
println!("Customer wallet formed -> now returning the structure to the caller.");
return CustomerWallet {
pk_c: pk_c,
sk_c: sk_c,
cust_balance: cust_bal,
merch_balance: merch_bal,
wpk: wpk,
wsk: wsk,
r: r,
w_com: w_com
}
}
pub fn generate_proof(&mut self, csprng: &mut R) {
}
}
///
/// Merchant wallet (NEW)
///
pub struct MerchantWallet<E: Engine> {
keypair: cl::BlindKeyPair<E>,
balance: i32,
pk: secp256k1::PublicKey, // pk_m
sk: secp256k1::SecretKey, // sk_m
comParams: CSMultiParams<E>
}
impl<E: Engine> MerchantWallet<E> {
pub fn new<R: Rng>(csprng: &mut R, channel: &mut ChannelState<E>, id: String) -> Self {
// generate keys here
let kp = channel.keygen(csprng, id);
let mut tx_kp = secp256k1::Secp256k1::new();
tx_kp.randomize(csprng);
let (wsk, wpk) = tx_kp.generate_keypair(csprng);
let cp = channel.cp.as_ref().unwrap(); // if not set, then panic!
let com_params = kp.generate_cs_multi_params(&cp.cl_mpk);
MerchantWallet {
keypair: kp,
balance: 0,
pk: wpk,
sk: wsk,
comParams: com_params
}
}
pub fn init<R: Rng>(&mut self, csprng: &mut R, channel: &mut ChannelState<E>) -> ChannelToken<E> {
return ChannelToken {
pk_c: None,
blind_pk_m: self.keypair.public.clone(),
pk_m: self.pk.clone(),
comParams: self.comParams.clone(),
is_initialized: false
}
}
}
//trait CustomerEstablishChannel<E: Engine> {
// // customer generates initial commitment for wallet and send to merchant
// fn init_wallet_open() -> CommitmentProof;
// // customer obtains the close signature for wallet
// fn verify_close_sig_phase2() -> bool;
//}
//
//trait MerchantEstablishChannel<E: Engine> {
// // verifies the commitment proof and channel token
// fn init_wallet_close() -> cl::Signature<E>;
// fn generate_pay_token_phase2() -> cl::Signature<E>;
//}
#[cfg(test)]
mod tests {
use super::*;
use ff::Rand;
use pairing::bls12_381::{Bls12};
use rand::{SeedableRng};
use rand_xorshift::XorShiftRng;
#[test]
fn init_channel() {
println!("Initializing channels...");
let mut channel = ChannelState::<Bls12>::new(String::from("Channel A <-> B"), false);
let mut rng = &mut rand::thread_rng();
// run setup to generate the public parameters
channel.setup(&mut rng); // or load_setup params
// generate keys for each party
// let cust_kp = channel.keygen(rng,String::from("Customer A"));
let b0_cust = 100;
let b0_merch = 20;
// 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 mut merch_wallet = MerchantWallet::<Bls12>::new(rng, &mut channel, String::from("Merchant B"));
// initialize the merchant wallet with the balance
let mut channel_token = merch_wallet.init(rng, &mut channel);
// retrieve commitment setup params (using merchant long lived pk params)
// initialize on the customer side with balance: b0_cust
let mut cust_wallet = CustomerWallet::<Bls12>::new(rng, &mut channel, &mut channel_token, b0_cust, b0_merch);
// lets establish the channel
let cust_init_proof = cust_wallet.generate_proof(rng);
println!("Done!");
}
}

View File

@ -8,6 +8,7 @@ use pairing::{CurveAffine, CurveProjective, Engine};
use ff::PrimeField;
use rand::Rng;
use ped92::{Commitment, CSMultiParams};
use std::fmt::LowerHex;
#[derive(Clone)]
pub struct PublicParams<E: Engine> {
@ -21,13 +22,33 @@ pub struct SecretKey<E: Engine> {
pub y: Vec<E::Fr>
}
//#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone)]
#[derive(Clone, Serialize, Deserialize)]
pub struct PublicKey<E: Engine> {
pub X: E::G2,
pub Y: Vec<E::G2>,
}
impl<E: Engine> fmt::Display for PublicKey<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//let y_vec: Vec<u8> = encode(&self.Y, Infinite).unwrap();
//let comp_x = self.X.into_compressed();
let mut x_vec: Vec<u8> = Vec::new();
x_vec.extend(format!("{:}", &self.X).bytes());
let mut x_s = String::new();
for x in x_vec.iter() {
x_s = format!("{} {:x}", x_s, x);
}
// let mut y_s = String::new();
// for y in y_vec.iter() {
// y_s = format!("{}{:x}", y_s, y);
// }
write!(f, "PK : (X=0x{}, Y=0x[TODO])", x_s)
}
}
//#[derive(Clone, Serialize, Deserialize)]
#[derive(Clone)]
pub struct BlindPublicKey<E: Engine> {
@ -445,6 +466,7 @@ mod tests {
use ped92::CSMultiParams;
#[test]
#[ignore]
fn sign_and_verify() {
// let mut rng = XorShiftRng::seed_from_u64(0xbc4f6d44d62f276c);
// let mut rng = XorShiftRng::seed_from_u64(0xb963afd05455863d);
@ -454,6 +476,8 @@ mod tests {
let mpk = setup(&mut rng);
let keypair = KeyPair::<Bls12>::generate(&mut rng, &mpk, l);
println!("PUBLIC KEY => {}", keypair.public);
let mut message1 : Vec<Fr> = Vec::new();
let mut message2 : Vec<Fr> = Vec::new();
@ -468,6 +492,7 @@ mod tests {
}
#[test]
#[ignore]
fn blind_sign_and_verify() {
let mut rng = &mut rand::thread_rng();
@ -502,6 +527,7 @@ mod tests {
}
#[test]
#[ignore]
fn blind_unblind_works() {
let mut rng = &mut rand::thread_rng();
@ -526,6 +552,7 @@ mod tests {
}
#[test]
#[ignore]
fn blind_sign_and_verify_works() {
let mut rng = &mut rand::thread_rng();

View File

@ -274,6 +274,7 @@ mod tests {
use debug_g2_in_hex;
#[test]
#[ignore]
fn efficient_protocols_for_cl_signatures() {
let rng = &mut rand::thread_rng();

View File

@ -396,6 +396,7 @@ mod tests {
use bn::{Fr, Group};
#[test]
#[ignore]
fn scheme_a_sign_and_verify_works() {
// test ability to sign/verify a single message
let rng = &mut thread_rng();
@ -413,6 +414,7 @@ mod tests {
}
#[test]
#[ignore]
fn scheme_d_sign_and_verify_works() {
// test ability to sign/verify a vector of messages
let rng = &mut thread_rng();

View File

@ -189,6 +189,7 @@ mod tests {
use bn::{Fr, Group};
#[test]
#[ignore]
fn commit_one_message_works() {
let rng = &mut thread_rng();
let pk = ped92_setup();
@ -203,6 +204,7 @@ mod tests {
}
#[test]
#[ignore]
fn commit_n_message_works() {
let rng = &mut thread_rng();
let len = 3;

View File

@ -68,6 +68,7 @@ pub mod clsigs;
pub mod ccs08;
pub mod commit_scheme;
pub mod ped92;
pub mod channels;
pub mod clproto;
pub mod serialization_wrappers;
pub mod nizk;
@ -2141,6 +2142,7 @@ mod tests {
}
#[test]
#[ignore]
fn bidirectional_payment_basics_work() {
let pp = bidirectional::setup(true);
@ -2185,6 +2187,7 @@ mod tests {
}
#[test]
#[ignore]
fn bidirectional_payment_negative_payment_works() {
let pp = bidirectional::setup(true);
@ -2274,6 +2277,7 @@ mod tests {
}
#[test]
#[ignore]
fn third_party_payment_basics_work() {
let pp = bidirectional::setup(true);

View File

@ -44,6 +44,7 @@ mod tests {
use bn::{G1, Group};
#[test]
#[ignore]
fn one_time_enc_dec_works() {
let rng = &mut rand::thread_rng();
@ -57,4 +58,4 @@ mod tests {
assert!(m.m1 == orig_m.m1 && m.m2 == orig_m.m2);
}
}
}

View File

@ -179,6 +179,7 @@ mod tests {
use ff::Field;
#[test]
#[ignore]
fn commit_one_message_works() {
let rng = &mut thread_rng();
let csp = CSParams::<Bls12>::setup(rng);
@ -194,6 +195,7 @@ mod tests {
}
#[test]
#[ignore]
fn commit_n_message_works() {
let rng = &mut thread_rng();
let len = 3;

View File

@ -31,6 +31,7 @@ mod tests {
use bn::{Fr, G1, Group};
#[test]
#[ignore]
fn prf_works() {
let rng = &mut rand::thread_rng();
let s = Fr::random(rng);
@ -43,4 +44,4 @@ mod tests {
// confirm that PRF(k, x) != PRF(k, x+1)
assert!(y != z);
}
}
}

View File

@ -59,6 +59,7 @@ mod tests {
use rand::{Rng, thread_rng};
#[test]
#[ignore]
fn symenc_dec_works() {
init_mod();
// SymKeyEnc tests
@ -79,6 +80,7 @@ mod tests {
#[test]
#[should_panic]
#[ignore]
fn symenc_dec_should_fail() {
init_mod();
// SymKeyEnc tests
@ -94,4 +96,4 @@ mod tests {
let pt3 = decrypt(&key2, &ciphertext);
// should fail and panic
}
}
}

View File

@ -28,6 +28,29 @@ pub fn hash_to_fr<E: Engine>(mut byteVec: Vec<u8>) -> E::Fr {
return result.unwrap();
}
pub fn hash_pubkey_to_fr<E: Engine>(wpk: &secp256k1::PublicKey) -> E::Fr {
let x_slice = wpk.serialize_uncompressed();
let sha2_digest = sha512::hash(&x_slice);
let mut hash_buf: [u8; 64] = [0; 64];
hash_buf.copy_from_slice(&sha2_digest[0..64]);
let hexresult = fmt_bytes_to_int(hash_buf);
let result = E::Fr::from_str(&hexresult);
return result.unwrap();
}
pub fn convert_int_to_fr<E: Engine>(value: i32) -> E::Fr {
if value > 0 {
return E::Fr::from_str(value.to_string().as_str()).unwrap();
} else {
// negative value
let value2 = value * -1;
let res = E::Fr::from_str(value2.to_string().as_str()).unwrap();
// TODO: look at how to do negation
return res;
}
}
#[cfg(test)]
mod tests {
@ -59,4 +82,4 @@ mod tests {
assert_eq!(fmt_bytes_to_int([12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123, 13, 43, 12, 235, 23, 123]),
"122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123134312235231231343122352312313431223523123");
}
}
}