Rule
predictable-commitment-randomness
A published private-derived commitment uses statically known randomness.
Specimen 18 of 96 · Audit-default ordinary rules
- Severity
- medium
- Confidence
- high
- Maturity
- experimental
- Selection
- Audit default
- Policy intent
- not required
- Release
- v0.1.1
- Engine facts used
private-provenancecommitmentspublic-sinksconstants
Selection and scope#
Selected by the default audit profile, so an ordinary scan runs it.
./.nightshade/node_modules/.bin/nightshade ./contracts --detectors predictable-commitment-randomness
./.nightshade/node_modules/.bin/nightshade detector show predictable-commitment-randomnessThe first command runs only this rule; --detectors takes a comma-separated list. The second prints the rule's metadata from your installed version.
Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental.
Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope.
Verified example#
Publishing a commitment with fixed randomness can expose a small private input domain to guessing. From the proof run of the released CLI; the examples page also has the lookalike and the files.
pragma language_version >= 0.26.0;
import CompactStandardLibrary;
export ledger published: Bytes<32>;
witness secret(): Field;
export circuit publish(): [] {
published = persistentCommit<Field>(secret(), pad(32, ""));
}$ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc
MEDIUM — Public commitment uses predictable randomness [predictable-commitment-randomness]
vulnerable.compact:6:3
6 | published = persistentCommit<Field>(secret(), pad(32, ""));
| ^
persistentCommit commits private-derived input using statically known randomness, and its result influences ledger-write published. This removes the protection supplied by secret, unpredictable commitment randomness; low-entropy inputs can remain guessable. Intentional deterministic commitments require review.
Source: vulnerable.compact:6:15
Call path: publish
Remediation: Use independently generated, sufficiently entropic private randomness appropriate to the primitive and protocol. Do not replace intentional deterministic protocol commitments without reviewing compatibility.
Semantic profile: compact-0.34.0-zkir2.
Baseline analysis: complete; selected rules: complete.
Rule coverage: 1 selected rule(s); 0 with incomplete entries.
1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed.Corrected: Take commitment randomness from a witness instead of a constant. Changed lines are marked.
pragma language_version >= 0.26.0;
import CompactStandardLibrary;
export ledger published: Bytes<32>;
witness secret(): Field;
witness randomness(): Bytes<32>;
export circuit publish(): [] {
published = persistentCommit<Field>(secret(), randomness());
}$ nightshade corrected.compact --config config.json --compiler /path/to/compactc
Semantic profile: compact-0.34.0-zkir2.
Baseline analysis: complete; selected rules: complete.
Rule coverage: 1 selected rule(s); 0 with incomplete entries.
0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed.The command line is shortened from the recorded run to what you would type; the output below it is verbatim, with absolute file paths shortened to the example folder. Long lines wrap. A quiet result shows that this rule stopped firing, not that the contract is secure.
Corpus checks#
Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis.
| Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete |
|---|---|---|---|---|
| 2/2 | 2/2 | 1/1 | 0/0 | 0 |
No deviations were recorded for this rule.
These are behavior checks on synthetic fixtures, not a precision or recall estimate. See evaluation.
Rule documentation#
From docs/detectors/predictable-commitment-randomness.md at v0.1.1.
Availability: default; no policy required. Severity medium, confidence high for the stated constant-randomness observation.
Reports a tracked commitment of private-derived input influencing a public sink when every modeled component of its randomness is constant. This removes the protection supplied by secret, unpredictable commitment randomness.
Example and review scenario#
The compiler-qualified owned fixture publishes a persistentCommit using a fixed byte string as randomness. The correction supplies a separate witness value:
published = persistentCommit<Field>(secret(), randomness());Review how a private value's commitment obtains its randomness, particularly when the value has a small set of possible inputs. Recommendation: use independently generated private randomness with entropy appropriate to the primitive and protocol. Review protocol compatibility before changing intentional deterministic commitments.
False positives and limitations#
Deterministic protocols can match intentionally. The authenticated pinned standard-library tokenType declaration uses public domain-separated token derivation and is excluded; user-defined namesakes are still checked. Unknown witness randomness is not proven unpredictable, independent or sufficiently entropic. The rule is a constant-only check, not an entropy estimator or a proof of concrete feasibility or exploitability. Incomplete analysis is not a clean result.
Source examples#
These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply.
Example 1#
Fixture (source: tests/corpus/vulnerable/predictable-randomness.compact).
pragma language_version >= 0.26.0;
import CompactStandardLibrary;
export ledger published: Bytes<32>;
witness secret(): Field;
export circuit publish(): [] {
published = persistentCommit<Field>(secret(), pad(32, ""));
}Example 2#
Correction (source: tests/corpus/safe/predictable-randomness.compact).
pragma language_version >= 0.26.0;
import CompactStandardLibrary;
export ledger published: Bytes<32>;
witness secret(): Field;
witness randomness(): Bytes<32>;
export circuit publish(): [] {
published = persistentCommit<Field>(secret(), randomness());
}Suppress a match#
If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters:
// nightshade-disable-next-line predictable-commitment-randomness -- Reason this match is intentionalDiagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See configuration for fingerprint suppressions and baselines.