From 4ffca8bdcc0e3a9d4575c1aeef8e868d669c1ad8 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 7 Dec 2022 13:09:07 +0800 Subject: [PATCH 1/8] zeroize ikm, add docs and doctest to bls sig --- primitives/Cargo.toml | 1 + primitives/src/errors.rs | 21 +++++- primitives/src/signatures/bls.rs | 124 ++++++++++++++++++++++++++++--- 3 files changed, 131 insertions(+), 15 deletions(-) diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 25c00a2d7..010decfec 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -53,6 +53,7 @@ bincode = "1.0" criterion = "0.4.0" hashbrown = "0.13.1" quickcheck = "1.0.0" +rand_core = { version = "^0.6.0", features = ["getrandom"] } [[bench]] name = "merkle_path" diff --git a/primitives/src/errors.rs b/primitives/src/errors.rs index 82e1abca2..ec2da68a8 100644 --- a/primitives/src/errors.rs +++ b/primitives/src/errors.rs @@ -8,7 +8,11 @@ use crate::rescue::errors::RescueError; use ark_serialize::SerializationError; -use ark_std::string::String; +use ark_std::{ + format, + string::{String, ToString}, +}; +use blst::BLST_ERROR; use displaydoc::Display; /// A `enum` specifying the possible failure modes of the primitives. @@ -43,5 +47,16 @@ impl From for PrimitivesError { } } -#[cfg(feature = "std")] -impl std::error::Error for PrimitivesError {} +impl From for PrimitivesError { + fn from(e: BLST_ERROR) -> Self { + match e { + BLST_ERROR::BLST_SUCCESS => { + Self::InternalError("Expecting an error, but got a sucess.".to_string()) + }, + BLST_ERROR::BLST_VERIFY_FAIL => Self::VerificationError(format!("{:?}", e)), + _ => Self::ParameterError(format!("{:?}", e)), + } + } +} + +impl ark_std::error::Error for PrimitivesError {} diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index cb63ac55f..99786d7a1 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -1,20 +1,88 @@ +// 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 . + //! BLS Signature Scheme +//! +//! Conforming to [IRTF draft][irtf], wrapping [`blst` crate][blst] under the +//! hood. +//! +//! [irtf]: https://datatracker.ietf.org/doc/pdf/draft-irtf-cfrg-bls-signature-05 +//! [blst]: https://github.com/supranational/blst +//! +//! # Examples +//! +//! ``` +//! use rand_core::{RngCore, OsRng}; +//! use jf_primitives::signatures::{SignatureScheme, bls::BLSSignatureScheme}; +//! +//! let pp = BLSSignatureScheme::param_gen::(None)?; +//! +//! // make sure the PRNG passed in is securely seeded, we RECOMMEND using `OsRng` +//! // from `rand_core` or `getrandom` crate. +//! let (sk, pk) = BLSSignatureScheme::key_gen(&pp, &mut OsRng)?; +//! +//! let msg = "The quick brown fox jumps over the lazy dog"; +//! let sig = BLSSignatureScheme::sign(&pp, &sk, &msg, &mut OsRng)?; +//! assert!(BLSSignatureScheme::verify(&pp, &pk, &msg, &sig).is_ok()); +//! +//! # Ok::<(), Box>(()) +//! ``` +//! +//! ## Generating independent keys from the same IKM +//! +//! In case you want to keep the IKM for multiple key pairs, and potentially +//! reconstruct them later on from IKM. +//! +//! ``` +//! use rand_core::{RngCore, OsRng}; +//! use sha2::{Sha256, Digest}; +//! use jf_primitives::signatures::{SignatureScheme, bls::BLSSignatureScheme}; +//! +//! let pp = BLSSignatureScheme::param_gen::(None)?; +//! +//! // NOTE: in practice, please use [`zeroize`][zeroize] to wipe sensitive +//! // key materials out of memory. +//! let mut ikm = [0u8; 32]; // should be at least 32 bytes +//! OsRng.fill_bytes(&mut ikm); +//! +//! let mut hasher = Sha256::new(); +//! hasher.update(b"MY-BLS-SIG-KEYGEN-SALT-DOM-SEP"); +//! let salt = hasher.finalize(); +//! +//! let (sk1, pk1) = BLSSignatureScheme::key_gen_v5(&ikm, &salt, b"banking".as_ref())?; +//! let (sk2, pk2) = BLSSignatureScheme::key_gen_v5(&ikm, &salt, b"legal".as_ref())?; +//! +//! let msg = "I authorize transfering 10 dollars to Alice"; +//! let sig = BLSSignatureScheme::sign(&pp, &sk1, &msg, &mut OsRng)?; +//! assert!(BLSSignatureScheme::verify(&pp, &pk1, &msg, &sig).is_ok()); +//! +//! let msg = "I agree to the Terms and Conditions."; +//! let sig = BLSSignatureScheme::sign(&pp, &sk2, &msg, &mut OsRng)?; +//! assert!(BLSSignatureScheme::verify(&pp, &pk2, &msg, &sig).is_ok()); +//! +//! # Ok::<(), Box>(()) +//! ``` +//! +//! [zeroize]: https://github.com/RustCrypto/utils/tree/master/zeroize use super::SignatureScheme; use crate::{constants::CS_ID_BLS_SIG_NAIVE, errors::PrimitivesError}; - use ark_std::{ format, + ops::{Deref, DerefMut}, rand::{CryptoRng, RngCore}, }; - -use blst::{min_sig::*, BLST_ERROR}; - pub use blst::min_sig::{ PublicKey as BLSVerKey, SecretKey as BLSSignKey, Signature as BLSSignature, }; +use blst::{min_sig::*, BLST_ERROR}; +use zeroize::Zeroizing; -/// BLS signature scheme. Imports blst library. +/// BLS signature scheme. Wrapping around structs from the `blst` crate. +/// See [module-level documentation](self) for example usage. pub struct BLSSignatureScheme; impl SignatureScheme for BLSSignatureScheme { @@ -43,18 +111,18 @@ impl SignatureScheme for BLSSignatureScheme { Ok(()) } - /// Sample a pair of keys. + /// Generate a BLS key pair. + /// Make sure the `prng` passed in are properly seeded with trusted entropy. fn key_gen( _pp: &Self::PublicParameter, prng: &mut R, ) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> { - let mut ikm = [0u8; 32]; - prng.fill_bytes(&mut ikm); - let sk = match SecretKey::key_gen(&ikm, &[]) { - Ok(sk) => sk, - Err(e) => return Err(PrimitivesError::InternalError(format!("{:?}", e))), - }; + let mut ikm = Zeroizing::new([0u8; 32]); + prng.fill_bytes(ikm.deref_mut()); + + let sk = SecretKey::key_gen(ikm.deref(), &[])?; let vk = sk.sk_to_pk(); + Ok((sk, vk)) } @@ -82,6 +150,38 @@ impl SignatureScheme for BLSSignatureScheme { } } +impl BLSSignatureScheme { + /// Alternative deterministic key_gen compatible with [IRTF draft v5][v5]. + /// + /// - Secret byte string `ikm` MUST be infeasible to guess, ideally + /// generated by a trusted source of randomness. `ikm` MUST be at least 32 + /// bytes long, but it MAY be longer. + /// - `salt` should either be empty or an unstructured byte string. It is + /// RECOMMENDED to fix a uniformly random byte string of length 32. See + /// details [here][salt]. + /// - `key_info` is optional, it MAY be used to derived multiple independent + /// keys from the same `ikm`. By default, `key_info` is the empty string. + /// + /// [v5]: https://datatracker.ietf.org/doc/pdf/draft-irtf-cfrg-bls-signature-05 + /// [salt]: https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-choosing-a-salt-value-for-k + pub fn key_gen_v5( + ikm: &[u8], + salt: &[u8], + key_info: &[u8], + ) -> Result< + ( + ::SigningKey, + ::VerificationKey, + ), + PrimitivesError, + > { + let sk = SecretKey::key_gen_v5(ikm, salt, key_info)?; + let vk = sk.sk_to_pk(); + + Ok((sk, vk)) + } +} + #[cfg(test)] mod test { use super::*; From 3e74826a062292be1d56273c7f10107a9a03196e Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 7 Dec 2022 14:26:34 +0800 Subject: [PATCH 2/8] conform with CipherSuite standard --- primitives/src/constants.rs | 5 +++-- primitives/src/signatures/bls.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index e017a4be7..f12e7cc90 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -9,5 +9,6 @@ /// ciphersuite identifier for schnorr signature pub const CS_ID_SCHNORR: &str = "SCHNORR_WITH_RESCUE_HASH_v01"; -/// ciphersuite identifier for BLS signature -pub const CS_ID_BLS_SIG_NAIVE: &str = "BLS_SIG_WITH_NAIVE_HtG_v01"; +/// ciphersuite identifier for BLS signature, see: +/// https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-ciphersuite-format +pub const CS_ID_BLS_MIN_SIG: &str = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"; diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index 99786d7a1..d28f4955c 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -69,7 +69,7 @@ //! [zeroize]: https://github.com/RustCrypto/utils/tree/master/zeroize use super::SignatureScheme; -use crate::{constants::CS_ID_BLS_SIG_NAIVE, errors::PrimitivesError}; +use crate::{constants::CS_ID_BLS_MIN_SIG, errors::PrimitivesError}; use ark_std::{ format, ops::{Deref, DerefMut}, @@ -86,7 +86,7 @@ use zeroize::Zeroizing; pub struct BLSSignatureScheme; impl SignatureScheme for BLSSignatureScheme { - const CS_ID: &'static str = CS_ID_BLS_SIG_NAIVE; + const CS_ID: &'static str = CS_ID_BLS_MIN_SIG; /// Public parameter type PublicParameter = (); From 19181b5d7910003564d7024f3fc797a95e63b4a1 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 7 Dec 2022 23:27:44 +0800 Subject: [PATCH 3/8] add test to canonical serde for bls sig --- primitives/src/constants.rs | 11 ++ primitives/src/signatures/bls.rs | 234 +++++++++++++++++++++++++++++-- 2 files changed, 237 insertions(+), 8 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index f12e7cc90..c461af75b 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -12,3 +12,14 @@ pub const CS_ID_SCHNORR: &str = "SCHNORR_WITH_RESCUE_HASH_v01"; /// ciphersuite identifier for BLS signature, see: /// https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-ciphersuite-format pub const CS_ID_BLS_MIN_SIG: &str = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"; + +/// Size in bytes of a secret key in our BLS signature scheme. +pub const BLS_SIG_SK_SIZE: usize = 32; +/// Size in bytes of a signature in our BLS signature scheme. +pub const BLS_SIG_SIGNATURE_SIZE: usize = 96; +/// Size in bytes of a compressed signature in our BLS signature scheme. +pub const BLS_SIG_COMPRESSED_SIGNATURE_SIZE: usize = 48; +/// Size in bytes of a verification key in our BLS signature scheme. +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; diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index d28f4955c..32b4f7445 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -69,17 +69,196 @@ //! [zeroize]: https://github.com/RustCrypto/utils/tree/master/zeroize use super::SignatureScheme; -use crate::{constants::CS_ID_BLS_MIN_SIG, errors::PrimitivesError}; +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, + }, + errors::PrimitivesError, +}; +use ark_serialize::*; use ark_std::{ format, ops::{Deref, DerefMut}, rand::{CryptoRng, RngCore}, -}; -pub use blst::min_sig::{ - PublicKey as BLSVerKey, SecretKey as BLSSignKey, Signature as BLSSignature, + vec::Vec, }; use blst::{min_sig::*, BLST_ERROR}; -use zeroize::Zeroizing; +use zeroize::{Zeroize, Zeroizing}; + +#[derive(Clone, Debug, Default, PartialEq, Eq, Copy)] +/// A BLS Public Key (Verification Key). +pub struct BLSVerKey(PublicKey); + +impl Deref for BLSVerKey { + type Target = PublicKey; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl CanonicalSerialize for BLSVerKey { + fn serialize(&self, mut w: W) -> Result<(), SerializationError> { + Ok(w.write_all(&self.compress())?) + } + + fn serialized_size(&self) -> usize { + BLS_SIG_COMPRESSED_PK_SIZE + } + + fn serialize_uncompressed(&self, mut w: W) -> Result<(), SerializationError> { + Ok(w.write_all(&PublicKey::serialize(self))?) + } + + fn uncompressed_size(&self) -> usize { + BLS_SIG_PK_SIZE + } +} + +// TODO: (alex) update these with combinations of compressed and checked +// when upgrading to use arkwork 0.4.0 +impl CanonicalDeserialize for BLSVerKey { + // compressed + validity checked + fn deserialize(mut r: R) -> Result { + let mut pk_bytes = [0u8; BLS_SIG_COMPRESSED_PK_SIZE]; + r.read_exact(&mut pk_bytes)?; + + let pk = PublicKey::uncompress(&pk_bytes).map_err(|_| SerializationError::InvalidData)?; + PublicKey::validate(&pk).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(pk)) + } + + // uncompressed + validity checked + fn deserialize_uncompressed(mut r: R) -> Result { + let mut pk_bytes = [0u8; BLS_SIG_PK_SIZE]; + r.read_exact(&mut pk_bytes)?; + + let pk = PublicKey::deserialize(&pk_bytes).map_err(|_| SerializationError::InvalidData)?; + PublicKey::validate(&pk).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(pk)) + } + + // uncompressed + validity unchekced + fn deserialize_unchecked(mut r: R) -> Result { + let mut pk_bytes = [0u8; BLS_SIG_PK_SIZE]; + r.read_exact(&mut pk_bytes)?; + let pk = PublicKey::deserialize(&pk_bytes).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(pk)) + } +} + +#[derive(Clone, Debug, Default, Zeroize)] +#[zeroize(drop)] +/// A BLS Secret Key (Signing Key). +pub struct BLSSignKey(SecretKey); + +impl Deref for BLSSignKey { + type Target = SecretKey; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl PartialEq for BLSSignKey { + fn eq(&self, other: &Self) -> bool { + // constant time comparison + let xor_res: Vec = self + .to_bytes() + .iter() + .zip(other.to_bytes().iter()) + .map(|(a, b)| a ^ b) + .collect(); + xor_res == [0u8; 32] + } +} + +impl CanonicalSerialize for BLSSignKey { + fn serialize(&self, mut w: W) -> Result<(), SerializationError> { + Ok(w.write_all(&self.to_bytes())?) + } + + fn serialized_size(&self) -> usize { + BLS_SIG_SK_SIZE + } +} + +impl CanonicalDeserialize for BLSSignKey { + fn deserialize(mut r: R) -> Result { + let mut sk_bytes = [0u8; BLS_SIG_SK_SIZE]; + r.read_exact(&mut sk_bytes)?; + let sk = SecretKey::from_bytes(&sk_bytes).map_err(|_| SerializationError::InvalidData)?; + Ok(Self(sk)) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Copy)] +/// A BLS Signature. +pub struct BLSSignature(Signature); + +impl Deref for BLSSignature { + type Target = Signature; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl CanonicalSerialize for BLSSignature { + fn serialize(&self, mut w: W) -> Result<(), SerializationError> { + Ok(w.write_all(&self.compress())?) + } + + fn serialized_size(&self) -> usize { + BLS_SIG_COMPRESSED_SIGNATURE_SIZE + } + + fn serialize_uncompressed(&self, mut w: W) -> Result<(), SerializationError> { + Ok(w.write_all(&Signature::serialize(self))?) + } + + fn uncompressed_size(&self) -> usize { + BLS_SIG_SIGNATURE_SIZE + } +} + +// TODO: (alex) update these with combinations of compressed and checked +// when upgrading to use arkwork 0.4.0 +impl CanonicalDeserialize for BLSSignature { + // compressed + validity checked + fn deserialize(mut r: R) -> Result { + let mut sig_bytes = [0u8; BLS_SIG_COMPRESSED_SIGNATURE_SIZE]; + r.read_exact(&mut sig_bytes)?; + + let sig = Signature::uncompress(&sig_bytes).map_err(|_| SerializationError::InvalidData)?; + Signature::validate(&sig, true).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(sig)) + } + + // uncompressed + validity checked + fn deserialize_uncompressed(mut r: R) -> Result { + let mut sig_bytes = [0u8; BLS_SIG_SIGNATURE_SIZE]; + r.read_exact(&mut sig_bytes)?; + + let sig = + Signature::deserialize(&sig_bytes).map_err(|_| SerializationError::InvalidData)?; + Signature::validate(&sig, true).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(sig)) + } + + // uncompressed + validity unchekced + fn deserialize_unchecked(mut r: R) -> Result { + let mut sig_bytes = [0u8; BLS_SIG_SIGNATURE_SIZE]; + r.read_exact(&mut sig_bytes)?; + let sig = + Signature::deserialize(&sig_bytes).map_err(|_| SerializationError::InvalidData)?; + + Ok(Self(sig)) + } +} /// BLS signature scheme. Wrapping around structs from the `blst` crate. /// See [module-level documentation](self) for example usage. @@ -123,7 +302,7 @@ impl SignatureScheme for BLSSignatureScheme { let sk = SecretKey::key_gen(ikm.deref(), &[])?; let vk = sk.sk_to_pk(); - Ok((sk, vk)) + Ok((BLSSignKey(sk), BLSVerKey(vk))) } /// Sign a message @@ -133,7 +312,11 @@ impl SignatureScheme for BLSSignatureScheme { msg: M, _prng: &mut R, ) -> Result { - Ok(sk.sign(msg.as_ref(), Self::CS_ID.as_bytes(), &[])) + Ok(BLSSignature(sk.sign( + msg.as_ref(), + Self::CS_ID.as_bytes(), + &[], + ))) } /// Verify a signature. @@ -178,7 +361,7 @@ impl BLSSignatureScheme { let sk = SecretKey::key_gen_v5(ikm, salt, key_info)?; let vk = sk.sk_to_pk(); - Ok((sk, vk)) + Ok((BLSSignKey(sk), BLSVerKey(vk))) } } @@ -186,6 +369,7 @@ impl BLSSignatureScheme { mod test { use super::*; use crate::signatures::tests::{failed_verification, sign_and_verify}; + use ark_std::{fmt::Debug, rand::rngs::StdRng, vec}; #[test] fn test_bls_sig() { @@ -194,4 +378,38 @@ mod test { sign_and_verify::(message.as_ref()); failed_verification::(message.as_ref(), message_bad.as_ref()); } + + #[test] + fn test_canonical_serde() { + let mut rng = ark_std::test_rng(); + let pp = BLSSignatureScheme::param_gen::(None).unwrap(); + let (sk, pk) = BLSSignatureScheme::key_gen(&pp, &mut rng).unwrap(); + let msg = "The quick brown fox jumps over the lazy dog"; + let sig = BLSSignatureScheme::sign(&pp, &sk, &msg, &mut rng).unwrap(); + + test_canonical_serde_helper(sk); + test_canonical_serde_helper(pk); + test_canonical_serde_helper(sig); + } + + // TODO: (alex) update this after upgrading to arkwork 0.4.0 + fn test_canonical_serde_helper(data: T) + where + T: CanonicalSerialize + CanonicalDeserialize + Debug + PartialEq, + { + let mut bytes = vec![]; + CanonicalSerialize::serialize(&data, &mut bytes).unwrap(); + let de: T = CanonicalDeserialize::deserialize(&bytes[..]).unwrap(); + assert_eq!(data, de); + + bytes = vec![]; + CanonicalSerialize::serialize_uncompressed(&data, &mut bytes).unwrap(); + let de: T = CanonicalDeserialize::deserialize_uncompressed(&bytes[..]).unwrap(); + assert_eq!(data, de); + + bytes = vec![]; + CanonicalSerialize::serialize_unchecked(&data, &mut bytes).unwrap(); + let de: T = CanonicalDeserialize::deserialize_unchecked(&bytes[..]).unwrap(); + assert_eq!(data, de); + } } From 4adf3dd61f1a651379902d879b99fdb2ef2acdb8 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 7 Dec 2022 23:41:15 +0800 Subject: [PATCH 4/8] upgrade to latest tagged, auto-derive serde on bls sig structs --- primitives/src/signatures/bls.rs | 8 +++++++- primitives/src/signatures/schnorr.rs | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index 32b4f7445..9e3c7c5bc 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -78,15 +78,19 @@ use crate::{ }; use ark_serialize::*; use ark_std::{ + convert::TryInto, format, ops::{Deref, DerefMut}, rand::{CryptoRng, RngCore}, vec::Vec, }; use blst::{min_sig::*, BLST_ERROR}; +use espresso_systems_common::jellyfish::tag; +use tagged_base64::tagged; use zeroize::{Zeroize, Zeroizing}; #[derive(Clone, Debug, Default, PartialEq, Eq, Copy)] +#[tagged(tag::BLS_VER_KEY)] /// A BLS Public Key (Verification Key). pub struct BLSVerKey(PublicKey); @@ -152,6 +156,7 @@ impl CanonicalDeserialize for BLSVerKey { #[derive(Clone, Debug, Default, Zeroize)] #[zeroize(drop)] +#[tagged(tag::BLS_SIGNING_KEY)] /// A BLS Secret Key (Signing Key). pub struct BLSSignKey(SecretKey); @@ -194,8 +199,9 @@ impl CanonicalDeserialize for BLSSignKey { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy)] /// A BLS Signature. +#[derive(Clone, Debug, PartialEq, Eq, Copy)] +#[tagged(tag::BLS_SIG)] pub struct BLSSignature(Signature); impl Deref for BLSSignature { diff --git a/primitives/src/signatures/schnorr.rs b/primitives/src/signatures/schnorr.rs index c726031f4..f75c77d97 100644 --- a/primitives/src/signatures/schnorr.rs +++ b/primitives/src/signatures/schnorr.rs @@ -127,7 +127,7 @@ impl SignKey { /// Signature public verification key // derive zeroize here so that keypair can be zeroized -#[tagged(tag::SCHNORRVERKEY)] +#[tagged(tag::SCHNORR_VER_KEY)] #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( Debug(bound = "P: Parameters"), @@ -196,7 +196,7 @@ impl VerKey

