Browse Source

Update Schnorr to last changes, rm MiMC7 methods

main
arnaucube 4 years ago
parent
commit
80d682ea93
3 changed files with 79 additions and 130 deletions
  1. +4
    -3
      README.md
  2. +4
    -6
      benches/bench_babyjubjub.rs
  3. +71
    -121
      src/lib.rs

+ 4
- 3
README.md

@ -1,13 +1,14 @@
# 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. A twisted edwards curve embedded in the curve of BN128.
BabyJubJub elliptic curve implementation in Rust. A twisted edwards curve embedded in the curve of BN128/BN256.
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
- Poseidon hash function https://github.com/arnaucube/poseidon-rs - Poseidon hash function https://github.com/arnaucube/poseidon-rs
Compatible with the BabyJubJub Go implementation from https://github.com/iden3/go-iden3-crypto
Compatible with the BabyJubJub implementations in:
- Go, from https://github.com/iden3/go-iden3-crypto
- circom & javascript, from https://github.com/iden3/circomlib
## 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**.

+ 4
- 6
benches/bench_babyjubjub.rs

@ -46,12 +46,10 @@ fn criterion_benchmark(c: &mut Criterion) {
let sk = babyjubjub_rs::new_key(); let sk = babyjubjub_rs::new_key();
let pk = sk.public().unwrap(); let pk = sk.public().unwrap();
let msg = 5.to_bigint().unwrap(); let msg = 5.to_bigint().unwrap();
c.bench_function("sign_poseidon", |b| {
b.iter(|| sk.sign_poseidon(msg.clone()))
});
let sig = sk.sign_poseidon(msg.clone()).unwrap();
c.bench_function("verify_poseidon", |b| {
b.iter(|| babyjubjub_rs::verify_poseidon(pk.clone(), sig.clone(), msg.clone()))
c.bench_function("sign", |b| b.iter(|| sk.sign(msg.clone())));
let sig = sk.sign(msg.clone()).unwrap();
c.bench_function("verify", |b| {
b.iter(|| babyjubjub_rs::verify(pk.clone(), sig.clone(), msg.clone()))
}); });
} }

+ 71
- 121
src/lib.rs

