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 225 & ZIP 244 #375

Merged
merged 26 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2ae55b4
Add more flexibility to vector serialization.
nuttycom May 12, 2021
4bcad97
Add amount conversion for Orchard values.
nuttycom May 12, 2021
fd1790f
Move sighash.rs -> sighash_v4.rs
nuttycom May 12, 2021
1138343
Add data structures for transaction digests.
nuttycom May 12, 2021
55d1090
Add v5 txid & signature hashing.
nuttycom May 12, 2021
1a5aad7
Use generalized signature_hash for transaction builder.
nuttycom May 13, 2021
e828dbf
Add v5 parsing and serialization for Sapling components.
nuttycom May 13, 2021
38b864c
Implement V5 transaction serialization & roundtrip property tests.
nuttycom May 13, 2021
dac68ce
Drop proptest space size to reduce test runtime.
nuttycom May 18, 2021
ab1b31e
Store partial authorizing data for transparent txs in transparent aut…
nuttycom Jun 3, 2021
6635895
Clean up TZE signature generation.
nuttycom Jun 4, 2021
6348400
Store patial authorizing data for sapling components in bundle author…
nuttycom Jun 4, 2021
df0095e
Add ZIP-244 test vectors.
nuttycom Jun 4, 2021
4623f98
Fix bugs in construction of Sapling txid hashes.
nuttycom Jun 4, 2021
e71a1ce
Rename Vector::write_items -> Array::write and Vector::read_count -> …
nuttycom Jun 4, 2021
28d3f48
Apply suggestions from code review.
nuttycom Jun 4, 2021
d0a911c
Fix rustdocs
nuttycom Jun 4, 2021
69e5a49
Fix generation of arbitrary jubjub points.
nuttycom Jun 4, 2021
47ce97c
Keep builder spend data in spend_auth_sig fields.
nuttycom Jun 5, 2021
97bef30
Remove consensus branch id from roundtrip serialization check.
nuttycom Jun 5, 2021
4f764c3
Use Vector read/write operations where possible instead of Array
nuttycom Jun 5, 2021
b93c503
Deserialize signatures directly into actions.
nuttycom Jun 5, 2021
0253442
Be more explicit about empty sapling & orchard hashes.
nuttycom Jun 5, 2021
371f84d
Minor error message improvement.
nuttycom Jun 5, 2021
f70285d
Fix error in transaction auth digest.
nuttycom Jun 5, 2021
eb3d01a
Apply suggestions from code review
nuttycom Jun 8, 2021
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
Prev Previous commit
Next Next commit
Be more explicit about empty sapling & orchard hashes.
  • Loading branch information
nuttycom committed Jun 7, 2021
commit 0253442af0c88043a1c369121be03bb86adbbc29
38 changes: 18 additions & 20 deletions zcash_primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,24 +950,22 @@ impl Transaction {
orchard_serialization::write_action_without_auth(w, a)
})?;

