diff --git a/Cargo.toml b/Cargo.toml index 9964e28..66cbd29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "babyjubjub-rs" -version = "0.0.1" +version = "0.0.2" authors = ["arnaucube "] edition = "2018" license = "GPL-3.0" description = "BabyJubJub elliptic curve implementation" +repository = "https://github.com/arnaucube/babyjubjub-rs" +readme = "README.md" [dependencies] num = "0.2.0" @@ -15,6 +17,7 @@ blake2 = "0.8" generic-array = "0.13.2" tiny-keccak = "1.5" rustc-hex = "1.0.0" -mimc-rs = "0.0.1" +mimc-rs = "0.0.2" +poseidon-rs = "0.0.1" arrayref = "0.3.5" lazy_static = "1.4.0" diff --git a/README.md b/README.md index cd08597..376490b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # babyjubjub-rs [![Crates.io](https://img.shields.io/crates/v/babyjubjub-rs.svg)](https://crates.io/crates/babyjubjub-rs) [![Build Status](https://travis-ci.org/arnaucube/babyjubjub-rs.svg?branch=master)](https://travis-ci.org/arnaucube/babyjubjub-rs) -BabyJubJub elliptic curve implementation in Rust. - -BabyJubJub is a twisted edwards curve embedded in the curve of BN128. +BabyJubJub elliptic curve implementation in Rust. Is a twisted edwards curve embedded in the curve of BN128. BabyJubJub curve explanation: https://medium.com/zokrates/efficient-ecc-in-zksnarks-using-zokrates-bd9ae37b8186 Uses: - MiMC7 hash function: https://github.com/arnaucube/mimc-rs +- Poseidon hash function https://github.com/arnaucube/poseidon-rs + +Compatible with the BabyJubJub Go implementation from https://github.com/iden3/go-iden3-crypto ## Warning Doing this in my free time to get familiar with Rust, do not use in production. @@ -16,7 +17,7 @@ Doing this in my free time to get familiar with Rust, do not use in production. - [x] eddsa keys generation - [x] eddsa signature - [x] eddsa signature verification -- [ ] {point, pk, signature} compress&decompress parsers +- [x] {point, pk, signature} compress&decompress parsers diff --git a/src/lib.rs b/src/lib.rs index bf85284..978a6e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ extern crate rand; use blake2::{Blake2b, Digest}; use mimc_rs::Mimc7; +use poseidon_rs::Poseidon; use std::cmp::min; use num_bigint::{BigInt, RandBigInt, Sign, ToBigInt}; @@ -196,7 +197,7 @@ impl PrivateKey { pk.clone() } - pub fn sign(&self, msg: BigInt) -> Signature { + pub fn sign_mimc(&self, msg: BigInt) -> Result { // https://tools.ietf.org/html/rfc8032#section-5.1.6 let mut hasher = Blake2b::new(); let (_, sk_bytes) = self.key.to_bytes_be(); @@ -213,17 +214,52 @@ impl PrivateKey { let hm_input = vec![r8.x.clone(), r8.y.clone(), a.x.clone(), a.y.clone(), msg]; let mimc7 = Mimc7::new(); - let hm = mimc7.hash(hm_input); + let hm = match mimc7.hash(hm_input) { + Result::Err(err) => return Err(err.to_string()), + Result::Ok(hm) => hm, + }; let mut s = &self.key << 3; s = hm * s; s = r + s; s = s % &SUBORDER.clone(); - Signature { + Ok(Signature { r_b8: r8.clone(), s: s, - } + }) + } + pub fn sign_poseidon(&self, msg: BigInt) -> Result { + // https://tools.ietf.org/html/rfc8032#section-5.1.6 + let mut hasher = Blake2b::new(); + let (_, sk_bytes) = self.key.to_bytes_be(); + 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_be(); + let r_bytes = utils::concatenate_arrays(s, &msg_bytes); + let mut r = BigInt::from_bytes_be(Sign::Plus, &r_bytes[..]); + r = utils::modulus(&r, &SUBORDER); + let r8: Point = B8.mul_scalar(r.clone()); + let a = &self.public(); + + let hm_input = vec![r8.x.clone(), r8.y.clone(), a.x.clone(), a.y.clone(), msg]; + let poseidon = Poseidon::new(); + let hm = match poseidon.hash(hm_input) { + Result::Err(err) => return Err(err.to_string()), + Result::Ok(hm) => hm, + }; + + let mut s = &self.key << 3; + s = hm * s; + s = r + s; + s = s % &SUBORDER.clone(); + + Ok(Signature { + r_b8: r8.clone(), + s: s, + }) } } @@ -246,7 +282,7 @@ pub fn new_key() -> PrivateKey { PrivateKey { key: sk } } -pub fn verify(pk: Point, sig: Signature, msg: BigInt) -> bool { +pub fn verify_mimc(pk: Point, sig: Signature, msg: BigInt) -> bool { let hm_input = vec![ sig.r_b8.x.clone(), sig.r_b8.y.clone(), @@ -255,7 +291,30 @@ pub fn verify(pk: Point, sig: Signature, msg: BigInt) -> bool { msg, ]; let mimc7 = Mimc7::new(); - let hm = mimc7.hash(hm_input); + let hm = match mimc7.hash(hm_input) { + Result::Err(_) => return false, + Result::Ok(hm) => hm, + }; + let l = B8.mul_scalar(sig.s); + let r = sig.r_b8.add(&pk.mul_scalar(8.to_bigint().unwrap() * hm)); + if l.x == r.x && l.y == r.y { + return true; + } + false +} +pub fn verify_poseidon(pk: Point, sig: Signature, msg: BigInt) -> bool { + let hm_input = vec![ + sig.r_b8.x.clone(), + sig.r_b8.y.clone(), + pk.x.clone(), + pk.y.clone(), + msg, + ]; + let poseidon = Poseidon::new(); + let hm = match poseidon.hash(hm_input) { + Result::Err(_) => return false, + Result::Ok(hm) => hm, + }; let l = B8.mul_scalar(sig.s); let r = sig.r_b8.add(&pk.mul_scalar(8.to_bigint().unwrap() * hm)); if l.x == r.x && l.y == r.y { @@ -386,6 +445,45 @@ mod tests { ); } + #[test] + fn test_new_key_sign_verify_mimc_0() { + let sk = new_key(); + let pk = sk.public(); + let msg = 5.to_bigint().unwrap(); + let sig = sk.sign_mimc(msg.clone()).unwrap(); + let v = verify_mimc(pk, sig, msg); + assert_eq!(v, true); + } + + #[test] + fn test_new_key_sign_verify_mimc_1() { + let sk = new_key(); + let pk = sk.public(); + let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap(); + let sig = sk.sign_mimc(msg.clone()).unwrap(); + let v = verify_mimc(pk, sig, msg); + assert_eq!(v, true); + } + #[test] + fn test_new_key_sign_verify_poseidon_0() { + let sk = new_key(); + let pk = sk.public(); + let msg = 5.to_bigint().unwrap(); + let sig = sk.sign_poseidon(msg.clone()).unwrap(); + let v = verify_poseidon(pk, sig, msg); + assert_eq!(v, true); + } + + #[test] + fn test_new_key_sign_verify_poseidon_1() { + let sk = new_key(); + let pk = sk.public(); + let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap(); + let sig = sk.sign_poseidon(msg.clone()).unwrap(); + let v = verify_poseidon(pk, sig, msg); + assert_eq!(v, true); + } + #[test] fn test_point_compress_decompress() { let p: Point = Point { @@ -410,26 +508,6 @@ mod tests { assert_eq!(p.y, p2.y); } - #[test] - fn test_new_key_sign_verify0() { - let sk = new_key(); - let pk = sk.public(); - let msg = 5.to_bigint().unwrap(); - let sig = sk.sign(msg.clone()); - let v = verify(pk, sig, msg); - assert_eq!(v, true); - } - - #[test] - fn test_new_key_sign_verify1() { - let sk = new_key(); - let pk = sk.public(); - let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap(); - let sig = sk.sign(msg.clone()); - let v = verify(pk, sig, msg); - assert_eq!(v, true); - } - #[test] fn test_point_decompress0() { let y_bytes_raw = "b5328f8791d48f20bec6e481d91c7ada235f1facf22547901c18656b6c3e042f" @@ -498,7 +576,7 @@ mod tests { for i in 0..5 { let msg_raw = "123456".to_owned() + &i.to_string(); let msg = BigInt::parse_bytes(msg_raw.as_bytes(), 10).unwrap(); - let sig = sk.sign(msg.clone()); + let sig = sk.sign_mimc(msg.clone()).unwrap(); let compressed_sig = sig.compress(); let decompressed_sig = decompress_signature(&compressed_sig).unwrap(); @@ -506,7 +584,7 @@ mod tests { assert_eq!(&sig.r_b8.y, &decompressed_sig.r_b8.y); assert_eq!(&sig.s, &decompressed_sig.s); - let v = verify(pk.clone(), decompressed_sig, msg); + let v = verify_mimc(pk.clone(), decompressed_sig, msg); assert_eq!(v, true); } }