diff --git a/Cargo.toml b/Cargo.toml index d0f64b1..e2a08a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,15 @@ [package] name = "babyjubjub-rs" version = "0.1.0" -authors = ["arnaucube "] +authors = ["arnaucube "] edition = "2018" [dependencies] num = "0.2.0" num-bigint = {version = "0.2.2", features = ["rand"]} num-traits = "0.2.8" +rand = "0.6.5" +blake2 = "0.8" +generic-array = "0.13.2" +tiny-keccak = "1.5" +rustc-hex = "1.0.0" diff --git a/README.md b/README.md index ade73ed..20dc4d6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Doing this in my free time to get familiar with Rust, do not use in production - [x] point addition - [x] point scalar multiplication - [ ] point compress&decompress parsers -- [ ] eddsa keys generation +- [x] eddsa keys generation - [ ] eddsa signature - [ ] eddsa signature verification diff --git a/src/lib.rs b/src/lib.rs index 8649742..7388898 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,18 @@ +extern crate generic_array; extern crate num; extern crate num_bigint; extern crate num_traits; +extern crate rand; -use num_bigint::BigInt; +use blake2::{Blake2b, Digest}; + +use num_bigint::RandBigInt; + +use num_bigint::{BigInt, Sign, ToBigInt}; use num_traits::{One, Zero}; +use generic_array::GenericArray; + mod utils; #[derive(Clone, Debug)] @@ -12,11 +20,18 @@ pub struct Point { pub x: BigInt, pub y: BigInt, } +pub struct Signature { + r_b8: Point, + s: BigInt, +} pub struct Babyjubjub { d: BigInt, a: BigInt, q: BigInt, + b8: Point, + order: BigInt, + sub_order: BigInt, } impl Babyjubjub { @@ -28,7 +43,33 @@ impl Babyjubjub { 10, ) .unwrap(); - Babyjubjub { d: d, a: a, q: q } + let b8: Point = Point { + x: BigInt::parse_bytes( + b"5299619240641551281634865583518297030282874472190772894086521144482721001553", + 10, + ) + .unwrap(), + y: BigInt::parse_bytes( + b"16950150798460657717958625567821834550301663161624707787222815936182638968203", + 10, + ) + .unwrap(), + }; + let order: BigInt = BigInt::parse_bytes( + b"21888242871839275222246405745257275088614511777268538073601725287587578984328", + 10, + ) + .unwrap(); + let sub_order: BigInt = &order >> 3; + + Babyjubjub { + d: d, + a: a, + q: q, + b8: b8, + order: order, + sub_order: sub_order, + } } pub fn add(&self, p: &Point, q: &Point) -> Point { @@ -76,12 +117,74 @@ impl Babyjubjub { } r } + + pub fn new_key(&self) -> BigInt { + // https://tools.ietf.org/html/rfc8032#section-5.1.5 + let mut rng = rand::thread_rng(); + let sk_raw = rng.gen_biguint(1024).to_bigint().unwrap(); + println!("sk {:?}", sk_raw.to_string()); + + let mut hasher = Blake2b::new(); + let (_, sk_raw_bytes) = sk_raw.to_bytes_le(); + hasher.input(sk_raw_bytes); + let mut h = hasher.result(); + + h[0] = h[0] & 0xF8; + h[31] = h[31] & 0x7F; + h[31] = h[31] | 0x40; + + let sk = BigInt::from_bytes_le(Sign::Plus, &h[..]); + + sk + } + + pub fn sk_to_pk(&self, sk: BigInt) -> Point { + // https://tools.ietf.org/html/rfc8032#section-5.1.5 + // TODO this will be moved into a method of PrivateKey type + let pk = &self.mul_scalar(self.b8.clone(), sk); + pk.clone() + } + + pub fn sign(&self, sk: BigInt, msg: BigInt) -> Signature { + // https://tools.ietf.org/html/rfc8032#section-5.1.6 + + let mut hasher = Blake2b::new(); + let (_, sk_bytes) = sk.to_bytes_le(); + hasher.input(sk_bytes); + let mut h = hasher.result(); // h: hash(sk) + // s: h[32:64] + let s = GenericArray::::from_mut_slice(&mut h[32..64]); + + let (_, msg_bytes) = msg.to_bytes_le(); + let r_bytes = utils::concatenate_arrays(s, &msg_bytes); + let mut r = BigInt::from_bytes_le(Sign::Plus, &r_bytes[..]); + r = r & &self.sub_order; + let r8: Point = self.mul_scalar(self.b8.clone(), r.clone()); + println!("r8 {:?}", r8); + let a = &self.sk_to_pk(sk.clone()); + + // TODO WARNING!!! [TEMP] use MIMC7 hash function (MIMC7 to be implemented) + let hm_input = r8.x + r8.y + &a.x + &a.y + msg; // TEMP + let mut hasher = Blake2b::new(); + let (_, sk_bytes) = sk.to_bytes_le(); + hasher.input(sk_bytes); + let hm = BigInt::from_bytes_le(Sign::Plus, &hasher.result()[..]); + + let mut s = sk << 3; + s = hm * s; + s = r + s; + s = s % &self.sub_order; + + Signature { + r_b8: self.b8.clone(), + s: s, + } + } } #[cfg(test)] mod tests { use super::*; - use num_bigint::ToBigInt; #[test] fn test_add_same_point() { @@ -109,8 +212,8 @@ mod tests { ) .unwrap(), }; - let bbj = Babyjubjub::new(); - let res = bbj.add(&p, &q); + let bbjj = Babyjubjub::new(); + let res = bbjj.add(&p, &q); assert_eq!( res.x.to_string(), "6890855772600357754907169075114257697580319025794532037257385534741338397365" @@ -146,8 +249,8 @@ mod tests { ) .unwrap(), }; - let bbj = Babyjubjub::new(); - let res = bbj.add(&p, &q); + let bbjj = Babyjubjub::new(); + let res = bbjj.add(&p, &q); assert_eq!( res.x.to_string(), "7916061937171219682591368294088513039687205273691143098332585753343424131937" @@ -172,10 +275,10 @@ mod tests { ) .unwrap(), }; - let bbj = Babyjubjub::new(); - let res_m = bbj.mul_scalar(p.clone(), 3.to_bigint().unwrap()); - let res_a = bbj.add(&p, &p); - let res_a = bbj.add(&res_a, &p); + let bbjj = Babyjubjub::new(); + let res_m = bbjj.mul_scalar(p.clone(), 3.to_bigint().unwrap()); + let res_a = bbjj.add(&p, &p); + let res_a = bbjj.add(&res_a, &p); assert_eq!(res_m.x, res_a.x); assert_eq!( res_m.x.to_string(), @@ -191,7 +294,7 @@ mod tests { 10, ) .unwrap(); - let res2 = bbj.mul_scalar(p.clone(), n); + let res2 = bbjj.mul_scalar(p.clone(), n); assert_eq!( res2.x.to_string(), "17070357974431721403481313912716834497662307308519659060910483826664480189605" @@ -201,4 +304,13 @@ mod tests { "4014745322800118607127020275658861516666525056516280575712425373174125159339" ); } + #[test] + fn test_new_key_sign() { + let bbjj = Babyjubjub::new(); + let sk = bbjj.new_key(); + println!("sk {:?}", sk); + let sig = bbjj.sign(sk, 5.to_bigint().unwrap()); + println!("sig {:?}", sig.r_b8); + println!("sig {:?}", sig.s); + } } diff --git a/src/utils.rs b/src/utils.rs index 978e3a7..8f8bed5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -70,6 +70,10 @@ pub fn mod_inverse2(a: BigInt, q: BigInt) -> BigInt { } */ +pub fn concatenate_arrays(x: &[T], y: &[T]) -> Vec { + x.iter().chain(y).cloned().collect() +} + #[cfg(test)] mod tests { use super::*;