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

adjust to zcash_note_encryption changes #2

Merged
merged 10 commits into from
Jul 31, 2024
3 changes: 1 addition & 2 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ harness = false
[[bench]]
name = "pedersen_hash"
harness = false

[patch.crates-io]
zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/zcash_note_encryption", branch = "zsa1" }
2 changes: 1 addition & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl PreparedOutputInfo {
cv,
cmu,
epk.to_bytes(),
enc_ciphertext,
enc_ciphertext.0,
out_ciphertext,
zkproof,
)
Expand Down
13 changes: 9 additions & 4 deletions src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use memuse::DynamicUsage;
use redjubjub::{Binding, SpendAuth};

use zcash_note_encryption::{
EphemeralKeyBytes, ShieldedOutput, COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
note_bytes::NoteBytesData, Domain, EphemeralKeyBytes, ShieldedOutput, COMPACT_NOTE_SIZE,
ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
};

use crate::{
Expand Down Expand Up @@ -404,7 +405,7 @@ impl<Proof: DynamicUsage> DynamicUsage for OutputDescription<Proof> {
}
}

impl<A> ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE> for OutputDescription<A> {
impl<A> ShieldedOutput<SaplingDomain> for OutputDescription<A> {
fn ephemeral_key(&self) -> EphemeralKeyBytes {
self.ephemeral_key.clone()
}
Expand All @@ -413,8 +414,12 @@ impl<A> ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE> for OutputDescription
self.cmu.to_bytes()
}

fn enc_ciphertext(&self) -> &[u8; ENC_CIPHERTEXT_SIZE] {
&self.enc_ciphertext
fn enc_ciphertext(&self) -> Option<<SaplingDomain as Domain>::NoteCiphertextBytes> {
Some(NoteBytesData(self.enc_ciphertext))
}

fn enc_ciphertext_compact(&self) -> <SaplingDomain as Domain>::CompactNoteCiphertextBytes {
todo!()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unimplemented!("This function is not required for sapling")
seems like a better option

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

}
}

Expand Down
68 changes: 50 additions & 18 deletions src/note_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use memuse::DynamicUsage;
use rand_core::RngCore;

use zcash_note_encryption::{
note_bytes::{NoteBytes, NoteBytesData},
try_compact_note_decryption, try_note_decryption, try_output_recovery_with_ock,
try_output_recovery_with_ovk, BatchDomain, Domain, EphemeralKeyBytes, NoteEncryption,
NotePlaintextBytes, OutPlaintextBytes, OutgoingCipherKey, ShieldedOutput, COMPACT_NOTE_SIZE,
OutPlaintextBytes, OutgoingCipherKey, ShieldedOutput, AEAD_TAG_SIZE, COMPACT_NOTE_SIZE,
ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_PLAINTEXT_SIZE,
};

Expand Down Expand Up @@ -144,6 +145,11 @@ impl Domain for SaplingDomain {
type ExtractedCommitmentBytes = [u8; 32];
type Memo = [u8; 512];

type NotePlaintextBytes = NoteBytesData<{ NOTE_PLAINTEXT_SIZE }>;
type NoteCiphertextBytes = NoteBytesData<{ ENC_CIPHERTEXT_SIZE }>;
type CompactNotePlaintextBytes = NoteBytesData<{ COMPACT_NOTE_SIZE }>;
type CompactNoteCiphertextBytes = NoteBytesData<{ COMPACT_NOTE_SIZE }>;

fn derive_esk(note: &Self::Note) -> Option<Self::EphemeralSecretKey> {
note.derive_esk()
}
Expand Down Expand Up @@ -184,7 +190,7 @@ impl Domain for SaplingDomain {
dhsecret.kdf_sapling(epk)
}

fn note_plaintext_bytes(note: &Self::Note, memo: &Self::Memo) -> NotePlaintextBytes {
fn note_plaintext_bytes(note: &Self::Note, memo: &Self::Memo) -> Self::NotePlaintextBytes {
// Note plaintext encoding is defined in section 5.5 of the Zcash Protocol
// Specification.
let mut input = [0; NOTE_PLAINTEXT_SIZE];
Expand All @@ -208,7 +214,8 @@ impl Domain for SaplingDomain {

input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&memo[..]);

NotePlaintextBytes(input)
// FIXME: avoid unwrap usage

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Self::NotePlaintextBytes::from_slice(input.as_ref()).unwrap()
}

fn derive_ock(
Expand Down Expand Up @@ -245,17 +252,17 @@ impl Domain for SaplingDomain {
fn parse_note_plaintext_without_memo_ivk(
&self,
ivk: &Self::IncomingViewingKey,
plaintext: &[u8],
plaintext: &Self::CompactNotePlaintextBytes,
) -> Option<(Self::Note, Self::Recipient)> {
sapling_parse_note_plaintext_without_memo(self, plaintext, |diversifier| {
sapling_parse_note_plaintext_without_memo(self, plaintext.as_ref(), |diversifier| {
DiversifiedTransmissionKey::derive(ivk, diversifier)
})
}

fn parse_note_plaintext_without_memo_ovk(
&self,
pk_d: &Self::DiversifiedTransmissionKey,
plaintext: &NotePlaintextBytes,
plaintext: &Self::CompactNotePlaintextBytes,
) -> Option<(Self::Note, Self::Recipient)> {
sapling_parse_note_plaintext_without_memo(self, &plaintext.0, |diversifier| {
diversifier.g_d().map(|_| *pk_d)
Expand All @@ -282,10 +289,32 @@ impl Domain for SaplingDomain {
.into()
}

fn extract_memo(&self, plaintext: &NotePlaintextBytes) -> Self::Memo {
plaintext.0[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]
.try_into()
.expect("correct length")
fn split_plaintext_at_memo(
&self,
plaintext: &Self::NotePlaintextBytes,
) -> Option<(Self::CompactNotePlaintextBytes, Self::Memo)> {
let (compact, memo) = plaintext.0.split_at(COMPACT_NOTE_SIZE);
Some((
Self::parse_compact_note_plaintext_bytes(compact)?,
memo.try_into().ok()?,
))
}

fn parse_note_plaintext_bytes(plaintext: &[u8]) -> Option<Self::NotePlaintextBytes> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the word "parse" here, but that's super minor concern

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of having these functions with such names comes from str4d's review comment. Because our initial approach using the From trait did not provide information about errors (and a possible TryFrom replacement did not align with their approach of using Option instead of Error).

There's also an interesting question from @PaulLaux in the corresponding orchard PR review: QED-it/orchard#111 (comment). Now, I am reconsidering whether we really need to implement these functions in bothorchard and sapling-crypto. We could implement them directly in the zcash_note_encryption crate using the new from_slice and from_slice_with_tag methods of the NoteBytes crate (I have described this approach in response to @PaulLaux's review in that orchard PR).

Self::NotePlaintextBytes::from_slice(plaintext)
}

fn parse_note_ciphertext_bytes(
output: &[u8],
tag: [u8; AEAD_TAG_SIZE],
) -> Option<Self::NoteCiphertextBytes> {
Self::NoteCiphertextBytes::from_slice_with_tag(output, tag)
}

fn parse_compact_note_plaintext_bytes(
plaintext: &[u8],
) -> Option<Self::CompactNotePlaintextBytes> {
Self::CompactNotePlaintextBytes::from_slice(plaintext)
}
}

Expand Down Expand Up @@ -331,7 +360,7 @@ pub struct CompactOutputDescription {

memuse::impl_no_dynamic_usage!(CompactOutputDescription);

impl ShieldedOutput<SaplingDomain, COMPACT_NOTE_SIZE> for CompactOutputDescription {
impl ShieldedOutput<SaplingDomain> for CompactOutputDescription {
fn ephemeral_key(&self) -> EphemeralKeyBytes {
self.ephemeral_key.clone()
}
Expand All @@ -340,8 +369,13 @@ impl ShieldedOutput<SaplingDomain, COMPACT_NOTE_SIZE> for CompactOutputDescripti
self.cmu.to_bytes()
}

fn enc_ciphertext(&self) -> &[u8; COMPACT_NOTE_SIZE] {
&self.enc_ciphertext
fn enc_ciphertext(&self) -> Option<<SaplingDomain as Domain>::NoteCiphertextBytes> {
None
}

fn enc_ciphertext_compact(&self) -> <SaplingDomain as Domain>::CompactNoteCiphertextBytes {
// FIXME: avoid unwrap usage

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

NoteBytesData::from_slice(self.enc_ciphertext.as_ref()).unwrap()
}
}

Expand Down Expand Up @@ -406,7 +440,7 @@ pub fn plaintext_version_is_valid(zip212_enforcement: Zip212Enforcement, leadbyt
}
}

pub fn try_sapling_note_decryption<Output: ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE>>(
pub fn try_sapling_note_decryption<Output: ShieldedOutput<SaplingDomain>>(
ivk: &PreparedIncomingViewingKey,
output: &Output,
zip212_enforcement: Zip212Enforcement,
Expand All @@ -415,9 +449,7 @@ pub fn try_sapling_note_decryption<Output: ShieldedOutput<SaplingDomain, ENC_CIP
try_note_decryption(&domain, ivk, output)
}

pub fn try_sapling_compact_note_decryption<
Output: ShieldedOutput<SaplingDomain, COMPACT_NOTE_SIZE>,
>(
pub fn try_sapling_compact_note_decryption<Output: ShieldedOutput<SaplingDomain>>(
ivk: &PreparedIncomingViewingKey,
output: &Output,
zip212_enforcement: Zip212Enforcement,
Expand Down Expand Up @@ -560,7 +592,7 @@ mod tests {
cv,
cmu,
epk.to_bytes(),
ne.encrypt_note_plaintext(),
ne.encrypt_note_plaintext().0,
out_ciphertext,
[0u8; GROTH_PROOF_SIZE],
);
Expand Down