Browse Source

add sign & verify with Poseidon hash, update MiMC use to v0.0.2

aggregated-schnorr-musig
arnaucube 4 years ago
parent
commit
2ab48ff3ad
3 changed files with 116 additions and 34 deletions
  1. +5
    -2
      Cargo.toml
  2. +5
    -4
      README.md
  3. +106
    -28
      src/lib.rs

+ 5
- 2
Cargo.toml

@ -1,10 +1,12 @@
[package] [package]
name = "babyjubjub-rs" name = "babyjubjub-rs"
version = "0.0.1"
version = "0.0.2"
authors = ["arnaucube <root@arnaucube.com>"] authors = ["arnaucube <root@arnaucube.com>"]
edition = "2018" edition = "2018"
license = "GPL-3.0" license = "GPL-3.0"
description = "BabyJubJub elliptic curve implementation" description = "BabyJubJub elliptic curve implementation"
repository = "https://github.com/arnaucube/babyjubjub-rs"
readme = "README.md"
[dependencies] [dependencies]
num = "0.2.0" num = "0.2.0"
@ -15,6 +17,7 @@ blake2 = "0.8"
generic-array = "0.13.2" generic-array = "0.13.2"
tiny-keccak = "1.5" tiny-keccak = "1.5"
rustc-hex = "1.0.0" rustc-hex = "1.0.0"
mimc-rs = "0.0.1"
mimc-rs = "0.0.2"
poseidon-rs = "0.0.1"
arrayref = "0.3.5" arrayref = "0.3.5"
lazy_static = "1.4.0" lazy_static = "1.4.0"

+ 5
- 4
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-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 BabyJubJub curve explanation: https://medium.com/zokrates/efficient-ecc-in-zksnarks-using-zokrates-bd9ae37b8186
Uses: Uses:
- MiMC7 hash function: https://github.com/arnaucube/mimc-rs - 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 ## Warning
Doing this in my free time to get familiar with Rust, do not use in production. 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 keys generation
- [x] eddsa signature - [x] eddsa signature
- [x] eddsa signature verification - [x] eddsa signature verification
- [ ] {point, pk, signature} compress&decompress parsers
- [x] {point, pk, signature} compress&decompress parsers

+ 106
- 28
src/lib.rs

@ -9,6 +9,7 @@ extern crate rand;
use blake2::{Blake2b, Digest}; use blake2::{Blake2b, Digest};
use mimc_rs::Mimc7; use mimc_rs::Mimc7;
use poseidon_rs::Poseidon;
use std::cmp::min; use std::cmp::min;
use num_bigint::{BigInt, RandBigInt, Sign, ToBigInt}; use num_bigint::{BigInt, RandBigInt, Sign, ToBigInt};
@ -196,7 +197,7 @@ impl PrivateKey {
pk.clone() pk.clone()
} }
pub fn sign(&self, msg: BigInt) -> Signature {
pub fn sign_mimc(&self, msg: BigInt) -> Result<Signature, String> {
// https://tools.ietf.org/html/rfc8032#section-5.1.6 // https://tools.ietf.org/html/rfc8032#section-5.1.6
let mut hasher = Blake2b::new(); let mut hasher = Blake2b::new();
let (_, sk_bytes) = self.key.to_bytes_be(); 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 hm_input = vec![r8.x.clone(), r8.y.clone(), a.x.clone(), a.y.clone(), msg];
let mimc7 = Mimc7::new(); 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; let mut s = &self.key << 3;
s = hm * s; s = hm * s;
s = r + s; s = r + s;
s = s % &SUBORDER.clone(); s = s % &SUBORDER.clone();
Signature {
Ok(Signature {
r_b8: r8.clone(), r_b8: r8.clone(),
s: s, s: s,
}
})
}
pub fn sign_poseidon(&self, msg: BigInt) -> Result<Signature, String> {
// 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::<u8, generic_array::typenum::U32>::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 } 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![ let hm_input = vec![
sig.r_b8.x.clone(), sig.r_b8.x.clone(),
sig.r_b8.y.clone(), sig.r_b8.y.clone(),
@ -255,7 +291,30 @@ pub fn verify(pk: Point, sig: Signature, msg: BigInt) -> bool {
msg, msg,
]; ];
let mimc7 = Mimc7::new(); 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 l = B8.mul_scalar(sig.s);
let r = sig.r_b8.add(&pk.mul_scalar(8.to_bigint().unwrap() * hm)); let r = sig.r_b8.add(&pk.mul_scalar(8.to_bigint().unwrap() * hm));
if l.x == r.x && l.y == r.y { 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] #[test]
fn test_point_compress_decompress() { fn test_point_compress_decompress() {
let p: Point = Point { let p: Point = Point {
@ -410,26 +508,6 @@ mod tests {
assert_eq!(p.y, p2.y); 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] #[test]
fn test_point_decompress0() { fn test_point_decompress0() {
let y_bytes_raw = "b5328f8791d48f20bec6e481d91c7ada235f1facf22547901c18656b6c3e042f" let y_bytes_raw = "b5328f8791d48f20bec6e481d91c7ada235f1facf22547901c18656b6c3e042f"
@ -498,7 +576,7 @@ mod tests {
for i in 0..5 { for i in 0..5 {
let msg_raw = "123456".to_owned() + &i.to_string(); let msg_raw = "123456".to_owned() + &i.to_string();
let msg = BigInt::parse_bytes(msg_raw.as_bytes(), 10).unwrap(); 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 compressed_sig = sig.compress();
let decompressed_sig = decompress_signature(&compressed_sig).unwrap(); 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.r_b8.y, &decompressed_sig.r_b8.y);
assert_eq!(&sig.s, &decompressed_sig.s); 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); assert_eq!(v, true);
} }
} }

Loading…
Cancel
Save