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

Add ZIP-0244 TxId Digest support #2129

Merged
merged 9 commits into from
Jul 6, 2021
Merged
1 change: 1 addition & 0 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion zebra-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"

[features]
default = []
proptest-impl = ["proptest", "proptest-derive", "itertools", "zebra-test"]
proptest-impl = ["proptest", "proptest-derive", "itertools", "zebra-test", "rand", "rand_chacha"]
bench = ["zebra-test"]

[dependencies]
Expand Down Expand Up @@ -45,10 +45,13 @@ zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "0c3e
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "0c3ed159985affa774e44d10172d4471d798a85a" }
bigint = "4"
uint = "0.9.1"
bls12_381 = "0.5.0"

proptest = { version = "0.10", optional = true }
proptest-derive = { version = "0.3.0", optional = true }
itertools = { version = "0.10.1", optional = true }
rand = { version = "0.8", optional = true }
rand_chacha = { version = "0.3", optional = true }

# ZF deps
ed25519-zebra = "2"
Expand Down
47 changes: 29 additions & 18 deletions zebra-chain/src/orchard/arbitrary.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use group::prime::PrimeCurveAffine;
use halo2::pasta::pallas;
use halo2::{arithmetic::FieldExt, pasta::pallas};
use proptest::{arbitrary::any, array, collection::vec, prelude::*};

use crate::primitives::redpallas::{Signature, SpendAuth, VerificationKeyBytes};
use crate::primitives::redpallas::{Signature, SpendAuth, VerificationKey, VerificationKeyBytes};

use super::{keys, note, tree, Action, AuthorizedAction, Flags, NoteCommitment, ValueCommitment};

Expand All @@ -17,21 +17,19 @@ impl Arbitrary for Action {
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<note::Nullifier>(),
array::uniform32(any::<u8>()),
any::<VerificationKeyBytes<SpendAuth>>(),
any::<note::EncryptedNote>(),
any::<note::WrappedNoteKey>(),
)
.prop_map(
|(nullifier, rpk_bytes, enc_ciphertext, out_ciphertext)| Self {
cv: ValueCommitment(pallas::Affine::identity()),
nullifier,
rk: VerificationKeyBytes::from(rpk_bytes),
cm_x: NoteCommitment(pallas::Affine::identity()).extract_x(),
ephemeral_key: keys::EphemeralPublicKey(pallas::Affine::identity()),
enc_ciphertext,
out_ciphertext,
},
)
.prop_map(|(nullifier, rk, enc_ciphertext, out_ciphertext)| Self {
cv: ValueCommitment(pallas::Affine::identity()),
nullifier,
rk,
cm_x: NoteCommitment(pallas::Affine::identity()).extract_x(),
ephemeral_key: keys::EphemeralPublicKey(pallas::Affine::identity()),
enc_ciphertext,
out_ciphertext,
})
.boxed()
}

