Skip to content

Precomputed-power-table fast path for HashDomain::hash (~3.8x)#1

Draft
p0mvn wants to merge 1 commit into
mainfrom
sinsemilla-precompute-speedup
Draft

Precomputed-power-table fast path for HashDomain::hash (~3.8x)#1
p0mvn wants to merge 1 commit into
mainfrom
sinsemilla-precompute-speedup

Conversation

@p0mvn

@p0mvn p0mvn commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Speeds up the CPU Sinsemilla hash (HashDomain::hash / hash_to_point) by ~3.8x using precomputed fixed-base power tables — the Sinsemilla analogue of the Pedersen fixed-base windowing trick.

The hash unfurls (the group is abelian) into a flat sum:

H = [2^n] Q  +  sum_{i=0}^{n-1} [2^{n-1-i}] S(m_i)

Each term [2^p] S(v) is a fixed point determined only by the chunk position p and its K-bit value v. We precompute all of them into affine tables T_p[v] = [2^p] S_v, so the hash becomes pure mixed additions with all the doublings baked in. This drops the reference recurrence's per-chunk cost (a mixed add plus a full projective add plus constant-time checks) down to a single mixed add.

Benchmark

HashDomain::hash on a 510-bit / 51-chunk Merkle input (benches/hash.rs):

Path Time
Reference 68.85 µs
Precompute 18.01 µs
Speedup ~3.8x

What's in scope

  • precompute feature, on by default, backed by once_cell::race::OnceBox so the fast path stays no_std + alloc. Table is ~16.5 MB, built once on first use (253 power levels × 1024 values, via doubling + per-level batch inversion). --no-default-features falls back to the unchanged reference path.
  • Only HashDomain::hash / hash_to_point use the fast path. CommitDomain (note commitment, commit_ivk) is unchanged — it keeps calling hash_to_point_inner, preserving exact incomplete-addition () semantics on every commitment path.
  • The original hash_to_point_inner / addition.rs remain in-tree as the reference oracle.

Correctness & consensus safety

The fast path adds with complete addition in a reordered sum. It is value-identical to the reference for every reachable input, because incomplete addition equals complete addition whenever it does not reject, and the flat sum is the same group element regardless of add order. It diverges from the reference only on the exceptional input set (where the reference returns ), which is:

  • discrete-log hard to construct (requires steering the accumulator onto a specific point),
  • unsatisfiable in the Orchard circuit (so no valid Action can reference such a Merkle path),
  • never reached on honest data.

Differential test (fast_matches_reference) asserts fast == reference over 2000 random inputs of random lengths plus structurally-adversarial inputs (empty, sub-chunk, chunk boundaries, all-zero, all-one, max length). All pass.

Call-site audit (orchard consensus)

The only changed entry points (hash / hash_to_point) are consumed by orchard in exactly one consensus spot — MerkleCRH (tree.rs), which does domain.hash(...).unwrap_or(zero). All -sensitive paths (ivk derivation, note commitment) go through CommitDomain and are unaffected.

⚠️ Consensus sign-off needed: for MerkleCRH, the fast path changes the result on the exceptional set from 0 (the unwrap_or fallback when the reference returns ) to the real hash. This is a measure-zero, unconstructible set, safe under the same assumptions Orchard soundness already relies on, but it is strictly a consensus-rule-relevant behavior change and should be consciously accepted before rollout (and rolled out network-wide, not mixed).

Note on rollout

This PR is the sinsemilla crate only. Wiring it into downstream (orchard currently pins sinsemilla = "0.1"; needs a patch/bump to pick up this fork) is a separate step.

Test plan

  • cargo test (default, precompute on) — 3 pass incl. differential test
  • cargo test --no-default-features (reference path, no_std) — 2 pass
  • cargo clippy / cargo clippy --no-default-features — clean
  • cargo bench vs cargo bench on a reference build — ~3.8x

🤖 Generated with Claude Code

Sinsemilla's hash unfurls (the group is abelian) into a flat sum

    H = [2^n] Q + sum_i [2^{n-1-i}] S(m_i)

where each term [2^p] S(v) is a fixed point. Precomputing them into affine
tables T_p[v] = [2^p] S_v turns the hash into pure mixed additions with the
doublings baked in, eliminating the per-chunk doubling + full projective add
+ constant-time bottom checks of the reference recurrence.

Measured on a 510-bit (51-chunk) Merkle input: 68.85us -> 18.01us (~3.8x).

- New `precompute` feature (on by default), backed by once_cell::race::OnceBox
  so the fast path stays no_std + alloc. `--no-default-features` falls back to
  the unchanged reference path, which is value-identical.
- Only `HashDomain::hash`/`hash_to_point` use the fast path. `CommitDomain`
  (note commitment, commit_ivk) keeps calling hash_to_point_inner, preserving
  exact incomplete-addition (bottom) semantics on every commitment path.
- Differential test asserts fast == reference over 2000 random + adversarial
  inputs; criterion bench added under benches/hash.rs.

The fast path is value-identical to the reference for all reachable inputs;
it diverges only on the exceptional set where the reference returns bottom,
which is discrete-log hard to construct and unsatisfiable in the Orchard
circuit. See src/precompute.rs for the full rationale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedonce_cell@​1.21.410010093100100
Addedcriterion@​0.5.19810098100100

View full report

@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: cargo libc is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ?cargo/rand@0.8.5cargo/criterion@0.5.1cargo/group@0.13.0cargo/pasta_curves@0.5.1cargo/libc@0.2.186

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/libc@0.2.186. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: cargo zerocopy is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ?cargo/rand@0.8.5cargo/criterion@0.5.1cargo/zerocopy@0.8.52

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/zerocopy@0.8.52. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@p0mvn
p0mvn marked this pull request as draft June 20, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant