Rule
publicly-derived-guard-tag
A supplied tag is required equal to a hash derived from preexisting public ledger data and caller-supplied inputs before an effect.
Specimen 95 of 96 · Other active opt-ins / Source structure and validation
- Severity
- medium
- Confidence
- medium
- Maturity
- experimental
- Selection
- Opt-in
- Policy intent
- not required
- Release
- v0.1.1
- Engine facts used
direct-hash-inputsall-successful-predicatesexact-effect-histories
Selection and scope#
Not selected by default. Select it with --detectors or the detectors list in nightshade.json. Either one replaces profile selection, so list every rule you want.
./.nightshade/node_modules/.bin/nightshade ./contracts --detectors publicly-derived-guard-tag
./.nightshade/node_modules/.bin/nightshade detector show publicly-derived-guard-tagThe 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.
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 |
|---|---|---|---|---|
| 1/1 | 1/1 | 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/publicly-derived-guard-tag.md at v0.1.1.
Availability: opt-in, no policy required. Severity/confidence: medium/high. Select with --detectors publicly-derived-guard-tag.
The rule reports a raw supplied tag required equal to an exact native hash recipe containing definite preexisting public ledger data, with remaining ingredients limited to constants, unchanged caller-supplied parameter leaves and recursively supported native hashes. The comparison must precede a ledger or kernel effect on every modeled successful reach of that exact effect invocation. Findings group the guard site and entry, listing affected effects and separate history evidence.
export ledger attestorKey: Bytes<32>;
export ledger accepted: Counter;
export circuit accept(message: Bytes<32>, tag: Bytes<32>): [] {
assert(tag == persistentHash<Vector<2, Bytes<32>>>([attestorKey, message]), "tag");
accepted.increment(1);
}If this tag is intended to authenticate an attestor, hashing its public key and the supplied message does not verify a signature or secret possession. Use the protocol's reviewed verifier bound to the trusted signer and intended message. Other proofs can still provide authorization; this rule never establishes a sole gate, authentication intent, concrete feasibility or deployed vulnerability. Caller-supplied does not mean public: an entry parameter can remain private, and only its supplier is assumed to know it. A private witness ingredient or witness-dependent recipe/control excludes the match, including nested hashes.
Intentional checksums and prototype mock attestations are known review shapes. They are why this rule is opt-in. A correct static match is not a confirmed authentication defect; source intent and other protocol proofs require review.
Supported hashes are canonical persistentHash, transientHash and keccak256. Tag operands are unchanged scalar Bytes<32> or Field sources. Constants must have no private provenance: an assertion-refined witness is not a public literal. Exact preexisting ledger provenance is required; may-ledger dependencies, fresh caller-written keys, wildcard equality and a namesake hash do not suffice. An immutable old ledger snapshot can remain an ingredient after a later write. Optional/bypassed, ignored, negative, after-effect, return-only and constructor comparisons stay quiet. Arithmetic-derived parameter recipes and general custom crypto are outside this boundary.
Entry-isolated exact observations retain all predicates and typed digest inputs under the existing 40,000-step/256-path/50,000-value limits. Values share the rule's pass allowance. Entries whose baseline semantics are incomplete remain explicitly unavailable for this rule, without an expensive duplicate attempt; this restriction is not a completion or absence certificate. Consumer recipe/intersection work is bounded to 200,000 checks per invocation; recursive recipe/Boolean traversal is limited to depth64 and immutable keys to 4,096 nodes/depth32. Missing predicate/invocation evidence, unsupported exact observations and exhaustion produce rule/entry-scoped incomplete diagnostics and discard that entry's partial findings. Baseline coverage and other rules' findings remain independent. No engine admission or budget is expanded.
The family is grounded in Compact's witness/claimed-input trust boundary and documented public-data mock attestations; no execution or exploit reproduction is needed. Tests preserve instruction/reference and cached/uncached agreement, nested summary replay, guard alternatives, storage snapshots and checkpoint prefixes.
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 publicly-derived-guard-tag -- 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.