feat: make memo size generic via MemoSize trait#1
Conversation
Introduce a `MemoSize` trait that parameterizes memo-dependent sizes across the Orchard protocol, allowing different protocols (e.g. Zcash with 512-byte memos, Dash with 36-byte memos) to share the same implementation. The memo is encrypted outside the ZK circuit via ChaCha20-Poly1305 AEAD, so changing its size has zero impact on the Halo2 proof system. All generic types use `M: MemoSize = ZcashMemo` default parameters for full backward compatibility. PCZT types remain at ZcashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a MemoSize abstraction and threads a generic memo parameter M through note encryption, Action, Bundle, Builder, PCZT, and related modules, replacing fixed 512-byte memos with trait-driven memo types (e.g., ZcashMemo, DashMemo). Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/action.rs (1)
159-163: Extract duplicated dummy ciphertext setup into a local helper.Both generators build the same placeholder
TransmittedNoteCiphertext; a helper avoids drift when ciphertext shape changes again.♻️ Proposed refactor
+ fn dummy_encrypted_note() -> TransmittedNoteCiphertext { + TransmittedNoteCiphertext::from_parts( + [0u8; 32], + NoteBytesData([0u8; 580]), + [0u8; 80], + ) + } + prop_compose! { @@ - let encrypted_note = TransmittedNoteCiphertext::from_parts( - [0u8; 32], - NoteBytesData([0u8; 580]), - [0u8; 80], - ); + let encrypted_note = dummy_encrypted_note(); @@ - let encrypted_note = TransmittedNoteCiphertext::from_parts( - [0u8; 32], - NoteBytesData([0u8; 580]), - [0u8; 80], - ); + let encrypted_note = dummy_encrypted_note();Also applies to: 191-195
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/action.rs` around lines 159 - 163, Duplicate construction of the placeholder TransmittedNoteCiphertext via TransmittedNoteCiphertext::from_parts and NoteBytesData([0u8; ...]) should be extracted into a small local helper (e.g., fn make_dummy_transmitted_note_ciphertext() -> TransmittedNoteCiphertext) that returns the same initialized value; replace both call sites currently creating the [0u8; 32], NoteBytesData([0u8; 580]), [0u8; 80] triple with a call to that helper so future changes to the ciphertext shape only need to be updated in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Cargo.toml`:
- Line 45: Cargo.toml currently lists the dependency zcash_note_encryption as a
git-only dependency which prevents publishing; update the crate metadata to
either mark the crate as non-publishable by adding publish = false in the
crate’s Cargo.toml, or replace the git-only entry for zcash_note_encryption with
Cargo’s multiple-location syntax by adding a proper version = "X.Y.Z" alongside
git and rev (or alternatively publish the forked zcash_note_encryption to
crates.io and reference that version), ensuring the dependency line for
zcash_note_encryption is changed accordingly.
In `@src/pczt/parse.rs`:
- Around line 231-241: The parser currently hardcodes Zcash memo size by calling
NoteBytes::from_slice without memo-specific type args, causing
NoteBytes::from_slice to default to ZcashMemo and fail for other sizes; change
the types to be generic over a MemoSize parameter (e.g., make Output<M:
MemoSize> and propagate M through Action and related types), update the parse
method signature to accept M and use the memo-aware instantiation when parsing
(call NoteBytes and TransmittedNoteCiphertext parameterized by M's
NoteCiphertextBytes / TransmittedNoteCiphertext<M>), and replace the current
error mapping (ParseError::InvalidEncCiphertext) usage with the same error but
for the memo-parameterized parsing path so non-default memo sizes parse
correctly.
---
Nitpick comments:
In `@src/action.rs`:
- Around line 159-163: Duplicate construction of the placeholder
TransmittedNoteCiphertext via TransmittedNoteCiphertext::from_parts and
NoteBytesData([0u8; ...]) should be extracted into a small local helper (e.g.,
fn make_dummy_transmitted_note_ciphertext() -> TransmittedNoteCiphertext) that
returns the same initialized value; replace both call sites currently creating
the [0u8; 32], NoteBytesData([0u8; 580]), [0u8; 80] triple with a call to that
helper so future changes to the ciphertext shape only need to be updated in one
place.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
Cargo.tomlsrc/action.rssrc/builder.rssrc/bundle.rssrc/bundle/batch.rssrc/bundle/commitments.rssrc/lib.rssrc/memo.rssrc/note.rssrc/note_encryption.rssrc/pczt/parse.rssrc/pczt/tx_extractor.rs
| sinsemilla = "0.1" | ||
| subtle = { version = "2.6", default-features = false } | ||
| zcash_note_encryption = "0.4" | ||
| zcash_note_encryption = { git = "https://github.com/dashpay/zcash_note_encryption", rev = "9f7e93d" } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
echo "Check publish policy (missing key means publish allowed by default):"
rg -n '^\s*publish\s*=' Cargo.toml || echo "No explicit publish setting found"
echo ""
echo "Check runtime git dependencies:"
rg -n '^\s*zcash_note_encryption\s*=\s*\{[^}]*git\s*=' Cargo.toml || echo "No git dependency found"
echo ""
echo "Show the full zcash_note_encryption entry in dependencies:"
rg -A 1 '^\s*zcash_note_encryption' Cargo.toml | head -20Repository: dashpay/orchard
Length of output: 839
Release blocker: git-only dependency in publishable crate.
Line 45 has zcash_note_encryption as a git-only dependency in [dependencies], and no publish = false is set. Crates with git-only dependencies cannot be published to crates.io. Either:
- Set
publish = falseif this is a workspace-only crate, OR - Use Cargo's multiple-location syntax:
version = "X.Y.Z"withgitandrev, OR - Publish the forked crate to crates.io first
Reference: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Cargo.toml` at line 45, Cargo.toml currently lists the dependency
zcash_note_encryption as a git-only dependency which prevents publishing; update
the crate metadata to either mark the crate as non-publishable by adding publish
= false in the crate’s Cargo.toml, or replace the git-only entry for
zcash_note_encryption with Cargo’s multiple-location syntax by adding a proper
version = "X.Y.Z" alongside git and rev (or alternatively publish the forked
zcash_note_encryption to crates.io and reference that version), ensuring the
dependency line for zcash_note_encryption is changed accordingly.
Propagate the MemoSize type parameter through all PCZT types (Bundle, Action, Output) and their impl blocks across parse, tx_extractor, io_finalizer, verify, updater, signer, and prover modules. This allows PCZT to work with non-default memo sizes like DashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/builder.rs (1)
553-708: Add one non-default memo-size test on the builder path.The generic API is wired well, but this critical path should include a regression test that instantiates
Builder<DashMemo>(or another non-defaultMemoSize) and exercisesadd_output+build_for_pczt(and ideally full signing flow) to prevent future fixed-size regressions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/builder.rs` around lines 553 - 708, The test-suite is missing a regression test for non-default memo sizes; add a unit/integration test that constructs a Builder<DashMemo> (using Builder::new or the same constructor used elsewhere), calls add_output with a DashMemo instance, and then calls build_for_pczt to exercise the PCZT build path (optionally following with the signing flow: create_proof/apply_signatures or equivalent functions used elsewhere) to ensure Builder<M>, add_output, and build_for_pczt work for non-default MemoSize; assert the build succeeds and the returned crate::pczt::Bundle contains the expected action count, flags, and value_sum to prevent regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/builder.rs`:
- Around line 553-708: The test-suite is missing a regression test for
non-default memo sizes; add a unit/integration test that constructs a
Builder<DashMemo> (using Builder::new or the same constructor used elsewhere),
calls add_output with a DashMemo instance, and then calls build_for_pczt to
exercise the PCZT build path (optionally following with the signing flow:
create_proof/apply_signatures or equivalent functions used elsewhere) to ensure
Builder<M>, add_output, and build_for_pczt work for non-default MemoSize; assert
the build succeeds and the returned crate::pczt::Bundle contains the expected
action count, flags, and value_sum to prevent regressions.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/builder.rssrc/pczt.rssrc/pczt/io_finalizer.rssrc/pczt/parse.rssrc/pczt/prover.rssrc/pczt/signer.rssrc/pczt/tx_extractor.rssrc/pczt/updater.rssrc/pczt/verify.rs
* Make memo size generic via MemoSize trait Introduce a `MemoSize` trait that parameterizes memo-dependent sizes across the Orchard protocol, allowing different protocols (e.g. Zcash with 512-byte memos, Dash with 36-byte memos) to share the same implementation. The memo is encrypted outside the ZK circuit via ChaCha20-Poly1305 AEAD, so changing its size has zero impact on the Halo2 proof system. All generic types use `M: MemoSize = ZcashMemo` default parameters for full backward compatibility. PCZT types remain at ZcashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix * use non local note encryption crate * export pub use zcash_note_encryption * Make PCZT types generic over MemoSize Propagate the MemoSize type parameter through all PCZT types (Bundle, Action, Output) and their impl blocks across parse, tx_extractor, io_finalizer, verify, updater, signer, and prover modules. This allows PCZT to work with non-default memo sizes like DashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Make memo size generic via MemoSize trait Introduce a `MemoSize` trait that parameterizes memo-dependent sizes across the Orchard protocol, allowing different protocols (e.g. Zcash with 512-byte memos, Dash with 36-byte memos) to share the same implementation. The memo is encrypted outside the ZK circuit via ChaCha20-Poly1305 AEAD, so changing its size has zero impact on the Halo2 proof system. All generic types use `M: MemoSize = ZcashMemo` default parameters for full backward compatibility. PCZT types remain at ZcashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix * use non local note encryption crate * export pub use zcash_note_encryption * Make PCZT types generic over MemoSize Propagate the MemoSize type parameter through all PCZT types (Bundle, Action, Output) and their impl blocks across parse, tx_extractor, io_finalizer, verify, updater, signer, and prover modules. This allows PCZT to work with non-default memo sizes like DashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Make memo size generic via MemoSize trait Introduce a `MemoSize` trait that parameterizes memo-dependent sizes across the Orchard protocol, allowing different protocols (e.g. Zcash with 512-byte memos, Dash with 36-byte memos) to share the same implementation. The memo is encrypted outside the ZK circuit via ChaCha20-Poly1305 AEAD, so changing its size has zero impact on the Halo2 proof system. All generic types use `M: MemoSize = ZcashMemo` default parameters for full backward compatibility. PCZT types remain at ZcashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix * use non local note encryption crate * export pub use zcash_note_encryption * Make PCZT types generic over MemoSize Propagate the MemoSize type parameter through all PCZT types (Bundle, Action, Output) and their impl blocks across parse, tx_extractor, io_finalizer, verify, updater, signer, and prover modules. This allows PCZT to work with non-default memo sizes like DashMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
MemoSizetrait and genericTransmittedNoteCiphertext<M: MemoSize>to allow variable memo sizes instead of the hardcoded 512-byte Zcash memoAction,Bundle,Builder, and note encryption types generic overMemoSize, withZcashMemoas the default for backwards compatibilityzcash_note_encryptiondependency to the dashpay fork that supports generic memo sizeszcash_note_encryptionfrom the crate root for downstream consumersChanges
src/memo.rsmodule withMemoSizetrait andZcashMemodefault implementationAction<A>→Action<A, M: MemoSize = ZcashMemo>,BundleandBuildersimilarly parameterizedTransmittedNoteCiphertextgeneric over memo size affectingenc_ciphertextlengthCompactAction,OrchardDomain) for generic memo supportTest plan
cargo test --verbosepassescargo clippy -- -D warningscleanZcashMemocontinue to work without changes🤖 Generated with Claude Code
Summary by CodeRabbit