Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dependency policy

This repository implements cryptography, so its dependency graph is part of its attack surface. The rules below exist to keep that surface small and reviewable, and to make the reasoning behind a pin visible instead of implicit.

Two rules

  1. One implementation of a cryptographic primitive per lockfile. If two versions of the same hash or signature crate resolve into the same build, the binary contains two implementations of the same primitive. That doubles the code that must be reviewed, makes “which one produced this digest” ambiguous at the call site, and means a fix in one does not reach the other. Prefer a single resolved version even when that means staying on an older release.
  2. A hash-dependency bump must be justified by known-answer tests, not by a green suite. “All tests pass” is not evidence that the digest is unchanged, because almost every test asserts a relationship between digests (equal inputs agree, unequal inputs differ) rather than a value. Such a suite stays green if the digest changes wholesale. Known-answer vectors computed independently of this code are the only evidence that survives.

Current state: sha2 is deliberately held at 0.10

sha2 0.11 is released, and neither repository should move to it yet. stellar-xdr 28 — the Stellar XDR crate this repository needs for the Soroban boundary — requires sha2 0.10, and so does the pinned crucible-simulator revision this repository compiles. Raising this repository’s own sha2 to 0.11 therefore resolves two sha2 versions, and two digest generations (0.10 and 0.11), into a single build. That is rule 1 violated to gain nothing: the digest output is byte-identical either way.

Evidence, reproducible from a checkout:

$ sed -i 's/^sha2 = "0.10"$/sha2 = "0.11"/' Cargo.toml
$ cargo update -p sha2
      Adding sha2 v0.11.0
$ grep -A1 'name = "sha2"' Cargo.lock | grep version
version = "0.10.9"
version = "0.11.0"
$ grep -c 'name = "generic-array"' Cargo.lock
1
$ cargo tree -i sha2@0.10.9
sha2 v0.10.9
├── crucible-core v0.1.0 (https://github.com/Crucible-TDA/crucible-simulator?rev=…)
└── stellar-xdr v28.0.0

Note also that generic-array 0.14 stays in the tree regardless, because it arrives through the same upstream that holds sha2 back — so the bump does not even reduce the dependency count.

Revisit when stellar-xdr and the pinned simulator both accept sha2 0.11. At that point the bump is a one-line change, and the acceptance test is that the known-answer vectors below still pass unchanged.

What protects the hash surface today

Both repositories now pin their digests with known-answer vectors computed with an independent implementation (Python’s hashlib), so a change in the hash, the encoding, or the domain separator fails loudly rather than silently rewriting persisted state:

RepositoryVectorsPins
crucible-provercrucible-interfaces (proof_provider::proof)ArtifactChecksum::from_bytes over fixed byte strings
crucible-provercrucible-artifacts (checksum)the whole-tree digest over a fixed entry list, plus a test asserting the result is not a hash of a hash
crucible-simulatorcrucible-core (hashing)hash_bytes / hash_str over fixed domains and payloads, plus a test asserting the digest is not a bare SHA-256 of the value

Any change to these constants in a diff is a change to a wire or state format and must be justified as such.