{ /// Signature secret key pair used to sign messages // make sure sk can be zeroized -#[tagged(tag::SIGNKEYPAIR)] +#[tagged(tag::SCHNORR_KEY_PAIR)] #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( Debug(bound = "P: Parameters"), @@ -217,7 +217,7 @@ where // ===================================================== /// The signature of Schnorr signature scheme -#[tagged(tag::SIG)] +#[tagged(tag::SCHNORR_SIG)] #[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)] #[derivative( Debug(bound = "P: Parameters"), From 75efdb3727ac9b4ed17690c07b45b99cb4e8a074 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 8 Dec 2022 00:20:51 +0800 Subject: [PATCH 5/8] fix rustdoc failure --- primitives/src/constants.rs | 2 +- utilities/src/serialize.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/primitives/src/constants.rs b/primitives/src/constants.rs index c461af75b..795d4b2ec 100644 --- a/primitives/src/constants.rs +++ b/primitives/src/constants.rs @@ -10,7 +10,7 @@ pub const CS_ID_SCHNORR: &str = "SCHNORR_WITH_RESCUE_HASH_v01"; /// ciphersuite identifier for BLS signature, see: -/// https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-ciphersuite-format +/// pub const CS_ID_BLS_MIN_SIG: &str = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"; /// Size in bytes of a secret key in our BLS signature scheme. diff --git a/utilities/src/serialize.rs b/utilities/src/serialize.rs index e7d43d36c..f76ff29dc 100644 --- a/utilities/src/serialize.rs +++ b/utilities/src/serialize.rs @@ -44,9 +44,11 @@ macro_rules! deserialize_canonical_bytes { /// Serializers for finite field elements. /// /// Field elements are typically foreign types that we cannot apply the -/// [macro@tagged_blob] macro to. Instead, use `#[serde(with = "field_elem")]` +/// [tagged] macro to. Instead, use `#[serde(with = "field_elem")]` /// at the point where the field element is used inside a struct or enum /// definition. +/// +/// [tagged]: tagged_base64::tagged pub mod field_elem { use super::*; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; From 2210003756e47ba089a0ff004cb44555c35d8b22 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 8 Dec 2022 13:04:45 +0800 Subject: [PATCH 6/8] minor doc language adjustment --- primitives/src/signatures/bls.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index 2bb7d3c87..ac5c8ba91 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -20,8 +20,9 @@ //! //! let pp = BLSSignatureScheme::param_gen::(None)?; //! -//! // make sure the PRNG passed in is securely seeded, we RECOMMEND using `OsRng` -//! // from `rand_core` or `getrandom` crate. +//! // make sure the PRNG passed has good and trusted entropy. +//! // you could use `OsRng` from `rand_core` or `getrandom` crate, +//! // or a `SeedableRng` like `ChaChaRng` with seed generated from good randomness source. //! let (sk, pk) = BLSSignatureScheme::key_gen(&pp, &mut OsRng)?; //! //! let msg = "The quick brown fox jumps over the lazy dog"; From 04e6f727bf001aa2c13acdce74e8f826f6dad425 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 8 Dec 2022 20:55:44 +0800 Subject: [PATCH 7/8] address Marti's PR comments --- primitives/src/signatures/bls.rs | 44 +++++++------------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/primitives/src/signatures/bls.rs b/primitives/src/signatures/bls.rs index ac5c8ba91..1d8e0608c 100644 --- a/primitives/src/signatures/bls.rs +++ b/primitives/src/signatures/bls.rs @@ -84,7 +84,6 @@ use ark_std::{ format, ops::{Deref, DerefMut}, rand::{CryptoRng, RngCore}, - vec::Vec, }; use blst::{min_sig::*, BLST_ERROR}; use espresso_systems_common::jellyfish::tag; @@ -92,7 +91,7 @@ use tagged_base64::tagged; use zeroize::{Zeroize, Zeroizing}; #[tagged(tag::BLS_SIGNING_KEY)] -#[derive(Clone, Debug, Default, Zeroize)] +#[derive(Clone, Debug, Zeroize)] #[zeroize(drop)] /// A BLS Secret Key (Signing Key). pub struct BLSSignKey(SecretKey); @@ -123,7 +122,7 @@ impl CanonicalDeserialize for BLSSignKey { let mut sk_bytes = [0u8; BLS_SIG_SK_SIZE]; reader.read_exact(&mut sk_bytes)?; - SecretKey::from_bytes(&sk_bytes) + SecretKey::deserialize(&sk_bytes) .map(Self) .map_err(|_| SerializationError::InvalidData) } @@ -131,14 +130,7 @@ impl CanonicalDeserialize for BLSSignKey { impl PartialEq for BLSSignKey { fn eq(&self, other: &Self) -> bool { - // constant time comparison - let xor_res: Vec = self - .to_bytes() - .iter() - .zip(other.to_bytes().iter()) - .map(|(a, b)| a ^ b) - .collect(); - xor_res == [0u8; 32] + self.0.serialize() == other.0.serialize() } } @@ -194,19 +186,11 @@ impl CanonicalDeserialize for BLSVerKey { } // uncompressed + validity checked - fn deserialize_uncompressed(mut reader: R) -> Result { - let len = ::deserialize(&mut reader)?; - if len != BLS_SIG_PK_SIZE { - return Err(SerializationError::InvalidData); - } - - let mut pk_bytes = [0u8; BLS_SIG_PK_SIZE]; - reader.read_exact(&mut pk_bytes)?; - - let pk = PublicKey::deserialize(&pk_bytes).map_err(|_| SerializationError::InvalidData)?; + fn deserialize_uncompressed(reader: R) -> Result { + let pk: Self = CanonicalDeserialize::deserialize_unchecked(reader)?; PublicKey::validate(&pk).map_err(|_| SerializationError::InvalidData)?; - Ok(Self(pk)) + Ok(pk) } // uncompressed + validity unchekced @@ -274,20 +258,10 @@ impl CanonicalDeserialize for BLSSignature { } // uncompressed + validity checked - fn deserialize_uncompressed(mut reader: R) -> Result { - let len = ::deserialize(&mut reader)?; - if len != BLS_SIG_SIGNATURE_SIZE { - return Err(SerializationError::InvalidData); - } - - let mut sig_bytes = [0u8; BLS_SIG_SIGNATURE_SIZE]; - reader.read_exact(&mut sig_bytes)?; - - let sig = - Signature::deserialize(&sig_bytes).map_err(|_| SerializationError::InvalidData)?; + fn deserialize_uncompressed(reader: R) -> Result { + let sig: Self = CanonicalDeserialize::deserialize_unchecked(reader)?; Signature::validate(&sig, true).map_err(|_| SerializationError::InvalidData)?; - - Ok(Self(sig)) + Ok(sig) } // uncompressed + validity unchekced From 3543246626c870243541e4d2b31e611c2b43c56d Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 8 Dec 2022 21:46:15 +0800 Subject: [PATCH 8/8] update CHANGELOG --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 716d6901e..fc413312f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,10 @@ and follow [semantic versioning](https://semver.org/) for our releases. - [#144](https://github.com/EspressoSystems/jellyfish/pull/144) (`jf-primitives`) Updated append-only merkle tree gadget with the latest MT API - [#119](https://github.com/EspressoSystems/jellyfish/pull/119) (all) Updated dependencies - Upgraded `criterion` from `0.3.1` to `0.4.0` - +- [#148](https://github.com/EspressoSystems/jellyfish/pull/148), [#156](https://github.com/EspressoSystems/jellyfish/pull/156) (`jf-primitives`) Refactored BLS Signature implementation + - #148 Added trait bounds on associated types of `trait SignatureScheme` + - #156 Improved BLS correctness and API compliance with IRTF standard with better doc + ### Fixed - [#76](https://github.com/EspressoSystems/jellyfish/pull/76) (`jf-plonk`) Splitting polynomials are masked to ensure zero-knowledge of Plonk