Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zeroize txs bench #2932

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions account-keys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ default = ["std", "prost", "serde", "mc-util-serial", "mc-crypto-digestible/defa
curve25519-dalek = { version = "4.0.0-pre.2", default-features = false, features = ["nightly"] }
# External dependencies
displaydoc = { version = "0.2", default-features = false }
hex_fmt = "0.3"
hkdf = "0.12.3"
prost = { version = "0.11", optional = true, default-features = false, features = ["prost-derive"] }
rand_core = { version = "0.6", default-features = false }
serde = { version = "1.0", default-features = false }
subtle = { version = "2", default-features = false }
zeroize = { version = "1", default-features = false }

# MobileCoin dependencies
mc-account-keys-types = { path = "types" }
Expand All @@ -28,10 +34,6 @@ mc-fog-sig-authority = { path = "../fog/sig/authority" }
mc-util-from-random = { path = "../util/from-random" }
mc-util-repr-bytes = { path = "../util/repr-bytes", default-features = false }
mc-util-serial = { path = "../util/serial", optional = true }
prost = { version = "0.11", optional = true, default-features = false, features = ["prost-derive"] }
rand_core = { version = "0.6", default-features = false }
subtle = { version = "2", default-features = false }
zeroize = { version = "1", default-features = false }

[dev-dependencies]
criterion = "0.4"
Expand Down
6 changes: 5 additions & 1 deletion account-keys/src/account_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,18 @@ use mc_util_from_random::FromRandom;
#[cfg(feature = "prost")]
use prost::Message;
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;

pub use mc_core::consts::{
CHANGE_SUBADDRESS_INDEX, DEFAULT_SUBADDRESS_INDEX, GIFT_CODE_SUBADDRESS_INDEX,
INVALID_SUBADDRESS_INDEX,
};

/// A MobileCoin user's public subaddress.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Digestible)]
#[derive(
Clone, Deserialize, Digestible, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Zeroize,
)]
#[cfg_attr(feature = "prost", derive(Message))]
pub struct PublicAddress {
/// The user's public subaddress view key 'C'.
Expand Down
9 changes: 8 additions & 1 deletion account-keys/src/address_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
//! This is used in certain memos, as a compact representation of the address.

use crate::account_keys::PublicAddress;
use hex_fmt::HexFmt;
use mc_crypto_digestible::{Digestible, MerlinTranscript};
use subtle::{Choice, ConstantTimeEq};

/// Represents a "standard" public address hash created using merlin,
/// used in memos as a compact representation of a MobileCoin public address.
/// This hash is collision resistant.
#[derive(Default, Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
#[derive(Clone, Default, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct ShortAddressHash([u8; 16]);

impl From<[u8; 16]> for ShortAddressHash {
Expand Down Expand Up @@ -43,3 +44,9 @@ impl ConstantTimeEq for ShortAddressHash {
self.0.ct_eq(&other.0)
}
}

impl core::fmt::Display for ShortAddressHash {
fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(formatter, "{}", HexFmt(self.0.as_ref()))
}
}
25 changes: 22 additions & 3 deletions api/proto/external.proto
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,30 @@ message UnsignedTx {
/// A "ring" of transaction outputs.
repeated InputRing rings = 2;

/// The amount and blinding factors of each of the outputs we are creating.
repeated OutputSecret output_secrets = 3;

/// The block version that this transaction is valid for.
uint32 block_version = 4;

/// The unblinding data for each of the outputs we are creating.
/// This also contains the output secrets needed for building the signature.
repeated TxOutSummaryUnblindingData tx_out_unblinding_data = 5;
}

message TxOutSummaryUnblindingData {
/// An unmasked amount, corresponding to the MaskedAmount field
/// The block version appears in the TxSummaryUnblindingData.
UnmaskedAmount unmasked_amount = 1;

/// The public address to which this TxOut is addressed.
/// If this output comes from an SCI then we may not know the public
/// address.
PublicAddress address = 2;

/// The tx_private_key generated for this TxOut. This is an entropy source
/// which introduces randomness into the cryptonote stealth addresses
/// (tx_public_key and tx_target_key) of the TxOut.
///
/// If this output comes from an SCI then we may not know this.
RistrettoPrivate tx_private_key = 3;
}

