mirror of
https://github.com/arnaucube/babyjubjub-ark.git
synced 2026-01-13 17:21:29 +01:00
add sign & verify with Poseidon hash, update MiMC use to v0.0.2
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
# babyjubjub-rs [](https://crates.io/crates/babyjubjub-rs) [](https://travis-ci.org/arnaucube/babyjubjub-rs)
|
# babyjubjub-rs [](https://crates.io/crates/babyjubjub-rs) [](https://travis-ci.org/arnaucube/babyjubjub-rs)
|
||||||
BabyJubJub elliptic curve implementation in Rust.
|
BabyJubJub elliptic curve implementation in Rust. Is a twisted edwards curve embedded in the curve of BN128.
|
||||||
|
|
||||||
BabyJubJub 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
134
src/lib.rs
134
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user