From 3e43cae526feeedc125b2865b6ab2f7848063760 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 27 Jul 2018 10:28:08 -0600 Subject: [PATCH 1/4] Add test that torsion doesn't affect signature verification. --- src/redjubjub.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/redjubjub.rs b/src/redjubjub.rs index 994ca52..d6604e9 100644 --- a/src/redjubjub.rs +++ b/src/redjubjub.rs @@ -155,10 +155,39 @@ mod tests { use pairing::bls12_381::Bls12; use rand::thread_rng; - use jubjub::JubjubBls12; + use jubjub::{JubjubBls12, fs::Fs, edwards}; use super::*; + #[test] + fn cofactor_check() { + let rng = &mut thread_rng(); + let params = &JubjubBls12::new(); + let inf = edwards::Point::zero(); + let p_g = FixedGenerators::SpendingKeyGenerator; + + let p8 = loop { + let r = edwards::Point::::rand(rng, params).mul(Fs::char(), params); + + let r2 = r.double(params); + let r4 = r2.double(params); + let r8 = r4.double(params); + + if r2 != inf && r4 != inf && r8 == inf { + break r; + } + }; + + let sk = PrivateKey::(rng.gen()); + let vk = PublicKey::from_private(&sk, p_g, params); + let msg = b"Foo bar"; + let sig = sk.sign(msg, rng, p_g, params); + assert!(vk.verify(msg, &sig, p_g, params)); + + let vktorsion = PublicKey(vk.0.add(&p8, params)); + assert!(vktorsion.verify(msg, &sig, p_g, params)); + } + #[test] fn round_trip_serialization() { let rng = &mut thread_rng(); From cae9715a8e1986269023501d0a638f1014500275 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 27 Jul 2018 10:37:26 -0600 Subject: [PATCH 2/4] Change signature verification equation to permit batch verification. --- src/redjubjub.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/redjubjub.rs b/src/redjubjub.rs index d6604e9..82eeee5 100644 --- a/src/redjubjub.rs +++ b/src/redjubjub.rs @@ -145,8 +145,11 @@ impl PublicKey { Ok(s) => s, Err(_) => return false, }; - // S . P_G = R + c . vk - self.0.mul(c, params).add(&r, params) == params.generator(p_g).mul(s, params).into() + // 0 = 8(-S . P_G + R + c . vk) + self.0.mul(c, params).add(&r, params).add( + ¶ms.generator(p_g).mul(s, params).negate().into(), + params + ).mul_by_cofactor(params).eq(&Point::zero()) } } From a57d2773ab7a4fac5cf9bd4cc9f951c9f5b095b9 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 27 Jul 2018 10:54:21 -0600 Subject: [PATCH 3/4] Add demonstration implementation of batch verification. --- src/redjubjub.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/redjubjub.rs b/src/redjubjub.rs index 82eeee5..7fc83b8 100644 --- a/src/redjubjub.rs +++ b/src/redjubjub.rs @@ -2,7 +2,7 @@ //! See section 5.4.6 of the Sapling protocol specification. use pairing::{Field, PrimeField, PrimeFieldRepr}; -use rand::Rng; +use rand::{Rng, Rand}; use std::io::{self, Read, Write}; use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; @@ -29,6 +29,7 @@ fn h_star(a: &[u8], b: &[u8]) -> E::Fs { hash_to_scalar::(b"Zcash_RedJubjubH", a, b) } +#[derive(Copy, Clone)] pub struct Signature { rbar: [u8; 32], sbar: [u8; 32], @@ -153,6 +154,52 @@ impl PublicKey { } } +pub struct BatchEntry<'a, E: JubjubEngine> { + vk: PublicKey, + msg: &'a [u8], + sig: Signature, +} + +pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( + rng: &mut R, + batch: &[BatchEntry<'a, E>], + params: &E::Params, + p_g: FixedGenerators +) -> bool +{ + let mut acc = Point::::zero(); + + for entry in batch { + let mut r = match Point::::read(&entry.sig.rbar[..], params) { + Ok(r) => r, + Err(_) => return false, + }; + let mut s = match read_scalar::(&entry.sig.sbar[..]) { + Ok(s) => s, + Err(_) => return false, + }; + + let mut c = h_star::(&entry.sig.rbar[..], entry.msg); + + let z = E::Fs::rand(rng); + + s.mul_assign(&z); + s.negate(); + + r = r.mul(z, params); + + c.mul_assign(&z); + + acc = acc.add(&r, params); + acc = acc.add(&entry.vk.0.mul(c, params), params); + acc = acc.add(¶ms.generator(p_g).mul(s, params).into(), params); + } + + acc = acc.mul_by_cofactor(params).into(); + + acc.eq(&Point::zero()) +} + #[cfg(test)] mod tests { use pairing::bls12_381::Bls12; @@ -162,6 +209,36 @@ mod tests { use super::*; + #[test] + fn test_batch_verify() { + let rng = &mut thread_rng(); + let params = &JubjubBls12::new(); + let p_g = FixedGenerators::SpendingKeyGenerator; + + let sk1 = PrivateKey::(rng.gen()); + let vk1 = PublicKey::from_private(&sk1, p_g, params); + let msg1 = b"Foo bar"; + let sig1 = sk1.sign(msg1, rng, p_g, params); + assert!(vk1.verify(msg1, &sig1, p_g, params)); + + let sk2 = PrivateKey::(rng.gen()); + let vk2 = PublicKey::from_private(&sk2, p_g, params); + let msg2 = b"Foo bar"; + let sig2 = sk2.sign(msg2, rng, p_g, params); + assert!(vk2.verify(msg2, &sig2, p_g, params)); + + let mut batch = vec![ + BatchEntry { vk: vk1, msg: msg1, sig: sig1 }, + BatchEntry { vk: vk2, msg: msg2, sig: sig2 } + ]; + + assert!(batch_verify(rng, &batch, params, p_g)); + + batch[0].sig = sig2; + + assert!(!batch_verify(rng, &batch, params, p_g)); + } + #[test] fn cofactor_check() { let rng = &mut thread_rng(); From 9cb8accf099714413488d055b9df8582417e505c Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 30 Jul 2018 07:29:23 -0600 Subject: [PATCH 4/4] Fix nits --- src/redjubjub.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/redjubjub.rs b/src/redjubjub.rs index 7fc83b8..dfae28c 100644 --- a/src/redjubjub.rs +++ b/src/redjubjub.rs @@ -146,7 +146,7 @@ impl PublicKey { Ok(s) => s, Err(_) => return false, }; - // 0 = 8(-S . P_G + R + c . vk) + // 0 = h_G(-S . P_G + R + c . vk) self.0.mul(c, params).add(&r, params).add( ¶ms.generator(p_g).mul(s, params).negate().into(), params @@ -160,11 +160,13 @@ pub struct BatchEntry<'a, E: JubjubEngine> { sig: Signature, } +// TODO: #82: This is a naive implementation currently, +// and doesn't use multiexp. pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( rng: &mut R, batch: &[BatchEntry<'a, E>], + p_g: FixedGenerators, params: &E::Params, - p_g: FixedGenerators ) -> bool { let mut acc = Point::::zero(); @@ -232,20 +234,21 @@ mod tests { BatchEntry { vk: vk2, msg: msg2, sig: sig2 } ]; - assert!(batch_verify(rng, &batch, params, p_g)); + assert!(batch_verify(rng, &batch, p_g, params)); batch[0].sig = sig2; - assert!(!batch_verify(rng, &batch, params, p_g)); + assert!(!batch_verify(rng, &batch, p_g, params)); } #[test] fn cofactor_check() { let rng = &mut thread_rng(); let params = &JubjubBls12::new(); - let inf = edwards::Point::zero(); + let zero = edwards::Point::zero(); let p_g = FixedGenerators::SpendingKeyGenerator; + // Get a point of order 8 let p8 = loop { let r = edwards::Point::::rand(rng, params).mul(Fs::char(), params); @@ -253,13 +256,15 @@ mod tests { let r4 = r2.double(params); let r8 = r4.double(params); - if r2 != inf && r4 != inf && r8 == inf { + if r2 != zero && r4 != zero && r8 == zero { break r; } }; let sk = PrivateKey::(rng.gen()); let vk = PublicKey::from_private(&sk, p_g, params); + + // TODO: This test will need to change when #77 is fixed let msg = b"Foo bar"; let sig = sk.sign(msg, rng, p_g, params); assert!(vk.verify(msg, &sig, p_g, params));