Skip to content

Commit

Permalink
Hash the inner transaction code before placement inside wrapper.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Jan 31, 2023
1 parent 6809564 commit e7f1e42
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 48 deletions.
24 changes: 18 additions & 6 deletions apps/src/lib/client/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub async fn sign_wrapper(
ctx: &Context,
args: &args::Tx,
epoch: Epoch,
tx: Tx,
mut tx: Tx,
keypair: &common::SecretKey,
#[cfg(not(feature = "mainnet"))] requires_pow: bool,
) -> TxBroadcastData {
Expand Down Expand Up @@ -236,6 +236,10 @@ pub async fn sign_wrapper(
None
}
};
// Get transaction code to later attach to a wrapper transaction
let tx_code = tx.code.code();
// Contract the transaction's code field to make transaction smaller
tx.code.contract();
// This object governs how the payload will be processed
let wrapper_tx = {
WrapperTx::new(
Expand All @@ -253,15 +257,23 @@ pub async fn sign_wrapper(
.bind(tx.clone())
};
// Then sign over the bound wrapper
let stx = wrapper_tx
let mut stx = wrapper_tx
.sign(keypair)
.expect("Wrapper tx signing keypair should be correct")
// Then encrypt and attach the payload to the wrapper
.attach_inner_tx(
&tx,
.expect("Wrapper tx signing keypair should be correct");
// If we have the transaction code, then attach it to the wrapper
if let Some(code) = tx_code {
stx = stx.attach_inner_tx_code(
&code,
// TODO: Actually use the fetched encryption key
Default::default(),
);
}
// Then encrypt and attach the payload to the wrapper
stx = stx.attach_inner_tx(
&tx,
// TODO: Actually use the fetched encryption key
Default::default(),
);
// We use this to determine when the wrapper tx makes it on-chain
let wrapper_hash = hash_tx(&wrapper_tx.try_to_vec().unwrap()).to_string();
// We use this to determine when the decrypted inner tx makes it
Expand Down
15 changes: 11 additions & 4 deletions apps/src/lib/node/ledger/shell/prepare_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,17 @@ where
has_valid_pow,
}| {
Tx::from(match inner_tx.clone().and_then(|x| tx.decrypt(privkey, x).ok()) {
Some(tx) => DecryptedTx::Decrypted {
tx,
#[cfg(not(feature = "mainnet"))]
has_valid_pow: *has_valid_pow,
Some(mut inner_tx) => {
if let Some(inner_tx_code) = inner_tx_code {
if let Some(inner_tx_code) = inner_tx.decrypt_code(privkey, inner_tx_code.clone()) {
inner_tx.code.expand(inner_tx_code);
}
}
DecryptedTx::Decrypted {
tx: inner_tx,
#[cfg(not(feature = "mainnet"))]
has_valid_pow: *has_valid_pow,
}
},
_ => DecryptedTx::Undecryptable(tx.clone()),
})
Expand Down
5 changes: 2 additions & 3 deletions apps/src/lib/node/ledger/shell/process_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,12 +497,11 @@ mod test_process_proposal {
None,
).bind(tx.clone());
shell.enqueue_tx(wrapper, Some(encrypted_tx.clone()), None);
let tx = Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
txs.push(Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
tx,
#[cfg(not(feature = "mainnet"))]
has_valid_pow: false,
}));
txs.push(tx);
})));
}
let req_1 = ProcessProposal {
txs: vec![txs[0].to_bytes()],
Expand Down
49 changes: 39 additions & 10 deletions core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ use crate::types::transaction::TxType;
use crate::types::transaction::encrypted::EncryptedTx;
#[cfg(feature = "ferveo-tpke")]
use crate::types::transaction::EncryptionKey;
#[cfg(feature = "ferveo-tpke")]
use crate::types::transaction::EllipticCurve;
#[cfg(feature = "ferveo-tpke")]
use ark_ec::PairingEngine;

#[derive(Error, Debug)]
pub enum Error {
Expand Down Expand Up @@ -196,14 +200,6 @@ pub struct Tx {
pub inner_tx_code: Option<Vec<u8>>,
}

impl Hash for Tx {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.code.hash(state);
self.data.hash(state);
self.timestamp.hash(state);
}
}

impl PartialEq for Tx {
fn eq(&self, other: &Self) -> bool {
self.code.eq(&other.code) &&
Expand Down Expand Up @@ -372,6 +368,28 @@ impl Tx {
}
}

/// Decrypt the wrapped transaction.
///
/// Will fail if the inner transaction does match the
/// hash commitment or we are unable to recover a
/// valid Tx from the decoded byte stream.
#[cfg(feature = "ferveo-tpke")]
pub fn decrypt_code(
&self,
privkey: <EllipticCurve as PairingEngine>::G2Affine,
inner_tx: EncryptedTx,
) -> Option<Vec<u8>> {
// decrypt the inner tx
let decrypted = inner_tx.decrypt(privkey);
// check that the hash equals commitment
if hash_tx(&decrypted).0 != self.code.code_hash() {
None
} else {
// convert back to Tx type
Some(decrypted)
}
}

pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = vec![];
let tx: types::Tx = self.clone().into();
Expand All @@ -384,8 +402,8 @@ impl Tx {
let timestamp = Some(self.timestamp.into());
let mut bytes = vec![];
types::Tx {
code: self.code.code().unwrap_or(self.code.code_hash().to_vec()),
is_literal: self.code.is_literal(),
code: self.code.code_hash().to_vec(),
is_literal: false,
data: self.data.clone(),
timestamp,
inner_tx: None,
Expand Down Expand Up @@ -452,6 +470,17 @@ impl Tx {
self.inner_tx = Some(inner_tx);
self
}

#[cfg(feature = "ferveo-tpke")]
pub fn attach_inner_tx_code(
mut self,
tx: &[u8],
encryption_key: EncryptionKey
) -> Self {
let inner_tx_code = EncryptedTx::encrypt(tx, encryption_key);
self.inner_tx_code = Some(inner_tx_code);
self
}
}

#[allow(dead_code)]
Expand Down
4 changes: 2 additions & 2 deletions core/src/types/transaction/decrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub mod decrypted_tx {

use super::EllipticCurve;
use crate::proto::Tx;
use crate::types::transaction::{hash_tx, Hash, TxType, WrapperTx};
use crate::types::transaction::{Hash, TxType, WrapperTx};
use crate::types::transaction::encrypted::EncryptedTx;

#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema)]
Expand Down Expand Up @@ -64,7 +64,7 @@ pub mod decrypted_tx {
tx,
#[cfg(not(feature = "mainnet"))]
has_valid_pow: _,
} => hash_tx(&tx.to_bytes()),
} => Hash(tx.hash()),
DecryptedTx::Undecryptable(wrapper) => wrapper.tx_hash.clone(),
}
}
Expand Down
13 changes: 7 additions & 6 deletions core/src/types/transaction/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,20 @@ pub mod wrapper_tx {
) -> Result<Tx, WrapperTxErr> {
// decrypt the inner tx
let decrypted = inner_tx.decrypt(privkey);
// convert back to Tx type
let decrypted_tx = Tx::try_from(decrypted.as_ref())
.map_err(|_| WrapperTxErr::InvalidTx)?;
// check that the hash equals commitment
if hash_tx(&decrypted) != self.tx_hash {
if decrypted_tx.hash() != self.tx_hash.0 {
Err(WrapperTxErr::DecryptedHash)
} else {
// convert back to Tx type
Tx::try_from(decrypted.as_ref())
.map_err(|_| WrapperTxErr::InvalidTx)
Ok(decrypted_tx)
}
}

/// Bind the given transaction to this wrapper by recording its hash
pub fn bind(mut self, tx: Tx) -> Self {
self.tx_hash = hash_tx(&tx.to_bytes());
self.tx_hash = Hash(tx.hash());
self
}

Expand Down Expand Up @@ -470,7 +471,7 @@ pub mod wrapper_tx {
);

// We change the commitment appropriately
wrapper.tx_hash = hash_tx(&malicious.to_bytes());
wrapper.tx_hash = Hash(malicious.hash());

// we check ciphertext validity still passes
assert!(WrapperTx::validate_ciphertext(inner_tx.clone()));
Expand Down
34 changes: 17 additions & 17 deletions wasm/checksums.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"tx_bond.wasm": "tx_bond.3fd1ebe744d6dd93cba1689a0616159024f230b72e3cfa41628655735662ccc6.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.dacb181b5443983d68220cde791cc7bfcf72aa85ad726dadae77888a73a61494.wasm",
"tx_ibc.wasm": "tx_ibc.17f4eedae336ca34147630a57b171b8d03aad77617d98c9af066bdee0a1a32f9.wasm",
"tx_init_account.wasm": "tx_init_account.ee26f0264400c8f909d5b761847c84aac9a8ef79e9f6c6e3df69028e81741631.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.aa577cebc4eb5af2fcf5f9ea6a2e70b915cb7c6e96b7341790ad4c23d79703d0.wasm",
"tx_init_validator.wasm": "tx_init_validator.764056876d03dcbadd18ff81ccc97b1fbe83290bc043faa5d290b34ebb9ca2c7.wasm",
"tx_bond.wasm": "tx_bond.0541f0497f7c14690cf49647c6be0324e5bdd44bf27ffb022dcf68a7f6b7827d.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.3ee9010b89ef090ddaaa21e898fc87257801aa49068818971ecbbe880dd210e0.wasm",
"tx_ibc.wasm": "tx_ibc.0daeeb69727f893a2f12d923e77c878eb7877f81774e8443cb2ed29339e7aac1.wasm",
"tx_init_account.wasm": "tx_init_account.495f96fcefbafa49b3aa1d8f80b984eb626f5fbb4db51c444ea48e900217b186.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.7accc0b5de2ef8f24e8c2efc4975d2eee62015b2a905405f79da8563e9c15b15.wasm",
"tx_init_validator.wasm": "tx_init_validator.34739c6f982ed63e9a6884cf0cc0f8e6ddb45cd2a2db0f35280af7c37830510b.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.f6230e04a8500ad3ae6b376d57b521b83ac16449f021f01019671b0a3ba76a8b.wasm",
"tx_transfer.wasm": "tx_transfer.12e9fc0525979db895249b0b42425b2d3bd503d8e1fb4cd84a7ac297517988cd.wasm",
"tx_unbond.wasm": "tx_unbond.9c0b90a0113193e9e044c5834b02a17ab5251cb0d88b219baa737d3121f6596a.wasm",
"tx_update_vp.wasm": "tx_update_vp.28511b213abd8e8c20358671407ba6e0be370253652dc36dc3a194f6e7bbb6a6.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.3f06ef8c94085f5e5ee29f5a2ca69195d245c03fb386cb70c597c6828648f4d5.wasm",
"tx_withdraw.wasm": "tx_withdraw.9364a2e5567e7f7c7b1feae360f0fb4e073bda8be642eede4e6101d2596a3ffe.wasm",
"vp_implicit.wasm": "vp_implicit.9f0ad14db8736862f2a4aaf0e501dc6df19c9ebf5f7ea3efe2f5b009d2736cf1.wasm",
"vp_masp.wasm": "vp_masp.39dd821246008d520f3bbe9bdfadd312e6b3f1d42f9135a339ea29cf86eb3a73.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.602ca75c656d97a63a5fa52250749f7a2f36af038d70027fa9730ccb1ebb5b1c.wasm",
"vp_token.wasm": "vp_token.afc39074d42066a9e7570a13821476edfa9424b651cbbd753d4a186872566739.wasm",
"vp_user.wasm": "vp_user.f2e5060eebee9dc55eabd566a7920dcc0e4ededb03f4d0dbeeba80fc9e558b77.wasm",
"vp_validator.wasm": "vp_validator.cd9d903c32c14aa5d7f96269d6fdcfc025b71676b82614d14194e8c0c8cb1697.wasm"
"tx_transfer.wasm": "tx_transfer.0baa64bdcc2031d70934531e892bb420fe908d2e3dba4cb84277323d35c26a3e.wasm",
"tx_unbond.wasm": "tx_unbond.72195f598ad3bcc82095e4f33df785bc3af1c02dac276cc5b0aaadef9d8c261f.wasm",
"tx_update_vp.wasm": "tx_update_vp.9f11e9e3cfb35396941db3d7d742aa38a9eeb1e042fab0839fcb9805554b0401.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.d944be9d5372c078a9118268e42dd48a43ac0ef4ce401ac6863b88cb647013a3.wasm",
"tx_withdraw.wasm": "tx_withdraw.42cc4c4926f32090964f0fcdf8a86ddfac282947f5710524d6bab2acfd75c147.wasm",
"vp_implicit.wasm": "vp_implicit.81355ce80471010b9db30addedcce27917b06148224f23fdb83e34045480ef27.wasm",
"vp_masp.wasm": "vp_masp.62a3fff9fada661591248738aa1b2cbd22b90fb58a3acb607b5ce8089c363b83.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.d7eee970bfd5704a6d969ca54a7afba0fbaf0695bbc12d97764329b6784cad14.wasm",
"vp_token.wasm": "vp_token.b72e854862166c91aac0528b68c64c28b4262cf4def47a821dc90e6597edf1ec.wasm",
"vp_user.wasm": "vp_user.28bcf125b9a8fddc94279c21bee36b879f2b2822184995d2220d739fe66982b7.wasm",
"vp_validator.wasm": "vp_validator.480fe41dc4d84e1cbb4bced845e6fbb2721e1fdadde24b0fb4a420b376213356.wasm"
}

0 comments on commit e7f1e42

Please sign in to comment.