Skip to content

Commit ba002bb

Browse files
authored
Remove get_public_key method from Signer. (#4088)
## Motivation The `get_public_key` method in the `Signer` API is a blocker for implementing that trait for EVM wallets - like MetaMask - which do not expose the public key to the users. ## Proposal Remove `Signer::get_public_key`. There were few palces where we used `get_public_key()` via `ChainClient` only to map that into `AccountOwner` - these were updated to call `client.identity()` directly instead. The biggest change is in the `BlockProposal` struct, which also carried `AccountPublicKey` used for verifying the signature later on. Here the public keys were "inlined" into the `AccountSignature`: for `Ed25519 and `Secp256k1` cases this meant simply adding the key to those variants: ```rust pub enum AccountSignature { Ed25519 { signature: ed25519::Ed25519Signature, public_key: ed25519::Ed25519PublicKey, }, Secp256k1 { signature: secp256k1::Secp256k1Signature, public_key: secp256k1::Secp256k1PublicKey, }, EvmSecp256k1(secp256k1::evm::EvmSignature) ``` and use the `public_key`s to verify the signatures later. For the EVM case we recover the `AccountOwner` (via recovering EVM address and turning that into `AccountOwner::Address20`) from the signature and the message. ## Test Plan CI ## Release Plan - Nothing to do / These changes follow the usual release cycle. ## Links Closes #4077 - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist)
1 parent c7c08d1 commit ba002bb

File tree

29 files changed

+450
-275
lines changed

29 files changed

+450
-275
lines changed

linera-base/src/crypto/hash.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ impl From<CryptoHash> for [u8; 32] {
141141
}
142142
}
143143

