From 4e8f8269edeaa78a2c6ec9541810816cef99afa7 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Mon, 13 Jan 2025 14:53:08 +0100 Subject: [PATCH 01/11] expose `point` and `from_point` on `GenericSignature` --- crypto/bls/src/generic_signature.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index 05e0a222bd5..7f347dcaed0 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -93,12 +93,12 @@ where } /// Returns a reference to the underlying BLS point. - pub(crate) fn point(&self) -> Option<&Sig> { + pub fn point(&self) -> Option<&Sig> { self.point.as_ref() } /// Instantiates `Self` from a `point`. - pub(crate) fn from_point(point: Sig, is_infinity: bool) -> Self { + pub fn from_point(point: Sig, is_infinity: bool) -> Self { Self { point: Some(point), is_infinity, From dfd7ab0373a24fcb6c62b2a6202ffafcf80cfdc3 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Tue, 14 Jan 2025 21:36:13 +0100 Subject: [PATCH 02/11] add `point` and `from_point` to `GenericSecretKey` --- crypto/bls/src/generic_secret_key.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crypto/bls/src/generic_secret_key.rs b/crypto/bls/src/generic_secret_key.rs index a0a43311107..c48fdc4198a 100644 --- a/crypto/bls/src/generic_secret_key.rs +++ b/crypto/bls/src/generic_secret_key.rs @@ -61,6 +61,20 @@ where GenericPublicKey::from_point(self.point.public_key()) } + /// Returns a reference to the underlying BLS point. + pub fn point(&self) -> &Sec { + &self.point + } + + /// Instantiates `Self` from a `point`. + pub fn from_point(point: Sec) -> Self { + Self { + point, + _phantom_signature: PhantomData, + _phantom_public_key: PhantomData, + } + } + /// Serialize `self` as compressed bytes. /// /// ## Note From 5dfda40285eab4bd2180cd31ea9013db11fd9c39 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Wed, 15 Jan 2025 12:49:28 +0100 Subject: [PATCH 03/11] add `serialize_uncompressed` to `GenericSignature` --- crypto/bls/src/generic_signature.rs | 11 +++++++++++ crypto/bls/src/impls/blst.rs | 5 +++++ crypto/bls/src/impls/fake_crypto.rs | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index 7f347dcaed0..4bb9c1597ba 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -14,6 +14,9 @@ use tree_hash::TreeHash; /// The byte-length of a BLS signature when serialized in compressed form. pub const SIGNATURE_BYTES_LEN: usize = 96; +/// The byte-length of a BLS signature when serialized in uncompressed form. +pub const SIGNATURE_UNCOMPRESSED_BYTES_LEN: usize = 192; + /// Represents the signature at infinity. pub const INFINITY_SIGNATURE: [u8; SIGNATURE_BYTES_LEN] = [ 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -31,6 +34,9 @@ pub trait TSignature: Sized + Clone { /// Serialize `self` as compressed bytes. fn serialize(&self) -> [u8; SIGNATURE_BYTES_LEN]; + /// Serialize `self` as uncompressed bytes. + fn serialize_uncompressed(&self) -> [u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN]; + /// Deserialize `self` from compressed bytes. fn deserialize(bytes: &[u8]) -> Result; @@ -115,6 +121,11 @@ where } } + /// Serialize `self` as compressed bytes. + pub fn serialize_uncompressed(&self) -> Option<[u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN]> { + self.point.as_ref().map(|point| point.serialize_uncompressed()) + } + /// Deserialize `self` from compressed bytes. pub fn deserialize(bytes: &[u8]) -> Result { let point = if bytes == &NONE_SIGNATURE[..] { diff --git a/crypto/bls/src/impls/blst.rs b/crypto/bls/src/impls/blst.rs index baa704e05a9..1937247a4fa 100644 --- a/crypto/bls/src/impls/blst.rs +++ b/crypto/bls/src/impls/blst.rs @@ -11,6 +11,7 @@ use crate::{ pub use blst::min_pk as blst_core; use blst::{blst_scalar, BLST_ERROR}; use rand::Rng; +use crate::generic_signature::SIGNATURE_UNCOMPRESSED_BYTES_LEN; pub const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; pub const RAND_BITS: usize = 64; @@ -189,6 +190,10 @@ impl TSignature for blst_core::Signature { self.to_bytes() } + fn serialize_uncompressed(&self) -> [u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN] { + self.serialize() + } + fn deserialize(bytes: &[u8]) -> Result { Self::from_bytes(bytes).map_err(Into::into) } diff --git a/crypto/bls/src/impls/fake_crypto.rs b/crypto/bls/src/impls/fake_crypto.rs index a09fb347e6b..f0884e0e6b3 100644 --- a/crypto/bls/src/impls/fake_crypto.rs +++ b/crypto/bls/src/impls/fake_crypto.rs @@ -8,6 +8,7 @@ use crate::{ generic_signature::{TSignature, SIGNATURE_BYTES_LEN}, Error, Hash256, ZeroizeHash, INFINITY_PUBLIC_KEY, INFINITY_SIGNATURE, }; +use crate::generic_signature::SIGNATURE_UNCOMPRESSED_BYTES_LEN; /// Provides the externally-facing, core BLS types. pub mod types { @@ -106,6 +107,12 @@ impl TSignature for Signature { self.0 } + fn serialize_uncompressed(&self) -> [u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN] { + let mut ret = [0; SIGNATURE_UNCOMPRESSED_BYTES_LEN]; + ret[0..SIGNATURE_BYTES_LEN].copy_from_slice(&self.0); + ret + } + fn deserialize(bytes: &[u8]) -> Result { let mut signature = Self::infinity(); signature.0[..].copy_from_slice(&bytes[0..SIGNATURE_BYTES_LEN]); From f551579e328409a6360ca2a01dfe59854de0e5a2 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Wed, 15 Jan 2025 13:35:40 +0100 Subject: [PATCH 04/11] add `deserialize_uncompressed` to `GenericSignature` --- crypto/bls/src/generic_signature.rs | 3 +++ crypto/bls/src/impls/blst.rs | 4 ++++ crypto/bls/src/impls/fake_crypto.rs | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index 4bb9c1597ba..e0a5ff6cdcb 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -40,6 +40,9 @@ pub trait TSignature: Sized + Clone { /// Deserialize `self` from compressed bytes. fn deserialize(bytes: &[u8]) -> Result; + /// Serialize `self` from uncompressed bytes. + fn deserialize_uncompressed(bytes: &[u8]) -> Result; + /// Returns `true` if `self` is a signature across `msg` by `pubkey`. fn verify(&self, pubkey: &GenericPublicKey, msg: Hash256) -> bool; } diff --git a/crypto/bls/src/impls/blst.rs b/crypto/bls/src/impls/blst.rs index 1937247a4fa..aef1e9695c4 100644 --- a/crypto/bls/src/impls/blst.rs +++ b/crypto/bls/src/impls/blst.rs @@ -198,6 +198,10 @@ impl TSignature for blst_core::Signature { Self::from_bytes(bytes).map_err(Into::into) } + fn deserialize_uncompressed(bytes: &[u8]) -> Result { + Self::deserialize(bytes).map_err(Into::into) + } + fn verify(&self, pubkey: &blst_core::PublicKey, msg: Hash256) -> bool { // Public keys have already been checked for subgroup and infinity // Check Signature inside function for subgroup diff --git a/crypto/bls/src/impls/fake_crypto.rs b/crypto/bls/src/impls/fake_crypto.rs index f0884e0e6b3..b2ac208da82 100644 --- a/crypto/bls/src/impls/fake_crypto.rs +++ b/crypto/bls/src/impls/fake_crypto.rs @@ -119,6 +119,10 @@ impl TSignature for Signature { Ok(signature) } + fn deserialize_uncompressed(bytes: &[u8]) -> Result { + Self::deserialize(bytes) + } + fn verify(&self, _pubkey: &PublicKey, _msg: Hash256) -> bool { true } From 87515cca2cd97f6766d7e09e4f7b7a9d37795938 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Wed, 15 Jan 2025 13:40:20 +0100 Subject: [PATCH 05/11] actually add `deserialize_uncompressed` to `GenericSignature` --- crypto/bls/src/generic_signature.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index e0a5ff6cdcb..c5ca4d9a189 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -143,6 +143,15 @@ where _phantom: PhantomData, }) } + + /// Deserialize `self` from uncompressed bytes. + pub fn deserialize_uncompressed(bytes: &[u8]) -> Result { + Ok(Self { + point: Some(Sig::deserialize_uncompressed(bytes)?), + is_infinity: false, // todo + _phantom: PhantomData, + }) + } } impl GenericSignature From a714c146f1ea823cb815342eb9d5f3ef5c647760 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Tue, 21 Jan 2025 12:57:19 +0100 Subject: [PATCH 06/11] cargo fmt --- crypto/bls/src/generic_signature.rs | 4 +++- crypto/bls/src/impls/blst.rs | 3 +-- crypto/bls/src/impls/fake_crypto.rs | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index c5ca4d9a189..355f17aef1c 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -126,7 +126,9 @@ where /// Serialize `self` as compressed bytes. pub fn serialize_uncompressed(&self) -> Option<[u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN]> { - self.point.as_ref().map(|point| point.serialize_uncompressed()) + self.point + .as_ref() + .map(|point| point.serialize_uncompressed()) } /// Deserialize `self` from compressed bytes. diff --git a/crypto/bls/src/impls/blst.rs b/crypto/bls/src/impls/blst.rs index aef1e9695c4..6ca0fe09b2d 100644 --- a/crypto/bls/src/impls/blst.rs +++ b/crypto/bls/src/impls/blst.rs @@ -5,13 +5,12 @@ use crate::{ GenericPublicKey, TPublicKey, PUBLIC_KEY_BYTES_LEN, PUBLIC_KEY_UNCOMPRESSED_BYTES_LEN, }, generic_secret_key::TSecretKey, - generic_signature::{TSignature, SIGNATURE_BYTES_LEN}, + generic_signature::{TSignature, SIGNATURE_BYTES_LEN, SIGNATURE_UNCOMPRESSED_BYTES_LEN}, BlstError, Error, Hash256, ZeroizeHash, INFINITY_SIGNATURE, }; pub use blst::min_pk as blst_core; use blst::{blst_scalar, BLST_ERROR}; use rand::Rng; -use crate::generic_signature::SIGNATURE_UNCOMPRESSED_BYTES_LEN; pub const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; pub const RAND_BITS: usize = 64; diff --git a/crypto/bls/src/impls/fake_crypto.rs b/crypto/bls/src/impls/fake_crypto.rs index b2ac208da82..7273697597b 100644 --- a/crypto/bls/src/impls/fake_crypto.rs +++ b/crypto/bls/src/impls/fake_crypto.rs @@ -5,10 +5,9 @@ use crate::{ GenericPublicKey, TPublicKey, PUBLIC_KEY_BYTES_LEN, PUBLIC_KEY_UNCOMPRESSED_BYTES_LEN, }, generic_secret_key::{TSecretKey, SECRET_KEY_BYTES_LEN}, - generic_signature::{TSignature, SIGNATURE_BYTES_LEN}, + generic_signature::{TSignature, SIGNATURE_BYTES_LEN, SIGNATURE_UNCOMPRESSED_BYTES_LEN}, Error, Hash256, ZeroizeHash, INFINITY_PUBLIC_KEY, INFINITY_SIGNATURE, }; -use crate::generic_signature::SIGNATURE_UNCOMPRESSED_BYTES_LEN; /// Provides the externally-facing, core BLS types. pub mod types { From b54cea986b18274bb1a16901c7e6f4241e6b5537 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Mon, 17 Feb 2025 16:53:36 +0100 Subject: [PATCH 07/11] take reference in from_point --- crypto/bls/src/generic_secret_key.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crypto/bls/src/generic_secret_key.rs b/crypto/bls/src/generic_secret_key.rs index c48fdc4198a..79da1f5b8bb 100644 --- a/crypto/bls/src/generic_secret_key.rs +++ b/crypto/bls/src/generic_secret_key.rs @@ -67,9 +67,10 @@ where } /// Instantiates `Self` from a `point`. - pub fn from_point(point: Sec) -> Self { + /// Takes a reference, as moves might accidentally leave behind key material + pub fn from_point(point: &Sec) -> Self { Self { - point, + point: point.clone(), _phantom_signature: PhantomData, _phantom_public_key: PhantomData, } From 246108b1a27e2a091504c7912d7f1c1847b45a1d Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Mon, 17 Feb 2025 16:58:17 +0100 Subject: [PATCH 08/11] provide from_point only if `Sec: Clone` --- crypto/bls/src/generic_secret_key.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/crypto/bls/src/generic_secret_key.rs b/crypto/bls/src/generic_secret_key.rs index 79da1f5b8bb..ed190cf86f2 100644 --- a/crypto/bls/src/generic_secret_key.rs +++ b/crypto/bls/src/generic_secret_key.rs @@ -66,16 +66,6 @@ where &self.point } - /// Instantiates `Self` from a `point`. - /// Takes a reference, as moves might accidentally leave behind key material - pub fn from_point(point: &Sec) -> Self { - Self { - point: point.clone(), - _phantom_signature: PhantomData, - _phantom_public_key: PhantomData, - } - } - /// Serialize `self` as compressed bytes. /// /// ## Note @@ -104,3 +94,21 @@ where } } } + +impl GenericSecretKey +where + Sig: TSignature, + Pub: TPublicKey, + Sec: TSecretKey + Clone, +{ + + /// Instantiates `Self` from a `point`. + /// Takes a reference, as moves might accidentally leave behind key material + pub fn from_point(point: &Sec) -> Self { + Self { + point: point.clone(), + _phantom_signature: PhantomData, + _phantom_public_key: PhantomData, + } + } +} From 04205ed1c4443ab12670c37c2e8eb28e51291637 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Mon, 17 Feb 2025 16:59:36 +0100 Subject: [PATCH 09/11] cargo fmt --- crypto/bls/src/generic_secret_key.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/bls/src/generic_secret_key.rs b/crypto/bls/src/generic_secret_key.rs index ed190cf86f2..62bfc1467db 100644 --- a/crypto/bls/src/generic_secret_key.rs +++ b/crypto/bls/src/generic_secret_key.rs @@ -101,7 +101,6 @@ where Pub: TPublicKey, Sec: TSecretKey + Clone, { - /// Instantiates `Self` from a `point`. /// Takes a reference, as moves might accidentally leave behind key material pub fn from_point(point: &Sec) -> Self { From 4ca8823f7a158433f4aad31b65761b91cab8f519 Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Mon, 17 Feb 2025 17:19:56 +0100 Subject: [PATCH 10/11] check for uncompressed infinity signatures --- crypto/bls/src/generic_signature.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crypto/bls/src/generic_signature.rs b/crypto/bls/src/generic_signature.rs index 355f17aef1c..0b375d3edd5 100644 --- a/crypto/bls/src/generic_signature.rs +++ b/crypto/bls/src/generic_signature.rs @@ -25,6 +25,16 @@ pub const INFINITY_SIGNATURE: [u8; SIGNATURE_BYTES_LEN] = [ 0, ]; +pub const INFINITY_SIGNATURE_UNCOMPRESSED: [u8; SIGNATURE_UNCOMPRESSED_BYTES_LEN] = [ + 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, +]; + /// The compressed bytes used to represent `GenericSignature::empty()`. pub const NONE_SIGNATURE: [u8; SIGNATURE_BYTES_LEN] = [0; SIGNATURE_BYTES_LEN]; @@ -148,9 +158,11 @@ where /// Deserialize `self` from uncompressed bytes. pub fn deserialize_uncompressed(bytes: &[u8]) -> Result { + // The "none signature" is a beacon chain concept. As we never directly deal with + // uncompressed signatures on the beacon chain, it does not apply here. Ok(Self { point: Some(Sig::deserialize_uncompressed(bytes)?), - is_infinity: false, // todo + is_infinity: bytes == &INFINITY_SIGNATURE_UNCOMPRESSED[..], _phantom: PhantomData, }) } From ec06b3b53a2f89e96c47a505df422cfdc4a16c0b Mon Sep 17 00:00:00 2001 From: Daniel Knopik Date: Tue, 18 Feb 2025 08:38:15 +0100 Subject: [PATCH 11/11] add test for hardcoded infinity sigs --- crypto/bls/src/lib.rs | 5 ++++- crypto/bls/tests/tests.rs | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crypto/bls/src/lib.rs b/crypto/bls/src/lib.rs index 6ea85548c0d..13b6dc2f2c7 100644 --- a/crypto/bls/src/lib.rs +++ b/crypto/bls/src/lib.rs @@ -37,7 +37,10 @@ pub use generic_public_key::{ INFINITY_PUBLIC_KEY, PUBLIC_KEY_BYTES_LEN, PUBLIC_KEY_UNCOMPRESSED_BYTES_LEN, }; pub use generic_secret_key::SECRET_KEY_BYTES_LEN; -pub use generic_signature::{INFINITY_SIGNATURE, SIGNATURE_BYTES_LEN}; +pub use generic_signature::{ + INFINITY_SIGNATURE, INFINITY_SIGNATURE_UNCOMPRESSED, SIGNATURE_BYTES_LEN, + SIGNATURE_UNCOMPRESSED_BYTES_LEN, +}; pub use get_withdrawal_credentials::get_withdrawal_credentials; pub use zeroize_hash::ZeroizeHash; diff --git a/crypto/bls/tests/tests.rs b/crypto/bls/tests/tests.rs index 26215771b5f..611dabbd648 100644 --- a/crypto/bls/tests/tests.rs +++ b/crypto/bls/tests/tests.rs @@ -1,4 +1,7 @@ -use bls::{FixedBytesExtended, Hash256, INFINITY_SIGNATURE, SECRET_KEY_BYTES_LEN}; +use bls::{ + FixedBytesExtended, Hash256, INFINITY_SIGNATURE, INFINITY_SIGNATURE_UNCOMPRESSED, + SECRET_KEY_BYTES_LEN, +}; use ssz::{Decode, Encode}; use std::borrow::Cow; use std::fmt::Debug; @@ -37,6 +40,18 @@ macro_rules! test_suite { assert!(AggregateSignature::infinity().is_infinity()); } + #[test] + fn infinity_sig_serializations_match() { + let sig = Signature::deserialize(&INFINITY_SIGNATURE).unwrap(); + assert_eq!( + sig.serialize_uncompressed().unwrap(), + INFINITY_SIGNATURE_UNCOMPRESSED + ); + let sig = + Signature::deserialize_uncompressed(&INFINITY_SIGNATURE_UNCOMPRESSED).unwrap(); + assert_eq!(sig.serialize(), INFINITY_SIGNATURE); + } + #[test] fn ssz_round_trip_multiple_types() { let mut agg_sig = AggregateSignature::infinity();