Skip to content

Commit

Permalink
allow transactions with "mixed" token types
Browse files Browse the repository at this point in the history
these are introduced at block version 3

the token type of every pseudo output and real output must be
listed in `pseudo_output_token_ids` and `output_token_ids` in the
`SignatureRctBulletproofs` object
  • Loading branch information
cbeck88 committed Apr 20, 2022
1 parent 63366fb commit 7e82974
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 89 deletions.
9 changes: 6 additions & 3 deletions api/proto/external.proto
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ message TxPrefix {
// The block index at which this transaction is no longer valid.
uint64 tombstone_block = 4;

// Token id for this transaction
fixed64 token_id = 5;
// Token id for the fee of this transaction
fixed64 fee_token_id = 5;
}

message RingMLSAG {
Expand All @@ -255,7 +255,10 @@ message RingMLSAG {
message SignatureRctBulletproofs {
repeated RingMLSAG ring_signatures = 1;
repeated CompressedRistretto pseudo_output_commitments = 2;
bytes range_proofs = 3;
bytes range_proof_bytes = 3;
repeated bytes range_proofs = 4;
repeated fixed64 pseudo_output_token_ids = 5;
repeated fixed64 output_token_ids = 6;
}

message Tx {
Expand Down
14 changes: 12 additions & 2 deletions api/src/convert/signature_rct_bulletproofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use mc_transaction_core::{
ring_signature::{RingMLSAG, SignatureRctBulletproofs},
CompressedCommitment,
};
use protobuf::RepeatedField;
use std::convert::TryFrom;

impl From<&SignatureRctBulletproofs> for external::SignatureRctBulletproofs {
Expand All @@ -25,7 +26,10 @@ impl From<&SignatureRctBulletproofs> for external::SignatureRctBulletproofs {
.collect();
signature.set_pseudo_output_commitments(pseudo_output_commitments.into());

signature.set_range_proofs(source.range_proof_bytes.clone());
signature.set_range_proof_bytes(source.range_proof_bytes.clone());
signature.set_range_proofs(RepeatedField::from_vec(source.range_proofs.clone()));
signature.set_pseudo_output_token_ids(source.pseudo_output_token_ids.clone());
signature.set_output_token_ids(source.output_token_ids.clone());

signature
}
Expand All @@ -46,12 +50,18 @@ impl TryFrom<&external::SignatureRctBulletproofs> for SignatureRctBulletproofs {
.push(CompressedCommitment::try_from(pseudo_output_commitment)?);
}

let range_proof_bytes = source.get_range_proofs().to_vec();
let range_proof_bytes = source.get_range_proof_bytes().to_vec();
let range_proofs = source.get_range_proofs().to_vec();
let pseudo_output_token_ids = source.get_pseudo_output_token_ids().to_vec();
let output_token_ids = source.get_output_token_ids().to_vec();

Ok(SignatureRctBulletproofs {
ring_signatures,
pseudo_output_commitments,
range_proof_bytes,
range_proofs,
pseudo_output_token_ids,
output_token_ids,
})
}
}
4 changes: 2 additions & 2 deletions api/src/convert/tx_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl From<&tx::TxPrefix> for external::TxPrefix {

tx_prefix.set_fee(source.fee);

tx_prefix.set_token_id(source.token_id);
tx_prefix.set_fee_token_id(source.fee_token_id);

tx_prefix.set_tombstone_block(source.tombstone_block);

Expand Down Expand Up @@ -47,7 +47,7 @@ impl TryFrom<&external::TxPrefix> for tx::TxPrefix {
inputs,
outputs,
fee: source.get_fee(),
token_id: source.get_token_id(),
fee_token_id: source.get_fee_token_id(),
tombstone_block: source.get_tombstone_block(),
};
Ok(tx_prefix)
Expand Down
6 changes: 3 additions & 3 deletions consensus/enclave/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl SgxConsensusEnclave {
// We need to make sure all transacctions are all valid. We also ensure they all
// point at the same root membership element.
for (tx, proofs) in transactions_with_proofs.iter() {
let token_id = TokenId::from(tx.prefix.token_id);
let token_id = TokenId::from(tx.prefix.fee_token_id);

let minimum_fee = ct_min_fees
.get(&token_id)
Expand Down Expand Up @@ -650,7 +650,7 @@ impl ConsensusEnclave for SgxConsensusEnclave {
.decrypt_bytes(locally_encrypted_tx.0)?;
let tx: Tx = mc_util_serial::decode(&decrypted_bytes)?;

let token_id = TokenId::from(tx.prefix.token_id);
let token_id = TokenId::from(tx.prefix.fee_token_id);

// Validate.
let mut csprng = McRng::default();
Expand Down Expand Up @@ -747,7 +747,7 @@ impl ConsensusEnclave for SgxConsensusEnclave {
// Compute the total fees for each known token id, for tx's in this block.
let mut total_fees: CtTokenMap<u128> = ct_min_fee_map.keys().cloned().collect();
for tx in transactions.iter() {
let token_id = TokenId::from(tx.prefix.token_id);
let token_id = TokenId::from(tx.prefix.fee_token_id);
total_fees.add(&token_id, tx.prefix.fee as u128);
}

Expand Down
26 changes: 22 additions & 4 deletions mobilecoind-json/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,10 @@ impl From<&RingMLSAG> for JsonRingMLSAG {
pub struct JsonSignatureRctBulletproofs {
pub ring_signatures: Vec<JsonRingMLSAG>,
pub pseudo_output_commitments: Vec<String>,
pub range_proofs: String,
pub range_proof_bytes: String,
pub range_proofs: Vec<String>,
pub pseudo_output_token_ids: Vec<u64>,
pub output_token_ids: Vec<u64>,
}

impl From<&SignatureRctBulletproofs> for JsonSignatureRctBulletproofs {
Expand All @@ -857,7 +860,14 @@ impl From<&SignatureRctBulletproofs> for JsonSignatureRctBulletproofs {
.iter()
.map(|x| hex::encode(x.get_data()))
.collect(),
range_proofs: hex::encode(src.get_range_proofs()),
range_proof_bytes: hex::encode(src.get_range_proof_bytes()),
range_proofs: src
.get_range_proofs()
.iter()
.map(|bytes| hex::encode(bytes))
.collect(),
pseudo_output_token_ids: src.pseudo_output_token_ids.clone(),
output_token_ids: src.output_token_ids.clone(),
}
}
}
Expand Down Expand Up @@ -910,9 +920,17 @@ impl TryFrom<&JsonSignatureRctBulletproofs> for SignatureRctBulletproofs {
let mut signature = SignatureRctBulletproofs::new();
signature.set_ring_signatures(RepeatedField::from_vec(ring_sigs));
signature.set_pseudo_output_commitments(RepeatedField::from_vec(commitments));
let proofs_bytes = hex::decode(&src.range_proofs)
let range_proof_bytes = hex::decode(&src.range_proof_bytes)
.map_err(|err| format!("Could not decode from hex: {}", err))?;
signature.set_range_proofs(proofs_bytes);
signature.set_range_proof_bytes(range_proof_bytes);
let range_proofs: Vec<Vec<u8>> = src
.range_proofs
.iter()
.map(|hex_str| {
hex::decode(hex_str).map_err(|err| format!("Could not decode from hex: {}", err))
})
.collect::<Result<Vec<Vec<u8>>, String>>()?;
signature.set_range_proofs(RepeatedField::from(range_proofs));

Ok(signature)
}
Expand Down
11 changes: 10 additions & 1 deletion transaction/core/src/blockchain/block_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl FromStr for BlockVersion {
impl BlockVersion {
/// The maximum value of block_version that this build of
/// mc-transaction-core has support for
pub const MAX: Self = Self(2);
pub const MAX: Self = Self(3);

/// Refers to the block version number at network launch.
pub const ZERO: Self = Self(0);
Expand All @@ -68,6 +68,9 @@ impl BlockVersion {
/// Constant for block version two
pub const TWO: Self = Self(2);

/// Constant for block version two
pub const THREE: Self = Self(3);

/// Iterator over block versions from one up to max, inclusive. For use in
/// tests.
pub fn iterator() -> BlockVersionIterator {
Expand Down Expand Up @@ -96,6 +99,12 @@ impl BlockVersion {
pub fn mint_transactions_are_supported(&self) -> bool {
self.0 >= 2
}

/// Mixed transactions [MCIP #31](https://github.com/mobilecoinfoundation/mcips/pull/31)
/// are introduced in block version 3
pub fn mixed_transactions_are_supported(&self) -> bool {
self.0 >= 3
}
}

impl Deref for BlockVersion {
Expand Down
27 changes: 27 additions & 0 deletions transaction/core/src/ring_signature/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,35 @@ pub enum Error {
/// Invalid RangeProof
RangeProofError,

/// RangeProof Deserialization failed
RangeProofDeserializationError,

/// TokenId is not allowed at this block version
TokenIdNotAllowed,

/// Missing pseudo-output token ids
MissingPseudoOutputTokenIds,

/// Missing output token ids
MissingOutputTokenIds,

/// Pseudo-output token ids not allowed at this block version
PseudoOutputTokenIdsNotAllowed,

/// Output token ids not allowed at this block version
OutputTokenIdsNotAllowed,

/// Mixed token ids in transactions not allowed at this block version
MixedTransactionsNotAllowed,

/// Too many range proofs for the block version
TooManyRangeProofs,

/// Unexpected range proof for the block version
UnexpectedRangeProof,

/// Missing expected range proofs (expected: {0}, found: {1})
MissingRangeProofs(usize, usize),
}

impl From<mc_util_repr_bytes::LengthMismatch> for Error {
Expand Down
25 changes: 25 additions & 0 deletions transaction/core/src/ring_signature/generator_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! A simple generator cache
use super::{generators, PedersenGens};
use crate::TokenId;
use alloc::collections::BTreeMap;

/// GeneratorCache is a simple object which caches computations of
/// generator: TokenId -> RistrettoPoint
///
/// This is intended just to be used in the scope of a single transaction,
/// and we therefore don't require it to be constant-time.
#[derive(Default, Clone)]
pub struct GeneratorCache {
cache: BTreeMap<TokenId, PedersenGens>,
}

impl GeneratorCache {
/// Get (and if necessary, cache) the Pedersen Generators corresponding to
/// a particular token id.
pub fn get(&mut self, token_id: TokenId) -> &PedersenGens {
self.cache
.entry(token_id)
.or_insert_with(|| generators(*token_id))
}
}
2 changes: 2 additions & 0 deletions transaction/core/src/ring_signature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ use mc_crypto_keys::RistrettoPublic;

mod curve_scalar;
mod error;
mod generator_cache;
mod key_image;
mod mlsag;
mod rct_bulletproofs;

pub use curve_scalar::*;
pub use error::Error;
pub use generator_cache::*;
pub use key_image::*;
pub use mlsag::*;
pub use rct_bulletproofs::*;
Expand Down
Loading

0 comments on commit 7e82974

Please sign in to comment.