if !bundle.actions().is_empty() {
orchard_serialization::write_flags(&mut writer, &bundle.flags())?;
writer.write_all(&bundle.value_balance().to_i64_le_bytes())?;
orchard_serialization::write_anchor(&mut writer, bundle.anchor())?;
Vector::write(
&mut writer,
bundle.authorization().proof().as_ref(),
|w, b| w.write_u8(*b),
)?;
Array::write(
&mut writer,
bundle.actions().iter().map(|a| a.authorization()),
|w, auth| w.write_all(&<[u8; 64]>::from(*auth)),
)?;
writer.write_all(&<[u8; 64]>::from(
bundle.authorization().binding_signature(),
))?;
}
orchard_serialization::write_flags(&mut writer, &bundle.flags())?;
writer.write_all(&bundle.value_balance().to_i64_le_bytes())?;
orchard_serialization::write_anchor(&mut writer, bundle.anchor())?;
Vector::write(
&mut writer,
bundle.authorization().proof().as_ref(),
|w, b| w.write_u8(*b),
)?;
Array::write(
&mut writer,
bundle.actions().iter().map(|a| a.authorization()),
|w, auth| w.write_all(&<[u8; 64]>::from(*auth)),
)?;
writer.write_all(&<[u8; 64]>::from(
bundle.authorization().binding_signature(),
))?;
} else {
CompactSize::write(&mut writer, 0)?;
}
Expand Down Expand Up @@ -1013,8 +1011,8 @@ pub struct TzeDigests<A> {
pub struct TxDigests<A> {
pub header_digest: A,
pub transparent_digests: Option<TransparentDigests<A>>,
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
pub sapling_digest: A,
pub orchard_digest: A,
pub sapling_digest: Option<A>,
pub orchard_digest: Option<A>,
#[cfg(feature = "zfuture")]
pub tze_digests: Option<TzeDigests<A>>,
}
Expand Down
110 changes: 61 additions & 49 deletions zcash_primitives/src/transaction/txid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,25 +253,25 @@ fn hash_transparent_txid_data(t_digests: Option<&TransparentDigests<Blake2bHash>
h.finalize()
}

fn hash_sapling_txid_data<A: sapling::Authorization>(
sapling_bundle: Option<&sapling::Bundle<A>>,
) -> Blake2bHash {
fn hash_sapling_txid_data<A: sapling::Authorization>(bundle: &sapling::Bundle<A>) -> Blake2bHash {
let mut h = hasher(ZCASH_SAPLING_HASH_PERSONALIZATION);
if let Some(bundle) = sapling_bundle {
if !(bundle.shielded_spends.is_empty() && bundle.shielded_outputs.is_empty()) {
h.write_all(hash_sapling_spends(&bundle.shielded_spends).as_bytes())
.unwrap();
if !(bundle.shielded_spends.is_empty() && bundle.shielded_outputs.is_empty()) {
h.write_all(hash_sapling_spends(&bundle.shielded_spends).as_bytes())
.unwrap();

h.write_all(hash_sapling_outputs(&bundle.shielded_outputs).as_bytes())
.unwrap();
h.write_all(hash_sapling_outputs(&bundle.shielded_outputs).as_bytes())
.unwrap();

h.write_all(&bundle.value_balance.to_i64_le_bytes())
.unwrap();
}
h.write_all(&bundle.value_balance.to_i64_le_bytes())
.unwrap();
}
h.finalize()
}

fn hash_sapling_txid_empty() -> Blake2bHash {
hasher(ZCASH_SAPLING_HASH_PERSONALIZATION).finalize()
}

/// Write disjoint parts of each Orchard shielded action as 3 separate hashes:
/// * \[(nullifier, cmx, ephemeral_key, enc_ciphertext\[..52\])*\] personalized
/// with ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION
Expand All @@ -283,43 +283,45 @@ fn hash_sapling_txid_data<A: sapling::Authorization>(
/// Then, hash these together along with (flags, value_balance_orchard, anchor_orchard),
/// personalized with ZCASH_ORCHARD_ACTIONS_HASH_PERSONALIZATION
fn hash_orchard_txid_data<A: orchard::Authorization>(
orchard_bundle: Option<&orchard::Bundle<A, Amount>>,
bundle: &orchard::Bundle<A, Amount>,
) -> Blake2bHash {
let mut h = hasher(ZCASH_ORCHARD_HASH_PERSONALIZATION);
if let Some(bundle) = orchard_bundle {
let mut ch = hasher(ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION);
let mut mh = hasher(ZCASH_ORCHARD_ACTIONS_MEMOS_HASH_PERSONALIZATION);
let mut nh = hasher(ZCASH_ORCHARD_ACTIONS_NONCOMPACT_HASH_PERSONALIZATION);

for action in bundle.actions().iter() {
ch.write_all(&action.nullifier().to_bytes()).unwrap();
ch.write_all(&action.cmx().to_bytes()).unwrap();
ch.write_all(&action.encrypted_note().epk_bytes).unwrap();
ch.write_all(&action.encrypted_note().enc_ciphertext[..52])
.unwrap();

mh.write_all(&action.encrypted_note().enc_ciphertext[52..564])
.unwrap();
let mut ch = hasher(ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION);
let mut mh = hasher(ZCASH_ORCHARD_ACTIONS_MEMOS_HASH_PERSONALIZATION);
let mut nh = hasher(ZCASH_ORCHARD_ACTIONS_NONCOMPACT_HASH_PERSONALIZATION);

for action in bundle.actions().iter() {
ch.write_all(&action.nullifier().to_bytes()).unwrap();
ch.write_all(&action.cmx().to_bytes()).unwrap();
ch.write_all(&action.encrypted_note().epk_bytes).unwrap();
ch.write_all(&action.encrypted_note().enc_ciphertext[..52])
.unwrap();

nh.write_all(&action.cv_net().to_bytes()).unwrap();
nh.write_all(&<[u8; 32]>::from(action.rk())).unwrap();
nh.write_all(&action.encrypted_note().enc_ciphertext[564..])
.unwrap();
nh.write_all(&action.encrypted_note().out_ciphertext)
.unwrap();
}
mh.write_all(&action.encrypted_note().enc_ciphertext[52..564])
.unwrap();

h.write_all(&ch.finalize().as_bytes()).unwrap();
h.write_all(&mh.finalize().as_bytes()).unwrap();
h.write_all(&nh.finalize().as_bytes()).unwrap();
ser_orch::write_flags(&mut h, bundle.flags()).unwrap();
h.write_all(&bundle.value_balance().to_i64_le_bytes())
nh.write_all(&action.cv_net().to_bytes()).unwrap();
nh.write_all(&<[u8; 32]>::from(action.rk())).unwrap();
nh.write_all(&action.encrypted_note().enc_ciphertext[564..])
.unwrap();
nh.write_all(&action.encrypted_note().out_ciphertext)
.unwrap();
ser_orch::write_anchor(&mut h, bundle.anchor()).unwrap();
}

h.write_all(&ch.finalize().as_bytes()).unwrap();
h.write_all(&mh.finalize().as_bytes()).unwrap();
h.write_all(&nh.finalize().as_bytes()).unwrap();
ser_orch::write_flags(&mut h, bundle.flags()).unwrap();
h.write_all(&bundle.value_balance().to_i64_le_bytes())
.unwrap();
ser_orch::write_anchor(&mut h, bundle.anchor()).unwrap();
h.finalize()
}

fn hash_orchard_txid_empty() -> Blake2bHash {
hasher(ZCASH_ORCHARD_HASH_PERSONALIZATION).finalize()
}

#[cfg(feature = "zfuture")]
fn hash_tze_txid_data(tze_digests: Option<&TzeDigests<Blake2bHash>>) -> Blake2bHash {
let mut h = hasher(ZCASH_TZE_HASH_PERSONALIZATION);
Expand All @@ -343,8 +345,8 @@ pub struct TxIdDigester;
impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
type HeaderDigest = Blake2bHash;
type TransparentDigest = Option<TransparentDigests<Blake2bHash>>;
type SaplingDigest = Blake2bHash;
type OrchardDigest = Blake2bHash;
type SaplingDigest = Option<Blake2bHash>;
type OrchardDigest = Option<Blake2bHash>;

#[cfg(feature = "zfuture")]
type TzeDigest = Option<TzeDigests<Blake2bHash>>;
Expand Down Expand Up @@ -372,14 +374,14 @@ impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
&self,
sapling_bundle: Option<&sapling::Bundle<A::SaplingAuth>>,
) -> Self::SaplingDigest {
hash_sapling_txid_data(sapling_bundle)
sapling_bundle.map(hash_sapling_txid_data)
}

fn digest_orchard(
&self,
orchard_bundle: Option<&orchard::Bundle<A::OrchardAuth, Amount>>,
) -> Self::OrchardDigest {
hash_orchard_txid_data(orchard_bundle)
orchard_bundle.map(hash_orchard_txid_data)
}

#[cfg(feature = "zfuture")]
Expand All @@ -406,13 +408,13 @@ impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
}
}

pub fn to_hash(
pub(crate) fn to_hash(
_txversion: TxVersion,
consensus_branch_id: BranchId,
header_digest: Blake2bHash,
transparent_digests: Option<&TransparentDigests<Blake2bHash>>,
sapling_digest: Blake2bHash,
orchard_digest: Blake2bHash,
sapling_digest: Option<Blake2bHash>,
orchard_digest: Option<Blake2bHash>,
#[cfg(feature = "zfuture")] tze_digests: Option<&TzeDigests<Blake2bHash>>,
) -> Blake2bHash {
let mut personal = [0; 16];
Expand All @@ -425,8 +427,18 @@ pub fn to_hash(
h.write_all(header_digest.as_bytes()).unwrap();
h.write_all(hash_transparent_txid_data(transparent_digests).as_bytes())
.unwrap();
h.write_all(sapling_digest.as_bytes()).unwrap();
h.write_all(orchard_digest.as_bytes()).unwrap();
h.write_all(
sapling_digest
.unwrap_or_else(hash_sapling_txid_empty)
.as_bytes(),
)
.unwrap();
h.write_all(
orchard_digest
.unwrap_or_else(hash_orchard_txid_empty)
.as_bytes(),
)
.unwrap();

#[cfg(feature = "zfuture")]
if _txversion.has_tze() {
Expand Down