Dependencies and Constant-Time Discipline
1. Why This Chapter Exists
The orchard crate is small because it delegates. Every
cryptographic primitive lives in an external crate, and changing
those crates changes Orchard. A contributor must know which crate
is responsible for which guarantee, and which dependencies are
load-bearing under no_std. After this chapter the reader can
read Cargo.toml and assess the impact of any version bump.
2. Definitions
Definition 2.1 (Constant-Time Operation)
An operation f(x) is constant-time if its execution time does
not depend on the value of x (only on its type). For an elliptic
curve point and scalar , is constant-time if the
scalar multiplication runs through the same sequence of curve
operations regardless of .
Definition 2.2 (Side-Channel-Free)
A higher-level guarantee that adds branch-free comparisons (subtle
ConstantTimeEq) and conditional selects (ConditionallySelectable)
to the constant-time operations.
Definition 2.3 (no_std Compatibility)
A crate is no_std if it can compile without the Rust standard
library, relying only on core (and optionally alloc).
orchard is #![no_std] and turns off the default features of
every dependency that pulls in std.
3. The Code
3.1 The Dependency Block
loading...
The cryptographically critical entries:
pasta_curves0.5: the Pallas and Vesta curve types (Chapter 3).halo2_proofs(viahalo2_gadgets) fromzcash/halo2: the proof system and chip library, behind featurecircuit.sinsemilla0.1: the hash function (Chapter 6).halo2_poseidon0.1 (re-exported asposeidon): the permutation (Chapter 7).reddsa0.5: the RedDSA implementation (Chapter 14).zcash_note_encryption0.4: the note encryption framework (Chapter 10).zip320.2.0 andzcash_spec0.2.1: shared key-derivation primitives.incrementalmerkletree0.8.1: the Merkle frontier maintenance.
Side-channel hygiene:
subtle2.6: constant-timeChoice,CtOption, comparisons.- The crate uses
#.
Symmetric primitives:
aes0.8: AES-256 used by FF1 for diversifier index encryption.blake2b_simd1.x: Blake2b for KDFs.fpe0.6: FF1 over AES-256.
3.2 Cargo Features
The crate ships several feature flags. The non-trivial ones at the pin:
-
circuit(off by default): pulls inhalo2_proofsandhalo2_gadgetsand compiles the Action circuit. A consumer that only needs to verify Bundles, parse notes, or work with keys can omit this feature and avoid the proof-system dependency entirely. -
multicore: forwards tohalo2_proofs/multicore; turns on parallel proving for the Action circuit. -
dev-graph: pulls inplottersandimageto render the circuit layout as a graph; useful when reviewing a chip layout change. Not part of release builds. -
unstable-voting-circuits(off by default): re-exports a set of otherwise-internal modules and types so that downstream voting-circuit projects can re-use Orchard's gadgets. These APIs are explicitly outside the crate's semver guarantees and may change in any release.Concretely, enabling the feature widens the visibility of
orchard::{constants, spec},orchard::circuit::{commit_ivk, commit_ivk::gadgets,note_commit, note_commit::gadgets, gadget::add_chip}, andorchard::note::{commitment, nullifier}, plus a number ofAddress,Note,CommitIvkChip,NoteCommitChip, andAddChipaccessors. The CHANGELOG entry ("unstable-voting-circuitsfeature flag") lists the full surface at the pin. The feature exists to let projects such as voting-circuit research build on top of Orchard's audited gadgets without forking the crate; a consumer that ships in production and depends on these symbols accepts the risk that a future Orchard point release moves or removes them.Mechanically the feature uses the
visibilityproc-macro: each gated item carries#[cfg_attr(feature = "unstable-voting-circuits", visibility::make(pub))], which promotes the item from its defaultpub(crate)or module-private visibility topubonly when the feature is on.
3.3 no_std Posture
The crate declares #![no_std] in
src/lib.rs
and turns off default features of every dependency that would
otherwise pull in std. CI runs build-nostd for
wasm32-wasip1 and thumbv7em-none-eabihf (see
Chapter 2).
3.4 Locking and the Latest-Deps Build
The default CI runs against the committed Cargo.lock. A
separate job removes the lock and re-builds with the latest
patch versions of every dependency. PRs that pin a non-trivial
new dependency must check both.
4. Failure Modes
- Latent
stdimport. A dependency adds astd-only feature default; the--no-default-featuresbuild breaks on the next bump. CI catches this only in thebuild-nostdmatrix. - Subtle version mismatch. Two transitive dependencies pull
in different
subtlemajor versions; theChoicetype becomes ambiguous.cargo tree -dsurfaces these. - Halo 2 version bump that changes the transcript. Any
semver-breaking change in
halo2_proofsinvalidates the pinned proof bytessrc/circuit_proof_test_case.bin. - Audit unaware dependency replacement. Replacing a crate with a fork (e.g. a faster Sinsemilla) silently shifts the audit boundary. The PR description must call this out.
5. Spec Pointers
- RUSTSEC advisory database and
cargo auditfor known vulnerabilities. - Halo 2 audit reports for the audited boundary of the upstream crates.
- Constant-time discipline in
dalek-cryptography/subtle: the canonical reference.
6. Exercises
- Run
cargo tree -e featuresagainst the crate at the pin and identify any transitive dependency that pulls instdindirectly. State the chain. - Search
Cargo.tomlfor everydefault-features = falseand explain in one sentence why each disable is necessary. - Code task. Run
cargo auditagainst the workspace. Triage any advisory: classify it as load-bearing-for-Orchard, transitive-but-test-only, or already-fixed-upstream. Open an issue or a PR for one finding if appropriate.
7. Further Reading
- The
pasta_curvesREADME, which documents the constant-time guarantees. halo2_proofsrelease notes for the cadence of breaking changes downstream.