Skip to content

Commit c88ef02

Browse files
committed
chore(signer): resolve TODOs
- simplify internals of `EcdsaPublicKey`: no need to store the actual abstract object, just its compressed encoding - we construct it when needed - extract verification logic into a separate trait `Verifier`, not in `SecretKey` - remove some (already) obsolete utility functions from `signature.rs`
1 parent a5450b6 commit c88ef02

File tree

6 files changed

+77
-143
lines changed

6 files changed

+77
-143
lines changed

crates/common/src/commit/request.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ impl fmt::Display for SignedProxyDelegation {
5454
// generalisation) and avoid the is_proxy flag
5555
#[derive(Debug, Clone, Serialize, Deserialize)]
5656
pub struct SignRequest {
57-
// TODO(David): Vec<u8> might not be the most memory inefficient, think about something on the
58-
// stack
5957
pub pubkey: Vec<u8>,
6058
pub is_proxy: bool,
6159
pub object_root: [u8; 32],

crates/common/src/signature.rs

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,35 @@
1-
use alloy::rpc::types::beacon::{constants::BLS_DST_SIG, BlsPublicKey, BlsSignature};
2-
use blst::{
3-
min_pk::{PublicKey, SecretKey as BlsSecretKey, Signature},
4-
BLST_ERROR,
5-
};
1+
use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
62
use ssz_derive::{Decode, Encode};
73
use tree_hash::TreeHash;
84
use tree_hash_derive::TreeHash;
95

106
use crate::{
117
constants::{APPLICATION_BUILDER_DOMAIN, GENESIS_VALIDATORS_ROOT},
128
error::BlstErrorWrapper,
13-
signer::SecretKey,
9+
signer::{SecretKey, Verifier},
1410
types::Chain,
15-
utils::{alloy_pubkey_to_blst, alloy_sig_to_blst},
1611
};
1712

18-
// TODO(David): Think about removing
19-
pub fn verify_signature(
20-
pubkey: &BlsPublicKey,
21-
msg: &[u8],
22-
signature: &BlsSignature,
23-
) -> Result<(), BlstErrorWrapper> {
24-
let pubkey: PublicKey = alloy_pubkey_to_blst(pubkey)?;
25-
let signature: Signature = alloy_sig_to_blst(signature)?;
26-
27-
let res = signature.verify(true, msg, BLS_DST_SIG, &[], &pubkey, true);
28-
if res == BLST_ERROR::BLST_SUCCESS {
29-
Ok(())
30-
} else {
31-
Err(res.into())
13+
pub fn compute_signing_root(object_root: [u8; 32], signing_domain: [u8; 32]) -> [u8; 32] {
14+
#[derive(Default, Debug, Encode, Decode, TreeHash)]
15+
struct SigningData {
16+
object_root: [u8; 32],
17+
signing_domain: [u8; 32],
3218
}
33-
}
34-
35-
pub fn sign_message(secret_key: &BlsSecretKey, msg: &[u8]) -> BlsSignature {
36-
let signature = secret_key.sign(msg, BLS_DST_SIG, &[]).to_bytes();
37-
BlsSignature::from_slice(&signature)
38-
}
3919

40-
#[derive(Default, Debug, Encode, Decode, TreeHash)]
41-
struct SigningData {
42-
object_root: [u8; 32],
43-
signing_domain: [u8; 32],
44-
}
45-
46-
pub fn compute_signing_root(object_root: [u8; 32], signing_domain: [u8; 32]) -> [u8; 32] {
4720
let signing_data = SigningData { object_root, signing_domain };
4821
signing_data.tree_hash_root().0
4922
}
5023

51-
#[derive(Debug, Encode, Decode, TreeHash)]
52-
struct ForkData {
53-
fork_version: [u8; 4],
54-
genesis_validators_root: [u8; 32],
55-
}
56-
5724
#[allow(dead_code)]
5825
fn compute_builder_domain(chain: Chain) -> [u8; 32] {
26+
27+
#[derive(Debug, Encode, Decode, TreeHash)]
28+
struct ForkData {
29+
fork_version: [u8; 4],
30+
genesis_validators_root: [u8; 32],
31+
}
32+
5933
let mut domain = [0u8; 32];
6034
domain[..4].copy_from_slice(&APPLICATION_BUILDER_DOMAIN);
6135

@@ -77,7 +51,7 @@ pub fn verify_signed_builder_message<T: TreeHash>(
7751
let domain = chain.builder_domain();
7852
let signing_root = compute_signing_root(msg.tree_hash_root().0, domain);
7953

80-
verify_signature(pubkey, &signing_root, signature)
54+
pubkey.verify_signature(&signing_root, signature)
8155
}
8256

8357
pub fn sign_builder_message<T: SecretKey>(
@@ -88,7 +62,6 @@ pub fn sign_builder_message<T: SecretKey>(
8862
sign_builder_root(chain, secret_key, msg.tree_hash_root().0)
8963
}
9064

91-
// TODO(David): This utility function seems unnecessary
9265
pub fn sign_builder_root<T: SecretKey>(
9366
chain: Chain,
9467
secret_key: &T,
@@ -97,7 +70,6 @@ pub fn sign_builder_root<T: SecretKey>(
9770
let domain = chain.builder_domain();
9871
let signing_root = compute_signing_root(object_root, domain);
9972
secret_key.sign(&signing_root)
100-
// sign_message(secret_key, &signing_root)
10173
}
10274

10375
#[cfg(test)]

crates/common/src/signer/mod.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{
33
fmt::{self, LowerHex},
44
};
55

6-
use eyre::{Context, Result};
6+
use eyre::Context;
77
use serde::{Deserialize, Serialize};
88
use ssz_derive::{Decode, Encode};
99
use tree_hash::TreeHash;
@@ -17,24 +17,30 @@ pub use signers::{GenericProxySigner, ProxySigner, Signer};
1717
pub type PubKey<T> = <T as SecretKey>::PubKey;
1818

1919
pub trait SecretKey {
20-
type PubKey: AsRef<[u8]> + Clone;
20+
type PubKey: AsRef<[u8]> + Clone + Verifier<Self>;
2121
type Signature: AsRef<[u8]> + Clone;
22-
type VerificationError: Error;
2322

2423
fn new_random() -> Self;
25-
fn new_from_bytes(bytes: &[u8]) -> Result<Self>
24+
fn new_from_bytes(bytes: &[u8]) -> eyre::Result<Self>
2625
where
2726
Self: Sized;
2827
fn pubkey(&self) -> Self::PubKey;
29-
fn sign(&self, msg: &[u8; 32]) -> Self::Signature;
28+
fn sign(&self, msg: &[u8]) -> Self::Signature;
3029
fn sign_msg(&self, msg: &impl TreeHash) -> Self::Signature {
3130
self.sign(&msg.tree_hash_root().0)
3231
}
32+
}
33+
34+
pub trait Verifier<T: SecretKey>
35+
where
36+
T: ?Sized,
37+
{
38+
type VerificationError: Error;
3339

3440
fn verify_signature(
35-
pubkey: &Self::PubKey,
41+
&self,
3642
msg: &[u8],
37-
signature: &Self::Signature,
43+
signature: &T::Signature,
3844
) -> Result<(), Self::VerificationError>;
3945
}
4046

@@ -49,14 +55,13 @@ pub enum GenericPubkey {
4955
impl GenericPubkey {
5056
pub fn verify_signature(&self, msg: &[u8], signature: &[u8]) -> eyre::Result<()> {
5157
match self {
52-
GenericPubkey::Bls(bls_pubkey) => Ok(<BlsSecretKey as SecretKey>::verify_signature(
53-
bls_pubkey,
54-
msg,
55-
signature.try_into().context("Invalid signature length for BLS.")?,
56-
)?),
58+
GenericPubkey::Bls(bls_pubkey) => {
59+
let sig = signature.try_into().context("Invalid signature length for BLS.")?;
60+
Ok(bls_pubkey.verify_signature(msg, &sig)?)
61+
}
5762
GenericPubkey::Ecdsa(ecdsa_pubkey) => {
5863
let sig = signature.try_into().context("Invalid signature for ECDSA.")?;
59-
Ok(<EcdsaSecretKey as SecretKey>::verify_signature(ecdsa_pubkey, msg, &sig)?)
64+
Ok(ecdsa_pubkey.verify_signature(msg, &sig)?)
6065
}
6166
}
6267
}

crates/common/src/signer/schemes/bls.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
1+
use alloy::rpc::types::beacon::{constants::BLS_DST_SIG, BlsPublicKey, BlsSignature};
2+
use blst::BLST_ERROR;
23

34
use crate::{
45
error::BlstErrorWrapper,
5-
signature::{sign_message, verify_signature},
6-
signer::{GenericPubkey, SecretKey},
6+
signer::{GenericPubkey, PubKey, SecretKey, Verifier},
77
utils::blst_pubkey_to_alloy,
88
};
99

@@ -12,7 +12,6 @@ pub type BlsSecretKey = blst::min_pk::SecretKey;
1212
impl SecretKey for BlsSecretKey {
1313
type PubKey = BlsPublicKey;
1414
type Signature = BlsSignature;
15-
type VerificationError = BlstErrorWrapper;
1615

1716
fn new_random() -> Self {
1817
use rand::RngCore;
@@ -36,16 +35,31 @@ impl SecretKey for BlsSecretKey {
3635
blst_pubkey_to_alloy(&self.sk_to_pk())
3736
}
3837

39-
fn sign(&self, msg: &[u8; 32]) -> Self::Signature {
40-
sign_message(self, msg)
38+
fn sign(&self, msg: &[u8]) -> Self::Signature {
39+
let signature = self.sign(msg, BLS_DST_SIG, &[]).to_bytes();
40+
BlsSignature::from_slice(&signature)
4141
}
42+
}
43+
44+
impl Verifier<BlsSecretKey> for PubKey<BlsSecretKey> {
45+
type VerificationError = BlstErrorWrapper;
4246

4347
fn verify_signature(
44-
pubkey: &Self::PubKey,
48+
&self,
4549
msg: &[u8],
46-
signature: &Self::Signature,
50+
signature: &<BlsSecretKey as SecretKey>::Signature,
4751
) -> Result<(), Self::VerificationError> {
48-
verify_signature(pubkey, msg, signature)
52+
use crate::utils::{alloy_pubkey_to_blst, alloy_sig_to_blst};
53+
54+
let pubkey = alloy_pubkey_to_blst(self)?;
55+
let signature = alloy_sig_to_blst(signature)?;
56+
57+
let res = signature.verify(true, msg, BLS_DST_SIG, &[], &pubkey, true);
58+
if res == BLST_ERROR::BLST_SUCCESS {
59+
Ok(())
60+
} else {
61+
Err(res.into())
62+
}
4963
}
5064
}
5165

crates/common/src/signer/schemes/ecdsa.rs

Lines changed: 21 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,26 @@ use std::hash::Hash;
33
use derive_more::derive::Into;
44
use eyre::Result;
55
use generic_array::GenericArray;
6-
use k256::{
7-
ecdsa::{Signature as EcdsaSignatureInner, VerifyingKey as EcdsaPublicKeyInner},
8-
AffinePoint,
9-
};
6+
use k256::ecdsa::{Signature as EcdsaSignatureInner, VerifyingKey as EcdsaPublicKeyInner};
107
use serde::{Deserialize, Serialize};
118
use ssz_types::{typenum::U33, FixedVector};
129
use tree_hash::TreeHash;
1310

14-
use crate::signer::{GenericPubkey, PubKey, SecretKey};
11+
use crate::signer::{GenericPubkey, PubKey, SecretKey, Verifier};
1512

1613
pub type EcdsaSecretKey = k256::ecdsa::SigningKey;
17-
type EcdsaCompressedKey = GenericArray<u8, U33>;
14+
15+
type CompressedPublicKey = GenericArray<u8, U33>;
1816

1917
#[derive(Debug, Clone, Copy, Into, Serialize, Deserialize, PartialEq, Eq)]
20-
#[serde(from = "JSONEcdsaPublicKey")]
2118
pub struct EcdsaPublicKey {
22-
#[serde(skip_serializing)]
23-
inner: EcdsaPublicKeyInner,
24-
encoded: EcdsaCompressedKey,
19+
encoded: CompressedPublicKey,
2520
}
2621

2722
impl EcdsaPublicKey {
2823
/// Size of the public key in bytes. We store the SEC1 encoded affine point
2924
/// compressed, thus 33 bytes.
3025
const SIZE: usize = 33;
31-
32-
pub fn new(inner: EcdsaPublicKeyInner) -> Self {
33-
use elliptic_curve::sec1::ToEncodedPoint;
34-
35-
let affine: &AffinePoint = inner.as_ref();
36-
let encoded: [u8; Self::SIZE] =
37-
affine.to_encoded_point(true).as_bytes().try_into().unwrap();
38-
39-
let encoded = GenericArray::from_array(encoded);
40-
41-
EcdsaPublicKey { inner, encoded }
42-
}
43-
44-
pub fn new_from_bytes(encoded: Vec<u8>) -> Result<Self, k256::ecdsa::Error> {
45-
let inner = EcdsaPublicKeyInner::from_sec1_bytes(&encoded)?;
46-
let encoded = GenericArray::from_array::<{ Self::SIZE }>(encoded.try_into().unwrap());
47-
Ok(Self { inner, encoded })
48-
}
49-
50-
fn new_from_bytes_infallible(encoded: [u8; Self::SIZE]) -> Self {
51-
Self {
52-
inner: EcdsaPublicKeyInner::from_sec1_bytes(&encoded).unwrap(),
53-
encoded: GenericArray::from_array(encoded),
54-
}
55-
}
5626
}
5727

5828
impl Hash for EcdsaPublicKey {
@@ -131,38 +101,21 @@ impl ssz::Decode for EcdsaPublicKey {
131101
let mut fixed_array = [0_u8; Self::SIZE];
132102
fixed_array.copy_from_slice(bytes);
133103

134-
Ok(EcdsaPublicKey::new_from_bytes_infallible(fixed_array))
104+
Ok(EcdsaPublicKey { encoded: fixed_array.into() })
135105
}
136106
}
137107

138-
impl TryFrom<Vec<u8>> for EcdsaPublicKey {
139-
type Error = k256::ecdsa::Error;
140-
141-
fn try_from(value: Vec<u8>) -> std::result::Result<Self, Self::Error> {
142-
Self::new_from_bytes(value)
143-
}
144-
}
145-
146-
impl From<EcdsaCompressedKey> for EcdsaPublicKey {
147-
fn from(value: EcdsaCompressedKey) -> Self {
148-
Self::new_from_bytes_infallible(value.into())
149-
}
150-
}
151-
152-
#[derive(Deserialize)]
153-
struct JSONEcdsaPublicKey {
154-
encoded: EcdsaCompressedKey,
155-
}
156-
157-
impl From<JSONEcdsaPublicKey> for EcdsaPublicKey {
158-
fn from(value: JSONEcdsaPublicKey) -> Self {
159-
Self::from(value.encoded)
108+
impl From<CompressedPublicKey> for EcdsaPublicKey {
109+
fn from(value: CompressedPublicKey) -> Self {
110+
Self { encoded: value }
160111
}
161112
}
162113

163114
impl From<EcdsaPublicKeyInner> for EcdsaPublicKey {
164115
fn from(value: EcdsaPublicKeyInner) -> Self {
165-
EcdsaPublicKey::new(value)
116+
let encoded: [u8; Self::SIZE] = value.to_encoded_point(true).as_bytes().try_into().unwrap();
117+
118+
EcdsaPublicKey { encoded: encoded.into() }
166119
}
167120
}
168121

@@ -210,8 +163,6 @@ impl SecretKey for EcdsaSecretKey {
210163

211164
type Signature = EcdsaSignature;
212165

213-
type VerificationError = k256::ecdsa::Error;
214-
215166
fn new_random() -> Self {
216167
EcdsaSecretKey::random(&mut rand::thread_rng())
217168
}
@@ -227,17 +178,22 @@ impl SecretKey for EcdsaSecretKey {
227178
EcdsaPublicKeyInner::from(self).into()
228179
}
229180

230-
fn sign(&self, msg: &[u8; 32]) -> Self::Signature {
181+
fn sign(&self, msg: &[u8]) -> Self::Signature {
231182
k256::ecdsa::signature::Signer::<EcdsaSignatureInner>::sign(self, msg).into()
232183
}
184+
}
185+
186+
impl Verifier<EcdsaSecretKey> for PubKey<EcdsaSecretKey> {
187+
type VerificationError = k256::ecdsa::Error;
233188

234189
fn verify_signature(
235-
pubkey: &Self::PubKey,
190+
&self,
236191
msg: &[u8],
237-
signature: &Self::Signature,
192+
signature: &<EcdsaSecretKey as SecretKey>::Signature,
238193
) -> Result<(), Self::VerificationError> {
239194
use k256::ecdsa::signature::Verifier;
240-
pubkey.inner.verify(msg, &signature.inner)
195+
let ecdsa_pubkey = EcdsaPublicKeyInner::from_sec1_bytes(&self.encoded)?;
196+
ecdsa_pubkey.verify(msg, &signature.inner)
241197
}
242198
}
243199

crates/common/src/signer/signers.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,6 @@ impl<T: SecretKey> Signer<T> {
3838
pub async fn sign_msg(&self, chain: Chain, msg: &impl TreeHash) -> T::Signature {
3939
self.sign(chain, msg.tree_hash_root().0).await
4040
}
41-
42-
// TODO(David):
43-
// This doesn't need to be here. A separate `Verifier` might make sense.
44-
// Left here for now (for convenience).
45-
pub async fn verify_signature(
46-
pubkey: &T::PubKey,
47-
msg: &[u8],
48-
signature: &T::Signature,
49-
) -> Result<(), T::VerificationError> {
50-
T::verify_signature(pubkey, msg, signature)
51-
}
5241
}
5342

5443
// For extra safety and to avoid risking signing malicious messages, use a proxy

0 commit comments

Comments
 (0)