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

ZIP-244 & ZIP-245: creation of non-malleable txids + TZE signature hashing #319

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions zcash_extensions/src/transparent/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ mod tests {

let mut mtx_a = TransactionData::zfuture();
mtx_a.tze_outputs.push(out_a);
let tx_a = mtx_a.freeze().unwrap();
let tx_a = mtx_a.freeze(BranchId::ZFuture).unwrap();

//
// Transfer
Expand All @@ -635,7 +635,7 @@ mod tests {
let mut mtx_b = TransactionData::zfuture();
mtx_b.tze_inputs.push(in_b);
mtx_b.tze_outputs.push(out_b);
let tx_b = mtx_b.freeze().unwrap();
let tx_b = mtx_b.freeze(BranchId::ZFuture).unwrap();

//
// Closing transaction
Expand All @@ -648,7 +648,7 @@ mod tests {

let mut mtx_c = TransactionData::zfuture();
mtx_c.tze_inputs.push(in_c);
let tx_c = mtx_c.freeze().unwrap();
let tx_c = mtx_c.freeze(BranchId::ZFuture).unwrap();

// Verify tx_b
{
Expand Down
2 changes: 1 addition & 1 deletion zcash_primitives/src/note_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const COMPACT_NOTE_SIZE: usize = 1 + // version
11 + // diversifier
8 + // value
32; // rcv
const NOTE_PLAINTEXT_SIZE: usize = COMPACT_NOTE_SIZE + 512;
const NOTE_PLAINTEXT_SIZE: usize = COMPACT_NOTE_SIZE + 512; //memo
const OUT_PLAINTEXT_SIZE: usize = 32 + // pk_d
32; // esk
pub const ENC_CIPHERTEXT_SIZE: usize = NOTE_PLAINTEXT_SIZE + 16;
Expand Down
6 changes: 6 additions & 0 deletions zcash_primitives/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ impl Nullifier {
}
}

impl AsRef<[u8]> for Nullifier {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl ConstantTimeEq for Nullifier {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
Expand Down
31 changes: 31 additions & 0 deletions zcash_primitives/src/transaction/blake2b_256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use blake2b_simd::{Hash, Params, State};
use std::io::{self, Write};

/// Abstraction over a writer which BLAKE2B-256-hashes the data being read.
pub struct HashWriter {
hasher: State,
}

impl HashWriter {
pub fn new(personal: &[u8; 16]) -> Self {
let hasher = Params::new().hash_length(32).personal(personal).to_state();

HashWriter { hasher }
}

pub fn finalize(&self) -> Hash {
self.hasher.finalize()
}
}

impl Write for HashWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.hasher.update(&buf);

Ok(buf.len())
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
60 changes: 44 additions & 16 deletions zcash_primitives/src/transaction/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::error;
use std::fmt;
use std::marker::PhantomData;

use blake2b_simd::Hash as Blake2bHash;
use ff::Field;
use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore};

Expand All @@ -24,7 +25,9 @@ use crate::{
components::{
amount::Amount, amount::DEFAULT_FEE, OutputDescription, SpendDescription, TxOut,
},
signature_hash_data, SignableInput, Transaction, TransactionData, SIGHASH_ALL,
signature_hash,
txid::TxIdDigester,
SignableInput, Transaction, TransactionData, TxDigests, TxId, SIGHASH_ALL,
},
util::generate_random_rseed_internal,
zip32::ExtendedSpendingKey,
Expand Down Expand Up @@ -265,21 +268,24 @@ impl TransparentInputs {
}

#[cfg(feature = "transparent-inputs")]
fn apply_signatures(
fn apply_signatures<F>(
&self,
mtx: &mut TransactionData,
consensus_branch_id: consensus::BranchId,
) {
let mut sighash = [0u8; 32];
txid_parts_cache: &mut F,
) where
F: FnMut(&TransactionData) -> TxDigests<Blake2bHash, TxId>,
{
for (i, info) in self.inputs.iter().enumerate() {
sighash.copy_from_slice(&signature_hash_data(
let sighash = signature_hash(
mtx,
consensus_branch_id,
SIGHASH_ALL,
SignableInput::transparent(i, &info.coin.script_pubkey, info.coin.value),
));
txid_parts_cache,
);

let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes");
let msg = secp256k1::Message::from_slice(sighash.as_ref()).expect("32 bytes");
let sig = self.secp.sign(&msg, &info.sk);

// Signature has to have "SIGHASH_ALL" appended to it
Expand All @@ -292,7 +298,11 @@ impl TransparentInputs {
}

#[cfg(not(feature = "transparent-inputs"))]
fn apply_signatures(&self, _: &mut TransactionData, _: consensus::BranchId) {}
fn apply_signatures<F>(&self, _: &mut TransactionData, _: consensus::BranchId, _: &F)
where
F: FnMut(&TransactionData) -> TxDigests<Blake2bHash, TxId>,
{
}
}

#[cfg(feature = "zfuture")]
Expand Down Expand Up @@ -801,21 +811,34 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
//
// Signatures -- everything but the signatures must already have been added.
//
let mut txid_parts: Option<TxDigests<Blake2bHash, TxId>> = None;
let mut txid_parts_cache = |mtx: &TransactionData| match &txid_parts {
Some(parts) => parts.clone(),
None => {
txid_parts = Some(mtx.digest(TxIdDigester {
consensus_branch_id,
}));
txid_parts.clone().unwrap()
}
};

let mut sighash = [0u8; 32];
sighash.copy_from_slice(&signature_hash_data(
let sighash = signature_hash(
&self.mtx,
consensus_branch_id,
SIGHASH_ALL,
SignableInput::Shielded,
));
&mut txid_parts_cache,
);

let mut sighash_bytes = [0u8; 32];
sighash_bytes.copy_from_slice(sighash.as_ref());

// Create Sapling spendAuth and binding signatures
for (i, (_, spend)) in spends.into_iter().enumerate() {
self.mtx.shielded_spends[i].spend_auth_sig = Some(spend_sig_internal(
PrivateKey(spend.extsk.expsk.ask),
spend.alpha,
&sighash,
&sighash_bytes,
&mut self.rng,
));
}
Expand All @@ -824,7 +847,7 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
self.mtx.binding_sig = if binding_sig_needed {
Some(
prover
.binding_sig(&mut ctx, self.mtx.value_balance, &sighash)
.binding_sig(&mut ctx, self.mtx.value_balance, &sighash_bytes)
.map_err(|_| Error::BindingSig)?,
)
} else {
Expand All @@ -847,11 +870,16 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
}

// Transparent signatures
self.transparent_inputs
.apply_signatures(&mut self.mtx, consensus_branch_id);
self.transparent_inputs.apply_signatures(
&mut self.mtx,
consensus_branch_id,
&mut txid_parts_cache,
);

Ok((
self.mtx.freeze().expect("Transaction should be complete"),
self.mtx
.freeze(consensus_branch_id)
.expect("Transaction should be complete"),
tx_metadata,
))
}
Expand Down
22 changes: 11 additions & 11 deletions zcash_primitives/src/transaction/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ impl OutputDescription {
}

#[derive(Clone)]
enum SproutProof {
pub(crate) enum SproutProof {
Groth([u8; GROTH_PROOF_SIZE]),
PHGR([u8; PHGR_PROOF_SIZE]),
}
Expand All @@ -458,16 +458,16 @@ impl std::fmt::Debug for SproutProof {

#[derive(Clone)]
pub struct JSDescription {
vpub_old: Amount,
vpub_new: Amount,
anchor: [u8; 32],
nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS],
commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS],
ephemeral_key: [u8; 32],
random_seed: [u8; 32],
macs: [[u8; 32]; ZC_NUM_JS_INPUTS],
proof: SproutProof,
ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
pub(crate) vpub_old: Amount,
pub(crate) vpub_new: Amount,
pub(crate) anchor: [u8; 32],
pub(crate) nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS],
pub(crate) commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS],
pub(crate) ephemeral_key: [u8; 32],
pub(crate) random_seed: [u8; 32],
pub(crate) macs: [[u8; 32]; ZC_NUM_JS_INPUTS],
pub(crate) proof: SproutProof,
pub(crate) ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
}

impl std::fmt::Debug for JSDescription {
Expand Down
Loading