reimplementing channel guts - almost done
This commit is contained in:
parent
7c26f40685
commit
79d1e25b4d
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
31
src/cl.rs
31
src/cl.rs
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
src/util.rs
25
src/util.rs
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue