Skip to content

Commit

Permalink
Merge remote-tracking branch 'namada/murisi/smaller-signing' (#807) i…
Browse files Browse the repository at this point in the history
…nto main

* namada/murisi/smaller-signing:
  proto/types: remove an & to placate 1.65 clippy
  changelog: add #807
  tx: sign hash of code rather than full code blob
  • Loading branch information
juped committed Nov 30, 2022
2 parents 8530a2e + d8c5e44 commit 4f79b7a
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/improvements/807-smaller-signing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Sign over the hash of code rather than code in transaction signing.
([#807](https://github.com/anoma/namada/pull/807))
129 changes: 102 additions & 27 deletions shared/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,100 @@ where
}
}

/// A Tx with its code replaced by a hash salted with the Borsh
/// serialized timestamp of the transaction. This structure will almost
/// certainly be smaller than a Tx, yet in the usual cases it contains
/// enough information to confirm that the Tx is as intended and make a
/// non-malleable signature.
#[derive(
Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema, Hash,
)]
pub struct SigningTx {
pub code_hash: [u8; 32],
pub data: Option<Vec<u8>>,
pub timestamp: DateTimeUtc,
}

impl SigningTx {
pub fn hash(&self) -> [u8; 32] {
let timestamp = Some(self.timestamp.into());
let mut bytes = vec![];
types::Tx {
code: self.code_hash.to_vec(),
data: self.data.clone(),
timestamp,
}
.encode(&mut bytes)
.expect("encoding a transaction failed");
hash_tx(&bytes).0
}

/// Sign a transaction using [`SignedTxData`].
pub fn sign(self, keypair: &common::SecretKey) -> Self {
let to_sign = self.hash();
let sig = common::SigScheme::sign(keypair, to_sign);
let signed = SignedTxData {
data: self.data,
sig,
}
.try_to_vec()
.expect("Encoding transaction data shouldn't fail");
SigningTx {
code_hash: self.code_hash,
data: Some(signed),
timestamp: self.timestamp,
}
}

/// Verify that the transaction has been signed by the secret key
/// counterpart of the given public key.
pub fn verify_sig(
&self,
pk: &common::PublicKey,
sig: &common::Signature,
) -> std::result::Result<(), VerifySigError> {
// Try to get the transaction data from decoded `SignedTxData`
let tx_data = self.data.clone().ok_or(VerifySigError::MissingData)?;
let signed_tx_data = SignedTxData::try_from_slice(&tx_data[..])
.expect("Decoding transaction data shouldn't fail");
let data = signed_tx_data.data;
let tx = SigningTx {
code_hash: self.code_hash,
data,
timestamp: self.timestamp,
};
let signed_data = tx.hash();
common::SigScheme::verify_signature_raw(pk, &signed_data, sig)
}

/// Expand this reduced Tx using the supplied code only if the the code
/// hashes to the stored code hash
pub fn expand(self, code: Vec<u8>) -> Option<Tx> {
if hash_tx(&code).0 == self.code_hash {
Some(Tx {
code,
data: self.data,
timestamp: self.timestamp,
})
} else {
None
}
}
}

impl From<Tx> for SigningTx {
fn from(tx: Tx) -> SigningTx {
SigningTx {
code_hash: hash_tx(&tx.code).0,
data: tx.data,
timestamp: tx.timestamp,
}
}
}

/// A SigningTx but with the full code embedded. This structure will almost
/// certainly be bigger than SigningTxs and contains enough information to
/// execute the transaction.
#[derive(
Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema, Hash,
)]
Expand Down Expand Up @@ -261,28 +355,20 @@ impl Tx {
}

pub fn hash(&self) -> [u8; 32] {
hash_tx(&self.to_bytes()).0
SigningTx::from(self.clone()).hash()
}

pub fn code_hash(&self) -> [u8; 32] {
hash_tx(&self.code).0
SigningTx::from(self.clone()).code_hash
}

/// Sign a transaction using [`SignedTxData`].
pub fn sign(self, keypair: &common::SecretKey) -> Self {
let to_sign = self.hash();
let sig = common::SigScheme::sign(keypair, to_sign);
let signed = SignedTxData {
data: self.data,
sig,
}
.try_to_vec()
.expect("Encoding transaction data shouldn't fail");
Tx {
code: self.code,
data: Some(signed),
timestamp: self.timestamp,
}
let code = self.code.clone();
SigningTx::from(self)
.sign(keypair)
.expand(code)
.expect("code hashes to unexpected value")
}

/// Verify that the transaction has been signed by the secret key
Expand All @@ -292,18 +378,7 @@ impl Tx {
pk: &common::PublicKey,
sig: &common::Signature,
) -> std::result::Result<(), VerifySigError> {
// Try to get the transaction data from decoded `SignedTxData`
let tx_data = self.data.clone().ok_or(VerifySigError::MissingData)?;
let signed_tx_data = SignedTxData::try_from_slice(&tx_data[..])
.expect("Decoding transaction data shouldn't fail");
let data = signed_tx_data.data;
let tx = Tx {
code: self.code.clone(),
data,
timestamp: self.timestamp,
};
let signed_data = tx.hash();
common::SigScheme::verify_signature_raw(pk, &signed_data, sig)
SigningTx::from(self.clone()).verify_sig(pk, sig)
}
}

Expand Down
36 changes: 18 additions & 18 deletions wasm/checksums.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"tx_bond.wasm": "tx_bond.27f2a447889b931c9ac5e175fbc19f124277cd677d83e1624a5467ac43f3551f.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.df16d46f67c5fe02392f87cf3dbfabb728f4be506fb2461af051e2a17efff383.wasm",
"tx_ibc.wasm": "tx_ibc.494dda55184d02f1d0061e99f642683b916d6eada6ade291e3be26d0c1385be9.wasm",
"tx_init_account.wasm": "tx_init_account.67805cd6d6b9280d1b907d7a2eec3f3b740c9863aebf4ed655b387c455f44922.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.1011afeb69c550014b4f8f989458af326258fc08b4ddb60067b7485b07eb2a55.wasm",
"tx_init_validator.wasm": "tx_init_validator.0df6c8985b40993b3ad62b2cde6a76aecaeb6282b6916a0c98e44deac38c5089.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.c5d4ddb9a9ce2b5e1f2c3c063e36549a535d383a73e569476c218548392d5ccc.wasm",
"tx_transfer.wasm": "tx_transfer.52f882ed5abe72b456e490e035a09ad220141fc04dd8606e3300c7bc4971aea6.wasm",
"tx_unbond.wasm": "tx_unbond.6b1d54cf6978b55e2318deb1a2a37fd77d810dbabefc0a7422ca21c0ac3f6a61.wasm",
"tx_update_vp.wasm": "tx_update_vp.98cea95bd9191b65d90188c733514843333ae1c653c03c2a317fc641116ff01f.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.d5da43dbe86aaa10ddd509cd451a762c52803af3e196b08cced3cee16feb63a7.wasm",
"tx_withdraw.wasm": "tx_withdraw.b6a713a643f6e5b7a4a8263881c4df7d50656990111ccd02e6596ca5575dbe8b.wasm",
"vp_implicit.wasm": "vp_implicit.5cfa9136bd218e9dcc44276265454a3dcebe81d0a11f2a090d354e3463098481.wasm",
"vp_masp.wasm": "vp_masp.00b2bfeb805847bc5f825b8ec632b6eae77cd64a9c5553b87599ba0756489fa4.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.d4f1f3f54348630ee8d805ac44e6799da193f3a1353728fcafe7634cfc3ca0e4.wasm",
"vp_token.wasm": "vp_token.3f887a991f03a6c447a88307d8e04c569162e126e6016740dd884724bc7b3969.wasm",
"vp_user.wasm": "vp_user.2f63cc6f131760edd0975d41c081288921e76d82883699bbfcc8005980c98aca.wasm",
"vp_validator.wasm": "vp_validator.32701a8c9c331a3814e72bcd406b7ae9de3f250e820ac729145841e2ff802123.wasm"
"tx_bond.wasm": "tx_bond.fabf8f0daea4602ef589c993f14c0cc613be6d1fab64ee7bfeab2952d055bc17.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.4a94b6517d06760c242b3f5f0d8be667c98a1271791f6480f53866b33176288e.wasm",
"tx_ibc.wasm": "tx_ibc.6d7783aa7610ed592cd7d38ebdc3a08ca0e1dac06114db739d150fd2db479a74.wasm",
"tx_init_account.wasm": "tx_init_account.e6a6999f85b08bec4fdad74e2cefb11a02c3a3ccfa22ac91c2bab675ebce78af.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.57e8dbd77c0ed7126fe6a30c69b0776086f9500eddc6115f577bef33debfb2ae.wasm",
"tx_init_validator.wasm": "tx_init_validator.0c17686f4f5cb7914a917b93089c33415da261a9920458c3f527228b3cc7c0c5.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.570e652620f16a5a3c77964cbe622dcf53235ff5954e4180530d3884421bda7d.wasm",
"tx_transfer.wasm": "tx_transfer.6db1b211f4896c914b55b01ee65cebcd982323729909e8567964bb862c2ccd0f.wasm",
"tx_unbond.wasm": "tx_unbond.3c1b61ca80181202dae3f64c007f3013232c2e415ab18e12138598a94ce4d6a0.wasm",
"tx_update_vp.wasm": "tx_update_vp.1c9559a300f2ebe16189467775c3c8fddd69c22a3a3ef6a09e658b5e769b3c03.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.95cb4c6d8de9e46bbbf9c0176161047bb3c0e810d691ba06e28774dbdceaae70.wasm",
"tx_withdraw.wasm": "tx_withdraw.e7fc0142c2c02fff4524e502e2cc136e0691da3ff755b5e5c256ac09757da4ed.wasm",
"vp_implicit.wasm": "vp_implicit.ed1630c4850beff44553e79836acc14a2286e4255778f050c665f901881423fc.wasm",
"vp_masp.wasm": "vp_masp.3efc9e4795526a64a8b1c8a4de6470d6ac57dbaa40ef71f3bfe8107c4e7d6016.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.94c8c0c0dba91aae890fa26e6b015b51c9ab8c1c44e01bb265438515a25ddbf8.wasm",
"vp_token.wasm": "vp_token.f4fc838a3007eacfecbf990992d0956c7ef5896b8a27bf54fd7283b26ab0fcc6.wasm",
"vp_user.wasm": "vp_user.7cc6e40deed64d39ed8b47a9ce067b3db6cf3d81d8f8003df75837b7554a1e4d.wasm",
"vp_validator.wasm": "vp_validator.34ffeca7c3e65782443ca6e0e18e06291cd537a888bf6fe70d50eb8121e66c4a.wasm"
}

0 comments on commit 4f79b7a

Please sign in to comment.