# predictable-commitment-randomness

> A published private-derived commitment uses statically known randomness.

Canonical: https://nightshade.dicksonwu.xyz/rules/predictable-commitment-randomness.html
Release: Nightshade 0.1.1 (v0.1.1)

| Field | Value |
| --- | --- |
| Rule ID | `predictable-commitment-randomness` |
| Severity | medium |
| Confidence | high |
| Maturity | experimental |
| Selection | Audit default |
| Policy intent | not required |
| Default enabled | yes |
| Category | Audit-default ordinary rules |
| Engine facts used | private-provenance, commitments, public-sinks, constants |
| 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 predictable-commitment-randomness
./.nightshade/node_modules/.bin/nightshade detector show predictable-commitment-randomness
```

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.

## Verified example

Synthetic example from the proof run of the released CLI. Publishing a commitment with fixed randomness can expose a small private input domain to guessing. Full example: https://nightshade.dicksonwu.xyz/examples.md#predictable-commitment-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, ""));
}
```

Output (exit code 1):

```text
$ 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.

```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());
}
```

Output (exit code 0):

```text
$ 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.
```

Paths are shortened to the example folder. 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](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus).

## Rule documentation

From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/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](#example-1)
publishes a `persistentCommit` using a fixed byte string as randomness. The
[correction](#example-2) supplies a separate
witness value:

```compact
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`).

```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`).

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

```compact
// nightshade-disable-next-line predictable-commitment-randomness -- 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/predictable-commitment-randomness.md)
- [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json)
- [Verified example](https://nightshade.dicksonwu.xyz/examples.md#predictable-commitment-randomness)
- [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules)
- [Limitations](https://nightshade.dicksonwu.xyz/limitations.md)