@ -1,3 +1,5 @@
// WARNING still updating the code, it works, but is still in process the refactor.
extern crate rand; extern crate rand;
#[macro_use] #[macro_use]
extern crate ff; extern crate ff;
@ -283,37 +285,10 @@ impl PrivateKey {
Ok(pk.clone()) Ok(pk.clone())
} }
// pub fn sign_mimc(&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)?;
// let a = &self.public()?;
//
// 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 mut s = &self.key << 3;
// s = hm * s;
// s = r + s;
// s = s % &SUBORDER.clone();
//
// Ok(Signature {
// r_b8: r8.clone(),
// s: s,
// })
// }
pub fn sign_poseidon(&self, msg: BigInt) -> Result<Signature, String> {
pub fn sign(&self, msg: BigInt) -> Result<Signature, String> {
if msg > Q.clone() {
return Err("msg outside the Finite Field".to_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();
@ -346,49 +321,48 @@ impl PrivateKey {
}) })
} }
// pub fn sign_schnorr(&self, m: Vec<u8>) -> Result<(Point, BigInt), String> {
// // random r
// let mut rng = rand::thread_rng();
// let k = rng.gen_biguint(1024).to_bigint().unwrap();
//
// // r = k·G
// let r = B8.mul_scalar(&k)?;
//
// // h = H(x, r, m)
// let pk = &self.public()?;
// let h = schnorr_hash(&pk, m, &r)?;
//
// // s= k+x·h
// let s = k + &self.key * &h;
// Ok((r, s))
// }
pub fn sign_schnorr(&self, m: BigInt) -> Result<(Point, BigInt), String> {
// random r
let mut rng = rand6::thread_rng();
let k = rng.gen_biguint(1024).to_bigint().unwrap();
// r = k·G
let r = B8.mul_scalar(&k)?;
// h = H(x, r, m)
let pk = &self.public()?;
let h = schnorr_hash(&pk, m, &r)?;
// s= k+x·h
let s = k + &self.key * &h;
Ok((r, s))
}
} }
// pub fn schnorr_hash(pk: &Point, m: Vec<u8>, c: &Point) -> Result<BigInt, String> {
// let b: &mut Vec<u8> = &mut Vec::new();
//
// // other option could be to do it without compressing the points, and concatenating x|y
// b.append(&mut pk.compress().to_vec());
// b.append(&mut c.compress().to_vec());
// b.append(&mut m.clone());
//
// let poseidon = Poseidon::new();
// let h = poseidon.hash_bytes(b.to_vec())?;
// println!("h {:?}", h.to_string());
// Ok(h)
// }
//
// pub fn verify_schnorr(pk: Point, m: Vec<u8>, r: Point, s: BigInt) -> Result<bool, String> {
// // sG = s·G
// let sg = B8.mul_scalar(&s)?;
//
// // r + h · x
// let h = schnorr_hash(&pk, m, &r)?;
// let pk_h = pk.mul_scalar(&h)?;
// let right = r.add(&pk_h)?;
//
// Ok(sg.equals(right))
// }
pub fn schnorr_hash(pk: &Point, msg: BigInt, c: &Point) -> Result<BigInt, String> {
if msg > Q.clone() {
return Err("msg outside the Finite Field".to_string());
}
let msgFr: Fr = Fr::from_str(&msg.to_string()).unwrap();
let hm_input = vec![pk.x.clone(), pk.y.clone(), c.x.clone(), c.y.clone(), msgFr];
let poseidon = Poseidon::new();
let h = poseidon.hash(hm_input)?;
println!("h {:?}", h.to_string());
let hB = BigInt::parse_bytes(to_hex(&h).as_bytes(), 16).unwrap();
Ok(hB)
}
pub fn verify_schnorr(pk: Point, m: BigInt, r: Point, s: BigInt) -> Result<bool, String> {
// sG = s·G
let sg = B8.mul_scalar(&s)?;
// r + h · x
let h = schnorr_hash(&pk, m, &r)?;
let pk_h = pk.mul_scalar(&h)?;
let right = r.projective().add(&pk_h.projective())?;
Ok(sg.equals(right.affine()))
}
pub fn new_key() -> PrivateKey { pub fn new_key() -> PrivateKey {
// https://tools.ietf.org/html/rfc8032#section-5.1.5 // https://tools.ietf.org/html/rfc8032#section-5.1.5
@ -409,34 +383,10 @@ pub fn new_key() -> PrivateKey {
PrivateKey { key: sk } PrivateKey { key: sk }
} }
// 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(),
// pk.x.clone(),
// pk.y.clone(),
// msg,
// ];
// let mimc7 = Mimc7::new();
// let hm = match mimc7.hash(hm_input) {
// Result::Err(_) => return false,
// Result::Ok(hm) => hm,
// };
// let l = match B8.mul_scalar(&sig.s) {
// Result::Err(_) => return false,
// Result::Ok(l) => l,
// };
// let r = match sig
// .r_b8
// .add(&pk.mul_scalar(&(8.to_bigint().unwrap() * hm)).unwrap())
// {
// Result::Err(_) => return false,
// Result::Ok(r) => r,
// };
// l.equals(r)
// }
pub fn verify_poseidon(pk: Point, sig: Signature, msg: BigInt) -> bool {
pub fn verify(pk: Point, sig: Signature, msg: BigInt) -> bool {
if msg > Q.clone() {
return false;
}
let (_, msg_bytes) = msg.to_bytes_be(); let (_, msg_bytes) = msg.to_bytes_be();
let msgFr: Fr = Fr::from_str(&msg.to_string()).unwrap(); let msgFr: Fr = Fr::from_str(&msg.to_string()).unwrap();
let hm_input = vec![ let hm_input = vec![
@ -628,22 +578,22 @@ mod tests {
// } // }
#[test] #[test]
fn test_new_key_sign_verify_poseidon_0() {
fn test_new_key_sign_verify_0() {
let sk = new_key(); let sk = new_key();
let pk = sk.public().unwrap(); let pk = sk.public().unwrap();
let msg = 5.to_bigint().unwrap(); let msg = 5.to_bigint().unwrap();
let sig = sk.sign_poseidon(msg.clone()).unwrap();
let v = verify_poseidon(pk, sig, msg);
let sig = sk.sign(msg.clone()).unwrap();
let v = verify(pk, sig, msg);
assert_eq!(v, true); assert_eq!(v, true);
} }
#[test] #[test]
fn test_new_key_sign_verify_poseidon_1() {
fn test_new_key_sign_verify_1() {
let sk = new_key(); let sk = new_key();
let pk = sk.public().unwrap(); let pk = sk.public().unwrap();
let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap(); let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap();
let sig = sk.sign_poseidon(msg.clone()).unwrap();
let v = verify_poseidon(pk, sig, msg);
let sig = sk.sign(msg.clone()).unwrap();
let v = verify(pk, sig, msg);
assert_eq!(v, true); assert_eq!(v, true);
} }
@ -739,7 +689,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_poseidon(msg.clone()).unwrap();
let sig = sk.sign(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();
@ -747,22 +697,22 @@ 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_poseidon(pk.clone(), decompressed_sig, msg);
let v = verify(pk.clone(), decompressed_sig, msg);
assert_eq!(v, true); assert_eq!(v, true);
} }
} }
// #[test]
// fn test_schnorr_signature() {
// let sk = new_key();
// let pk = sk.public().unwrap();
//
// let msg: Vec<u8> = ("123456".to_owned() + &1.to_string()).as_bytes().to_vec();
// let (s, e) = sk.sign_schnorr(msg.clone()).unwrap();
// println!("s {:?}", s.x.to_string());
// println!("s {:?}", s.y.to_string());
// println!("e {:?}", e.to_string());
// let verification = verify_schnorr(pk, msg, s, e).unwrap();
// assert_eq!(true, verification);
// }
#[test]
fn test_schnorr_signature() {
let sk = new_key();
let pk = sk.public().unwrap();
let msg = BigInt::parse_bytes(b"123456789012345678901234567890", 10).unwrap();
let (s, e) = sk.sign_schnorr(msg.clone()).unwrap();
println!("s {:?}", s.x.to_string());
println!("s {:?}", s.y.to_string());
println!("e {:?}", e.to_string());
let verification = verify_schnorr(pk, msg, s, e).unwrap();
assert_eq!(true, verification);
}
} }

Loading…
Cancel
Save