# low-entropy-hash-disclosure

> A published direct hash has one private input drawn from a small declared domain.

Canonical: https://nightshade.dicksonwu.xyz/rules/low-entropy-hash-disclosure.html
Release: Nightshade 0.1.1 (v0.1.1)

| Field | Value |
| --- | --- |
| Rule ID | `low-entropy-hash-disclosure` |
| Severity | medium |
| Confidence | high |
| Maturity | experimental |
| Selection | Audit default |
| Policy intent | not required |
| Default enabled | yes |
| Category | Audit-default ordinary rules |
| Engine facts used | resolved-types, private-provenance, public-sinks, direct-hash-inputs |
| Release | v0.1.1 |

## Selection and scope

Selected by the default audit profile, so an ordinary scan runs it.

```sh
./.nightshade/node_modules/.bin/nightshade ./contracts --detectors low-entropy-hash-disclosure
./.nightshade/node_modules/.bin/nightshade detector show low-entropy-hash-disclosure
```

The 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](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus).

## Rule documentation

From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/low-entropy-hash-disclosure.md at v0.1.1.

Availability: **default-on**; select only this rule with `--detectors low-entropy-hash-disclosure`;
severity **medium**, confidence **high**. Explicit selection replaces defaults.

The rule reports an exact published native digest with one direct private source
whose selected private leaf type has at most **65,536** values. Boolean, small Uint, Bytes and
enum domains (including nominal aliases) are supported. Public ledger context does
not add secret uncertainty. The bound is a type-domain upper bound, not an entropy
estimate, a secrecy policy or proof that an application has a vulnerability.

### Example and scenario

```compact
export circuit recordVote(vote: Boolean): [] {
  voteDigest = disclose(persistentHash<Boolean>(vote));
}
```

A digest of a Boolean is drawn from a two-candidate input domain. Hashing alone
supplies no useful hiding for this vote when its digest is published. A protocol
that intends to keep votes hidden should use a suitable commitment with
sufficiently unpredictable private opening randomness, then reveal it only at
the intended phase. The pinned standard-library documentation explicitly requires
acknowledged disclosure for hashes and distinguishes commitments with random
openings; `disclose` itself is permission, not secrecy protection.

Publishing a low-domain digest can be intentional when the input is already public
or the protocol explicitly accepts that disclosure. Review the actual privacy
requirement; a match is a domain-size warning, not proof that a secret or exploitable
value has been exposed.

### Evidence and limitations

Immutable typed native digest inputs follow aliases, helpers and aggregate copies
to public sinks. Projected fields retain their leaf type. A raw input published
on the same successful history is public context, including later atomic writes;
publishing a transformed salt does not establish publication of its preimage. A hash comparison or hash-dependent branch is not publication of
the digest. Private-salted/multiple-private-source hashes, arbitrary transformed
inputs, commitments and domains above the threshold stay outside this rule's
scope. There is no claim of general entropy analysis or multi-secret guessing.
An exported return is an application-output boundary, not necessarily a globally
public ledger. Raw witness and entry-parameter origins are both considered.

Traversal is bounded at 200,000 work units and domain expansion at 4,096 units,
with saturation above the threshold. Exhaustion produces `hash-domain-budget`
and incomplete status, never a clean result. Ordinary unsupported effects and
analysis budgets also remain incomplete. A bounded applicability check enables exact typed
digest observation for reachable native hashes with a represented small-domain input leaf, nonempty Bytes inputs that may retain constructed byte leaves, and native hash callbacks. It conservatively enables observation if its scope allowance is exhausted. Observation bypasses general fold compression.
Three exact compressed transfers remain available: a total hash-order choice whose arms hash the same typed
leaves in another order, the native scalar little-endian comparison fold, and the bounded pure-fold join
when all callback alternatives are equal up to the order of direct-digest input items (for example the
standard-library Merkle path fold). Their elided selector, branch-constraint or
byte-partition identities (and identities computed from them) may not reach a published digest input,
a constraint relating them to other values, or a storage key/location; any such dependency reports
`observation-compression-dependency` and leaves the rule incomplete for that entry. Summaries are not
cached across these transfers.
Branch-expanding entries first try a `conservative-absence` certificate (see
docs/coverage.md): a complete conservative may-view in which no evaluated native hash
has a direct input leaf that is a joined value with a raw dependency, or a
represented raw private leaf whose declared domain is small, unless the input also
has two distinct represented raw private leaves whose declarations are never
published raw on any possible sink and never a raw operand of a constraint or
checked narrowing (so both stay private and non-constant on every history).
Otherwise publication, salts and the single-private-leaf condition are ignored, so
a certificate implies no finding on any exact history. Candidates fall back to the exact pass with the remaining
entry allowance; the certificate never reports findings.
It may complete fewer contracts than a scan with this rule disabled under the same budgets;
missing exact input evidence gives `hash-domain-evidence-unavailable`. This rule
consumes immutable typed inputs from the shared native digest transfer; it does
not perform candidate enumeration or contact a contract or author.

## 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:

```compact
// nightshade-disable-next-line low-entropy-hash-disclosure -- Reason this match is intentional
```

Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines.

## References

- [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/low-entropy-hash-disclosure.md)
- [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json)
- [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules)
- [Limitations](https://nightshade.dicksonwu.xyz/limitations.md)
