Skip to content

Commit 6714f3a

Browse files
authored
Merge pull request #4994 from namada-net/grarco/pubkeys-for-mock-sigs
Public keys when mocking signatures
2 parents bb6d2c5 + 1e103ce commit 6714f3a

File tree

12 files changed

+189
-199
lines changed

12 files changed

+189
-199
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Changed the SDK signing functions to accept a public key instead of a
2+
private one when mocking a signature. ([\#4994](https://github.com/namada-
3+
net/namada/pull/4994))

crates/account/src/auth.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
66
use namada_core::collections::HashMap;
77
use namada_core::hints;
88
use namada_core::key::common;
9+
use namada_core::key::common::SigOrPubKey;
910
use namada_macros::BorshDeserializer;
1011
#[cfg(feature = "migrations")]
1112
use namada_migrations::*;
@@ -77,16 +78,15 @@ impl AccountPublicKeysMap {
7778
self.pk_to_idx.get(public_key).cloned()
7879
}
7980

80-
/// Index the given set of secret keys
81-
pub fn index_secret_keys(
82-
&self,
83-
secret_keys: Vec<common::SecretKey>,
84-
) -> BTreeMap<u8, common::SecretKey> {
85-
secret_keys
86-
.into_iter()
87-
.filter_map(|secret_key: common::SecretKey| {
88-
self.get_index_from_public_key(&secret_key.to_public())
89-
.map(|index| (index, secret_key))
81+
/// Index the given set of keys
82+
pub fn index_keys<KEY>(&self, keys: Vec<KEY>) -> BTreeMap<u8, KEY>
83+
where
84+
KEY: SigOrPubKey,
85+
{
86+
keys.into_iter()
87+
.filter_map(|key| {
88+
self.get_index_from_public_key(&key.pubkey())
89+
.map(|index| (index, key))
9090
})
9191
.collect()
9292
}

crates/benches/host_env.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn tx_section_signature_validation(c: &mut Criterion) {
4141

4242
let multisig = Authorization::new(
4343
vec![section_hash],
44-
pkim.index_secret_keys(vec![defaults::albert_keypair()]),
44+
pkim.index_keys(vec![defaults::albert_keypair()]),
4545
None,
4646
);
4747

crates/core/src/key/common.rs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -517,18 +517,68 @@ impl super::SigScheme for SigScheme {
517517
}
518518
}
519519

520-
fn mock(keypair: &SecretKey) -> Self::Signature {
521-
match keypair {
522-
SecretKey::Ed25519(kp) => {
523-
Signature::Ed25519(ed25519::SigScheme::mock(kp))
520+
fn mock(pubkey: &Self::PublicKey) -> Self::Signature {
521+
match pubkey {
522+
PublicKey::Ed25519(pk) => {
523+
Signature::Ed25519(ed25519::SigScheme::mock(pk))
524524
}
525-
SecretKey::Secp256k1(kp) => {
526-
Signature::Secp256k1(secp256k1::SigScheme::mock(kp))
525+
PublicKey::Secp256k1(pk) => {
526+
Signature::Secp256k1(secp256k1::SigScheme::mock(pk))
527527
}
528528
}
529529
}
530530
}
531531

532+
/// Share behavior for both private and public keys. Useful to dispatch function
533+
/// calls when mocking signatures
534+
pub trait SigOrPubKey {
535+
/// Get the public key
536+
fn pubkey(&self) -> PublicKey;
537+
538+
/// Get the private key if possible ([`None`] if the underlying type is a
539+
/// public key)
540+
fn sigkey(&self) -> Option<SecretKey>;
541+
542+
/// Produce a signature (either a valid or a mock one)
543+
fn sign(
544+
&self,
545+
data: impl SignableBytes,
546+
) -> <SigScheme as super::SigScheme>::Signature;
547+
}
548+
549+
impl SigOrPubKey for SecretKey {
550+
fn pubkey(&self) -> PublicKey {
551+
self.ref_to()
552+
}
553+
554+
fn sigkey(&self) -> Option<SecretKey> {
555+
Some(self.to_owned())
556+
}
557+
558+
fn sign(
559+
&self,
560+
data: impl SignableBytes,
561+
) -> <SigScheme as super::SigScheme>::Signature {
562+
SigScheme::sign(self, data)
563+
}
564+
}
565+
impl SigOrPubKey for PublicKey {
566+
fn pubkey(&self) -> PublicKey {
567+
self.to_owned()
568+
}
569+
570+
fn sigkey(&self) -> Option<SecretKey> {
571+
None
572+
}
573+
574+
fn sign(
575+
&self,
576+
_: impl SignableBytes,
577+
) -> <SigScheme as super::SigScheme>::Signature {
578+
SigScheme::mock(self)
579+
}
580+
}
581+
532582
#[cfg(test)]
533583
mod tests {
534584
use super::*;

crates/core/src/key/ed25519.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ impl super::SigScheme for SigScheme {
403403
}
404404
}
405405

406-
fn mock(_: &Self::SecretKey) -> Self::Signature {
406+
fn mock(_: &Self::PublicKey) -> Self::Signature {
407407
Signature(ed25519_consensus::Signature::from([0; 64]))
408408
}
409409
}

crates/core/src/key/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ pub trait SigScheme: Eq + Ord + Debug + Serialize + Default {
270270
}
271271

272272
/// Provide a dummy signature
273-
fn mock(keypair: &Self::SecretKey) -> Self::Signature;
273+
fn mock(pubkey: &Self::PublicKey) -> Self::Signature;
274274
}
275275

276276
/// Public key hash derived from `common::Key` borsh encoded bytes (hex string

crates/core/src/key/secp256k1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ impl super::SigScheme for SigScheme {
603603
}
604604
}
605605

606-
fn mock(_: &Self::SecretKey) -> Self::Signature {
606+
fn mock(_: &Self::PublicKey) -> Self::Signature {
607607
Signature(
608608
k256::ecdsa::Signature::from_scalars(
609609
k256::Scalar::ONE,

crates/sdk/src/signing.rs

Lines changed: 56 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use namada_core::address::{Address, ImplicitAddress, MASP};
1717
use namada_core::arith::checked;
1818
use namada_core::collections::{HashMap, HashSet};
1919
use namada_core::ibc::primitives::IntoHostTime;
20-
use namada_core::key::common::{CommonPublicKey, CommonSignature};
2120
use namada_core::key::*;
2221
use namada_core::masp::{AssetData, MaspTxId, PaymentAddress};
2322
use namada_core::tendermint::Time as TmTime;
@@ -38,9 +37,7 @@ use namada_token::storage_key::balance_key;
3837
use namada_tx::data::pgf::UpdateStewardCommission;
3938
use namada_tx::data::pos;
4039
use namada_tx::data::pos::BecomeValidator;
41-
use namada_tx::{
42-
Authorization, MaspBuilder, Section, SignatureIndex, Signer, Tx,
43-
};
40+
use namada_tx::{Authorization, MaspBuilder, Section, SignatureIndex, Tx};
4441
use rand::rngs::OsRng;
4542
use serde::{Deserialize, Serialize};
4643
use tokio::sync::RwLock;
@@ -277,42 +274,6 @@ pub async fn default_sign(
277274
)))
278275
}
279276

280-
/// When mocking signatures, if a key is in a hardware wallet,
281-
/// use this function instead to mock the signature
282-
fn mock_hw_sig(tx: &mut Tx, pk: common::PublicKey, signable: Signable) {
283-
let targets = match signable {
284-
Signable::FeeRawHeader => {
285-
vec![tx.sechashes(), vec![tx.raw_header_hash()]]
286-
}
287-
Signable::RawHeader => vec![vec![tx.raw_header_hash()]],
288-
};
289-
tx.protocol_filter();
290-
let sig = match pk {
291-
CommonPublicKey::Ed25519(_) => {
292-
// this key has no effect other than to satisfy api constraints
293-
let kp = ed25519::SigScheme::from_bytes([0; 32]);
294-
CommonSignature::Ed25519(ed25519::SigScheme::mock(&kp))
295-
}
296-
CommonPublicKey::Secp256k1(_) => {
297-
// this key has no effect other than to satisfy api constraints
298-
const SECRET_KEY_HEX: &str = "c2c72dfbff11dfb4e9d5b0a20c620c58b15bb7552753601f043db91331b0db15";
299-
let sk_bytes = HEXLOWER.decode(SECRET_KEY_HEX.as_bytes()).unwrap();
300-
let kp =
301-
secp256k1::SecretKey::try_from_slice(&sk_bytes[..]).unwrap();
302-
CommonSignature::Secp256k1(secp256k1::SigScheme::mock(&kp))
303-
}
304-
};
305-
for t in targets {
306-
let mut signatures = BTreeMap::new();
307-
signatures.insert(0, sig.clone());
308-
tx.add_section(Section::Authorization(Authorization {
309-
targets: t,
310-
signer: Signer::PubKeys(vec![pk.clone()]),
311-
signatures,
312-
}));
313-
}
314-
}
315-
316277
/// Sign a transaction with a given signing key or public key of a given signer.
317278
/// If no explicit signer given, use the `default`. If no `default` is given,
318279
/// Error.
@@ -361,40 +322,55 @@ where
361322
signing_tx_data.account_public_keys_map
362323
{
363324
let mut wallet = wallet.write().await;
364-
let mut signing_tx_keypairs = vec![];
365-
366-
for public_key in &signing_tx_data.public_keys {
367-
if !used_pubkeys.contains(public_key) {
368-
let Ok(secret_key) =
369-
find_key_by_pk(&mut wallet, args, public_key)
370-
else {
371-
// If the secret key is not found, continue because the
372-
// hardware wallet may still be able to sign this
373-
continue;
374-
};
375-
used_pubkeys.insert(public_key.clone());
376-
signing_tx_keypairs.push(secret_key);
325+
326+
if args.dry_run.is_some() {
327+
// For dry-runs produce mock signatures
328+
let mut signing_tx_pubkeys = vec![];
329+
330+
for public_key in &signing_tx_data.public_keys {
331+
if !used_pubkeys.contains(public_key) {
332+
used_pubkeys.insert(public_key.clone());
333+
signing_tx_pubkeys.push(public_key.to_owned());
334+
}
377335
}
378-
}
379336

380-
if !signing_tx_keypairs.is_empty() {
381-
if args.dry_run.is_some() {
337+
if !signing_tx_pubkeys.is_empty() {
382338
tx.mock(
383-
signing_tx_keypairs,
339+
signing_tx_pubkeys,
384340
account_public_keys_map,
385341
signing_tx_data.owner,
386-
)
387-
} else {
342+
);
343+
}
344+
} else {
345+
let mut signing_tx_keypairs = vec![];
346+
347+
for public_key in &signing_tx_data.public_keys {
348+
if !used_pubkeys.contains(public_key) {
349+
let Ok(secret_key) =
350+
find_key_by_pk(&mut wallet, args, public_key)
351+
else {
352+
// If the secret key is not found, continue because
353+
// the hardware wallet
354+
// may still be able to sign this
355+
continue;
356+
};
357+
used_pubkeys.insert(public_key.clone());
358+
signing_tx_keypairs.push(secret_key);
359+
}
360+
}
361+
362+
if !signing_tx_keypairs.is_empty() {
388363
tx.sign_raw(
389364
signing_tx_keypairs,
390365
account_public_keys_map,
391366
signing_tx_data.owner,
392-
)
393-
};
367+
);
368+
}
394369
}
395370
}
396371

397-
// Then try to sign the raw header using the hardware wallet
372+
// Then try to sign the raw header using the hardware wallet (only if
373+
// this is not a dry-run requiring mock signatures)
398374
for pubkey in &signing_tx_data.public_keys {
399375
if !used_pubkeys.contains(pubkey) {
400376
match &fee_auth {
@@ -407,14 +383,10 @@ where
407383
used_pubkeys.insert(pubkey.clone());
408384
}
409385
_ => {
410-
if args.dry_run.is_some() {
411-
mock_hw_sig(
412-
tx,
413-
pubkey.clone(),
414-
Signable::RawHeader,
415-
);
416-
used_pubkeys.insert(pubkey.clone());
417-
} else if let Ok(ntx) = sign(
386+
// No need to account for mock signatures when dealing
387+
// with the hardware wallet as those are produced fully
388+
// in software here above
389+
if let Ok(ntx) = sign(
418390
tx.clone(),
419391
pubkey.clone(),
420392
Signable::RawHeader,
@@ -456,25 +428,22 @@ where
456428
pubkey,
457429
disposable_fee_payer: _,
458430
}) => {
459-
let key = {
460-
// Lock the wallet just long enough to extract a key from it
461-
// without interfering with the sign closure
462-
// call
463-
let mut wallet = wallet.write().await;
464-
find_key_by_pk(&mut *wallet, args, pubkey)
465-
};
466-
match key {
467-
Ok(fee_payer_keypair) => {
468-
if args.dry_run.is_some() {
469-
tx.mock_sign_wrapper(fee_payer_keypair);
470-
} else {
431+
if args.dry_run.is_some() {
432+
tx.mock_sign_wrapper(pubkey.to_owned());
433+
} else {
434+
let key = {
435+
// Lock the wallet just long enough to extract a key from it
436+
// without interfering with the sign closure
437+
// call
438+
let mut wallet = wallet.write().await;
439+
find_key_by_pk(&mut *wallet, args, pubkey)
440+
};
441+
442+
match key {
443+
Ok(fee_payer_keypair) => {
471444
tx.sign_wrapper(fee_payer_keypair);
472445
}
473-
}
474-
Err(_) => {
475-
if args.dry_run.is_some() {
476-
mock_hw_sig(tx, pubkey.clone(), Signable::FeeRawHeader);
477-
} else {
446+
Err(_) => {
478447
*tx = sign(
479448
tx.clone(),
480449
pubkey.clone(),

0 commit comments

Comments
 (0)