Expand All @@ -42,8 +40,6 @@ impl Arbitrary for note::Nullifier {
type Parameters = ();

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use halo2::arithmetic::FieldExt;

(vec(any::<u8>(), 64))
.prop_map(|bytes| {
let bytes = bytes.try_into().expect("vec is the correct length");
Expand Down Expand Up @@ -87,6 +83,23 @@ impl Arbitrary for Signature<SpendAuth> {
type Strategy = BoxedStrategy<Self>;
}

impl Arbitrary for VerificationKeyBytes<SpendAuth> {
type Parameters = ();

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(vec(any::<u8>(), 64))
.prop_map(|bytes| {
let bytes = bytes.try_into().expect("vec is the correct length");
let sk = pallas::Scalar::from_bytes_wide(&bytes);
let pk = VerificationKey::from_scalar(&sk);
pk.into()
})
.boxed()
}

type Strategy = BoxedStrategy<Self>;
}
dconnolly marked this conversation as resolved.
Show resolved Hide resolved

impl Arbitrary for Flags {
type Parameters = ();

Expand All @@ -101,8 +114,6 @@ impl Arbitrary for tree::Root {
type Parameters = ();

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use halo2::arithmetic::FieldExt;

(vec(any::<u8>(), 64))
.prop_map(|bytes| {
let bytes = bytes.try_into().expect("vec is the correct length");
Expand Down
1 change: 1 addition & 0 deletions zebra-chain/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ pub use x25519_dalek as x25519;
pub use proofs::{Bctv14Proof, Groth16Proof, Halo2Proof, ZkSnarkProof};

pub mod zcash_history;
mod zcash_primitives;
46 changes: 46 additions & 0 deletions zebra-chain/src/primitives/zcash_primitives.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! Contains code that interfaces with the zcash_primitives crate from
//! librustzcash.

use std::{
convert::{TryFrom, TryInto},
io,
};

use crate::{serialization::ZcashSerialize, transaction::Transaction};

impl TryFrom<&Transaction> for zcash_primitives::transaction::Transaction {
type Error = io::Error;

/// Convert a Zebra transaction into a librustzcash one.
///
/// # Panics
///
/// If the transaction is not V5. (Currently there is no need for this
/// conversion for other versions.)
fn try_from(trans: &Transaction) -> Result<Self, Self::Error> {
let network_upgrade = match trans {
Transaction::V5 {
network_upgrade, ..
} => network_upgrade,
Transaction::V1 { .. }
| Transaction::V2 { .. }
| Transaction::V3 { .. }
| Transaction::V4 { .. } => panic!("Zebra only uses librustzcash for V5 transactions"),
};

let serialized_tx = trans.zcash_serialize_to_vec()?;
// The `read` method currently ignores the BranchId for V5 transactions;
// but we use the correct BranchId anyway.
let branch_id: u32 = network_upgrade
.branch_id()
.expect("Network upgrade must have a Branch ID")
.into();
// We've already parsed this transaction, so its network upgrade must be valid.
let branch_id: zcash_primitives::consensus::BranchId = branch_id
.try_into()
.expect("zcash_primitives and Zebra have the same branch ids");
let alt_tx =
zcash_primitives::transaction::Transaction::read(&serialized_tx[..], branch_id)?;
Ok(alt_tx)
}
}
66 changes: 47 additions & 19 deletions zebra-chain/src/sapling/arbitrary.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use std::convert::TryInto;

use jubjub::AffinePoint;
use proptest::{arbitrary::any, array, collection::vec, prelude::*};
use proptest::{arbitrary::any, collection::vec, prelude::*};
use rand::SeedableRng;
use rand_chacha::ChaChaRng;

use crate::primitives::Groth16Proof;

Expand All @@ -15,24 +19,22 @@ impl Arbitrary for Spend<PerSpendAnchor> {
(
any::<tree::Root>(),
any::<note::Nullifier>(),
array::uniform32(any::<u8>()),
spendauth_verification_key_bytes(),
any::<Groth16Proof>(),
vec(any::<u8>(), 64),
)
.prop_map(
|(per_spend_anchor, nullifier, rpk_bytes, proof, sig_bytes)| Self {
per_spend_anchor,
cv: ValueCommitment(AffinePoint::identity()),
nullifier,
rk: redjubjub::VerificationKeyBytes::from(rpk_bytes),
zkproof: proof,
spend_auth_sig: redjubjub::Signature::from({
let mut b = [0u8; 64];
b.copy_from_slice(sig_bytes.as_slice());
b
}),
},
)
.prop_map(|(per_spend_anchor, nullifier, rk, proof, sig_bytes)| Self {
per_spend_anchor,
cv: ValueCommitment(AffinePoint::identity()),
nullifier,
rk,
zkproof: proof,
spend_auth_sig: redjubjub::Signature::from({
let mut b = [0u8; 64];
b.copy_from_slice(sig_bytes.as_slice());
b
}),
})
.boxed()
}

Expand All @@ -45,15 +47,15 @@ impl Arbitrary for Spend<SharedAnchor> {
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<note::Nullifier>(),
array::uniform32(any::<u8>()),
spendauth_verification_key_bytes(),
any::<Groth16Proof>(),
vec(any::<u8>(), 64),
)
.prop_map(|(nullifier, rpk_bytes, proof, sig_bytes)| Self {
.prop_map(|(nullifier, rk, proof, sig_bytes)| Self {
per_spend_anchor: FieldNotPresent,
cv: ValueCommitment(AffinePoint::identity()),
nullifier,
rk: redjubjub::VerificationKeyBytes::from(rpk_bytes),
rk,
zkproof: proof,
spend_auth_sig: redjubjub::Signature::from({
let mut b = [0u8; 64];
Expand Down Expand Up @@ -99,3 +101,29 @@ impl Arbitrary for OutputInTransactionV4 {

type Strategy = BoxedStrategy<Self>;
}

/// Creates Strategy for generation VerificationKeyBytes, since the `redjubjub`
/// crate does not provide an Arbitrary implementation for it.
fn spendauth_verification_key_bytes(
) -> impl Strategy<Value = redjubjub::VerificationKeyBytes<redjubjub::SpendAuth>> {
prop::array::uniform32(any::<u8>()).prop_map(|bytes| {
let mut rng = ChaChaRng::from_seed(bytes);
let sk = redjubjub::SigningKey::<redjubjub::SpendAuth>::new(&mut rng);
redjubjub::VerificationKey::<redjubjub::SpendAuth>::from(&sk).into()
})
}
dconnolly marked this conversation as resolved.
Show resolved Hide resolved

impl Arbitrary for tree::Root {
type Parameters = ();

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(vec(any::<u8>(), 64))
.prop_map(|bytes| {
let bytes = bytes.try_into().expect("vec is the correct length");
jubjub::Fq::from_bytes_wide(&bytes).to_bytes().into()
})
.boxed()
}

type Strategy = BoxedStrategy<Self>;
}
6 changes: 1 addition & 5 deletions zebra-chain/src/sapling/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@

use std::{collections::VecDeque, fmt};

use super::commitment::{pedersen_hashes::pedersen_hash, NoteCommitment};
use bitvec::prelude::*;
use lazy_static::lazy_static;
#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;

use super::commitment::{pedersen_hashes::pedersen_hash, NoteCommitment};

const MERKLE_DEPTH: usize = 32;

Expand Down Expand Up @@ -75,7 +72,6 @@ pub struct Position(pub(crate) u64);
/// this block. A root of a note commitment tree is associated with
/// each treestate.
#[derive(Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize, Hash)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub struct Root(pub [u8; 32]);

impl fmt::Debug for Root {
Expand Down
1 change: 1 addition & 0 deletions zebra-chain/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod lock_time;
mod memo;
mod serialize;
mod sighash;
mod txid;

#[cfg(any(test, feature = "proptest-impl"))]
pub mod arbitrary;
Expand Down
13 changes: 6 additions & 7 deletions zebra-chain/src/transaction/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use std::fmt;
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

use crate::serialization::{sha256d, SerializationError, ZcashSerialize};
use crate::serialization::SerializationError;

use super::Transaction;
use super::{txid::TxIdBuilder, Transaction};

/// A transaction hash.
///
Expand All @@ -19,11 +19,10 @@ pub struct Hash(pub [u8; 32]);

impl<'a> From<&'a Transaction> for Hash {
fn from(transaction: &'a Transaction) -> Self {
let mut hash_writer = sha256d::Writer::default();
transaction
.zcash_serialize(&mut hash_writer)
.expect("Transactions must serialize into the hash.");
Self(hash_writer.finish())
let hasher = TxIdBuilder::new(&transaction);
hasher
.txid()
.expect("zcash_primitives and Zebra transaction formats must be compatible")
}
}

Expand Down
Loading