From 5dc6d75b4aacc9b4053754c337ea49c2e577e041 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 29 Mar 2023 11:50:18 -0300 Subject: [PATCH 01/23] Skeleton of code compiling --- primitives/Cargo.toml | 4 +- primitives/src/signatures/bls_arkwors.rs | 588 +++++++++++++++++++++++ primitives/src/signatures/mod.rs | 2 + 3 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 primitives/src/signatures/bls_arkwors.rs diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 5a493d19b..2c6908c20 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -12,14 +12,14 @@ ark-bls12-377 = "0.4.0" ark-bls12-381 = "0.4.0" ark-bn254 = "0.4.0" ark-bw6-761 = "0.4.0" +ark-crypto-primitives = { version = "0.4.0", features = ["sponge"] } ark-ec = "0.4.0" ark-ed-on-bls12-377 = "0.4.0" ark-ed-on-bls12-381 = "0.4.0" ark-ed-on-bn254 = "0.4.0" ark-ff = "0.4.0" ark-poly = "0.4.0" -ark-serialize = "0.4.0" -ark-crypto-primitives = { version = "0.4.0", features = ["sponge"] } +ark-serialize = { version = "0.4.0", features = ["derive"] } ark-std = { version = "0.4.0", default-features = false } blst = "0.3.10" crypto_box = "0.8.1" diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs new file mode 100644 index 000000000..ab8d554ce --- /dev/null +++ b/primitives/src/signatures/bls_arkwors.rs @@ -0,0 +1,588 @@ +// Copyright (c) 2022 Espresso Systems (espressosys.com) +// This file is part of the Jellyfish library. + +// You should have received a copy of the MIT License +// along with the Jellyfish library. If not, see . + +//! This module implements the Schnorr signature over the various Edwards +//! curves. + +use super::SignatureScheme; +use crate::{ + constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN128 curve + // crhf::{VariableLengthRescueCRHF, CRHF}, + errors::PrimitivesError, + // rescue::RescueParameter, + // utils::curve_cofactor, +}; +// use ark_ec::{ +// twisted_edwards::{Affine, Projective, TECurveConfig as Config}, +// AffineRepr, CurveConfig, CurveGroup, Group, +// }; + +use ark_ec::{ + bn::{ + BnConfig as Config, + // G1Affine, + G1Projective, + G2Affine, + G2Projective, + }, + AffineRepr, CurveGroup, Group, +}; + +use ark_ff::PrimeField; +use ark_serialize::*; +use ark_std::{ + hash::{Hash, Hasher}, + marker::PhantomData, + rand::{CryptoRng, Rng, RngCore}, + // string::ToString, + // vec, + vec::Vec, +}; +use espresso_systems_common::jellyfish::tag; +// use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; +use tagged_base64::tagged; +use zeroize::Zeroize; + +/// BLS signature scheme. +pub struct BLSOverBNCurveSignatureScheme

{ + curve_param: PhantomData

, // TODO what is this? +} + +impl

SignatureScheme for BLSOverBNCurveSignatureScheme

+where + P: Config + PrimeField, +{ + const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this + + /// Signing key. + type SigningKey = SignKey

; + + /// Verification key + type VerificationKey = VerKey

; + + /// Public Parameter + type PublicParameter = (); + + /// Signature + type Signature = Signature

; + + /// A message is &\[MessageUnit\] + type MessageUnit = P; // TODO Is that correct? + + /// generate public parameters from RNG. + fn param_gen( + _prng: Option<&mut R>, + ) -> Result { + Ok(()) + } + + /// Sample a pair of keys. + fn key_gen( + _pp: &Self::PublicParameter, + prng: &mut R, + ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { + let kp = KeyPair::

::generate(prng); + Ok((kp.sk, kp.vk)) + } + + /// Sign a message with the signing key + fn sign>( + _pp: &Self::PublicParameter, + _sk: &Self::SigningKey, + _msg: M, + _prng: &mut R, + ) -> Result { + // TODO + Ok(Signature { + sigma: G1Projective::

::generator(), + }) + } + + /// Verify a signature. + fn verify>( + _pp: &Self::PublicParameter, + vk: &Self::VerificationKey, + msg: M, + sig: &Self::Signature, + ) -> Result<(), PrimitivesError> { + vk.verify(msg.as_ref(), sig, Self::CS_ID) + } +} + +// ===================================================== +// Signing key +// ===================================================== +#[tagged(tag::SCHNORR_SIGNING_KEY)] +#[derive( + Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, +)] +/// Signing key for BLS signature. +pub struct SignKey(pub(crate) F); + +impl Drop for SignKey { + fn drop(&mut self) { + self.0.zeroize(); + } +} + +impl SignKey { + // returns the randomized key + // fn randomize_with(&self, randomizer: &F) -> Self { + // Self(self.0 + randomizer) + // } +} + +// ===================================================== +// Verification key +// ===================================================== + +/// Signature public verification key +// derive zeroize here so that keypair can be zeroized +#[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Config"), + Default(bound = "P: Config"), + Eq(bound = "P: Config"), + Clone(bound = "P: Config") +)] +pub struct VerKey

(pub(crate) G2Projective

) +where + P: Config; + +impl VerKey

{ + // TODO is this needed? + // Return a randomized verification key. + // pub fn randomize_with(&self, randomizer: &F) -> Self + // where + // F: PrimeField, + // P: Config, + // { + // + // Self(G1Projective::

::generator() * randomizer + self.0) + // } +} + +impl

Hash for VerKey

+where + P: Config, +{ + fn hash(&self, state: &mut H) { + Hash::hash(&self.0.into_affine(), state) + } +} + +impl

PartialEq for VerKey

+where + P: Config, +{ + fn eq(&self, other: &Self) -> bool { + self.0.into_affine().eq(&other.0.into_affine()) + } +} + +impl

From> for VerKey

+where + P: Config, +{ + fn from(point: G2Affine

) -> Self { + VerKey(point.into_group()) + } +} + +impl VerKey

{ + /// Convert the verification key into the affine form. + pub fn to_affine(&self) -> G2Affine

{ + self.0.into_affine() + } +} + +// ===================================================== +// Key pair +// ===================================================== + +/// Signature secret key pair used to sign messages +// make sure sk can be zeroized +#[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Config"), + Default(bound = "P: Config"), + Clone(bound = "P: Config"), + PartialEq(bound = "P: Config") +)] +pub struct KeyPair

+where + P: Config + PrimeField, +{ + sk: SignKey

, + vk: VerKey

, +} + +// ===================================================== +// Signature +// ===================================================== + +/// The signature of BLS signature scheme +#[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Config"), + Default(bound = "P: Config"), + Eq(bound = "P: Config"), + Clone(bound = "P: Config") +)] +#[allow(non_snake_case)] +pub struct Signature

+where + P: Config, +{ + pub(crate) sigma: G1Projective

, +} + +impl

Hash for Signature

+where + P: Config, +{ + fn hash(&self, state: &mut H) { + Hash::hash(&self.sigma, state); + } +} + +impl

PartialEq for Signature

+where + P: Config, +{ + fn eq(&self, other: &Self) -> bool { + self.sigma == other.sigma + } +} +// ===================================================== +// end of definitions +// ===================================================== + +impl

KeyPair

+where + P: Config + PrimeField, +{ + /// Key-pair generation algorithm + pub fn generate(prng: &mut R) -> KeyPair

{ + let sk = SignKey::generate(prng); + let vk = VerKey::from(&sk); + KeyPair { sk, vk } + } + + /// Key pair generation using a particular sign key secret `sk` + pub fn generate_with_sign_key(sk: P) -> Self { + let sk = SignKey(sk); + let vk = VerKey::from(&sk); + KeyPair { sk, vk } + } + + /// Get reference to verification key + pub fn ver_key_ref(&self) -> &VerKey

{ + &self.vk + } + + /// Get the verification key + pub fn ver_key(&self) -> VerKey

{ + self.vk.clone() + } + + /// Get the internal of the signing key, namely a P::ScalarField element + pub fn sign_key_internal(&self) -> &P { + &self.sk.0 + } + + /// Signature function + #[allow(non_snake_case)] + pub fn sign>(&self, _msg: &[P], _csid: B) -> Signature

{ + // TODO + + let sigma = G1Projective::

::generator(); + Signature { sigma } + } +} + +impl SignKey { + fn generate(prng: &mut R) -> SignKey { + SignKey(F::rand(prng)) + } +} + +impl From<&SignKey> for VerKey

+where + P: Config, + F: PrimeField, +{ + fn from(_sk: &SignKey) -> Self { + // TODO + // VerKey(G2Projective::

::generator().clone() * sk.0.clone()) + VerKey(G2Projective::

::generator()) + } +} + +impl

VerKey

+where + P: Config, +{ + /// Get the internal of verifying key, namely a curve Point + pub fn internal(&self) -> &G2Projective

{ + &self.0 + } + + /// Signature verification function + #[allow(non_snake_case)] + pub fn verify>( + &self, + _msg: &[P], + _sig: &Signature

, + _csid: B, + ) -> Result<(), PrimitivesError> { + // Reject if public key is of small order + Ok(()) + } +} + +// impl

VerKey

+// where +// P: Config, +// { +// // TODO: this function should be generic w.r.t. hash functions +// // Fixme after the hash-api PR is merged. +// #[allow(non_snake_case)] +// fn challenge>(&self, R: &Projective

, msg: &[F], csid: +// B) -> P::ScalarField { // is the domain separator always an Fr? If so +// how about using Fr as domain // separator rather than bytes? +// let instance_description = F::from_be_bytes_mod_order(csid.as_ref()); +// let mut challenge_input = { +// let vk_affine = self.0.into_affine(); +// let R_affine = R.into_affine(); +// vec![ +// instance_description, +// vk_affine.x, +// vk_affine.y, +// R_affine.x, +// R_affine.y, +// ] +// }; +// challenge_input.extend(msg); +// let challenge_fq = VariableLengthRescueCRHF::::evaluate(challenge_input).unwrap()[0]; // safe unwrap +// +// // this masking will drop the last byte, and the resulting +// // challenge will be 248 bits +// fq_to_fr_with_mask(&challenge_fq) +// } +// } + +#[cfg(test)] +mod tests { + + #[test] + fn test() { + assert!(true); + } + + // use super::*; + // use crate::{ + // constants::CS_ID_SCHNORR, + // signatures::tests::{failed_verification, sign_and_verify}, + // }; + // use ark_ed_on_bls12_377::EdwardsConfig as Param377; + // use ark_ed_on_bls12_381::EdwardsConfig as Param381; + // use ark_ed_on_bls12_381_bandersnatch::EdwardsConfig as Param381b; + // use ark_ed_on_bn254::EdwardsConfig as Param254; + // use ark_std::UniformRand; + // + // macro_rules! test_signature { + // ($curve_param:tt) => { + // let mut rng = jf_utils::test_rng(); + // + // let keypair1 = KeyPair::generate(&mut rng); + // // test randomized key pair + // let randomizer2 = <$curve_param as + // CurveConfig>::ScalarField::rand(&mut rng); let keypair2 = + // keypair1.randomize_with(&randomizer2); let randomizer3 = + // <$curve_param as CurveConfig>::ScalarField::rand(&mut rng); + // let keypair3 = keypair2.randomize_with(&randomizer3); + // let keypairs = vec![keypair1, keypair2, keypair3]; + // + // let pk_bad: VerKey<$curve_param> = KeyPair::generate(&mut + // rng).ver_key_ref().clone(); + // + // let mut msg = vec![]; + // for i in 0..20 { + // for keypair in &keypairs { + // assert_eq!(keypair.vk, VerKey::from(&keypair.sk)); + // + // let sig = keypair.sign(&msg, CS_ID_SCHNORR); + // let pk = keypair.ver_key_ref(); + // assert!(pk.verify(&msg, &sig, CS_ID_SCHNORR).is_ok()); + // // wrong public key + // assert!(pk_bad.verify(&msg, &sig, + // CS_ID_SCHNORR).is_err()); // wrong message + // msg.push(<$curve_param as CurveConfig>::BaseField::from(i + // as u64)); assert!(pk.verify(&msg, &sig, + // CS_ID_SCHNORR).is_err()); } + // } + // + // let message = <$curve_param as CurveConfig>::BaseField::rand(&mut + // rng); + // sign_and_verify::>(& + // [message]); + // failed_verification::>( + // &[message], + // &[<$curve_param as CurveConfig>::BaseField::rand(&mut rng)], + // ); + // }; + // } + // + // #[test] + // fn test_signature() { + // test_signature!(Param254); + // test_signature!(Param377); + // test_signature!(Param381); + // test_signature!(Param381b); + // } + + // mod serde { + + // use super::super::{KeyPair, SignKey, Signature, VerKey}; + // use crate::constants::CS_ID_SCHNORR; + // use ark_ec::twisted_edwards::Projective; + // use ark_ed_on_bls12_377::{EdwardsConfig as Param377, Fq as FqEd377, Fr as + // FrEd377}; use ark_ed_on_bls12_381::{EdwardsConfig as Param381, Fq as + // FqEd381, Fr as FrEd381}; use ark_ed_on_bls12_381_bandersnatch::{ + // EdwardsConfig as Param381b, Fq as FqEd381b, Fr as FrEd381b, + // }; + // use ark_ed_on_bn254::{EdwardsConfig as Param254, Fq as FqEd254, Fr as + // FrEd254}; use ark_ff::Zero; + // use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + // use ark_std::{vec, vec::Vec, UniformRand}; + // + // macro_rules! test_ver_key { + // ($curve_param:tt, $scalar_field:tt) => { + // let mut rng = jf_utils::test_rng(); + // + // // happy path + // let keypair: KeyPair<$curve_param> = KeyPair::generate(&mut rng); + // let vk = keypair.ver_key_ref(); + // let sig = keypair.sign(&[], CS_ID_SCHNORR); + // assert!(&vk.verify(&[], &sig, CS_ID_SCHNORR).is_ok()); + // + // // Bad path + // let bad_ver_key = VerKey(Projective::<$curve_param>::zero()); + // let bad_keypair = KeyPair { + // sk: SignKey($scalar_field::zero()), + // vk: bad_ver_key.clone(), + // }; + // + // let sig_on_bad_key = bad_keypair.sign(&[], CS_ID_SCHNORR); + // assert!(&bad_ver_key + // .verify(&[], &sig_on_bad_key, CS_ID_SCHNORR) + // .is_err()); + // + // // test serialization + // let mut vk_bytes = vec![]; + // vk.serialize_compressed(&mut vk_bytes).unwrap(); + // let vk_de: VerKey<$curve_param> = + // VerKey::deserialize_compressed(vk_bytes.as_slice()).unwrap(); + // assert_eq!(*vk, vk_de, "normal ser/de should pass"); + // }; + // } + // #[test] + // fn test_ver_key() { + // test_ver_key!(Param254, FrEd254); + // test_ver_key!(Param377, FrEd377); + // test_ver_key!(Param381, FrEd381); + // test_ver_key!(Param381b, FrEd381b); + // } + // + // macro_rules! test_signature { + // ($curve_param:tt, $base_field:tt) => { + // let mut rng = jf_utils::test_rng(); + // let keypair: KeyPair<$curve_param> = KeyPair::generate(&mut rng); + // + // // Happy path + // let msg = vec![$base_field::from(8u8), $base_field::from(10u8)]; + // let sig = keypair.sign(&msg, CS_ID_SCHNORR); + // assert!(keypair.vk.verify(&msg, &sig, CS_ID_SCHNORR).is_ok()); + // assert!(keypair.vk.verify(&[], &sig, CS_ID_SCHNORR).is_err()); + // let mut bytes_sig = vec![]; + // sig.serialize_compressed(&mut bytes_sig).unwrap(); + // let sig_de: Signature<$curve_param> = + // + // Signature::deserialize_compressed(bytes_sig.as_slice()).unwrap(); + // assert_eq!(sig, sig_de); + // + // // Bad path 1: when s bytes overflow + // let mut bad_bytes_sig = bytes_sig.clone(); + // let mut q_minus_one_bytes = vec![]; + // (-$base_field::from(1u32)) + // .serialize_compressed(&mut q_minus_one_bytes) + // .unwrap(); + // bad_bytes_sig.splice(.., q_minus_one_bytes.iter().cloned()); + // assert!(Signature::<$curve_param>::deserialize_compressed( + // bad_bytes_sig.as_slice() + // ) + // .is_err()); + // }; + // } + // + // #[test] + // fn test_signature() { + // test_signature!(Param254, FqEd254); + // test_signature!(Param377, FqEd377); + // test_signature!(Param381, FqEd381); + // test_signature!(Param381b, FqEd381b); + // } + // + // macro_rules! test_serde { + // ($curve_param:tt, $scalar_field:tt, $base_field:tt) => { + // let mut rng = jf_utils::test_rng(); + // let keypair = KeyPair::generate(&mut rng); + // let sk = SignKey::<$scalar_field>::generate(&mut rng); + // let vk = keypair.ver_key(); + // let msg = vec![$base_field::rand(&mut rng)]; + // let sig = keypair.sign(&msg, CS_ID_SCHNORR); + // + // let mut ser_bytes: Vec = Vec::new(); + // keypair.serialize_compressed(&mut ser_bytes).unwrap(); + // let de: KeyPair<$curve_param> = + // KeyPair::deserialize_compressed(&ser_bytes[..]).unwrap(); + // assert_eq!(de.ver_key_ref(), keypair.ver_key_ref()); + // assert_eq!(de.ver_key_ref(), &VerKey::from(&de.sk)); + // + // let mut ser_bytes: Vec = Vec::new(); + // sk.serialize_compressed(&mut ser_bytes).unwrap(); + // let de: SignKey<$scalar_field> = + // SignKey::deserialize_compressed(&ser_bytes[..]).unwrap(); + // assert_eq!(VerKey::<$curve_param>::from(&de), VerKey::from(&sk)); + // + // let mut ser_bytes: Vec = Vec::new(); + // vk.serialize_compressed(&mut ser_bytes).unwrap(); + // let de: VerKey<$curve_param> = + // VerKey::deserialize_compressed(&ser_bytes[..]).unwrap(); + // assert_eq!(de, vk); + // + // let mut ser_bytes: Vec = Vec::new(); + // sig.serialize_compressed(&mut ser_bytes).unwrap(); + // let de: Signature<$curve_param> = + // Signature::deserialize_compressed(&ser_bytes[..]).unwrap(); + // assert_eq!(de, sig); + // }; + // } + // + // #[test] + // fn test_serde() { + // test_serde!(Param254, FrEd254, FqEd254); + // test_serde!(Param377, FrEd377, FqEd377); + // test_serde!(Param381, FrEd381, FqEd381); + // test_serde!(Param381b, FrEd381b, FqEd381b); + // } + // } +} diff --git a/primitives/src/signatures/mod.rs b/primitives/src/signatures/mod.rs index 8e8f689aa..66f68e8bb 100644 --- a/primitives/src/signatures/mod.rs +++ b/primitives/src/signatures/mod.rs @@ -4,7 +4,9 @@ use crate::errors::PrimitivesError; use ark_std::rand::{CryptoRng, RngCore}; pub mod bls; +mod bls_arkwors; pub mod schnorr; + pub use bls::BLSSignatureScheme; use core::fmt::Debug; pub use schnorr::SchnorrSignatureScheme; From dd4009885b3717a5b3f4da6259c10def6b64e294 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 29 Mar 2023 12:49:31 -0300 Subject: [PATCH 02/23] Fix type errors --- primitives/src/signatures/bls_arkwors.rs | 55 +++++++++++++++--------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index ab8d554ce..37b095c18 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -4,8 +4,7 @@ // You should have received a copy of the MIT License // along with the Jellyfish library. If not, see . -//! This module implements the Schnorr signature over the various Edwards -//! curves. +//! This module implements the BLS signature over BN curves. use super::SignatureScheme; use crate::{ @@ -51,14 +50,15 @@ pub struct BLSOverBNCurveSignatureScheme

{ curve_param: PhantomData

, // TODO what is this? } -impl

SignatureScheme for BLSOverBNCurveSignatureScheme

+impl SignatureScheme for BLSOverBNCurveSignatureScheme

where - P: Config + PrimeField, + P: Config, + F: PrimeField, { const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this /// Signing key. - type SigningKey = SignKey

; + type SigningKey = SignKey; /// Verification key type VerificationKey = VerKey

; @@ -70,7 +70,7 @@ where type Signature = Signature

; /// A message is &\[MessageUnit\] - type MessageUnit = P; // TODO Is that correct? + type MessageUnit = F; // TODO Is that correct? /// generate public parameters from RNG. fn param_gen( @@ -84,7 +84,7 @@ where _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let kp = KeyPair::

::generate(prng); + let kp = KeyPair::::generate(prng); Ok((kp.sk, kp.vk)) } @@ -214,11 +214,12 @@ impl VerKey

{ Clone(bound = "P: Config"), PartialEq(bound = "P: Config") )] -pub struct KeyPair

+pub struct KeyPair where - P: Config + PrimeField, + P: Config, + F: PrimeField, { - sk: SignKey

, + sk: SignKey, vk: VerKey

, } @@ -264,19 +265,20 @@ where // end of definitions // ===================================================== -impl

KeyPair

+impl KeyPair where - P: Config + PrimeField, + P: Config, + F: PrimeField, { /// Key-pair generation algorithm - pub fn generate(prng: &mut R) -> KeyPair

{ + pub fn generate(prng: &mut R) -> KeyPair { let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); KeyPair { sk, vk } } /// Key pair generation using a particular sign key secret `sk` - pub fn generate_with_sign_key(sk: P) -> Self { + pub fn generate_with_sign_key(sk: F) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); KeyPair { sk, vk } @@ -293,7 +295,7 @@ where } /// Get the internal of the signing key, namely a P::ScalarField element - pub fn sign_key_internal(&self) -> &P { + pub fn sign_key_internal(&self) -> &F { &self.sk.0 } @@ -313,21 +315,32 @@ impl SignKey { } } -impl From<&SignKey> for VerKey

+// impl

From<&SignKey> for VerKey

+// where +// P: Config, +// { +// fn from( +// sk: &SignKey) -> Self { +// // TODO +// // VerKey(G2Projective::

::generator().clone() * sk.0.clone()) +// VerKey(G2Projective::

::generator() * sk.0) +// } +// } + +impl From<&SignKey> for VerKey