/// A structure that contains all the data required to sign a transaction that
Expand Down
2 changes: 1 addition & 1 deletion api/src/convert/signing_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ mod tests {
.build_unsigned::<DefaultTxOutputsOrdering>()
.unwrap();

let (signing_data, _, _) = unsigned_tx.get_signing_data(&mut rng).unwrap();
let (signing_data, _, _, _) = unsigned_tx.get_signing_data(&mut rng).unwrap();

// Converting mc_transaction_core::ring_ct::SigningData -> external::SigningData
// -> mc_transaction_core::ring_ct::SigningData should be the identity
Expand Down
70 changes: 63 additions & 7 deletions api/src/convert/unsigned_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use crate::{external, ConversionError};
use mc_blockchain_types::BlockVersion;
use mc_transaction_extra::UnsignedTx;
use mc_transaction_extra::{TxOutSummaryUnblindingData, UnmaskedAmount, UnsignedTx};

impl From<&UnsignedTx> for external::UnsignedTx {
fn from(source: &UnsignedTx) -> Self {
Expand All @@ -13,11 +13,11 @@ impl From<&UnsignedTx> for external::UnsignedTx {
unsigned_tx.set_rings(protobuf::RepeatedField::from_vec(
source.rings.iter().map(|input| input.into()).collect(),
));
unsigned_tx.set_output_secrets(protobuf::RepeatedField::from_vec(
unsigned_tx.set_tx_out_unblinding_data(protobuf::RepeatedField::from_vec(
source
.output_secrets
.tx_out_unblinding_data
.iter()
.map(|output| output.into())
.map(Into::into)
.collect(),
));
unsigned_tx.set_block_version(*source.block_version);
Expand All @@ -36,16 +36,72 @@ impl TryFrom<&external::UnsignedTx> for UnsignedTx {
.iter()
.map(|input| input.try_into())
.collect::<Result<_, _>>()?,
output_secrets: source
.get_output_secrets()
tx_out_unblinding_data: source
.tx_out_unblinding_data
.iter()
.map(|output| output.try_into())
.map(|data| data.try_into())
.collect::<Result<_, _>>()?,
block_version: BlockVersion::try_from(source.get_block_version())?,
})
}
}

impl From<&TxOutSummaryUnblindingData> for external::TxOutSummaryUnblindingData {
fn from(src: &TxOutSummaryUnblindingData) -> Self {
let mut data = external::TxOutSummaryUnblindingData::new();
data.set_unmasked_amount((&src.unmasked_amount).into());
if let Some(address) = &src.address {
data.set_address(address.into());
}
if let Some(tx_private_key) = &src.tx_private_key {
data.set_tx_private_key(tx_private_key.into());
}
data
}
}

impl TryFrom<&external::TxOutSummaryUnblindingData> for TxOutSummaryUnblindingData {
type Error = ConversionError;

fn try_from(source: &external::TxOutSummaryUnblindingData) -> Result<Self, Self::Error> {
Ok(TxOutSummaryUnblindingData {
unmasked_amount: source
.unmasked_amount
.as_ref()
.ok_or_else(|| ConversionError::MissingField("unmasked_amount".into()))?
.try_into()?,
address: source.address.as_ref().map(TryInto::try_into).transpose()?,
tx_private_key: source
.tx_private_key
.as_ref()
.map(TryInto::try_into)
.transpose()?,
})
}
}

impl From<&UnmaskedAmount> for external::UnmaskedAmount {
fn from(src: &UnmaskedAmount) -> Self {
let mut data = external::UnmaskedAmount::new();
data.set_value(src.value);
data.set_token_id(src.token_id);
data.set_blinding((&src.blinding).into());
data
}
}

impl TryFrom<&external::UnmaskedAmount> for UnmaskedAmount {
type Error = ConversionError;

fn try_from(source: &external::UnmaskedAmount) -> Result<Self, Self::Error> {
Ok(UnmaskedAmount {
value: source.get_value(),
token_id: source.get_token_id(),
blinding: source.get_blinding().try_into()?,
})
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion consensus/enclave/mock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ impl ConsensusEnclave for ConsensusServiceMockEnclave {
let mut outputs: Vec<TxOut> = Vec::new();
for (tx, _proofs) in transactions_with_proofs {
key_images.extend(tx.key_images().into_iter());
outputs.extend(tx.prefix.outputs.into_iter());
outputs.extend(tx.prefix.outputs.iter().cloned());
}

let minted_tx_outs = get_outputs(
Expand Down
2 changes: 2 additions & 0 deletions consensus/enclave/trusted/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crypto/keys/src/ristretto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ use subtle::{Choice, ConstantTimeEq};
use zeroize::Zeroize;

/// A Ristretto-format private scalar
#[derive(Clone, Copy, Default, Zeroize)]
#[derive(Clone, Copy, Default, Digestible, Zeroize)]
#[digestible(transparent)]
pub struct RistrettoPrivate(pub(crate) Scalar);

impl Eq for RistrettoPrivate {}
Expand Down
3 changes: 2 additions & 1 deletion crypto/ring-signature/src/ring_signature/key_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ use mc_util_repr_bytes::{
derive_core_cmp_from_as_ref, derive_debug_and_display_hex_from_as_ref,
derive_repr_bytes_from_as_ref_and_try_from, typenum::U32, LengthMismatch,
};
use zeroize::Zeroize;

#[cfg(feature = "prost")]
use mc_util_repr_bytes::derive_prost_message_from_repr_bytes;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[derive(Copy, Clone, Default, Digestible)]
#[derive(Clone, Copy, Default, Digestible, Zeroize)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[digestible(transparent)]
/// The "image" of a private key `x`: I = x * Hp(x * G) = x * Hp(P).
Expand Down
4 changes: 2 additions & 2 deletions crypto/ring-signature/src/ring_signature/mlsag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPrivate, RistrettoPubli
use prost::Message;
use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};
use zeroize::Zeroizing;
use zeroize::{Zeroize, Zeroizing};

use crate::{
domain_separators::RING_MLSAG_CHALLENGE_DOMAIN_TAG,
Expand All @@ -34,7 +34,7 @@ pub struct ReducedTxOut {
/// MLSAG for a ring of public keys and amount commitments.
/// Note: Serialize and Deserialize appear to be cruft left over from
/// sdk_json_interface.
#[derive(Clone, Digestible, PartialEq, Eq, Serialize, Deserialize, Message)]
#[derive(Clone, Deserialize, Digestible, Eq, Message, PartialEq, Serialize, Zeroize)]
pub struct RingMLSAG {
/// The initial challenge `c[0]`.
#[prost(message, required, tag = "1")]
Expand Down
2 changes: 2 additions & 0 deletions fog/ingest/enclave/trusted/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions fog/ledger/enclave/trusted/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion fog/sample-paykit/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ mod test_build_transaction_helper {

// Each TxIn should contain a ring of `ring_size` elements. If `ring_size` is
// zero, the ring will have size 1 after the input is included.
for tx_in in tx.prefix.inputs {
for tx_in in tx.prefix.inputs.iter() {
assert_eq!(tx_in.ring.len(), ring_size);
}

Expand Down
2 changes: 2 additions & 0 deletions fog/view/enclave/trusted/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ledger/db/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ pub fn initialize_ledger(
);

let key_images = tx.key_images();
(tx.prefix.outputs, key_images)
(tx.prefix.outputs.clone(), key_images)
}
None => {
// Create an origin block.
Expand Down
4 changes: 2 additions & 2 deletions mobilecoind/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4137,7 +4137,7 @@ mod test {
{
let tx_proposal = TxProposal::try_from(response.get_tx_proposal()).unwrap();
let key_images = tx_proposal.tx.key_images();
let outputs = tx_proposal.tx.prefix.outputs;
let outputs = tx_proposal.tx.prefix.outputs.clone();
add_txos_and_key_images_to_ledger(
&mut ledger_db,
BLOCK_VERSION,
Expand Down Expand Up @@ -5286,7 +5286,7 @@ mod test {

let submitted_tx = opt_submitted_tx.unwrap();
let mut change_subaddress_found = false;
for tx_out in submitted_tx.prefix.outputs {
for tx_out in submitted_tx.prefix.outputs.iter() {
let tx_out_target_key = RistrettoPublic::try_from(&tx_out.target_key).unwrap();
let tx_public_key = RistrettoPublic::try_from(&tx_out.public_key).unwrap();

Expand Down
Loading