Skip to content

Commit

Permalink
feat: function to get commitments from transaction
Browse files Browse the repository at this point in the history
This is some code that currently exists in the node implementation when we are processing a spend
request. It needs to be shared between a couple of crates in the `safe_network` workspace, so I'm
opting to move it into this crate, which makes more sense than putting it in `sn_interface`, since
it's very specific to DBCs.

No test coverage has been added because it's difficult to setup the conditions for testing the
function. This could be done at a later point.

It could have potentially went into the transaction verifier, but I'm reluctant to change the
behaviour of that without having any tests. At the moment it would cost me too much time to work out
all the conditions necessary for covering the code in `TransactionVerifier`.
  • Loading branch information
jacderida authored and bochaco committed Sep 23, 2022
1 parent 976441a commit fa23ff9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ pub enum Error {
)]
SpentProofInputLenMismatch { current: usize, expected: usize },

#[error(
"The number of commitments ({current}) does not match the number of input MlsagSignature ({expected})"
)]
CommitmentsInputLenMismatch { current: usize, expected: usize },

#[error("A SpentProof KeyImage does not match an MlsagSignature KeyImage")]
SpentProofInputKeyImageMismatch,

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub use crate::{
SpentProofShare,
},
token::Token,
verification::TransactionVerifier,
verification::{get_public_commitments_from_transaction, TransactionVerifier},
};

#[cfg(feature = "serde")]
Expand Down
54 changes: 54 additions & 0 deletions src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,57 @@ impl TransactionVerifier {
Ok(())
}
}

/// Get the public commitments for the transaction for a key image spend.
///
/// They will be assigned to the spent proof share that is generated.
///
/// In the process of doing so, we verify the correct set of spent proofs and transactions have
/// been provided.
///
/// For the moment this function will only be called outside the library, hence the dead code
/// exception.
#[allow(dead_code)]
pub fn get_public_commitments_from_transaction(
tx: &RingCtTransaction,
spent_proofs: &BTreeSet<SpentProof>,
spent_transactions: &BTreeSet<RingCtTransaction>,
) -> Result<Vec<(KeyImage, Vec<Commitment>)>> {
let mut public_commitments_info = Vec::<(KeyImage, Vec<Commitment>)>::new();
for mlsag in &tx.mlsags {
// For each public key in ring, look up the matching Commitment
// using the SpentProofs and spent TX set provided by the client.
let commitments: Vec<Commitment> = mlsag
.public_keys()
.iter()
.flat_map(move |input_pk| {
spent_proofs.iter().flat_map(move |proof| {
// Make sure the spent proof corresponds to any of the spent TX provided,
// and the TX output PK matches the ring PK
spent_transactions.iter().filter_map(move |spent_tx| {
let tx_hash = Hash::from(spent_tx.hash());
if tx_hash == proof.transaction_hash() {
spent_tx
.outputs
.iter()
.find(|output| output.public_key() == &input_pk.clone())
.map(|output| output.commitment())
} else {
None
}
})
})
})
.collect();

if commitments.len() != mlsag.public_keys().len() {
return Err(Error::CommitmentsInputLenMismatch {
current: commitments.len(),
expected: mlsag.public_keys().len(),
});
}

public_commitments_info.push((mlsag.key_image.into(), commitments));
}
Ok(public_commitments_info)
}

0 comments on commit fa23ff9

Please sign in to comment.