where P: Config, F: PrimeField, { fn from(_sk: &SignKey) -> Self { - // TODO - // VerKey(G2Projective::

::generator().clone() * sk.0.clone()) VerKey(G2Projective::

::generator()) } } -impl

VerKey

+impl VerKey

where - P: Config, + P: Config, + F: PrimeField, { /// Get the internal of verifying key, namely a curve Point pub fn internal(&self) -> &G2Projective

{ @@ -338,7 +351,7 @@ where #[allow(non_snake_case)] pub fn verify>( &self, - _msg: &[P], + _msg: &[F], _sig: &Signature

, _csid: B, ) -> Result<(), PrimitivesError> { From c56670771503d40c189922edb26a45869c402b02 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 29 Mar 2023 16:22:51 -0300 Subject: [PATCH 03/23] Fix trait errors --- primitives/src/signatures/bls_arkwors.rs | 166 ++++++++++++----------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 37b095c18..68c4a4ff0 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -19,27 +19,16 @@ use crate::{ // AffineRepr, CurveConfig, CurveGroup, Group, // }; -use ark_ec::{ - bn::{ - BnConfig as Config, - // G1Affine, - G1Projective, - G2Affine, - G2Projective, - }, - AffineRepr, CurveGroup, Group, -}; - -use ark_ff::PrimeField; +use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, marker::PhantomData, rand::{CryptoRng, Rng, RngCore}, - // string::ToString, - // vec, vec::Vec, + UniformRand, }; + use espresso_systems_common::jellyfish::tag; // use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; use tagged_base64::tagged; @@ -50,15 +39,14 @@ pub struct BLSOverBNCurveSignatureScheme

{ curve_param: PhantomData

, // TODO what is this? } -impl SignatureScheme for BLSOverBNCurveSignatureScheme

+impl

SignatureScheme for BLSOverBNCurveSignatureScheme

where - P: Config, - F: PrimeField, + P: Pairing + Zeroize + Default, { const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this /// Signing key. - type SigningKey = SignKey; + type SigningKey = SignKey

; /// Verification key type VerificationKey = VerKey

; @@ -70,7 +58,7 @@ where type Signature = Signature

; /// A message is &\[MessageUnit\] - type MessageUnit = F; // TODO Is that correct? + type MessageUnit = P::ScalarField; // TODO Is that correct? /// generate public parameters from RNG. fn param_gen( @@ -84,7 +72,7 @@ where _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let kp = KeyPair::::generate(prng); + let kp = KeyPair::

::generate(prng); Ok((kp.sk, kp.vk)) } @@ -97,7 +85,7 @@ where ) -> Result { // TODO Ok(Signature { - sigma: G1Projective::

::generator(), + sigma: P::G1::generator(), }) } @@ -115,20 +103,20 @@ where // ===================================================== // Signing key // ===================================================== -#[tagged(tag::SCHNORR_SIGNING_KEY)] +#[tagged(tag::BLS_SIGNING_KEY)] #[derive( Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] /// Signing key for BLS signature. -pub struct SignKey(pub(crate) F); +pub struct SignKey(pub(crate) P::ScalarField); -impl Drop for SignKey { +impl Drop for SignKey

{ fn drop(&mut self) { self.0.zeroize(); } } -impl SignKey { +impl SignKey

{ // returns the randomized key // fn randomize_with(&self, randomizer: &F) -> Self { // Self(self.0 + randomizer) @@ -144,16 +132,16 @@ impl SignKey { #[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( - Debug(bound = "P: Config"), - Default(bound = "P: Config"), - Eq(bound = "P: Config"), - Clone(bound = "P: Config") + Debug(bound = "P: Pairing"), + Default(bound = "P: Pairing"), + Eq(bound = "P: Pairing"), + Clone(bound = "P: Pairing") )] -pub struct VerKey

(pub(crate) G2Projective

) +pub struct VerKey

(pub(crate) P::G2) where - P: Config; + P: Pairing; -impl VerKey

{ +impl VerKey

{ // TODO is this needed? // Return a randomized verification key. // pub fn randomize_with(&self, randomizer: &F) -> Self @@ -168,7 +156,7 @@ impl VerKey

{ impl

Hash for VerKey

where - P: Config, + P: Pairing, { fn hash(&self, state: &mut H) { Hash::hash(&self.0.into_affine(), state) @@ -177,25 +165,34 @@ where impl

PartialEq for VerKey

where - P: Config, + P: Pairing, { fn eq(&self, other: &Self) -> bool { self.0.into_affine().eq(&other.0.into_affine()) } } -impl

From> for VerKey

-where - P: Config, -{ - fn from(point: G2Affine

) -> Self { - VerKey(point.into_group()) - } -} +// impl

Default for VerKey

+// where +// P: Pairing, +// { +// fn default() -> Self { +// P::G2::generator() +// } +// } -impl VerKey

{ +// impl

From for VerKey

+// where +// P: Pairing, +// { +// fn from(point: P::G2) -> Self { +// VerKey(point) +// } +// } + +impl VerKey

{ /// Convert the verification key into the affine form. - pub fn to_affine(&self) -> G2Affine

{ + pub fn to_affine(&self) -> P::G2Affine { self.0.into_affine() } } @@ -209,20 +206,30 @@ impl VerKey

{ #[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( - Debug(bound = "P: Config"), - Default(bound = "P: Config"), - Clone(bound = "P: Config"), - PartialEq(bound = "P: Config") + Debug(bound = "P: Pairing"), + Clone(bound = "P: Pairing"), + PartialEq(bound = "P: Pairing") )] -pub struct KeyPair +pub struct KeyPair

where - P: Config, - F: PrimeField, + P: Pairing, { - sk: SignKey, + sk: SignKey

, vk: VerKey

, } +// impl

Default for KeyPair

+// where +// P: Pairing, +// { +// fn default() -> Self { +// KeyPair { +// sk: SignKey::

::default(), +// vk: VerKey::

::default(), +// } +// } +// } + // ===================================================== // Signature // ===================================================== @@ -231,22 +238,22 @@ where #[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( - Debug(bound = "P: Config"), - Default(bound = "P: Config"), - Eq(bound = "P: Config"), - Clone(bound = "P: Config") + Debug(bound = "P: Pairing"), + Default(bound = "P: Pairing"), + Eq(bound = "P: Pairing"), + Clone(bound = "P: Pairing") )] #[allow(non_snake_case)] pub struct Signature

where - P: Config, + P: Pairing, { - pub(crate) sigma: G1Projective

, + pub(crate) sigma: P::G1, } impl

Hash for Signature

where - P: Config, + P: Pairing, { fn hash(&self, state: &mut H) { Hash::hash(&self.sigma, state); @@ -255,7 +262,7 @@ where impl

PartialEq for Signature

where - P: Config, + P: Pairing, { fn eq(&self, other: &Self) -> bool { self.sigma == other.sigma @@ -265,20 +272,19 @@ where // end of definitions // ===================================================== -impl KeyPair +impl

KeyPair

where - P: Config, - F: PrimeField, + P: Pairing + Default, { /// Key-pair generation algorithm - pub fn generate(prng: &mut R) -> KeyPair { + pub fn generate(prng: &mut R) -> KeyPair

{ let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); KeyPair { sk, vk } } /// Key pair generation using a particular sign key secret `sk` - pub fn generate_with_sign_key(sk: F) -> Self { + pub fn generate_with_sign_key(sk: P::ScalarField) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); KeyPair { sk, vk } @@ -295,7 +301,7 @@ where } /// Get the internal of the signing key, namely a P::ScalarField element - pub fn sign_key_internal(&self) -> &F { + pub fn sign_key_internal(&self) -> &P::ScalarField { &self.sk.0 } @@ -304,14 +310,14 @@ where pub fn sign>(&self, _msg: &[P], _csid: B) -> Signature

{ // TODO - let sigma = G1Projective::

::generator(); + let sigma = P::G1::generator(); Signature { sigma } } } -impl SignKey { - fn generate(prng: &mut R) -> SignKey { - SignKey(F::rand(prng)) +impl SignKey

{ + fn generate(prng: &mut R) -> SignKey

{ + SignKey(P::ScalarField::rand(prng)) } } @@ -327,31 +333,29 @@ impl SignKey { // } // } -impl From<&SignKey> for VerKey

+impl

From<&SignKey

> for VerKey

where - P: Config, - F: PrimeField, + P: Pairing, { - fn from(_sk: &SignKey) -> Self { - VerKey(G2Projective::

::generator()) + fn from(sk: &SignKey

) -> Self { + VerKey(P::G2::generator() * sk.0) } } -impl VerKey

+impl

VerKey

where - P: Config, - F: PrimeField, + P: Pairing, { /// Get the internal of verifying key, namely a curve Point - pub fn internal(&self) -> &G2Projective

{ - &self.0 + pub fn internal(&self) -> P::G2 { + self.0 } /// Signature verification function #[allow(non_snake_case)] pub fn verify>( &self, - _msg: &[F], + _msg: &[P::ScalarField], _sig: &Signature

, _csid: B, ) -> Result<(), PrimitivesError> { From 17c4ab5109150c5e95ace2062816b9414fcf2494 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 29 Mar 2023 16:36:20 -0300 Subject: [PATCH 04/23] Key pair generation --- primitives/src/signatures/bls_arkwors.rs | 66 ++++++------------------ 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 68c4a4ff0..21dc5e80c 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -214,6 +214,7 @@ pub struct KeyPair

where P: Pairing, { + phantom: PhantomData

, sk: SignKey

, vk: VerKey

, } @@ -274,20 +275,28 @@ where impl

KeyPair

where - P: Pairing + Default, + P: Pairing, { /// Key-pair generation algorithm pub fn generate(prng: &mut R) -> KeyPair

{ let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); - KeyPair { sk, vk } + KeyPair { + phantom: Default::default(), + sk, + vk, + } } /// Key pair generation using a particular sign key secret `sk` pub fn generate_with_sign_key(sk: P::ScalarField) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); - KeyPair { sk, vk } + KeyPair { + phantom: Default::default(), + sk, + vk, + } } /// Get reference to verification key @@ -321,18 +330,6 @@ impl SignKey

{ } } -// impl

From<&SignKey> for VerKey

-// where -// P: Config, -// { -// fn from( -// sk: &SignKey) -> Self { -// // TODO -// // VerKey(G2Projective::

::generator().clone() * sk.0.clone()) -// VerKey(G2Projective::

::generator() * sk.0) -// } -// } - impl

From<&SignKey

> for VerKey

where P: Pairing, @@ -364,44 +361,15 @@ where } } -// impl

VerKey

-// where -// P: Config, -// { -// // TODO: this function should be generic w.r.t. hash functions -// // Fixme after the hash-api PR is merged. -// #[allow(non_snake_case)] -// fn challenge>(&self, R: &Projective

, msg: &[F], csid: -// B) -> P::ScalarField { // is the domain separator always an Fr? If so -// how about using Fr as domain // separator rather than bytes? -// let instance_description = F::from_be_bytes_mod_order(csid.as_ref()); -// let mut challenge_input = { -// let vk_affine = self.0.into_affine(); -// let R_affine = R.into_affine(); -// vec![ -// instance_description, -// vk_affine.x, -// vk_affine.y, -// R_affine.x, -// R_affine.y, -// ] -// }; -// challenge_input.extend(msg); -// let challenge_fq = VariableLengthRescueCRHF::::evaluate(challenge_input).unwrap()[0]; // safe unwrap -// -// // this masking will drop the last byte, and the resulting -// // challenge will be 248 bits -// fq_to_fr_with_mask(&challenge_fq) -// } -// } - #[cfg(test)] mod tests { + use crate::signatures::bls_arkwors::KeyPair; + use ark_bn254::Bn254; #[test] - fn test() { - assert!(true); + fn test_bls_signature() { + let mut rng = jf_utils::test_rng(); + let _key_pair = KeyPair::::generate(&mut rng); } // use super::*; From 52b45ef2c48532df68c662e06a6cd218f4536768 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 29 Mar 2023 18:13:22 -0300 Subject: [PATCH 05/23] Fix clippy error. --- primitives/src/signatures/bls_arkwors.rs | 265 +++++------------------ 1 file changed, 49 insertions(+), 216 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 21dc5e80c..553e679b6 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -7,30 +7,27 @@ //! This module implements the BLS signature over BN curves. use super::SignatureScheme; + use crate::{ constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN128 curve - // crhf::{VariableLengthRescueCRHF, CRHF}, errors::PrimitivesError, - // rescue::RescueParameter, - // utils::curve_cofactor, }; -// use ark_ec::{ -// twisted_edwards::{Affine, Projective, TECurveConfig as Config}, -// AffineRepr, CurveConfig, CurveGroup, Group, -// }; - use ark_ec::{pairing::Pairing, CurveGroup, Group}; +use ark_ff::field_hashers::{DefaultFieldHasher, HashToField}; use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, marker::PhantomData, rand::{CryptoRng, Rng, RngCore}, + string::ToString, vec::Vec, UniformRand, }; use espresso_systems_common::jellyfish::tag; +use sha2::Sha256; // use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; +use crate::errors::PrimitivesError::VerificationError; use tagged_base64::tagged; use zeroize::Zeroize; @@ -58,7 +55,7 @@ where type Signature = Signature

; /// A message is &\[MessageUnit\] - type MessageUnit = P::ScalarField; // TODO Is that correct? + type MessageUnit = u8; /// generate public parameters from RNG. fn param_gen( @@ -273,6 +270,15 @@ where // end of definitions // ===================================================== +// TODO insecure!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// +fn hash_to_curve(msg: &[u8]) -> P::G1 { + let hasher_init = &[1u8]; + let hasher = as HashToField>::new(hasher_init); + let field_elems: jf_utils::Vec = hasher.hash_to_field(msg, 1); + P::G1::generator() * field_elems[0] +} + impl

KeyPair

where P: Pairing, @@ -316,10 +322,11 @@ where /// Signature function #[allow(non_snake_case)] - pub fn sign>(&self, _msg: &[P], _csid: B) -> Signature

{ - // TODO + pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature

{ + // TODO take into account csid - let sigma = P::G1::generator(); + let hash_value: P::G1 = hash_to_curve::

(msg); + let sigma = hash_value * self.sk.0; Signature { sigma } } } @@ -352,222 +359,48 @@ where #[allow(non_snake_case)] pub fn verify>( &self, - _msg: &[P::ScalarField], - _sig: &Signature

, + msg: &[u8], + sig: &Signature

, _csid: B, ) -> Result<(), PrimitivesError> { - // Reject if public key is of small order - Ok(()) + // TODO Check public key + // TODO take into account csid + + let group_elem = hash_to_curve::

(msg); + let g2 = P::G2::generator(); + let is_sig_valid = P::pairing(sig.sigma, g2) == P::pairing(group_elem, self.0); + if is_sig_valid { + Ok(()) + } else { + Err(VerificationError("Pairing check failed".to_string())) + } } } #[cfg(test)] mod tests { - use crate::signatures::bls_arkwors::KeyPair; + use crate::{constants::CS_ID_BLS_MIN_SIG, signatures::bls_arkwors::KeyPair}; use ark_bn254::Bn254; + use ark_ff::vec; // TODO new constant #[test] fn test_bls_signature() { + // TODO use SignatureScheme instead + let mut rng = jf_utils::test_rng(); - let _key_pair = KeyPair::::generate(&mut rng); - } + let key_pair = KeyPair::::generate(&mut rng); + let msg = vec![15u8, 44u8]; + let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); - // use super::*; - // use crate::{ - // constants::CS_ID_SCHNORR, - // signatures::tests::{failed_verification, sign_and_verify}, - // }; - // use ark_ed_on_bls12_377::EdwardsConfig as Param377; - // use ark_ed_on_bls12_381::EdwardsConfig as Param381; - // use ark_ed_on_bls12_381_bandersnatch::EdwardsConfig as Param381b; - // use ark_ed_on_bn254::EdwardsConfig as Param254; - // use ark_std::UniformRand; - // - // macro_rules! test_signature { - // ($curve_param:tt) => { - // let mut rng = jf_utils::test_rng(); - // - // let keypair1 = KeyPair::generate(&mut rng); - // // test randomized key pair - // let randomizer2 = <$curve_param as - // CurveConfig>::ScalarField::rand(&mut rng); let keypair2 = - // keypair1.randomize_with(&randomizer2); let randomizer3 = - // <$curve_param as CurveConfig>::ScalarField::rand(&mut rng); - // let keypair3 = keypair2.randomize_with(&randomizer3); - // let keypairs = vec![keypair1, keypair2, keypair3]; - // - // let pk_bad: VerKey<$curve_param> = KeyPair::generate(&mut - // rng).ver_key_ref().clone(); - // - // let mut msg = vec![]; - // for i in 0..20 { - // for keypair in &keypairs { - // assert_eq!(keypair.vk, VerKey::from(&keypair.sk)); - // - // let sig = keypair.sign(&msg, CS_ID_SCHNORR); - // let pk = keypair.ver_key_ref(); - // assert!(pk.verify(&msg, &sig, CS_ID_SCHNORR).is_ok()); - // // wrong public key - // assert!(pk_bad.verify(&msg, &sig, - // CS_ID_SCHNORR).is_err()); // wrong message - // msg.push(<$curve_param as CurveConfig>::BaseField::from(i - // as u64)); assert!(pk.verify(&msg, &sig, - // CS_ID_SCHNORR).is_err()); } - // } - // - // let message = <$curve_param as CurveConfig>::BaseField::rand(&mut - // rng); - // sign_and_verify::>(& - // [message]); - // failed_verification::>( - // &[message], - // &[<$curve_param as CurveConfig>::BaseField::rand(&mut rng)], - // ); - // }; - // } - // - // #[test] - // fn test_signature() { - // test_signature!(Param254); - // test_signature!(Param377); - // test_signature!(Param381); - // test_signature!(Param381b); - // } + let ver_key = key_pair.vk; - // mod serde { - - // use super::super::{KeyPair, SignKey, Signature, VerKey}; - // use crate::constants::CS_ID_SCHNORR; - // use ark_ec::twisted_edwards::Projective; - // use ark_ed_on_bls12_377::{EdwardsConfig as Param377, Fq as FqEd377, Fr as - // FrEd377}; use ark_ed_on_bls12_381::{EdwardsConfig as Param381, Fq as - // FqEd381, Fr as FrEd381}; use ark_ed_on_bls12_381_bandersnatch::{ - // EdwardsConfig as Param381b, Fq as FqEd381b, Fr as FrEd381b, - // }; - // use ark_ed_on_bn254::{EdwardsConfig as Param254, Fq as FqEd254, Fr as - // FrEd254}; use ark_ff::Zero; - // use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; - // use ark_std::{vec, vec::Vec, UniformRand}; - // - // macro_rules! test_ver_key { - // ($curve_param:tt, $scalar_field:tt) => { - // let mut rng = jf_utils::test_rng(); - // - // // happy path - // let keypair: KeyPair<$curve_param> = KeyPair::generate(&mut rng); - // let vk = keypair.ver_key_ref(); - // let sig = keypair.sign(&[], CS_ID_SCHNORR); - // assert!(&vk.verify(&[], &sig, CS_ID_SCHNORR).is_ok()); - // - // // Bad path - // let bad_ver_key = VerKey(Projective::<$curve_param>::zero()); - // let bad_keypair = KeyPair { - // sk: SignKey($scalar_field::zero()), - // vk: bad_ver_key.clone(), - // }; - // - // let sig_on_bad_key = bad_keypair.sign(&[], CS_ID_SCHNORR); - // assert!(&bad_ver_key - // .verify(&[], &sig_on_bad_key, CS_ID_SCHNORR) - // .is_err()); - // - // // test serialization - // let mut vk_bytes = vec![]; - // vk.serialize_compressed(&mut vk_bytes).unwrap(); - // let vk_de: VerKey<$curve_param> = - // VerKey::deserialize_compressed(vk_bytes.as_slice()).unwrap(); - // assert_eq!(*vk, vk_de, "normal ser/de should pass"); - // }; - // } - // #[test] - // fn test_ver_key() { - // test_ver_key!(Param254, FrEd254); - // test_ver_key!(Param377, FrEd377); - // test_ver_key!(Param381, FrEd381); - // test_ver_key!(Param381b, FrEd381b); - // } - // - // macro_rules! test_signature { - // ($curve_param:tt, $base_field:tt) => { - // let mut rng = jf_utils::test_rng(); - // let keypair: KeyPair<$curve_param> = KeyPair::generate(&mut rng); - // - // // Happy path - // let msg = vec![$base_field::from(8u8), $base_field::from(10u8)]; - // let sig = keypair.sign(&msg, CS_ID_SCHNORR); - // assert!(keypair.vk.verify(&msg, &sig, CS_ID_SCHNORR).is_ok()); - // assert!(keypair.vk.verify(&[], &sig, CS_ID_SCHNORR).is_err()); - // let mut bytes_sig = vec![]; - // sig.serialize_compressed(&mut bytes_sig).unwrap(); - // let sig_de: Signature<$curve_param> = - // - // Signature::deserialize_compressed(bytes_sig.as_slice()).unwrap(); - // assert_eq!(sig, sig_de); - // - // // Bad path 1: when s bytes overflow - // let mut bad_bytes_sig = bytes_sig.clone(); - // let mut q_minus_one_bytes = vec![]; - // (-$base_field::from(1u32)) - // .serialize_compressed(&mut q_minus_one_bytes) - // .unwrap(); - // bad_bytes_sig.splice(.., q_minus_one_bytes.iter().cloned()); - // assert!(Signature::<$curve_param>::deserialize_compressed( - // bad_bytes_sig.as_slice() - // ) - // .is_err()); - // }; - // } - // - // #[test] - // fn test_signature() { - // test_signature!(Param254, FqEd254); - // test_signature!(Param377, FqEd377); - // test_signature!(Param381, FqEd381); - // test_signature!(Param381b, FqEd381b); - // } - // - // macro_rules! test_serde { - // ($curve_param:tt, $scalar_field:tt, $base_field:tt) => { - // let mut rng = jf_utils::test_rng(); - // let keypair = KeyPair::generate(&mut rng); - // let sk = SignKey::<$scalar_field>::generate(&mut rng); - // let vk = keypair.ver_key(); - // let msg = vec![$base_field::rand(&mut rng)]; - // let sig = keypair.sign(&msg, CS_ID_SCHNORR); - // - // let mut ser_bytes: Vec = Vec::new(); - // keypair.serialize_compressed(&mut ser_bytes).unwrap(); - // let de: KeyPair<$curve_param> = - // KeyPair::deserialize_compressed(&ser_bytes[..]).unwrap(); - // assert_eq!(de.ver_key_ref(), keypair.ver_key_ref()); - // assert_eq!(de.ver_key_ref(), &VerKey::from(&de.sk)); - // - // let mut ser_bytes: Vec = Vec::new(); - // sk.serialize_compressed(&mut ser_bytes).unwrap(); - // let de: SignKey<$scalar_field> = - // SignKey::deserialize_compressed(&ser_bytes[..]).unwrap(); - // assert_eq!(VerKey::<$curve_param>::from(&de), VerKey::from(&sk)); - // - // let mut ser_bytes: Vec = Vec::new(); - // vk.serialize_compressed(&mut ser_bytes).unwrap(); - // let de: VerKey<$curve_param> = - // VerKey::deserialize_compressed(&ser_bytes[..]).unwrap(); - // assert_eq!(de, vk); - // - // let mut ser_bytes: Vec = Vec::new(); - // sig.serialize_compressed(&mut ser_bytes).unwrap(); - // let de: Signature<$curve_param> = - // Signature::deserialize_compressed(&ser_bytes[..]).unwrap(); - // assert_eq!(de, sig); - // }; - // } - // - // #[test] - // fn test_serde() { - // test_serde!(Param254, FrEd254, FqEd254); - // test_serde!(Param377, FrEd377, FqEd377); - // test_serde!(Param381, FrEd381, FqEd381); - // test_serde!(Param381b, FrEd381b, FqEd381b); - // } - // } + assert!(ver_key.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_ok()); + + let wrong_message = vec![0u8, 0u8]; + assert!(ver_key + .verify(&wrong_message, &sig, CS_ID_BLS_MIN_SIG) + .is_err()); + } + + // TODO check tests of Schnorr signature } From ff4ecbc9afb29ae27fe98a2cb3292cfcf23b633d Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Thu, 30 Mar 2023 18:15:16 -0300 Subject: [PATCH 06/23] Sketch for hash to curve. --- primitives/src/signatures/bls_arkwors.rs | 71 +++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 553e679b6..e39501268 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -7,13 +7,30 @@ //! This module implements the BLS signature over BN curves. use super::SignatureScheme; +use ark_bn254::{ + g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, + Fq, Fr, G1Affine, +}; use crate::{ constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN128 curve errors::PrimitivesError, }; -use ark_ec::{pairing::Pairing, CurveGroup, Group}; -use ark_ff::field_hashers::{DefaultFieldHasher, HashToField}; + +use ark_ec::{ + hashing::{ + curve_maps::swu::{SWUConfig, SWUMap}, + map_to_curve_hasher::MapToCurve, + HashToCurveError, + }, + pairing::Pairing, + short_weierstrass::{Affine, SWCurveConfig}, + CurveConfig, CurveGroup, Group, +}; +use ark_ff::{ + field_hashers::{DefaultFieldHasher, HashToField}, + Field, MontFp, +}; use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, @@ -25,6 +42,7 @@ use ark_std::{ }; use espresso_systems_common::jellyfish::tag; +use num_traits::Zero; use sha2::Sha256; // use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; use crate::errors::PrimitivesError::VerificationError; @@ -376,6 +394,55 @@ where } } } +#[allow(warnings)] +fn hash_to_curve_bn254(_msg: &[u8]) -> Result { + // TODO how to avoid copy pasting this info from ark-bn254-0.4.0/src/g1.rs ? + // Only implement the missing trait SWUConfig? + struct Bn254CurveConfig; + + impl CurveConfig for Bn254CurveConfig { + type BaseField = Fq; + type ScalarField = Fr; + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[0x1]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 + const COFACTOR_INV: Fr = Fr::ONE; + } + + impl SWCurveConfig for Bn254CurveConfig { + /// COEFF_A = 0 + const COEFF_A: Fq = Fq::ZERO; + + /// COEFF_B = 3 + const COEFF_B: Fq = MontFp!("3"); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const GENERATOR: Affine = Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } + } + + impl SWUConfig for Bn254CurveConfig { + // TODO not clear about this... Copy pasting the documentation of the SWUConfig + // trait here + /// An element of the base field that is not a square root see \[WB2019, + /// Section 4\]. It is also convenient to have $g(b/ZETA * a)$ + /// to be square. In general we use a `ZETA` with low absolute + /// value coefficients when they are represented as integers. + + const ZETA: Fq = MontFp!("-1"); + } + + // TODO hash msg to field element + let test_map_to_curve = SWUMap::::new().unwrap(); + let p = test_map_to_curve.map_to_curve(Fq::from(1)).unwrap(); + Ok(G1Affine::new(p.x, p.y)) +} #[cfg(test)] mod tests { From 2ba50b4cd3998b1baa6b4f354cb4e67232e5ac64 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Fri, 31 Mar 2023 11:01:42 -0300 Subject: [PATCH 07/23] Remove type parameter P:Pairing. --- primitives/src/signatures/bls_arkwors.rs | 185 ++++++++--------------- 1 file changed, 63 insertions(+), 122 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index e39501268..c2f029ac3 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -9,7 +9,7 @@ use super::SignatureScheme; use ark_bn254::{ g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, - Fq, Fr, G1Affine, + Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; use crate::{ @@ -34,7 +34,6 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, - marker::PhantomData, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, @@ -50,27 +49,24 @@ use tagged_base64::tagged; use zeroize::Zeroize; /// BLS signature scheme. -pub struct BLSOverBNCurveSignatureScheme

{ - curve_param: PhantomData

, // TODO what is this? +pub struct BLSOverBNCurveSignatureScheme { + // curve_param: PhantomData

, // TODO what is this? } -impl

SignatureScheme for BLSOverBNCurveSignatureScheme

-where - P: Pairing + Zeroize + Default, -{ +impl SignatureScheme for BLSOverBNCurveSignatureScheme { const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this /// Signing key. - type SigningKey = SignKey

; + type SigningKey = SignKey; /// Verification key - type VerificationKey = VerKey

; + type VerificationKey = VerKey; /// Public Parameter type PublicParameter = (); /// Signature - type Signature = Signature

; + type Signature = Signature; /// A message is &\[MessageUnit\] type MessageUnit = u8; @@ -87,7 +83,7 @@ where _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let kp = KeyPair::

::generate(prng); + let kp = KeyPair::generate(prng); Ok((kp.sk, kp.vk)) } @@ -100,7 +96,7 @@ where ) -> Result { // TODO Ok(Signature { - sigma: P::G1::generator(), + sigma: G1Projective::generator(), }) } @@ -123,15 +119,15 @@ where Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] /// Signing key for BLS signature. -pub struct SignKey(pub(crate) P::ScalarField); +pub struct SignKey(pub(crate) ScalarField); -impl Drop for SignKey

{ +impl Drop for SignKey { fn drop(&mut self) { self.0.zeroize(); } } -impl SignKey

{ +impl SignKey { // returns the randomized key // fn randomize_with(&self, randomizer: &F) -> Self { // Self(self.0 + randomizer) @@ -145,18 +141,10 @@ impl SignKey

{ /// Signature public verification key // derive zeroize here so that keypair can be zeroized #[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Default(bound = "P: Pairing"), - Eq(bound = "P: Pairing"), - Clone(bound = "P: Pairing") -)] -pub struct VerKey

(pub(crate) P::G2) -where - P: Pairing; +#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] +pub struct VerKey(pub(crate) G2Projective); -impl VerKey

{ +impl VerKey { // TODO is this needed? // Return a randomized verification key. // pub fn randomize_with(&self, randomizer: &F) -> Self @@ -169,19 +157,13 @@ impl VerKey

{ // } } -impl

Hash for VerKey

-where - P: Pairing, -{ +impl Hash for VerKey { fn hash(&self, state: &mut H) { Hash::hash(&self.0.into_affine(), state) } } -impl

PartialEq for VerKey

-where - P: Pairing, -{ +impl PartialEq for VerKey { fn eq(&self, other: &Self) -> bool { self.0.into_affine().eq(&other.0.into_affine()) } @@ -205,9 +187,9 @@ where // } // } -impl VerKey

{ +impl VerKey { /// Convert the verification key into the affine form. - pub fn to_affine(&self) -> P::G2Affine { + pub fn to_affine(&self) -> G2Affine { self.0.into_affine() } } @@ -219,19 +201,11 @@ impl VerKey

{ /// Signature secret key pair used to sign messages // make sure sk can be zeroized #[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Clone(bound = "P: Pairing"), - PartialEq(bound = "P: Pairing") -)] -pub struct KeyPair

-where - P: Pairing, -{ - phantom: PhantomData

, - sk: SignKey

, - vk: VerKey

, +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] +pub struct KeyPair { + // phantom: PhantomData, + sk: SignKey, + vk: VerKey, } // impl

Default for KeyPair

@@ -252,34 +226,19 @@ where /// The signature of BLS signature scheme #[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Default(bound = "P: Pairing"), - Eq(bound = "P: Pairing"), - Clone(bound = "P: Pairing") -)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] #[allow(non_snake_case)] -pub struct Signature

-where - P: Pairing, -{ - pub(crate) sigma: P::G1, +pub struct Signature { + pub(crate) sigma: G1Projective, } -impl

Hash for Signature

-where - P: Pairing, -{ +impl Hash for Signature { fn hash(&self, state: &mut H) { Hash::hash(&self.sigma, state); } } -impl

PartialEq for Signature

-where - P: Pairing, -{ +impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { self.sigma == other.sigma } @@ -290,86 +249,69 @@ where // TODO insecure!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -fn hash_to_curve(msg: &[u8]) -> P::G1 { +fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; - let hasher = as HashToField>::new(hasher_init); - let field_elems: jf_utils::Vec = hasher.hash_to_field(msg, 1); - P::G1::generator() * field_elems[0] + let hasher = as HashToField>::new(hasher_init); + let field_elems: Vec = hasher.hash_to_field(msg, 1); + G1Projective::generator() * field_elems[0] } -impl

KeyPair

-where - P: Pairing, -{ +impl KeyPair { /// Key-pair generation algorithm - pub fn generate(prng: &mut R) -> KeyPair

{ + pub fn generate(prng: &mut R) -> KeyPair { let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); - KeyPair { - phantom: Default::default(), - sk, - vk, - } + KeyPair { sk, vk } } /// Key pair generation using a particular sign key secret `sk` - pub fn generate_with_sign_key(sk: P::ScalarField) -> Self { + pub fn generate_with_sign_key(sk: ScalarField) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); - KeyPair { - phantom: Default::default(), - sk, - vk, - } + KeyPair { sk, vk } } /// Get reference to verification key - pub fn ver_key_ref(&self) -> &VerKey

{ + pub fn ver_key_ref(&self) -> &VerKey { &self.vk } /// Get the verification key - pub fn ver_key(&self) -> VerKey

{ + pub fn ver_key(&self) -> VerKey { self.vk.clone() } /// Get the internal of the signing key, namely a P::ScalarField element - pub fn sign_key_internal(&self) -> &P::ScalarField { + pub fn sign_key_internal(&self) -> &ScalarField { &self.sk.0 } /// Signature function #[allow(non_snake_case)] - pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature

{ + pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature { // TODO take into account csid - let hash_value: P::G1 = hash_to_curve::

(msg); + let hash_value: G1Projective = hash_to_curve(msg); let sigma = hash_value * self.sk.0; Signature { sigma } } } -impl SignKey

{ - fn generate(prng: &mut R) -> SignKey

{ - SignKey(P::ScalarField::rand(prng)) +impl SignKey { + fn generate(prng: &mut R) -> SignKey { + SignKey(ScalarField::rand(prng)) } } -impl

From<&SignKey

> for VerKey

-where - P: Pairing, -{ - fn from(sk: &SignKey

) -> Self { - VerKey(P::G2::generator() * sk.0) +impl From<&SignKey> for VerKey { + fn from(sk: &SignKey) -> Self { + VerKey(G2Projective::generator() * sk.0) } } -impl

VerKey

-where - P: Pairing, -{ +impl VerKey { /// Get the internal of verifying key, namely a curve Point - pub fn internal(&self) -> P::G2 { + pub fn internal(&self) -> G2Projective { self.0 } @@ -378,15 +320,15 @@ where pub fn verify>( &self, msg: &[u8], - sig: &Signature

, + sig: &Signature, _csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key // TODO take into account csid - let group_elem = hash_to_curve::

(msg); - let g2 = P::G2::generator(); - let is_sig_valid = P::pairing(sig.sigma, g2) == P::pairing(group_elem, self.0); + let group_elem = hash_to_curve(msg); + let g2 = G2Projective::generator(); + let is_sig_valid = Bn254::pairing(sig.sigma, g2) == Bn254::pairing(group_elem, self.0); if is_sig_valid { Ok(()) } else { @@ -401,22 +343,22 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { struct Bn254CurveConfig; impl CurveConfig for Bn254CurveConfig { - type BaseField = Fq; - type ScalarField = Fr; + type BaseField = BaseField; + type ScalarField = ScalarField; /// COFACTOR = 1 const COFACTOR: &'static [u64] = &[0x1]; /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 - const COFACTOR_INV: Fr = Fr::ONE; + const COFACTOR_INV: ScalarField = ScalarField::ONE; } impl SWCurveConfig for Bn254CurveConfig { /// COEFF_A = 0 - const COEFF_A: Fq = Fq::ZERO; + const COEFF_A: BaseField = BaseField::ZERO; /// COEFF_B = 3 - const COEFF_B: Fq = MontFp!("3"); + const COEFF_B: BaseField = MontFp!("3"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const GENERATOR: Affine = Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); @@ -435,19 +377,18 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { /// to be square. In general we use a `ZETA` with low absolute /// value coefficients when they are represented as integers. - const ZETA: Fq = MontFp!("-1"); + const ZETA: BaseField = MontFp!("-1"); } // TODO hash msg to field element let test_map_to_curve = SWUMap::::new().unwrap(); - let p = test_map_to_curve.map_to_curve(Fq::from(1)).unwrap(); + let p = test_map_to_curve.map_to_curve(BaseField::from(1)).unwrap(); Ok(G1Affine::new(p.x, p.y)) } #[cfg(test)] mod tests { use crate::{constants::CS_ID_BLS_MIN_SIG, signatures::bls_arkwors::KeyPair}; - use ark_bn254::Bn254; use ark_ff::vec; // TODO new constant #[test] @@ -455,7 +396,7 @@ mod tests { // TODO use SignatureScheme instead let mut rng = jf_utils::test_rng(); - let key_pair = KeyPair::::generate(&mut rng); + let key_pair = KeyPair::generate(&mut rng); let msg = vec![15u8, 44u8]; let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); From d25d39d02f0e4fcaa2fa844a1470bc795f431688 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 13:07:56 -0400 Subject: [PATCH 08/23] Revert "Remove type parameter P:Pairing." This reverts commit 2ba50b4cd3998b1baa6b4f354cb4e67232e5ac64. --- primitives/src/signatures/bls_arkwors.rs | 185 +++++++++++++++-------- 1 file changed, 122 insertions(+), 63 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index c2f029ac3..e39501268 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -9,7 +9,7 @@ use super::SignatureScheme; use ark_bn254::{ g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, - Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, + Fq, Fr, G1Affine, }; use crate::{ @@ -34,6 +34,7 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, + marker::PhantomData, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, @@ -49,24 +50,27 @@ use tagged_base64::tagged; use zeroize::Zeroize; /// BLS signature scheme. -pub struct BLSOverBNCurveSignatureScheme { - // curve_param: PhantomData

, // TODO what is this? +pub struct BLSOverBNCurveSignatureScheme

{ + curve_param: PhantomData

, // TODO what is this? } -impl SignatureScheme for BLSOverBNCurveSignatureScheme { +impl

SignatureScheme for BLSOverBNCurveSignatureScheme

+where + P: Pairing + Zeroize + Default, +{ const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this /// Signing key. - type SigningKey = SignKey; + type SigningKey = SignKey

; /// Verification key - type VerificationKey = VerKey; + type VerificationKey = VerKey

; /// Public Parameter type PublicParameter = (); /// Signature - type Signature = Signature; + type Signature = Signature

; /// A message is &\[MessageUnit\] type MessageUnit = u8; @@ -83,7 +87,7 @@ impl SignatureScheme for BLSOverBNCurveSignatureScheme { _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let kp = KeyPair::generate(prng); + let kp = KeyPair::

::generate(prng); Ok((kp.sk, kp.vk)) } @@ -96,7 +100,7 @@ impl SignatureScheme for BLSOverBNCurveSignatureScheme { ) -> Result { // TODO Ok(Signature { - sigma: G1Projective::generator(), + sigma: P::G1::generator(), }) } @@ -119,15 +123,15 @@ impl SignatureScheme for BLSOverBNCurveSignatureScheme { Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] /// Signing key for BLS signature. -pub struct SignKey(pub(crate) ScalarField); +pub struct SignKey(pub(crate) P::ScalarField); -impl Drop for SignKey { +impl Drop for SignKey

{ fn drop(&mut self) { self.0.zeroize(); } } -impl SignKey { +impl SignKey

{ // returns the randomized key // fn randomize_with(&self, randomizer: &F) -> Self { // Self(self.0 + randomizer) @@ -141,10 +145,18 @@ impl SignKey { /// Signature public verification key // derive zeroize here so that keypair can be zeroized #[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? -#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] -pub struct VerKey(pub(crate) G2Projective); +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Pairing"), + Default(bound = "P: Pairing"), + Eq(bound = "P: Pairing"), + Clone(bound = "P: Pairing") +)] +pub struct VerKey

(pub(crate) P::G2) +where + P: Pairing; -impl VerKey { +impl VerKey

{ // TODO is this needed? // Return a randomized verification key. // pub fn randomize_with(&self, randomizer: &F) -> Self @@ -157,13 +169,19 @@ impl VerKey { // } } -impl Hash for VerKey { +impl

Hash for VerKey

+where + P: Pairing, +{ fn hash(&self, state: &mut H) { Hash::hash(&self.0.into_affine(), state) } } -impl PartialEq for VerKey { +impl

PartialEq for VerKey

+where + P: Pairing, +{ fn eq(&self, other: &Self) -> bool { self.0.into_affine().eq(&other.0.into_affine()) } @@ -187,9 +205,9 @@ impl PartialEq for VerKey { // } // } -impl VerKey { +impl VerKey

{ /// Convert the verification key into the affine form. - pub fn to_affine(&self) -> G2Affine { + pub fn to_affine(&self) -> P::G2Affine { self.0.into_affine() } } @@ -201,11 +219,19 @@ impl VerKey { /// Signature secret key pair used to sign messages // make sure sk can be zeroized #[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] -pub struct KeyPair { - // phantom: PhantomData, - sk: SignKey, - vk: VerKey, +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Pairing"), + Clone(bound = "P: Pairing"), + PartialEq(bound = "P: Pairing") +)] +pub struct KeyPair

+where + P: Pairing, +{ + phantom: PhantomData

, + sk: SignKey

, + vk: VerKey

, } // impl

Default for KeyPair

@@ -226,19 +252,34 @@ pub struct KeyPair { /// The signature of BLS signature scheme #[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] +#[derivative( + Debug(bound = "P: Pairing"), + Default(bound = "P: Pairing"), + Eq(bound = "P: Pairing"), + Clone(bound = "P: Pairing") +)] #[allow(non_snake_case)] -pub struct Signature { - pub(crate) sigma: G1Projective, +pub struct Signature

+where + P: Pairing, +{ + pub(crate) sigma: P::G1, } -impl Hash for Signature { +impl

Hash for Signature

+where + P: Pairing, +{ fn hash(&self, state: &mut H) { Hash::hash(&self.sigma, state); } } -impl PartialEq for Signature { +impl

PartialEq for Signature

+where + P: Pairing, +{ fn eq(&self, other: &Self) -> bool { self.sigma == other.sigma } @@ -249,69 +290,86 @@ impl PartialEq for Signature { // TODO insecure!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -fn hash_to_curve(msg: &[u8]) -> G1Projective { +fn hash_to_curve(msg: &[u8]) -> P::G1 { let hasher_init = &[1u8]; - let hasher = as HashToField>::new(hasher_init); - let field_elems: Vec = hasher.hash_to_field(msg, 1); - G1Projective::generator() * field_elems[0] + let hasher = as HashToField>::new(hasher_init); + let field_elems: jf_utils::Vec = hasher.hash_to_field(msg, 1); + P::G1::generator() * field_elems[0] } -impl KeyPair { +impl

KeyPair

+where + P: Pairing, +{ /// Key-pair generation algorithm - pub fn generate(prng: &mut R) -> KeyPair { + pub fn generate(prng: &mut R) -> KeyPair

{ let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); - KeyPair { sk, vk } + KeyPair { + phantom: Default::default(), + sk, + vk, + } } /// Key pair generation using a particular sign key secret `sk` - pub fn generate_with_sign_key(sk: ScalarField) -> Self { + pub fn generate_with_sign_key(sk: P::ScalarField) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); - KeyPair { sk, vk } + KeyPair { + phantom: Default::default(), + sk, + vk, + } } /// Get reference to verification key - pub fn ver_key_ref(&self) -> &VerKey { + pub fn ver_key_ref(&self) -> &VerKey

{ &self.vk } /// Get the verification key - pub fn ver_key(&self) -> VerKey { + pub fn ver_key(&self) -> VerKey

{ self.vk.clone() } /// Get the internal of the signing key, namely a P::ScalarField element - pub fn sign_key_internal(&self) -> &ScalarField { + pub fn sign_key_internal(&self) -> &P::ScalarField { &self.sk.0 } /// Signature function #[allow(non_snake_case)] - pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature { + pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature

{ // TODO take into account csid - let hash_value: G1Projective = hash_to_curve(msg); + let hash_value: P::G1 = hash_to_curve::

(msg); let sigma = hash_value * self.sk.0; Signature { sigma } } } -impl SignKey { - fn generate(prng: &mut R) -> SignKey { - SignKey(ScalarField::rand(prng)) +impl SignKey

{ + fn generate(prng: &mut R) -> SignKey

{ + SignKey(P::ScalarField::rand(prng)) } } -impl From<&SignKey> for VerKey { - fn from(sk: &SignKey) -> Self { - VerKey(G2Projective::generator() * sk.0) +impl

From<&SignKey

> for VerKey

+where + P: Pairing, +{ + fn from(sk: &SignKey

) -> Self { + VerKey(P::G2::generator() * sk.0) } } -impl VerKey { +impl

VerKey

+where + P: Pairing, +{ /// Get the internal of verifying key, namely a curve Point - pub fn internal(&self) -> G2Projective { + pub fn internal(&self) -> P::G2 { self.0 } @@ -320,15 +378,15 @@ impl VerKey { pub fn verify>( &self, msg: &[u8], - sig: &Signature, + sig: &Signature

, _csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key // TODO take into account csid - let group_elem = hash_to_curve(msg); - let g2 = G2Projective::generator(); - let is_sig_valid = Bn254::pairing(sig.sigma, g2) == Bn254::pairing(group_elem, self.0); + let group_elem = hash_to_curve::

(msg); + let g2 = P::G2::generator(); + let is_sig_valid = P::pairing(sig.sigma, g2) == P::pairing(group_elem, self.0); if is_sig_valid { Ok(()) } else { @@ -343,22 +401,22 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { struct Bn254CurveConfig; impl CurveConfig for Bn254CurveConfig { - type BaseField = BaseField; - type ScalarField = ScalarField; + type BaseField = Fq; + type ScalarField = Fr; /// COFACTOR = 1 const COFACTOR: &'static [u64] = &[0x1]; /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 - const COFACTOR_INV: ScalarField = ScalarField::ONE; + const COFACTOR_INV: Fr = Fr::ONE; } impl SWCurveConfig for Bn254CurveConfig { /// COEFF_A = 0 - const COEFF_A: BaseField = BaseField::ZERO; + const COEFF_A: Fq = Fq::ZERO; /// COEFF_B = 3 - const COEFF_B: BaseField = MontFp!("3"); + const COEFF_B: Fq = MontFp!("3"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const GENERATOR: Affine = Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); @@ -377,18 +435,19 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { /// to be square. In general we use a `ZETA` with low absolute /// value coefficients when they are represented as integers. - const ZETA: BaseField = MontFp!("-1"); + const ZETA: Fq = MontFp!("-1"); } // TODO hash msg to field element let test_map_to_curve = SWUMap::::new().unwrap(); - let p = test_map_to_curve.map_to_curve(BaseField::from(1)).unwrap(); + let p = test_map_to_curve.map_to_curve(Fq::from(1)).unwrap(); Ok(G1Affine::new(p.x, p.y)) } #[cfg(test)] mod tests { use crate::{constants::CS_ID_BLS_MIN_SIG, signatures::bls_arkwors::KeyPair}; + use ark_bn254::Bn254; use ark_ff::vec; // TODO new constant #[test] @@ -396,7 +455,7 @@ mod tests { // TODO use SignatureScheme instead let mut rng = jf_utils::test_rng(); - let key_pair = KeyPair::generate(&mut rng); + let key_pair = KeyPair::::generate(&mut rng); let msg = vec![15u8, 44u8]; let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); From 6f86ed33c974a0c4329721da155ee898479aaa5d Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 15:30:41 -0400 Subject: [PATCH 09/23] Revert "Revert "Remove type parameter P:Pairing."" This reverts commit d25d39d02f0e4fcaa2fa844a1470bc795f431688. --- primitives/src/signatures/bls_arkwors.rs | 185 ++++++++--------------- 1 file changed, 63 insertions(+), 122 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index e39501268..c2f029ac3 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -9,7 +9,7 @@ use super::SignatureScheme; use ark_bn254::{ g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, - Fq, Fr, G1Affine, + Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; use crate::{ @@ -34,7 +34,6 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, - marker::PhantomData, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, @@ -50,27 +49,24 @@ use tagged_base64::tagged; use zeroize::Zeroize; /// BLS signature scheme. -pub struct BLSOverBNCurveSignatureScheme

{ - curve_param: PhantomData

, // TODO what is this? +pub struct BLSOverBNCurveSignatureScheme { + // curve_param: PhantomData

, // TODO what is this? } -impl

SignatureScheme for BLSOverBNCurveSignatureScheme

-where - P: Pairing + Zeroize + Default, -{ +impl SignatureScheme for BLSOverBNCurveSignatureScheme { const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this /// Signing key. - type SigningKey = SignKey

; + type SigningKey = SignKey; /// Verification key - type VerificationKey = VerKey

; + type VerificationKey = VerKey; /// Public Parameter type PublicParameter = (); /// Signature - type Signature = Signature

; + type Signature = Signature; /// A message is &\[MessageUnit\] type MessageUnit = u8; @@ -87,7 +83,7 @@ where _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let kp = KeyPair::

::generate(prng); + let kp = KeyPair::generate(prng); Ok((kp.sk, kp.vk)) } @@ -100,7 +96,7 @@ where ) -> Result { // TODO Ok(Signature { - sigma: P::G1::generator(), + sigma: G1Projective::generator(), }) } @@ -123,15 +119,15 @@ where Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] /// Signing key for BLS signature. -pub struct SignKey(pub(crate) P::ScalarField); +pub struct SignKey(pub(crate) ScalarField); -impl Drop for SignKey

{ +impl Drop for SignKey { fn drop(&mut self) { self.0.zeroize(); } } -impl SignKey

{ +impl SignKey { // returns the randomized key // fn randomize_with(&self, randomizer: &F) -> Self { // Self(self.0 + randomizer) @@ -145,18 +141,10 @@ impl SignKey

{ /// Signature public verification key // derive zeroize here so that keypair can be zeroized #[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Default(bound = "P: Pairing"), - Eq(bound = "P: Pairing"), - Clone(bound = "P: Pairing") -)] -pub struct VerKey

(pub(crate) P::G2) -where - P: Pairing; +#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] +pub struct VerKey(pub(crate) G2Projective); -impl VerKey

{ +impl VerKey { // TODO is this needed? // Return a randomized verification key. // pub fn randomize_with(&self, randomizer: &F) -> Self @@ -169,19 +157,13 @@ impl VerKey

{ // } } -impl

Hash for VerKey

-where - P: Pairing, -{ +impl Hash for VerKey { fn hash(&self, state: &mut H) { Hash::hash(&self.0.into_affine(), state) } } -impl

PartialEq for VerKey

-where - P: Pairing, -{ +impl PartialEq for VerKey { fn eq(&self, other: &Self) -> bool { self.0.into_affine().eq(&other.0.into_affine()) } @@ -205,9 +187,9 @@ where // } // } -impl VerKey

{ +impl VerKey { /// Convert the verification key into the affine form. - pub fn to_affine(&self) -> P::G2Affine { + pub fn to_affine(&self) -> G2Affine { self.0.into_affine() } } @@ -219,19 +201,11 @@ impl VerKey

{ /// Signature secret key pair used to sign messages // make sure sk can be zeroized #[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Clone(bound = "P: Pairing"), - PartialEq(bound = "P: Pairing") -)] -pub struct KeyPair

-where - P: Pairing, -{ - phantom: PhantomData

, - sk: SignKey

, - vk: VerKey

, +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] +pub struct KeyPair { + // phantom: PhantomData, + sk: SignKey, + vk: VerKey, } // impl

Default for KeyPair

@@ -252,34 +226,19 @@ where /// The signature of BLS signature scheme #[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] -#[derivative( - Debug(bound = "P: Pairing"), - Default(bound = "P: Pairing"), - Eq(bound = "P: Pairing"), - Clone(bound = "P: Pairing") -)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] #[allow(non_snake_case)] -pub struct Signature

-where - P: Pairing, -{ - pub(crate) sigma: P::G1, +pub struct Signature { + pub(crate) sigma: G1Projective, } -impl

Hash for Signature

-where - P: Pairing, -{ +impl Hash for Signature { fn hash(&self, state: &mut H) { Hash::hash(&self.sigma, state); } } -impl

PartialEq for Signature

-where - P: Pairing, -{ +impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { self.sigma == other.sigma } @@ -290,86 +249,69 @@ where // TODO insecure!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -fn hash_to_curve(msg: &[u8]) -> P::G1 { +fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; - let hasher = as HashToField>::new(hasher_init); - let field_elems: jf_utils::Vec = hasher.hash_to_field(msg, 1); - P::G1::generator() * field_elems[0] + let hasher = as HashToField>::new(hasher_init); + let field_elems: Vec = hasher.hash_to_field(msg, 1); + G1Projective::generator() * field_elems[0] } -impl

KeyPair

-where - P: Pairing, -{ +impl KeyPair { /// Key-pair generation algorithm - pub fn generate(prng: &mut R) -> KeyPair

{ + pub fn generate(prng: &mut R) -> KeyPair { let sk = SignKey::generate(prng); let vk = VerKey::from(&sk); - KeyPair { - phantom: Default::default(), - sk, - vk, - } + KeyPair { sk, vk } } /// Key pair generation using a particular sign key secret `sk` - pub fn generate_with_sign_key(sk: P::ScalarField) -> Self { + pub fn generate_with_sign_key(sk: ScalarField) -> Self { let sk = SignKey(sk); let vk = VerKey::from(&sk); - KeyPair { - phantom: Default::default(), - sk, - vk, - } + KeyPair { sk, vk } } /// Get reference to verification key - pub fn ver_key_ref(&self) -> &VerKey

{ + pub fn ver_key_ref(&self) -> &VerKey { &self.vk } /// Get the verification key - pub fn ver_key(&self) -> VerKey

{ + pub fn ver_key(&self) -> VerKey { self.vk.clone() } /// Get the internal of the signing key, namely a P::ScalarField element - pub fn sign_key_internal(&self) -> &P::ScalarField { + pub fn sign_key_internal(&self) -> &ScalarField { &self.sk.0 } /// Signature function #[allow(non_snake_case)] - pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature

{ + pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature { // TODO take into account csid - let hash_value: P::G1 = hash_to_curve::

(msg); + let hash_value: G1Projective = hash_to_curve(msg); let sigma = hash_value * self.sk.0; Signature { sigma } } } -impl SignKey

{ - fn generate(prng: &mut R) -> SignKey

{ - SignKey(P::ScalarField::rand(prng)) +impl SignKey { + fn generate(prng: &mut R) -> SignKey { + SignKey(ScalarField::rand(prng)) } } -impl

From<&SignKey

> for VerKey

-where - P: Pairing, -{ - fn from(sk: &SignKey

) -> Self { - VerKey(P::G2::generator() * sk.0) +impl From<&SignKey> for VerKey { + fn from(sk: &SignKey) -> Self { + VerKey(G2Projective::generator() * sk.0) } } -impl

VerKey

-where - P: Pairing, -{ +impl VerKey { /// Get the internal of verifying key, namely a curve Point - pub fn internal(&self) -> P::G2 { + pub fn internal(&self) -> G2Projective { self.0 } @@ -378,15 +320,15 @@ where pub fn verify>( &self, msg: &[u8], - sig: &Signature

, + sig: &Signature, _csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key // TODO take into account csid - let group_elem = hash_to_curve::

(msg); - let g2 = P::G2::generator(); - let is_sig_valid = P::pairing(sig.sigma, g2) == P::pairing(group_elem, self.0); + let group_elem = hash_to_curve(msg); + let g2 = G2Projective::generator(); + let is_sig_valid = Bn254::pairing(sig.sigma, g2) == Bn254::pairing(group_elem, self.0); if is_sig_valid { Ok(()) } else { @@ -401,22 +343,22 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { struct Bn254CurveConfig; impl CurveConfig for Bn254CurveConfig { - type BaseField = Fq; - type ScalarField = Fr; + type BaseField = BaseField; + type ScalarField = ScalarField; /// COFACTOR = 1 const COFACTOR: &'static [u64] = &[0x1]; /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 - const COFACTOR_INV: Fr = Fr::ONE; + const COFACTOR_INV: ScalarField = ScalarField::ONE; } impl SWCurveConfig for Bn254CurveConfig { /// COEFF_A = 0 - const COEFF_A: Fq = Fq::ZERO; + const COEFF_A: BaseField = BaseField::ZERO; /// COEFF_B = 3 - const COEFF_B: Fq = MontFp!("3"); + const COEFF_B: BaseField = MontFp!("3"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const GENERATOR: Affine = Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); @@ -435,19 +377,18 @@ fn hash_to_curve_bn254(_msg: &[u8]) -> Result { /// to be square. In general we use a `ZETA` with low absolute /// value coefficients when they are represented as integers. - const ZETA: Fq = MontFp!("-1"); + const ZETA: BaseField = MontFp!("-1"); } // TODO hash msg to field element let test_map_to_curve = SWUMap::::new().unwrap(); - let p = test_map_to_curve.map_to_curve(Fq::from(1)).unwrap(); + let p = test_map_to_curve.map_to_curve(BaseField::from(1)).unwrap(); Ok(G1Affine::new(p.x, p.y)) } #[cfg(test)] mod tests { use crate::{constants::CS_ID_BLS_MIN_SIG, signatures::bls_arkwors::KeyPair}; - use ark_bn254::Bn254; use ark_ff::vec; // TODO new constant #[test] @@ -455,7 +396,7 @@ mod tests { // TODO use SignatureScheme instead let mut rng = jf_utils::test_rng(); - let key_pair = KeyPair::::generate(&mut rng); + let key_pair = KeyPair::generate(&mut rng); let msg = vec![15u8, 44u8]; let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); From 5192c5589f0827b4927ddd7d7e8e1e931aa828c9 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 15:36:51 -0400 Subject: [PATCH 10/23] First version of hash and pray function for Bn254 curve. --- primitives/src/signatures/bls_arkwors.rs | 30 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index c2f029ac3..60c98040b 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -34,6 +34,7 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, + println, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, @@ -247,13 +248,32 @@ impl PartialEq for Signature { // end of definitions // ===================================================== -// TODO insecure!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// +/// Hash and pray algorithm fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; - let hasher = as HashToField>::new(hasher_init); - let field_elems: Vec = hasher.hash_to_field(msg, 1); - G1Projective::generator() * field_elems[0] + let hasher = as HashToField>::new(hasher_init); + let field_elems: Vec = hasher.hash_to_field(msg, 1); + + // Coefficients of the curve: y^2 = x^3 + ax + b + // For BN254 we have a=0 and b=3 + + let coeff_a = BaseField::from(0); // TODO cleaner, fetch from config? + let coeff_b = BaseField::from(3); // TODO cleaner, fetch from config? TODO is this correct? + + let mut x_affine = field_elems[0]; + let mut y_square_affine: BaseField = + x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; + + while y_square_affine.legendre().is_qnr() { + println!("point with x={} is off the curve!!", x_affine); + x_affine += BaseField::from(1); + y_square_affine = x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; + } + + let y_affine = y_square_affine.sqrt().unwrap(); // SAFE unwrap as y_square_affine is a quadratic residue + + let g1_affine = G1Affine::new(x_affine, y_affine); + G1Projective::from(g1_affine) } impl KeyPair { From b9f6038210adb9816281ef7b95a4f8559e9f18ba Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 16:19:25 -0400 Subject: [PATCH 11/23] Signature trait tests passing. --- primitives/src/signatures/bls_arkwors.rs | 140 +++++++++-------------- 1 file changed, 53 insertions(+), 87 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 60c98040b..aaf8c38b4 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -8,28 +8,18 @@ use super::SignatureScheme; use ark_bn254::{ - g1::{G1_GENERATOR_X, G1_GENERATOR_Y}, Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; use crate::{ - constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN128 curve + constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN254 curve errors::PrimitivesError, }; -use ark_ec::{ - hashing::{ - curve_maps::swu::{SWUConfig, SWUMap}, - map_to_curve_hasher::MapToCurve, - HashToCurveError, - }, - pairing::Pairing, - short_weierstrass::{Affine, SWCurveConfig}, - CurveConfig, CurveGroup, Group, -}; +use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_ff::{ field_hashers::{DefaultFieldHasher, HashToField}, - Field, MontFp, + Field, }; use ark_serialize::*; use ark_std::{ @@ -42,7 +32,6 @@ use ark_std::{ }; use espresso_systems_common::jellyfish::tag; -use num_traits::Zero; use sha2::Sha256; // use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; use crate::errors::PrimitivesError::VerificationError; @@ -91,14 +80,12 @@ impl SignatureScheme for BLSOverBNCurveSignatureScheme { /// Sign a message with the signing key fn sign>( _pp: &Self::PublicParameter, - _sk: &Self::SigningKey, - _msg: M, + sk: &Self::SigningKey, + msg: M, _prng: &mut R, ) -> Result { - // TODO - Ok(Signature { - sigma: G1Projective::generator(), - }) + let kp = KeyPair::generate_with_sign_key(sk.0); + Ok(kp.sign(msg.as_ref(), Self::CS_ID)) } /// Verify a signature. @@ -264,13 +251,15 @@ fn hash_to_curve(msg: &[u8]) -> G1Projective { let mut y_square_affine: BaseField = x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; + // Loop until we find a quadratic residue while y_square_affine.legendre().is_qnr() { println!("point with x={} is off the curve!!", x_affine); x_affine += BaseField::from(1); y_square_affine = x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; } - let y_affine = y_square_affine.sqrt().unwrap(); // SAFE unwrap as y_square_affine is a quadratic residue + // Safe unwrap as y_square_affine is a quadratic residue + let y_affine = y_square_affine.sqrt().unwrap(); let g1_affine = G1Affine::new(x_affine, y_affine); G1Projective::from(g1_affine) @@ -345,6 +334,8 @@ impl VerKey { ) -> Result<(), PrimitivesError> { // TODO Check public key // TODO take into account csid + // TODO comment: the signature of this function differs from the code of + // schnorr.rs: the message is a vectory of bytes instead of field elements let group_elem = hash_to_curve(msg); let g2 = G2Projective::generator(); @@ -356,79 +347,54 @@ impl VerKey { } } } -#[allow(warnings)] -fn hash_to_curve_bn254(_msg: &[u8]) -> Result { - // TODO how to avoid copy pasting this info from ark-bn254-0.4.0/src/g1.rs ? - // Only implement the missing trait SWUConfig? - struct Bn254CurveConfig; - - impl CurveConfig for Bn254CurveConfig { - type BaseField = BaseField; - type ScalarField = ScalarField; - - /// COFACTOR = 1 - const COFACTOR: &'static [u64] = &[0x1]; - - /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 - const COFACTOR_INV: ScalarField = ScalarField::ONE; - } - - impl SWCurveConfig for Bn254CurveConfig { - /// COEFF_A = 0 - const COEFF_A: BaseField = BaseField::ZERO; - - /// COEFF_B = 3 - const COEFF_B: BaseField = MontFp!("3"); - - /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) - const GENERATOR: Affine = Affine::new_unchecked(G1_GENERATOR_X, G1_GENERATOR_Y); - - #[inline(always)] - fn mul_by_a(_: Self::BaseField) -> Self::BaseField { - Self::BaseField::zero() - } - } - - impl SWUConfig for Bn254CurveConfig { - // TODO not clear about this... Copy pasting the documentation of the SWUConfig - // trait here - /// An element of the base field that is not a square root see \[WB2019, - /// Section 4\]. It is also convenient to have $g(b/ZETA * a)$ - /// to be square. In general we use a `ZETA` with low absolute - /// value coefficients when they are represented as integers. - - const ZETA: BaseField = MontFp!("-1"); - } - - // TODO hash msg to field element - let test_map_to_curve = SWUMap::::new().unwrap(); - let p = test_map_to_curve.map_to_curve(BaseField::from(1)).unwrap(); - Ok(G1Affine::new(p.x, p.y)) -} #[cfg(test)] mod tests { - use crate::{constants::CS_ID_BLS_MIN_SIG, signatures::bls_arkwors::KeyPair}; - use ark_ff::vec; // TODO new constant + use crate::signatures::{ + bls_arkwors::{BLSOverBNCurveSignatureScheme, VerKey}, + tests::{failed_verification, sign_and_verify}, + }; + use crate::{ + constants::CS_ID_BLS_MIN_SIG, // TODO change constant + signatures::bls_arkwors::KeyPair, + }; + use ark_ff::vec; #[test] - fn test_bls_signature() { - // TODO use SignatureScheme instead - + fn test_bls_signature_internals() { let mut rng = jf_utils::test_rng(); - let key_pair = KeyPair::generate(&mut rng); - let msg = vec![15u8, 44u8]; - let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); - - let ver_key = key_pair.vk; - - assert!(ver_key.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_ok()); + let key_pair1 = KeyPair::generate(&mut rng); + let key_pair2 = KeyPair::generate(&mut rng); + let key_pair3 = KeyPair::generate(&mut rng); + let pk_bad: VerKey = KeyPair::generate(&mut rng).ver_key(); + let key_pairs = [key_pair1, key_pair2, key_pair3]; + + let mut msg = vec![]; + for i in 0..10 { + for key_pair in &key_pairs { + assert_eq!(key_pair.vk, VerKey::from(&key_pair.sk)); + let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); + let pk = key_pair.ver_key_ref(); + assert!(pk.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_ok()); + // wrong public key + assert!(pk_bad.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_err()); + // wrong message + msg.push(i as u8); + assert!(pk.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_err()); + } + } + } - let wrong_message = vec![0u8, 0u8]; - assert!(ver_key - .verify(&wrong_message, &sig, CS_ID_BLS_MIN_SIG) - .is_err()); + #[test] + fn test_sig_trait() { + let message = vec![87u8, 32u8]; + let wrong_message = vec![255u8]; + sign_and_verify::(message.as_slice()); + failed_verification::( + message.as_slice(), + wrong_message.as_slice(), + ); } - // TODO check tests of Schnorr signature + // TODO check tests of Schnorr signature (serde) } From b53f097e6c06d1fffcf8a68247e86ae7c61e2a1f Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 17:58:56 -0400 Subject: [PATCH 12/23] Take into account the algorithm id --- primitives/src/signatures/bls_arkwors.rs | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index aaf8c38b4..25301f015 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -24,24 +24,21 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, - println, + // println, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, UniformRand, }; +use crate::errors::PrimitivesError::VerificationError; use espresso_systems_common::jellyfish::tag; use sha2::Sha256; -// use jf_utils::{fq_to_fr, fq_to_fr_with_mask, fr_to_fq}; -use crate::errors::PrimitivesError::VerificationError; use tagged_base64::tagged; use zeroize::Zeroize; /// BLS signature scheme. -pub struct BLSOverBNCurveSignatureScheme { - // curve_param: PhantomData

, // TODO what is this? -} +pub struct BLSOverBNCurveSignatureScheme; impl SignatureScheme for BLSOverBNCurveSignatureScheme { const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this @@ -253,7 +250,7 @@ fn hash_to_curve(msg: &[u8]) -> G1Projective { // Loop until we find a quadratic residue while y_square_affine.legendre().is_qnr() { - println!("point with x={} is off the curve!!", x_affine); + // println!("point with x={} is off the curve!!", x_affine); x_affine += BaseField::from(1); y_square_affine = x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; } @@ -297,10 +294,9 @@ impl KeyPair { /// Signature function #[allow(non_snake_case)] - pub fn sign>(&self, msg: &[u8], _csid: B) -> Signature { - // TODO take into account csid - - let hash_value: G1Projective = hash_to_curve(msg); + pub fn sign>(&self, msg: &[u8], csid: B) -> Signature { + let msg_input = [msg, csid.as_ref()].concat(); + let hash_value: G1Projective = hash_to_curve(&msg_input); let sigma = hash_value * self.sk.0; Signature { sigma } } @@ -330,15 +326,18 @@ impl VerKey { &self, msg: &[u8], sig: &Signature, - _csid: B, + csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key // TODO take into account csid // TODO comment: the signature of this function differs from the code of // schnorr.rs: the message is a vectory of bytes instead of field elements - let group_elem = hash_to_curve(msg); + let msg_input = [msg, csid.as_ref()].concat(); + let group_elem = hash_to_curve(&msg_input); let g2 = G2Projective::generator(); + + // TODO write this in a more elegant way let is_sig_valid = Bn254::pairing(sig.sigma, g2) == Bn254::pairing(group_elem, self.0); if is_sig_valid { Ok(()) From c16c1d81a3db1b4b349710963dc8e487592ad54a Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 18:01:17 -0400 Subject: [PATCH 13/23] Remove commented code. --- primitives/src/signatures/bls_arkwors.rs | 53 +----------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 25301f015..3669a9feb 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -112,36 +112,16 @@ impl Drop for SignKey { } } -impl SignKey { - // returns the randomized key - // fn randomize_with(&self, randomizer: &F) -> Self { - // Self(self.0 + randomizer) - // } -} - // ===================================================== // Verification key // ===================================================== /// Signature public verification key -// derive zeroize here so that keypair can be zeroized +// Derive zeroize here so that keypair can be zeroized #[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? #[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] pub struct VerKey(pub(crate) G2Projective); -impl VerKey { - // TODO is this needed? - // Return a randomized verification key. - // pub fn randomize_with(&self, randomizer: &F) -> Self - // where - // F: PrimeField, - // P: Config, - // { - // - // Self(G1Projective::

::generator() * randomizer + self.0) - // } -} - impl Hash for VerKey { fn hash(&self, state: &mut H) { Hash::hash(&self.0.into_affine(), state) @@ -154,24 +134,6 @@ impl PartialEq for VerKey { } } -// impl

Default for VerKey

-// where -// P: Pairing, -// { -// fn default() -> Self { -// P::G2::generator() -// } -// } - -// impl

From for VerKey

-// where -// P: Pairing, -// { -// fn from(point: P::G2) -> Self { -// VerKey(point) -// } -// } - impl VerKey { /// Convert the verification key into the affine form. pub fn to_affine(&self) -> G2Affine { @@ -188,23 +150,10 @@ impl VerKey { #[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? #[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] pub struct KeyPair { - // phantom: PhantomData, sk: SignKey, vk: VerKey, } -// impl

Default for KeyPair

-// where -// P: Pairing, -// { -// fn default() -> Self { -// KeyPair { -// sk: SignKey::

::default(), -// vk: VerKey::

::default(), -// } -// } -// } - // ===================================================== // Signature // ===================================================== From 9ca2f686e891b5b78ea76c4d9134920922d13895 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 18:08:53 -0400 Subject: [PATCH 14/23] Fix ID of signature algorithm. --- primitives/src/constants.rs | 6 +++++- primitives/src/signatures/bls.rs | 5 +++-- primitives/src/signatures/bls_arkwors.rs | 26 ++++++++++-------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index 795d4b2ec..dec716d4e 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -9,7 +9,7 @@ /// ciphersuite identifier for schnorr signature pub const CS_ID_SCHNORR: &str = "SCHNORR_WITH_RESCUE_HASH_v01"; -/// ciphersuite identifier for BLS signature, see: +/// ciphersuite identifier for BLS signature over BLS12_381, see: /// pub const CS_ID_BLS_MIN_SIG: &str = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"; @@ -23,3 +23,7 @@ pub const BLS_SIG_COMPRESSED_SIGNATURE_SIZE: usize = 48; pub const BLS_SIG_PK_SIZE: usize = 192; /// Size in bytes of a compressed verification key in our BLS signature scheme. pub const BLS_SIG_COMPRESSED_PK_SIZE: usize = 96; + +/// ciphersuite identifier for BLS signature over BN254 +/// TODO fit the format described in +pub const CS_ID_BLS_BN254: &str = "BLS_SIG_BN254"; diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index 545541a53..40297fb8e 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -73,11 +73,12 @@ use super::SignatureScheme; use crate::{ constants::{ BLS_SIG_COMPRESSED_PK_SIZE, BLS_SIG_COMPRESSED_SIGNATURE_SIZE, BLS_SIG_PK_SIZE, - BLS_SIG_SIGNATURE_SIZE, BLS_SIG_SK_SIZE, CS_ID_BLS_MIN_SIG, + BLS_SIG_SIGNATURE_SIZE, BLS_SIG_SK_SIZE, }, errors::PrimitivesError, }; +use crate::constants::CS_ID_BLS_BN254; use ark_serialize::*; use ark_std::{ format, @@ -323,7 +324,7 @@ impl Valid for BLSSignature { pub struct BLSSignatureScheme; impl SignatureScheme for BLSSignatureScheme { - const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; + const CS_ID: &'static str = CS_ID_BLS_BN254; /// Public parameter type PublicParameter = (); diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_arkwors.rs index 3669a9feb..af5b3008e 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_arkwors.rs @@ -11,10 +11,7 @@ use ark_bn254::{ Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; -use crate::{ - constants::CS_ID_BLS_MIN_SIG, // TODO update this as we are using the BN254 curve - errors::PrimitivesError, -}; +use crate::{constants::CS_ID_BLS_BN254, errors::PrimitivesError}; use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_ff::{ @@ -41,7 +38,7 @@ use zeroize::Zeroize; pub struct BLSOverBNCurveSignatureScheme; impl SignatureScheme for BLSOverBNCurveSignatureScheme { - const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; // TODO change this + const CS_ID: &'static str = CS_ID_BLS_BN254; /// Signing key. type SigningKey = SignKey; @@ -298,13 +295,12 @@ impl VerKey { #[cfg(test)] mod tests { - use crate::signatures::{ - bls_arkwors::{BLSOverBNCurveSignatureScheme, VerKey}, - tests::{failed_verification, sign_and_verify}, - }; use crate::{ - constants::CS_ID_BLS_MIN_SIG, // TODO change constant - signatures::bls_arkwors::KeyPair, + constants::CS_ID_BLS_BN254, + signatures::{ + bls_arkwors::{BLSOverBNCurveSignatureScheme, KeyPair, VerKey}, + tests::{failed_verification, sign_and_verify}, + }, }; use ark_ff::vec; @@ -321,14 +317,14 @@ mod tests { for i in 0..10 { for key_pair in &key_pairs { assert_eq!(key_pair.vk, VerKey::from(&key_pair.sk)); - let sig = key_pair.sign(&msg, CS_ID_BLS_MIN_SIG); + let sig = key_pair.sign(&msg, CS_ID_BLS_BN254); let pk = key_pair.ver_key_ref(); - assert!(pk.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_ok()); + assert!(pk.verify(&msg, &sig, CS_ID_BLS_BN254).is_ok()); // wrong public key - assert!(pk_bad.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_err()); + assert!(pk_bad.verify(&msg, &sig, CS_ID_BLS_BN254).is_err()); // wrong message msg.push(i as u8); - assert!(pk.verify(&msg, &sig, CS_ID_BLS_MIN_SIG).is_err()); + assert!(pk.verify(&msg, &sig, CS_ID_BLS_BN254).is_err()); } } } From 5160bea02acad392c8fadf2d795c8b5211f86676 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Mon, 3 Apr 2023 18:25:59 -0400 Subject: [PATCH 15/23] Serde tests --- .../{bls_arkwors.rs => bls_over_bn254.rs} | 38 +++++++++++++++++-- primitives/src/signatures/mod.rs | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) rename primitives/src/signatures/{bls_arkwors.rs => bls_over_bn254.rs} (86%) diff --git a/primitives/src/signatures/bls_arkwors.rs b/primitives/src/signatures/bls_over_bn254.rs similarity index 86% rename from primitives/src/signatures/bls_arkwors.rs rename to primitives/src/signatures/bls_over_bn254.rs index af5b3008e..59b34964a 100644 --- a/primitives/src/signatures/bls_arkwors.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -275,7 +275,6 @@ impl VerKey { csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key - // TODO take into account csid // TODO comment: the signature of this function differs from the code of // schnorr.rs: the message is a vectory of bytes instead of field elements @@ -295,14 +294,18 @@ impl VerKey { #[cfg(test)] mod tests { + + // This tests are adapted from schnorr.rs use crate::{ constants::CS_ID_BLS_BN254, signatures::{ - bls_arkwors::{BLSOverBNCurveSignatureScheme, KeyPair, VerKey}, + bls_over_bn254::{BLSOverBNCurveSignatureScheme, KeyPair, SignKey, Signature, VerKey}, tests::{failed_verification, sign_and_verify}, }, }; use ark_ff::vec; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + use jf_utils::Vec; #[test] fn test_bls_signature_internals() { @@ -340,5 +343,34 @@ mod tests { ); } - // TODO check tests of Schnorr signature (serde) + #[test] + fn test_serde() { + let mut rng = jf_utils::test_rng(); + let keypair = KeyPair::generate(&mut rng); + let sk = SignKey::generate(&mut rng); + let vk = keypair.ver_key(); + let msg = vec![87u8]; + let sig = keypair.sign(&msg, CS_ID_BLS_BN254); + + let mut ser_bytes: Vec = Vec::new(); + keypair.serialize_compressed(&mut ser_bytes).unwrap(); + let de: KeyPair = KeyPair::deserialize_compressed(&ser_bytes[..]).unwrap(); + assert_eq!(de.ver_key_ref(), keypair.ver_key_ref()); + assert_eq!(de.ver_key_ref(), &VerKey::from(&de.sk)); + + let mut ser_bytes: Vec = Vec::new(); + sk.serialize_compressed(&mut ser_bytes).unwrap(); + let de: SignKey = SignKey::deserialize_compressed(&ser_bytes[..]).unwrap(); + assert_eq!(VerKey::from(&de), VerKey::from(&sk)); + + let mut ser_bytes: Vec = Vec::new(); + vk.serialize_compressed(&mut ser_bytes).unwrap(); + let de: VerKey = VerKey::deserialize_compressed(&ser_bytes[..]).unwrap(); + assert_eq!(de, vk); + + let mut ser_bytes: Vec = Vec::new(); + sig.serialize_compressed(&mut ser_bytes).unwrap(); + let de: Signature = Signature::deserialize_compressed(&ser_bytes[..]).unwrap(); + assert_eq!(de, sig); + } } diff --git a/primitives/src/signatures/mod.rs b/primitives/src/signatures/mod.rs index 66f68e8bb..1a2a202be 100644 --- a/primitives/src/signatures/mod.rs +++ b/primitives/src/signatures/mod.rs @@ -4,7 +4,7 @@ use crate::errors::PrimitivesError; use ark_std::rand::{CryptoRng, RngCore}; pub mod bls; -mod bls_arkwors; +mod bls_over_bn254; pub mod schnorr; pub use bls::BLSSignatureScheme; From 203af5ea3936d6fe2bb497e64db478a001423c30 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Tue, 4 Apr 2023 13:43:47 -0400 Subject: [PATCH 16/23] Parametrize `hash_to_curve` with the hash function for mapping bytes to a field element. --- primitives/src/signatures/bls_over_bn254.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index 59b34964a..c267b2446 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -7,11 +7,11 @@ //! This module implements the BLS signature over BN curves. use super::SignatureScheme; +use crate::{constants::CS_ID_BLS_BN254, errors::PrimitivesError}; use ark_bn254::{ Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; - -use crate::{constants::CS_ID_BLS_BN254, errors::PrimitivesError}; +use sha3::Keccak256; use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_ff::{ @@ -27,10 +27,11 @@ use ark_std::{ vec::Vec, UniformRand, }; +use digest::DynDigest; use crate::errors::PrimitivesError::VerificationError; use espresso_systems_common::jellyfish::tag; -use sha2::Sha256; + use tagged_base64::tagged; use zeroize::Zeroize; @@ -179,9 +180,9 @@ impl PartialEq for Signature { // ===================================================== /// Hash and pray algorithm -fn hash_to_curve(msg: &[u8]) -> G1Projective { +fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; - let hasher = as HashToField>::new(hasher_init); + let hasher = as HashToField>::new(hasher_init); let field_elems: Vec = hasher.hash_to_field(msg, 1); // Coefficients of the curve: y^2 = x^3 + ax + b @@ -242,7 +243,7 @@ impl KeyPair { #[allow(non_snake_case)] pub fn sign>(&self, msg: &[u8], csid: B) -> Signature { let msg_input = [msg, csid.as_ref()].concat(); - let hash_value: G1Projective = hash_to_curve(&msg_input); + let hash_value: G1Projective = hash_to_curve::(&msg_input); let sigma = hash_value * self.sk.0; Signature { sigma } } @@ -279,7 +280,7 @@ impl VerKey { // schnorr.rs: the message is a vectory of bytes instead of field elements let msg_input = [msg, csid.as_ref()].concat(); - let group_elem = hash_to_curve(&msg_input); + let group_elem = hash_to_curve::(&msg_input); let g2 = G2Projective::generator(); // TODO write this in a more elegant way @@ -295,7 +296,7 @@ impl VerKey { #[cfg(test)] mod tests { - // This tests are adapted from schnorr.rs + // These tests are adapted from schnorr.rs use crate::{ constants::CS_ID_BLS_BN254, signatures::{ From ba4825b0c8700c13d0ffde035cb283cb2b75bda3 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Tue, 4 Apr 2023 15:48:01 -0400 Subject: [PATCH 17/23] Add some comments / todos. --- primitives/src/signatures/bls_over_bn254.rs | 42 ++++++++++----------- primitives/src/signatures/mod.rs | 2 +- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index c267b2446..9b0ec665a 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -4,15 +4,13 @@ // You should have received a copy of the MIT License // along with the Jellyfish library. If not, see . -//! This module implements the BLS signature over BN curves. - +//! This module implements the BLS signature over the BN254 curve.ç +// TODO more comments use super::SignatureScheme; use crate::{constants::CS_ID_BLS_BN254, errors::PrimitivesError}; use ark_bn254::{ Bn254, Fq as BaseField, Fr as ScalarField, G1Affine, G1Projective, G2Affine, G2Projective, }; -use sha3::Keccak256; - use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_ff::{ field_hashers::{DefaultFieldHasher, HashToField}, @@ -21,13 +19,13 @@ use ark_ff::{ use ark_serialize::*; use ark_std::{ hash::{Hash, Hasher}, - // println, rand::{CryptoRng, Rng, RngCore}, string::ToString, vec::Vec, UniformRand, }; use digest::DynDigest; +use sha3::Keccak256; use crate::errors::PrimitivesError::VerificationError; use espresso_systems_common::jellyfish::tag; @@ -36,9 +34,9 @@ use tagged_base64::tagged; use zeroize::Zeroize; /// BLS signature scheme. -pub struct BLSOverBNCurveSignatureScheme; +pub struct BLSOverBN254CurveSignatureScheme; -impl SignatureScheme for BLSOverBNCurveSignatureScheme { +impl SignatureScheme for BLSOverBN254CurveSignatureScheme { const CS_ID: &'static str = CS_ID_BLS_BN254; /// Signing key. @@ -97,7 +95,7 @@ impl SignatureScheme for BLSOverBNCurveSignatureScheme { // ===================================================== // Signing key // ===================================================== -#[tagged(tag::BLS_SIGNING_KEY)] +#[tagged(tag::BLS_SIGNING_KEY)] // TODO what iis this tagging thing? #[derive( Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] @@ -144,8 +142,8 @@ impl VerKey { // ===================================================== /// Signature secret key pair used to sign messages -// make sure sk can be zeroized -#[tagged(tag::SCHNORR_KEY_PAIR)] // TODO what is this tag for? +// Make sure sk can be zeroized // TODO +#[tagged(tag::BLS_VER_KEY)] // TODO what is this tag for? #[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] pub struct KeyPair { sk: SignKey, @@ -157,7 +155,7 @@ pub struct KeyPair { // ===================================================== /// The signature of BLS signature scheme -#[tagged(tag::SCHNORR_SIG)] // TODO what is this tag for? +#[tagged(tag::BLS_SIG)] // TODO what is this tag for? #[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] #[allow(non_snake_case)] pub struct Signature { @@ -180,6 +178,8 @@ impl PartialEq for Signature { // ===================================================== /// Hash and pray algorithm +// TODO comment +// TODO make public? fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; let hasher = as HashToField>::new(hasher_init); @@ -240,7 +240,6 @@ impl KeyPair { } /// Signature function - #[allow(non_snake_case)] pub fn sign>(&self, msg: &[u8], csid: B) -> Signature { let msg_input = [msg, csid.as_ref()].concat(); let hash_value: G1Projective = hash_to_curve::(&msg_input); @@ -268,7 +267,6 @@ impl VerKey { } /// Signature verification function - #[allow(non_snake_case)] pub fn verify>( &self, msg: &[u8], @@ -276,19 +274,15 @@ impl VerKey { csid: B, ) -> Result<(), PrimitivesError> { // TODO Check public key - // TODO comment: the signature of this function differs from the code of - // schnorr.rs: the message is a vectory of bytes instead of field elements let msg_input = [msg, csid.as_ref()].concat(); let group_elem = hash_to_curve::(&msg_input); let g2 = G2Projective::generator(); - // TODO write this in a more elegant way let is_sig_valid = Bn254::pairing(sig.sigma, g2) == Bn254::pairing(group_elem, self.0); - if is_sig_valid { - Ok(()) - } else { - Err(VerificationError("Pairing check failed".to_string())) + match is_sig_valid { + true => Ok(()), + false => Err(VerificationError("Pairing check failed".to_string())), } } } @@ -300,7 +294,9 @@ mod tests { use crate::{ constants::CS_ID_BLS_BN254, signatures::{ - bls_over_bn254::{BLSOverBNCurveSignatureScheme, KeyPair, SignKey, Signature, VerKey}, + bls_over_bn254::{ + BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, Signature, VerKey, + }, tests::{failed_verification, sign_and_verify}, }, }; @@ -337,8 +333,8 @@ mod tests { fn test_sig_trait() { let message = vec![87u8, 32u8]; let wrong_message = vec![255u8]; - sign_and_verify::(message.as_slice()); - failed_verification::( + sign_and_verify::(message.as_slice()); + failed_verification::( message.as_slice(), wrong_message.as_slice(), ); diff --git a/primitives/src/signatures/mod.rs b/primitives/src/signatures/mod.rs index 1a2a202be..102276e65 100644 --- a/primitives/src/signatures/mod.rs +++ b/primitives/src/signatures/mod.rs @@ -4,7 +4,7 @@ use crate::errors::PrimitivesError; use ark_std::rand::{CryptoRng, RngCore}; pub mod bls; -mod bls_over_bn254; +pub mod bls_over_bn254; pub mod schnorr; pub use bls::BLSSignatureScheme; From af922feb651225b643ba99ffaa7fe639218df7bc Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Tue, 4 Apr 2023 16:22:19 -0400 Subject: [PATCH 18/23] Document hash_to_curve function. --- primitives/src/signatures/bls_over_bn254.rs | 43 ++++++++++++--------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index 9b0ec665a..3a1a9b0a8 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -14,7 +14,7 @@ use ark_bn254::{ use ark_ec::{pairing::Pairing, CurveGroup, Group}; use ark_ff::{ field_hashers::{DefaultFieldHasher, HashToField}, - Field, + Field, MontFp, }; use ark_serialize::*; use ark_std::{ @@ -177,35 +177,42 @@ impl PartialEq for Signature { // end of definitions // ===================================================== -/// Hash and pray algorithm -// TODO comment -// TODO make public? -fn hash_to_curve(msg: &[u8]) -> G1Projective { +/// Non constant time hash to curve algorithm (a.k.a "hash-and-pray") +/// The hashing algorithm consists of the following steps: +/// 1. Hash the bytes to a field element `x`. +/// 2. Compute `Y = x^3 + 3`. +/// 3. Check if `Y` is a quadratic residue (QR), in which case return +/// `y=sqrt(Y)` otherwise try with `x+1, x+2` etc... until `Y` is a QR. +/// 4. Return `P=(x,y)` +/// +/// In the future we may switch to a constant time algorithm such as Fouque-Tibouchi +/// * `H` - parameterizable hash function (e.g. SHA256, Keccak) +/// * `msg` - input message +/// * `returns` - A group element in G1 +#[allow(non_snake_case)] +pub fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; let hasher = as HashToField>::new(hasher_init); let field_elems: Vec = hasher.hash_to_field(msg, 1); // Coefficients of the curve: y^2 = x^3 + ax + b - // For BN254 we have a=0 and b=3 - - let coeff_a = BaseField::from(0); // TODO cleaner, fetch from config? - let coeff_b = BaseField::from(3); // TODO cleaner, fetch from config? TODO is this correct? + // For BN254 we have a=0 and b=3 so we only use b + let coeff_b: BaseField = MontFp!("3"); - let mut x_affine = field_elems[0]; - let mut y_square_affine: BaseField = - x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; + let mut x = field_elems[0]; + let mut Y: BaseField = x * x * x + coeff_b; // Loop until we find a quadratic residue - while y_square_affine.legendre().is_qnr() { + while Y.legendre().is_qnr() { // println!("point with x={} is off the curve!!", x_affine); - x_affine += BaseField::from(1); - y_square_affine = x_affine * x_affine * x_affine + coeff_a * x_affine + coeff_b; + x += BaseField::from(1); + Y = x * x * x + coeff_b; } - // Safe unwrap as y_square_affine is a quadratic residue - let y_affine = y_square_affine.sqrt().unwrap(); + // Safe unwrap as `y` is a quadratic residue + let y = Y.sqrt().unwrap(); - let g1_affine = G1Affine::new(x_affine, y_affine); + let g1_affine = G1Affine::new(x, y); G1Projective::from(g1_affine) } From 4491b3c076af06ba1139e79271ff1c85b510dae0 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Tue, 4 Apr 2023 17:53:16 -0400 Subject: [PATCH 19/23] Misc improvements, renaming. --- primitives/src/constants.rs | 2 +- .../{bls.rs => bls_over_bls12381.rs} | 14 ++-- primitives/src/signatures/bls_over_bn254.rs | 67 ++++++++++++------- primitives/src/signatures/mod.rs | 6 +- primitives/src/vrf/blsvrf.rs | 2 +- 5 files changed, 55 insertions(+), 36 deletions(-) rename primitives/src/signatures/{bls.rs => bls_over_bls12381.rs} (98%) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index dec716d4e..2063d7e45 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -25,5 +25,5 @@ pub const BLS_SIG_PK_SIZE: usize = 192; pub const BLS_SIG_COMPRESSED_PK_SIZE: usize = 96; /// ciphersuite identifier for BLS signature over BN254 -/// TODO fit the format described in +/// Note this does **not** follow pub const CS_ID_BLS_BN254: &str = "BLS_SIG_BN254"; diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls_over_bls12381.rs similarity index 98% rename from primitives/src/signatures/bls.rs rename to primitives/src/signatures/bls_over_bls12381.rs index 40297fb8e..8ed755cfb 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls_over_bls12381.rs @@ -16,7 +16,7 @@ //! //! ``` //! use rand_core::{RngCore, OsRng}; -//! use jf_primitives::signatures::{SignatureScheme, bls::BLSSignatureScheme}; +//! use jf_primitives::signatures::{SignatureScheme, bls_over_bls12381::BLSSignatureScheme}; //! //! let pp = BLSSignatureScheme::param_gen::(None)?; //! @@ -40,7 +40,7 @@ //! ``` //! use rand_core::{RngCore, OsRng}; //! use sha2::{Sha256, Digest}; -//! use jf_primitives::signatures::{SignatureScheme, bls::BLSSignatureScheme}; +//! use jf_primitives::signatures::{SignatureScheme, bls_over_bls12381::BLSSignatureScheme}; //! //! let pp = BLSSignatureScheme::param_gen::(None)?; //! @@ -78,7 +78,7 @@ use crate::{ errors::PrimitivesError, }; -use crate::constants::CS_ID_BLS_BN254; +use crate::constants::CS_ID_BLS_MIN_SIG; use ark_serialize::*; use ark_std::{ format, @@ -324,10 +324,7 @@ impl Valid for BLSSignature { pub struct BLSSignatureScheme; impl SignatureScheme for BLSSignatureScheme { - const CS_ID: &'static str = CS_ID_BLS_BN254; - - /// Public parameter - type PublicParameter = (); + const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; /// Signing key type SigningKey = BLSSignKey; @@ -335,6 +332,9 @@ impl SignatureScheme for BLSSignatureScheme { /// Verification key type VerificationKey = BLSVerKey; + /// Public parameter + type PublicParameter = (); + /// Signature type Signature = BLSSignature; diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index 3a1a9b0a8..531f0e585 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -4,8 +4,36 @@ // You should have received a copy of the MIT License // along with the Jellyfish library. If not, see . -//! This module implements the BLS signature over the BN254 curve.ç -// TODO more comments +//! This module implements the BLS signature over the BN254 curve. +//! The [BLS signature scheme][bls] relies on a bilinear map `e:G1 x G2 -> GT` +//! and a hash function `H` from a message input space (e.g. bytes) to a group +//! element `G1`. `H` must be such that for all `m`, the discrete logarithm +//! `H(m)` w.r.t to the generator of `G1` is unknown. +//! +//! The scheme works as follows: +//! Let `g1` and `g2` be generators of `G1` and `G2`. +//! +//! **KeyGen()** +//! * sample a random `s` in the scalar field `Fr` and return the key pair +//! `(sk,pk):=(s,g2^s)` +//! +//! **Sign(sk,m)** +//! * return `sigma=H(m)^{sk}` +//! +//! **Verify(pk,m,sigma)** +//! * Check that `e(sigma,g_2)=e(H(m),pk)` +//! +//! In this module: +//! * `e` is the pairing over the curve [BN254][bn254] supported by the EVM +//! [EIP-196][eip196], [EIP197][eip197] +//! * `H` is implemented using the "hash-and-pray" approach. See function +//! [`hash_to_curve`] +//! +//! [bls]: https://hovav.net/ucsd/dist/sigs.pdf +//! [bn254]: https://eprint.iacr.org/2005/133.pdf +//! [eip196]: https://eips.ethereum.org/EIPS/eip-196 +//! [eip197]: https://eips.ethereum.org/EIPS/eip-197 + use super::SignatureScheme; use crate::{constants::CS_ID_BLS_BN254, errors::PrimitivesError}; use ark_bn254::{ @@ -54,7 +82,7 @@ impl SignatureScheme for BLSOverBN254CurveSignatureScheme { /// A message is &\[MessageUnit\] type MessageUnit = u8; - /// generate public parameters from RNG. + /// Generate public parameters from RNG. fn param_gen( _prng: Option<&mut R>, ) -> Result { @@ -67,7 +95,7 @@ impl SignatureScheme for BLSOverBN254CurveSignatureScheme { prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { let kp = KeyPair::generate(prng); - Ok((kp.sk, kp.vk)) + Ok((kp.sk.clone(), kp.vk.clone())) } /// Sign a message with the signing key @@ -95,27 +123,21 @@ impl SignatureScheme for BLSOverBN254CurveSignatureScheme { // ===================================================== // Signing key // ===================================================== -#[tagged(tag::BLS_SIGNING_KEY)] // TODO what iis this tagging thing? +#[tagged(tag::BLS_SIGNING_KEY)] #[derive( Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug, )] +#[zeroize(drop)] /// Signing key for BLS signature. pub struct SignKey(pub(crate) ScalarField); -impl Drop for SignKey { - fn drop(&mut self) { - self.0.zeroize(); - } -} - // ===================================================== // Verification key // ===================================================== /// Signature public verification key -// Derive zeroize here so that keypair can be zeroized -#[tagged(tag::BLS_VER_KEY)] // TODO how does this work??? -#[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] +#[tagged(tag::BLS_VER_KEY)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Zeroize, Eq, Clone, Debug)] pub struct VerKey(pub(crate) G2Projective); impl Hash for VerKey { @@ -142,9 +164,8 @@ impl VerKey { // ===================================================== /// Signature secret key pair used to sign messages -// Make sure sk can be zeroized // TODO -#[tagged(tag::BLS_VER_KEY)] // TODO what is this tag for? -#[derive(CanonicalSerialize, CanonicalDeserialize, Clone)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Zeroize)] +#[zeroize(drop)] pub struct KeyPair { sk: SignKey, vk: VerKey, @@ -155,7 +176,7 @@ pub struct KeyPair { // ===================================================== /// The signature of BLS signature scheme -#[tagged(tag::BLS_SIG)] // TODO what is this tag for? +#[tagged(tag::BLS_SIG)] #[derive(CanonicalSerialize, CanonicalDeserialize, Eq, Clone, Debug)] #[allow(non_snake_case)] pub struct Signature { @@ -180,9 +201,9 @@ impl PartialEq for Signature { /// Non constant time hash to curve algorithm (a.k.a "hash-and-pray") /// The hashing algorithm consists of the following steps: /// 1. Hash the bytes to a field element `x`. -/// 2. Compute `Y = x^3 + 3`. -/// 3. Check if `Y` is a quadratic residue (QR), in which case return -/// `y=sqrt(Y)` otherwise try with `x+1, x+2` etc... until `Y` is a QR. +/// 2. Compute `Y = x^3 + 3`. (Note: the equation of the BN curve is +/// y^2=x^3+3) 3. Check if `Y` is a quadratic residue (QR), in which case +/// return `y=sqrt(Y)` otherwise try with `x+1, x+2` etc... until `Y` is a QR. /// 4. Return `P=(x,y)` /// /// In the future we may switch to a constant time algorithm such as Fouque-Tibouchi @@ -195,7 +216,7 @@ pub fn hash_to_curve(msg: &[u8]) -> G1Projective let hasher = as HashToField>::new(hasher_init); let field_elems: Vec = hasher.hash_to_field(msg, 1); - // Coefficients of the curve: y^2 = x^3 + ax + b + // General equation of the curve: y^2 = x^3 + ax + b // For BN254 we have a=0 and b=3 so we only use b let coeff_b: BaseField = MontFp!("3"); @@ -280,8 +301,6 @@ impl VerKey { sig: &Signature, csid: B, ) -> Result<(), PrimitivesError> { - // TODO Check public key - let msg_input = [msg, csid.as_ref()].concat(); let group_elem = hash_to_curve::(&msg_input); let g2 = G2Projective::generator(); diff --git a/primitives/src/signatures/mod.rs b/primitives/src/signatures/mod.rs index 102276e65..6a95ea553 100644 --- a/primitives/src/signatures/mod.rs +++ b/primitives/src/signatures/mod.rs @@ -3,11 +3,11 @@ use crate::errors::PrimitivesError; use ark_std::rand::{CryptoRng, RngCore}; -pub mod bls; +pub mod bls_over_bls12381; pub mod bls_over_bn254; pub mod schnorr; -pub use bls::BLSSignatureScheme; +pub use bls_over_bls12381::BLSSignatureScheme; use core::fmt::Debug; pub use schnorr::SchnorrSignatureScheme; use serde::{Deserialize, Serialize}; @@ -62,7 +62,7 @@ pub trait SignatureScheme { // FIXME: the API looks a bit strange when the default generator is used. // For example: // `S::param_gen::(None)` - // wheere `StdRng` is redundent. + // where `StdRng` is redundant. fn param_gen( prng: Option<&mut R>, ) -> Result; diff --git a/primitives/src/vrf/blsvrf.rs b/primitives/src/vrf/blsvrf.rs index 1a1187f4c..5b63b0658 100644 --- a/primitives/src/vrf/blsvrf.rs +++ b/primitives/src/vrf/blsvrf.rs @@ -3,7 +3,7 @@ use super::Vrf; use crate::{ errors::PrimitivesError, signatures::{ - bls::{BLSSignKey, BLSSignature, BLSVerKey}, + bls_over_bls12381::{BLSSignKey, BLSSignature, BLSVerKey}, BLSSignatureScheme, SignatureScheme, }, }; From 18f5243bfe9aaa13774753636bf0884f4037f304 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 5 Apr 2023 10:41:45 -0400 Subject: [PATCH 20/23] Add `Copy` trait to `VerKey` and remove superfluous use of `clone()`. --- primitives/src/signatures/bls_over_bn254.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index 531f0e585..cd1ddcf18 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -95,7 +95,7 @@ impl SignatureScheme for BLSOverBN254CurveSignatureScheme { prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { let kp = KeyPair::generate(prng); - Ok((kp.sk.clone(), kp.vk.clone())) + Ok((kp.sk.clone(), kp.vk)) } /// Sign a message with the signing key @@ -137,7 +137,7 @@ pub struct SignKey(pub(crate) ScalarField); /// Signature public verification key #[tagged(tag::BLS_VER_KEY)] -#[derive(CanonicalSerialize, CanonicalDeserialize, Zeroize, Eq, Clone, Debug)] +#[derive(CanonicalSerialize, CanonicalDeserialize, Zeroize, Eq, Clone, Debug, Copy)] pub struct VerKey(pub(crate) G2Projective); impl Hash for VerKey { @@ -259,7 +259,7 @@ impl KeyPair { /// Get the verification key pub fn ver_key(&self) -> VerKey { - self.vk.clone() + self.vk } /// Get the internal of the signing key, namely a P::ScalarField element From bc539445b04e1ae7f272f77cbea549cf0627ab41 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 5 Apr 2023 10:56:17 -0400 Subject: [PATCH 21/23] Simplify code for computing initial field element x. --- primitives/src/signatures/bls_over_bn254.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index cd1ddcf18..b2e625fa6 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -214,13 +214,12 @@ impl PartialEq for Signature { pub fn hash_to_curve(msg: &[u8]) -> G1Projective { let hasher_init = &[1u8]; let hasher = as HashToField>::new(hasher_init); - let field_elems: Vec = hasher.hash_to_field(msg, 1); // General equation of the curve: y^2 = x^3 + ax + b // For BN254 we have a=0 and b=3 so we only use b let coeff_b: BaseField = MontFp!("3"); - let mut x = field_elems[0]; + let mut x: BaseField = hasher.hash_to_field(msg, 1)[0]; let mut Y: BaseField = x * x * x + coeff_b; // Loop until we find a quadratic residue From ac9511171e75a448d651c9b4c4e016ae601f7623 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 5 Apr 2023 12:54:34 -0400 Subject: [PATCH 22/23] Better ciphersuite identifier for BLS signature scheme over BN254 curve. --- primitives/src/constants.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index 2063d7e45..51f5b59d0 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -25,5 +25,6 @@ pub const BLS_SIG_PK_SIZE: usize = 192; pub const BLS_SIG_COMPRESSED_PK_SIZE: usize = 96; /// ciphersuite identifier for BLS signature over BN254 -/// Note this does **not** follow -pub const CS_ID_BLS_BN254: &str = "BLS_SIG_BN254"; +/// Note this is **adapted** from . +/// In particular the "hash-and-pray" method is not part of , so the tag "NCTH" (non constant time hash) is not standard. +pub const CS_ID_BLS_BN254: &str = "BLS_SIG_BN254G1_XMD:KECCAK_NCTH_NUL_"; From a07c2293296248f89e47d4b0634bbe7b47fea7a8 Mon Sep 17 00:00:00 2001 From: Philippe Camacho Date: Wed, 5 Apr 2023 13:41:19 -0400 Subject: [PATCH 23/23] Test for long messages. --- primitives/src/signatures/bls_over_bn254.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/primitives/src/signatures/bls_over_bn254.rs b/primitives/src/signatures/bls_over_bn254.rs index b2e625fa6..caffd4c79 100644 --- a/primitives/src/signatures/bls_over_bn254.rs +++ b/primitives/src/signatures/bls_over_bn254.rs @@ -352,6 +352,17 @@ mod tests { assert!(pk.verify(&msg, &sig, CS_ID_BLS_BN254).is_err()); } } + + // Test for long messages + const SIZE: usize = 35; // Bigger than 32 which is the number of bytes needed to encode a field element + let key_pair = KeyPair::generate(&mut rng); + let msg = [33u8; SIZE]; + let sig = key_pair.sign(&msg, CS_ID_BLS_BN254); + let pk = key_pair.ver_key_ref(); + assert!(pk.verify(&msg, &sig, CS_ID_BLS_BN254).is_ok()); + + let wrong_msg = [33u8; SIZE + 1]; + assert!(pk.verify(&wrong_msg, &sig, CS_ID_BLS_BN254).is_err()); } #[test]