144+
impl From<[u8; 32]> for CryptoHash {
145+
fn from(bytes: [u8; 32]) -> Self {
146+
CryptoHash(B256::from(bytes))
147+
}
148+
}
149+
144150
impl From<[u64; 4]> for CryptoHash {
145151
fn from(integers: [u64; 4]) -> Self {
146152
CryptoHash(crate::crypto::u64_array_to_be_bytes(integers).into())

linera-base/src/crypto/mod.rs

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use serde::{Deserialize, Serialize};
2424
pub use signer::*;
2525
use thiserror::Error;
2626

27+
use crate::{hex_debug, identifiers::AccountOwner};
28+
2729
/// The public key of a validator.
2830
pub type ValidatorPublicKey = secp256k1::Secp256k1PublicKey;
2931
/// The private key of a validator.
@@ -86,11 +88,27 @@ pub enum AccountSecretKey {
8688
#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)]
8789
pub enum AccountSignature {
8890
/// Ed25519 signature.
89-
Ed25519(ed25519::Ed25519Signature),
91+
Ed25519 {
92+
/// Signature of the value.
93+
signature: ed25519::Ed25519Signature,
94+
/// Public key of the signer.
95+
public_key: ed25519::Ed25519PublicKey,
96+
},
9097
/// secp256k1 signature.
91-
Secp256k1(secp256k1::Secp256k1Signature),
98+
Secp256k1 {
99+
/// Signature of the value.
100+
signature: secp256k1::Secp256k1Signature,
101+
/// Public key of the signer.
102+
public_key: secp256k1::Secp256k1PublicKey,
103+
},
92104
/// EVM secp256k1 signature.
93-
EvmSecp256k1(secp256k1::evm::EvmSignature),
105+
EvmSecp256k1 {
106+
/// Signature of the value.
107+
signature: secp256k1::evm::EvmSignature,
108+
/// EVM address of the signer.
109+
#[debug(with = "hex_debug")]
110+
address: [u8; 20],
111+
},
94112
}
95113

96114
impl AccountSecretKey {
@@ -122,15 +140,24 @@ impl AccountSecretKey {
122140
match self {
123141
AccountSecretKey::Ed25519(secret) => {
124142
let signature = Ed25519Signature::new(value, secret);
125-
AccountSignature::Ed25519(signature)
143+
let public_key = secret.public();
144+
AccountSignature::Ed25519 {
145+
signature,
146+
public_key,
147+
}
126148
}
127149
AccountSecretKey::Secp256k1(secret) => {
128150
let signature = secp256k1::Secp256k1Signature::new(value, secret);
129-
AccountSignature::Secp256k1(signature)
151+
let public_key = secret.public();
152+
AccountSignature::Secp256k1 {
153+
signature,
154+
public_key,
155+
}
130156
}
131157
AccountSecretKey::EvmSecp256k1(secret) => {
132158
let signature = secp256k1::evm::EvmSignature::new(CryptoHash::new(value), secret);
133-
AccountSignature::EvmSecp256k1(signature)
159+
let address: [u8; 20] = secret.address().into();
160+
AccountSignature::EvmSecp256k1 { signature, address }
134161
}
135162
}
136163
}
@@ -140,15 +167,24 @@ impl AccountSecretKey {
140167
match self {
141168
AccountSecretKey::Ed25519(secret) => {
142169
let signature = Ed25519Signature::sign_prehash(secret, value);
143-
AccountSignature::Ed25519(signature)
170+
let public_key = secret.public();
171+
AccountSignature::Ed25519 {
172+
signature,
173+
public_key,
174+
}
144175
}
145176
AccountSecretKey::Secp256k1(secret) => {
146177
let signature = secp256k1::Secp256k1Signature::sign_prehash(secret, value);
147-
AccountSignature::Secp256k1(signature)
178+
let public_key = secret.public();
179+
AccountSignature::Secp256k1 {
180+
signature,
181+
public_key,
182+
}
148183
}
149184
AccountSecretKey::EvmSecp256k1(secret) => {
150185
let signature = secp256k1::evm::EvmSignature::sign_prehash(secret, value);
151-
AccountSignature::EvmSecp256k1(signature)
186+
let address: [u8; 20] = secret.address().into();
187+
AccountSignature::EvmSecp256k1 { signature, address }
152188
}
153189
}
154190
}
@@ -197,41 +233,25 @@ impl AccountPublicKey {
197233

198234
impl AccountSignature {
199235
/// Verifies the signature for the `value` using the provided `public_key`.
200-
pub fn verify<'de, T>(&self, value: &T, author: AccountPublicKey) -> Result<(), CryptoError>
236+
pub fn verify<'de, T>(&self, value: &T) -> Result<(), CryptoError>
201237
where
202238
T: BcsSignable<'de> + std::fmt::Debug,
203239
{
204-
match (self, author) {
205-
(AccountSignature::Ed25519(signature), AccountPublicKey::Ed25519(public_key)) => {
206-
signature.check(value, public_key)
207-
}
208-
(AccountSignature::Secp256k1(signature), AccountPublicKey::Secp256k1(public_key)) => {
209-
signature.check(value, &public_key)
210-
}
211-
(
212-
AccountSignature::EvmSecp256k1(signature),
213-
AccountPublicKey::EvmSecp256k1(public_key),
214-
) => signature.check(value, &public_key),
215-
(AccountSignature::Ed25519(_), _) => {
216-
let type_name = std::any::type_name::<T>();
217-
Err(CryptoError::InvalidSignature {
218-
error: "invalid signature scheme. Expected Ed25519 signature.".to_string(),
219-
type_name: type_name.to_string(),
220-
})
221-
}
222-
(AccountSignature::Secp256k1(_), _) => {
223-
let type_name = std::any::type_name::<T>();
224-
Err(CryptoError::InvalidSignature {
225-
error: "invalid signature scheme. Expected secp256k1 signature.".to_string(),
226-
type_name: type_name.to_string(),
227-
})
228-
}
229-
(AccountSignature::EvmSecp256k1(_), _) => {
230-
let type_name = std::any::type_name::<T>();
231-
Err(CryptoError::InvalidSignature {
232-
error: "invalid signature scheme. Expected EvmSecp256k1 signature.".to_string(),
233-
type_name: type_name.to_string(),
234-
})
240+
match self {
241+
AccountSignature::Ed25519 {
242+
signature,
243+
public_key,
244+
} => signature.check(value, *public_key),
245+
AccountSignature::Secp256k1 {
246+
signature,
247+
public_key,
248+
} => signature.check(value, *public_key),
249+
AccountSignature::EvmSecp256k1 {
250+
signature,
251+
address: sender_address,
252+
} => {
253+
signature.check_with_recover(value, *sender_address)?;
254+
Ok(())
235255
}
236256
}
237257
}
@@ -245,6 +265,15 @@ impl AccountSignature {
245265
pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
246266
bcs::from_bytes(bytes).map_err(CryptoError::SignatureParseError)
247267
}
268+
269+
/// Returns the AccountOwner of the account that signed the value.
270+
pub fn owner(&self) -> AccountOwner {
271+
match self {
272+
AccountSignature::Ed25519 { public_key, .. } => AccountOwner::from(*public_key),
273+
AccountSignature::Secp256k1 { public_key, .. } => AccountOwner::from(*public_key),
274+
AccountSignature::EvmSecp256k1 { address, .. } => AccountOwner::Address20(*address),
275+
}
276+
}
248277
}
249278

250279
impl FromStr for AccountPublicKey {
@@ -521,6 +550,7 @@ mod tests {
521550
roundtrip_test(AccountSecretKey::Secp256k1(
522551
Secp256k1KeyPair::generate().secret_key,
523552
));
553+
roundtrip_test(AccountSecretKey::EvmSecp256k1(EvmSecretKey::generate()));
524554
}
525555

526556
#[test]

0 commit comments

Comments
 (0)