docs: point NU7 join page at the kresko release; drop source-build wrappers#1
Closed
evan-forbes wants to merge 2 commits into
Closed
docs: point NU7 join page at the kresko release; drop source-build wrappers#1evan-forbes wants to merge 2 commits into
evan-forbes wants to merge 2 commits into
Conversation
…appers The NU7 join flow moved to a single script published as a kresko release asset (valargroup/kresko: scripts/join-nu7-testnet.sh) that downloads prebuilt zebrad/kresko binaries instead of building from source. - Repoint book/src/dev/nu7-testnet-join.md at the released join script and the binary-download flow; drop the obsolete in-page source-build instructions and the live-script display that relied on a same-origin served copy. - Remove the now-obsolete downloader wrappers (scripts/join-nu7-testnet.sh and the served book copy) — both are replaced by the kresko release script. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author
|
Closing: this PR targets the |
evan-forbes
pushed a commit
that referenced
this pull request
Jun 10, 2026
…5709) (ZcashFoundation#10679) * fix(network): stop poisoning inventory registry on transient errors Only mark inventory as missing for explicit notfound responses. Transport failures (timeouts, drops) no longer poison the routing registry. Combined with #131 FindBlocks registration + re-request. Co-Authored-By: Gustavo Valverde <g.valverde02@gmail.com> * feat(sync): source-aware block routing with contiguous-prefix guard Track which peer announced each block hash from FindBlocks/ExtendTips responses. Route block requests to the announcing peer via BlocksByHashFrom, falling back to inventory routing if the source is not ready. Force the first CONTIGUOUS_PREFIX_P2C hashes to reliable P2C routing so the checkpoint verifier always gets its next-needed block. Based on v5.0.0 + no-poison fix. No #131 (re-request is superseded by proper routing). Co-Authored-By: Gustavo Valverde <g.valverde02@gmail.com> * feat(sync): add block re-request for failed downloads (ZcashFoundation#5709) Re-queue blocks whose download failed with NotFound instead of silently dropping them. Bounded by MAX_BLOCK_REOBTAIN_RETRIES. Combined with source-aware routing, this handles the case where the source peer is busy and the fallback misroutes — the block gets another chance via normal routing. Co-Authored-By: Zaki Manian <zaki@manian.org> * feat(sync): match #129 behavior — prefix=2000, batch by source peer Three fixes to match #129's proven 0-error genesis-to-tip result: 1. CONTIGUOUS_PREFIX_P2C: 32 → 2000 (most blocks use reliable P2C) 2. Batch blocks by source peer (SOURCE_BLOCK_BATCH_LIMIT=8) 3. Unsourced blocks dispatched individually via P2C Co-Authored-By: Gustavo Valverde <g.valverde02@gmail.com> * chore: remove unused download_and_verify_from and dead variable * fix(ci): allow large_enum_variant on pre-existing Setup enum The Setup enum in inbound.rs has a 224-byte Initialized variant vs 16-byte Pending variant. This is pre-existing and unrelated to the sync fix, but clippy with --all-features -D warnings now flags it. * docs: clarify re-request intent and batch dispatch semantics Address review feedback: - Clarify that re-requests go through P2C to avoid re-asking the NotFound peer (Zaki point C) - Fix misleading doc comment on download_and_verify_batch — each block gets its own readiness check, not a single shared one (Copilot #1) * refactor: remove dead source-aware routing code, keep behavioral fix Remove BlocksByHashFrom, source_by_hash tracking, route_source(), CONTIGUOUS_PREFIX_P2C, SOURCE_BLOCK_BATCH_LIMIT, and download_and_verify_batch. These were unreachable under any default config (prefix 2000 > max batch size in all modes). Keep the three behavioral changes that produce the 0-error result: - No-poison: stop registry poisoning on transient errors (client.rs) - Re-request: re-queue NotFound blocks instead of dropping (sync.rs) - Duplicate-tolerant dispatch: catch DuplicateBlockQueuedForDownload and continue instead of dropping the batch (sync.rs) 3 files, +128/-31 vs main. --------- Co-authored-by: Gustavo Valverde <g.valverde02@gmail.com> Co-authored-by: Zaki Manian <zaki@manian.org>
4 tasks
p0mvn
added a commit
that referenced
this pull request
Jun 19, 2026
PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking.
p0mvn
added a commit
that referenced
this pull request
Jun 19, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 21, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 22, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 22, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 23, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 23, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jun 23, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
p0mvn
added a commit
that referenced
this pull request
Jul 2, 2026
…tic path (#136) * proto(chain): defer Sapling value-commitment point decompression PROTOTYPE for benchmarking lever #1. After the native-digest and dropped-reparse changes, a flamegraph of the checkpoint heavy region attributes about 60% of CPU to Sapling Jubjub point decompression (a field square root in jubjub::AffinePoint::from_bytes), almost entirely the value commitment cv on every spend and output. Checkpoint sync never uses cv as a point: it verifies no signatures or proofs, and the note-commitment tree uses cm_u, not cv. Store cv as its canonical 32-byte encoding and decompress lazily, only when a consumer needs the point. Deserialization just copies the bytes, serialization and the txid digest use them directly, and the binding-signature verification in the semantic verifier decompresses on demand via ValueCommitment::commitment. This mirrors what Orchard already does for rk, which is why Orchard decompression is negligible in the profile. Prototype caveat: ValueCommitment::commitment panics on a non-canonical encoding rather than returning an error, and the not-small-order check now happens at the point of use instead of at parse. Correct for checkpoint sync (block hashes are trusted) and exercised by the unit tests, but the production version must make the accessor fallible so the semantic and mempool paths reject a malformed point cleanly instead of panicking. * proto(chain): also defer Sapling ephemeral_key point decompression Extends the lazy value-commitment prototype. With cv deferred, the profile showed the remaining ~50% of heavy-region CPU is the other per-output Jubjub point, the ephemeral_key, decompressed at parse. The validator only needs its bytes (txid digest and serialization); the point is needed only for wallet trial-decryption. Store ephemeral_key as its canonical 32-byte encoding and skip decompression at deserialization, like cv. Same prototype caveat: the not-small-order consensus check is deferred and must be re-added on the semantic and mempool paths in a production version. * proto(chain): validate lazy Sapling cv/epk consensus safety The deferred not-small-order checks for cv and ephemeral_key are not actually missing on the consensus path: librustzcash enforces them for every untrusted transaction, which all go through to_librustzcash (CachedFfiTransaction::new) on the semantic and mempool paths. cv is rejected at read (zcash_primitives read_value_commitment uses from_bytes_not_small_order); epk is rejected at verify (sapling-crypto verifier check_output uses epk.is_small_order). The checkpoint verifier trusts block hashes and does not need them. Add a regression test that constructs a v5 transaction with a small-order cv and epk and asserts both the deferral (Zebra now deserializes it) and the safety net (to_librustzcash rejects it), plus that the exact library detection functions flag the point. Correct the type docs accordingly. * perf(chain): enforce deferred Sapling cv/epk check on the semantic path Hardens the lazy Sapling cv/ephemeral_key prototype into a safer design. The lazy types keep point decompression off the checkpoint-sync hot path (the measured ~2.5x win), but the not-small-order consensus check is now re-enforced explicitly by Zebra on the untrusted boundary instead of relying solely on librustzcash. Add `Transaction::sapling_point_encodings_are_valid` (and the underlying `ShieldedData::point_encodings_are_valid`, `ValueCommitment::is_valid_not_small_order`, `EphemeralPublicKey::is_valid_not_small_order`), and call it from `verify_v4_transaction` / `verify_v5_transaction`, returning `TransactionError::SmallOrder` for a small-order or off-curve cv or epk. This runs on the semantic verification path and the mempool, which process untrusted transactions; the checkpoint verifier never calls it (it trusts block hashes), so the checkpoint throughput is unchanged. This restores a Zebra-side, auditable enforcement of the rule and makes the epk check isolatedly testable (it runs independently of proof verification). Spend rk is still validated at deserialization. Validated by `sapling_point_encodings_check_rejects_bad_points` and the existing lazy-cv/epk tests. * fix(consensus): run the deferred Sapling cv/epk check before to_librustzcash Adversarial review of the lazy Sapling change found one non-consensus issue: a small-order or off-curve cv failed inside CachedFfiTransaction::new (mapped to UnsupportedByNetworkUpgrade, mempool misbehavior score 0) before the explicit SmallOrder check ran, so a peer spamming bad-cv transactions received a lighter penalty than before the change (when it was a deserialization error). Move the sapling_point_encodings_are_valid check into the verifier's early quick checks, before the state lookups and the librustzcash conversion. Now a bad cv or epk fails fast with TransactionError::SmallOrder (score 100), restoring the peer penalty and making the check the primary, version-agnostic enforcer for v4, v5, and v6. Remove the now-redundant per-version copies. No consensus behavior change: the same transactions are accepted and rejected. The review confirmed no path commits or relays a transaction with a bad point without this check or checkpoint hash-trust, the commitment() panic is not reachable in release (no non-test caller), and there is no DoS amplification. * refactor(chain): make ValueCommitment::commitment fallible Removes the latent panic in `ValueCommitment::commitment`, which is the only caller-facing point that could decompress a deferred (unvalidated) value commitment. It now returns `Option`, so a future caller must handle an invalid encoding instead of getting a hidden panic, eliminating a possible DoS if the helper were ever moved onto a production path. `ShieldedData::binding_verification_key` (its only caller, used in tests) now propagates the `Option`. No production code calls either; the consensus encoding check happens on the semantic path via `sapling_point_encodings_are_valid`. * test(consensus): end-to-end reject of a Sapling output with an invalid epk Adds the missing end-to-end test for the deferred Sapling cv/epk check: it takes a real Sapling-output transaction, corrupts the first output's ephemeral key to an off-curve point, and runs it through the full transaction Verifier, asserting TransactionError::SmallOrder. The state service is unreachable!, proving the check fires in the early quick checks before any state lookup, and that the rejection is the explicit SmallOrder error rather than a later proof failure. This closes the last gap from the security review: the epk rejection is now confirmed by execution through the live verifier, not only by the isolated check and the librustzcash backstop. * consensus equivalence tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The NU7 join flow moved to a single script published as a kresko release asset (
valargroup/kresko→scripts/join-nu7-testnet.sh, see valargroup/kresko#4) that downloads the prebuiltzebrad/kreskobinaries instead of building from source on the host.This cleans up the zebra-fork side that's now obsolete:
book/src/dev/nu7-testnet-join.mdat the released join script and the binary-download flow. Drops the old source-build instructions and the in-page live-script display (it relied on a same-origin served copy that no longer exists). Keeps the interactive command builder and the bundle download.scripts/join-nu7-testnet.shand the served book copybook/src/dev/nu7-testnet/join-nu7-testnet.sh— both replaced by the kresko release script.No code changes; docs/scripts only.
🤖 Generated with Claude Code