From 88090174da0b0aacc141c571c5e0021f0d742e51 Mon Sep 17 00:00:00 2001 From: "J. Ayo Akinyele" Date: Sat, 24 Mar 2018 09:44:45 -0400 Subject: [PATCH] finish initial CL04 sigs impl --- .idea/libraries/Cargo__libbolt_.xml | 32 +- bin/bolt.rs | 40 ++- src/lib.rs | 482 +++++++++++++++++++++------- 3 files changed, 425 insertions(+), 129 deletions(-) diff --git a/.idea/libraries/Cargo__libbolt_.xml b/.idea/libraries/Cargo__libbolt_.xml index b1cecb0..f642bd2 100644 --- a/.idea/libraries/Cargo__libbolt_.xml +++ b/.idea/libraries/Cargo__libbolt_.xml @@ -1,28 +1,28 @@ - + + + + + + - - + + + + + + + + + + - - - - - - - - - - - - - diff --git a/bin/bolt.rs b/bin/bolt.rs index 3088d5c..e6df6b4 100644 --- a/bin/bolt.rs +++ b/bin/bolt.rs @@ -3,6 +3,9 @@ extern crate rand; extern crate libbolt; use bn::{Group, Fr, G1, G2, pairing}; +use libbolt::clsigs; +use libbolt::commit_scheme; + fn main() { let rng = &mut rand::thread_rng(); @@ -23,10 +26,41 @@ fn main() { let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk); assert!(alice_ss == bob_ss && bob_ss == carol_ss); - println!("All bn tests succeeded!"); + println!("All bn unit tests succeeded!"); - let pk = libbolt::setup(); + println!("******************************************"); + + // CL sig tests + let mpk = clsigs::setup(); + let keypair = clsigs::keygen(&mpk); + println!("{}", keypair.pk); + + let msg1 = clsigs::Message::new(String::from("refund"), alice_sk, 10); + let msg2 = clsigs::Message::new(String::from("refund"), alice_sk, 12); + let signature = clsigs::sign(&keypair.sk, &msg1); + println!("{}", signature); + assert!(clsigs::verify(&mpk, &keypair.pk, &msg1, &signature) == true); + assert!(clsigs::verify(&mpk, &keypair.pk, &msg2, &signature) == false); + + println!("CL signature verified!"); + + println!("******************************************"); + // commitment scheme tests + let pk = commit_scheme::setup(); + // let sk = libbolt::SecretKeySigs { x: Fr::random(rng), y: Fr::random(rng) }; // let msg = String::from("Hello, World!"); + let msg1 = commit_scheme::Message::new(alice_sk, bob_sk, 10); + let msg2 = commit_scheme::Message::new(alice_sk, bob_sk, 11); + let msg3 = commit_scheme::Message::new(bob_sk, alice_sk, 10); - // let cm = libbolt::commit(pk, msg); + let cm = commit_scheme::commit(&pk, &msg1); + + assert!(commit_scheme::decommit(&pk, &cm, &msg1) == true); + assert!(commit_scheme::decommit(&pk, &cm, &msg2) == false); + assert!(commit_scheme::decommit(&pk, &cm, &msg3) == false); + println!("Commitment scheme works!"); + + println!("******************************************"); + + // TODO: write tests } diff --git a/src/lib.rs b/src/lib.rs index 23c0f69..47214b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,93 +2,69 @@ extern crate bn; extern crate rand; extern crate bincode; extern crate sodiumoxide; + use std::fmt; +use std::str; +use std::default; use bn::{Group, Fr, G1, G2, pairing}; use bincode::SizeLimit::Infinite; use bincode::rustc_serialize::{encode, decode}; -use sodiumoxide::crypto::hash::sha256; - -// define some structures here -pub struct PublicKey { - g: G1, - h: G1 -} - -pub struct Commitment { - c: G1, - d: Fr -} +use sodiumoxide::crypto::hash::sha512; // Begin CL Signature scheme data structures -pub struct PublicKeySigs { - X: G1, - Y: G1 -} - -pub struct SecretKeySigs { - x: Fr, - y: Fr -} // End CL Signature scheme data structures +//pub fn hash_string(s: &str) -> String { +// let digest = sha256::hash(s.as_bytes()); +// format!("{:X}", HexSlice::new(&digest)) +//} +pub fn debug_elem_in_hex(prefix: &str, r: &Fr) { + let encoded: Vec = encode(&r, Infinite).unwrap(); + print!("{} (hex) = 0x", prefix); + for e in encoded.iter() { + print!("{:x}", e); + } + print!("\n"); +} +struct HexSlice<'a>(&'a [u8]); + +impl<'a> HexSlice<'a> { + fn new(data: &'a T) -> HexSlice<'a> + where T: ?Sized + AsRef<[u8]> + 'a + { + HexSlice(data.as_ref()) + } +} + +impl<'a> fmt::LowerHex for HexSlice<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + 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)?; + } + Ok(()) + } +} + +impl<'a> fmt::UpperHex for HexSlice<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + 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)?; + } + Ok(()) + } +} // To hash this message structure, encode each element in the tuple // as a byte stream, then apply a hash on it. Then, convert the output value into // a Fr element. -pub struct Message { - sk_sigs: SecretKeySigs, // the secret key for the signature scheme - k1: Fr, // seed 1 for PRF - k2: Fr, // seed 2 for PRF - balance: i32 // the balance for the user -} - -// TODO: add a function that operates over the Message structure -// TODO: to perform the encodng an hash -impl Message { - fn hash(&self) -> Fr { - let rng = &mut rand::thread_rng(); - let a = Fr::random(rng); - return a; - } -} - -impl fmt::Display for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let g_vec: Vec = encode(&self.g, Infinite).unwrap(); - let h_vec: Vec = encode(&self.h, Infinite).unwrap(); - let mut g_s = String::new(); - for x in g_vec.iter() { - g_s = format!("{}{:x}", g_s, x); - } - - let mut h_s = String::new(); - for y in h_vec.iter() { - h_s = format!("{}{:x}", h_s, y); - } - - write!(f, "PK : (g=0x{}, h=0x{})", g_s, h_s) - } -} - - -impl fmt::Display for Commitment { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let c_vec: Vec = encode(&self.c, Infinite).unwrap(); - let mut c_s = String::new(); - for x in c_vec.iter() { - c_s = format!("{}{:x}", c_s, x); - } - - let d_vec: Vec = encode(&self.d, Infinite).unwrap(); - let mut d_s = String::new(); - for x in d_vec.iter() { - d_s = format!("{}{:x}", d_s, x); - } - write!(f, "Commitment : (c=0x{}, d=0x{})", c_s, d_s) - } -} pub fn misc_tests() { let rng = &mut rand::thread_rng(); @@ -106,45 +82,331 @@ pub fn misc_tests() { } -/* +////////////////////////////////// CL Sigs ///////////////////////////////////// + +pub mod clsigs { + use std::fmt; + use std::str; + use std::default; + use rand; + use bn::{Group, Fr, G1, G2, pairing}; + use debug_elem_in_hex; + use bincode::SizeLimit::Infinite; + use bincode::rustc_serialize::encode; + use sodiumoxide::crypto::hash::sha512; + + pub struct PublicParams { + g: G1 + } + + pub struct PublicKey { + X: G1, + Y: G1 + } + + impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let x_vec: Vec = encode(&self.X, Infinite).unwrap(); + let y_vec: Vec = encode(&self.Y, Infinite).unwrap(); + 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{})", x_s, y_s) + } + } + + pub struct SecretKey { + x: Fr, + y: Fr + } + + pub struct KeyPair { + pub sk: SecretKey, + pub pk: PublicKey + } + + pub struct Signature { + a: G2, + b: G2, + c: G2 + } + + impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let a_vec: Vec = encode(&self.a, Infinite).unwrap(); + let b_vec: Vec = encode(&self.b, Infinite).unwrap(); + let c_vec: Vec = encode(&self.c, Infinite).unwrap(); + let mut a_s = String::new(); + for x in a_vec.iter() { + a_s = format!("{}{:x}", a_s, x); + } + + let mut b_s = String::new(); + for y in b_vec.iter() { + b_s = format!("{}{:x}", b_s, y); + } + + let mut c_s = String::new(); + for y in c_vec.iter() { + c_s = format!("{}{:x}", c_s, y); + } + + write!(f, "Signature : (\na = 0x{},\nb = 0x{},\nc = 0x{}\n)", a_s, b_s, c_s) + } + } + + #[derive(Clone)] + pub struct Message { + prefix: String, // the secret key for the signature scheme + c_id: Fr, // uniquely identifies the + index: i32, // index + // ck: Fr, // TODO: l-bit key (from SymKeyEnc) + } + + impl Message { + pub fn new(_prefix: String, _c_id: Fr, _index: i32) -> Message { + Message { + prefix: _prefix, c_id: _c_id, index: _index, + } + } + + fn hash(&self) -> Fr { + let mut input_buf = Vec::new(); + input_buf.extend_from_slice(self.prefix.as_bytes()); + let c_id_vec: Vec = encode(&self.c_id, Infinite).unwrap(); + // encode cId in the vector + input_buf.extend(c_id_vec); + // encoee the balance as a hex string + let b = format!("{:x}", self.index); + input_buf.extend_from_slice(b.as_bytes()); + // TODO: add the ck vector (l-bit key) + // let mut in_str = String::new(); + // for y in input_buf.iter() { + // in_str = format!("{}{:x}", in_str, y); + // } + // println!("input_buf: {}", in_str); + + // hash the inputs via SHA256 + let sha2_digest = sha512::hash(input_buf.as_slice()); + // println!("hash: {:?}", sha2_digest); + // let h = format!("{:x}", HexSlice::new(&sha2_digest)); + let mut hash_buf: [u8; 64] = [0; 64]; + hash_buf.copy_from_slice(&sha2_digest[0..64]); + return Fr::interpret(&hash_buf); + } + } + + + pub fn setup() -> PublicParams { + let rng = &mut rand::thread_rng(); + let g = G1::random(rng); + let mpk = PublicParams { g: g }; + return mpk; + } + + pub fn keygen(mpk : &PublicParams) -> KeyPair { + let rng = &mut rand::thread_rng(); + let x = Fr::random(rng); + let y = Fr::random(rng); + let sk = SecretKey { x: x, y: y }; + let pk = PublicKey { X: mpk.g * x, + Y: mpk.g * y + }; + return KeyPair { sk: sk, pk: pk } + } + + pub fn sign(sk: &SecretKey, msg: &Message) -> Signature { + let rng = &mut rand::thread_rng(); + let a = G2::random(rng); + let m = msg.hash(); + let b = a * sk.y; + let c = a * (sk.x + (m * sk.x * sk.y)); + let sig = Signature { a: a, b: b, c: c }; + return sig; + } + + pub fn verify(mpk: &PublicParams, pk: &PublicKey, msg: &Message, sig: &Signature) -> bool { + let m = msg.hash(); + let lhs1 = pairing(pk.Y, sig.a); + let rhs1 = pairing(mpk.g, sig.b); + let lhs2 = pairing(pk.X, sig.a) * (pairing(pk.X, sig.b).pow(m)); + let rhs2 = pairing(mpk.g, sig.c); + return (lhs1 == rhs1) && (lhs2 == rhs2); + } + +} + +////////////////////////////////// CL Sigs ///////////////////////////////////// + +////////////////////////////////// COMMITMENT ////////////////////////////////// + +pub mod commit_scheme { + use std::fmt; + use rand; + use std::str; + use std::default; + use bn::{Group, Fr, G1}; + use debug_elem_in_hex; + use bincode::SizeLimit::Infinite; + use bincode::rustc_serialize::encode; + use sodiumoxide::crypto::hash::sha512; + + // define some structures here + #[derive(Copy, Clone)] + pub struct PublicKey { + g: G1, + h: G1 + } + + #[derive(Copy, Clone)] + pub struct Commitment { + c: G1, + d: Fr + } + + impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let g_vec: Vec = encode(&self.g, Infinite).unwrap(); + let h_vec: Vec = encode(&self.h, Infinite).unwrap(); + let mut g_s = String::new(); + for x in g_vec.iter() { + g_s = format!("{}{:x}", g_s, x); + } + + let mut h_s = String::new(); + for y in h_vec.iter() { + h_s = format!("{}{:x}", h_s, y); + } + + write!(f, "PK : (g=0x{}, h=0x{})", g_s, h_s) + } + } + + + impl fmt::Display for Commitment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let c_vec: Vec = encode(&self.c, Infinite).unwrap(); + let mut c_s = String::new(); + for x in c_vec.iter() { + c_s = format!("{}{:x}", c_s, x); + } + + let d_vec: Vec = encode(&self.d, Infinite).unwrap(); + let mut d_s = String::new(); + for x in d_vec.iter() { + d_s = format!("{}{:x}", d_s, x); + } + write!(f, "Commitment : (c=0x{}, d=0x{})", c_s, d_s) + } + } + + /* Implements the setup algorithm for the Pedersen92 commitment scheme -*/ -pub fn setup() -> PublicKey { - println!("Run Setup..."); - let rng = &mut rand::thread_rng(); - let g = G1::random(rng); - let h = G1::random(rng); - let pk = PublicKey { g: g, h: h }; - println!("{}", pk); - return pk; + */ + pub fn setup() -> PublicKey { + println!("Run Setup..."); + let rng = &mut rand::thread_rng(); + let g = G1::random(rng); + let h = G1::random(rng); + let pk = PublicKey { g: g, h: h }; + println!("{}", pk); + return pk; + } + + #[derive(Copy, Clone)] + pub struct Message { + // sk_sigs: SecretKeySigs, // the secret key for the signature scheme + k1: Fr, // seed 1 for PRF + k2: Fr, // seed 2 for PRF + balance: i32 // the balance for the user + } + + impl Message { + pub fn new(_k1: Fr, _k2: Fr, _balance: i32) -> Message { + Message { + k1: _k1, k2: _k2, balance: _balance, + } + } + + fn hash(&self) -> Fr { + let mut input_buf = Vec::new(); + // TODO: add sk_sigs to encode it + let k1_vec: Vec = encode(&self.k1, Infinite).unwrap(); + let k2_vec: Vec = encode(&self.k2, Infinite).unwrap(); + // encode k1 in the vector + input_buf.extend(k1_vec); + // encode k2 in the vector + input_buf.extend(k2_vec); + // encoee the balance as a hex string + let b = format!("{:x}", self.balance); + // println!("Balance: {}", b); + input_buf.extend_from_slice(b.as_bytes()); + // let mut in_str = String::new(); + // for y in input_buf.iter() { + // in_str = format!("{}{:x}", in_str, y); + // } + // println!("input_buf: {}", in_str); + + // hash the inputs via SHA256 + let sha2_digest = sha512::hash(input_buf.as_slice()); + // println!("hash: {:?}", sha2_digest); + // let h = format!("{:x}", HexSlice::new(&sha2_digest)); + let mut hash_buf: [u8; 64] = [0; 64]; + hash_buf.copy_from_slice(&sha2_digest[0..64]); + return Fr::interpret(&hash_buf); + } + } + + + /* + commit(pk, msg) -> cm where + - pk is the public key generated from setup() + - msg is the message structure for the commitment scheme + - cm is the output commitment message for the given message + */ + pub fn commit(pk: &PublicKey, msg: &Message) -> Commitment { + let rng = &mut rand::thread_rng(); + + let r = Fr::random(rng); + + let m = msg.hash(); + let p = "commit -> m"; + debug_elem_in_hex(p, &m); + + let c = (pk.g * m) + (pk.h * r); + // return (c, r) <- d=r + let commitment = Commitment { c: c, d: r }; + + // debugging + println!("{}", commitment); + return commitment; + } + + /* + decommit(pk, cm, msg) -> bool where + - pk is the public key generated from setup() + - cm is the commitment + - msg is the message to validate + - outputs T/F for whether the cm is a valid commitmentt to the msg + */ + pub fn decommit(pk: &PublicKey, cm: &Commitment, msg: &Message) -> bool { + let m = msg.hash(); + let p = "decommit -> m"; + debug_elem_in_hex(p, &m); + + let dm = (pk.g * m) + (pk.h * cm.d); + return dm == cm.c; + } + } - -// TODO: need to be able to handle a message structure -pub fn commit(pk : PublicKey, msg : Message) -> Commitment { - let rng = &mut rand::thread_rng(); - - let r = Fr::random(rng); - // TODO: replace with hash of message into m (of type Fr) - let m = msg.hash(); - let c = (pk.g * m) + (pk.h * r); - // return (c, r) <- d=r - let commitment = Commitment { c: c, d: r }; - - // debugging - println!("{}", commitment); - return commitment; -} - -/* -pub fn decommit(pk: PublicKey, cm: Commitment, msg: Message) -> bool { - // TODO: replace with hash of message into m (of type Fr) - let m = Fr::random(rng); - let dm = (pk.g * m) + (pk.h * cm.d); - return dm == cm.c; -} -*/ - - +////////////////////////////////// COMMITMENT ////////////////////////////////// //pub fn keygen() { // println!("Run Keygen...");