Skip to content

SMT Candidate Evaluation

NOOSChain currently uses the iden3 JavaScript sparse Merkle tree adapter for consensus state roots. That path is consensus-critical. Candidate evaluation is therefore deliberately isolated from production execution: candidates are benchmarked against deterministic vectors before any state-root backend change is considered.

This process is for evaluating maintained alternatives. It is not permission to write a custom NOOSChain sparse tree.

Candidate Selection

A candidate can enter the benchmark queue only when it is a maintained implementation with a clear license and realistic Windows/Linux support.

Prefer candidates that provide:

  • deterministic insert, update, delete, root, and proof operations;
  • 256-bit key/value support or a deterministic documented field mapping;
  • independent proof verification;
  • a stable Rust, Go, WASM, or CLI/process interface;
  • a permissive license compatible with NOOSChain distribution;
  • enough maintenance history to trust consensus-critical behavior.

Reject candidates that require custom NOOSChain tree logic, silently change key or value semantics, cannot run on Windows and Linux, or cannot produce proofs compatible with replay/snapshot verification.

Vector Contract

The evaluation runner writes one deterministic vector JSON document:

json
{
  "vectorHash": "sha256-of-operations-json",
  "operations": [
    {
      "kind": "set",
      "stateKey": "64-character-sha256-hex",
      "valueHash": "64-character-sha256-hex"
    },
    {
      "kind": "delete",
      "stateKey": "64-character-sha256-hex"
    },
    {
      "kind": "proof",
      "stateKey": "64-character-sha256-hex",
      "expectedValueHash": "64-character-sha256-hex"
    }
  ]
}

Operations must be applied in order. stateKey and valueHash are canonical NOOSChain hashes. If a candidate needs field elements, it must use a documented mapping that produces roots compatible with the current baseline or be rejected.

Candidate Output Contract

The candidate process writes exactly one JSON object to stdout:

json
{
  "name": "candidate-name",
  "root": "64-character-hex-root",
  "proofChecks": 25,
  "proofFailures": 0,
  "memoryStartMb": 0,
  "memoryEndMb": 0,
  "memoryMaxMb": 0,
  "operationTotals": {
    "setLeafMs": 0,
    "deleteLeafMs": 0,
    "generateProofMs": 0,
    "verifyProofMs": 0,
    "getRootMs": 0
  },
  "internalTimingTotals": {}
}

Only root is mandatory for parsing, but proofFailures and timing fields are required for meaningful review. Human-readable diagnostics should go to stderr.

Running The Contract Fixture

The repository includes an external iden3 fixture. It is not an alternative SMT; it proves the process boundary and output parser.

powershell
npm run benchmark:smt:evaluation:external-fixture

Larger profile:

powershell
$env:NOOS_SMT_EVAL_LEAVES="5000"
$env:NOOS_SMT_EVAL_UPDATE_ROUNDS="1"
$env:NOOS_SMT_EVAL_DELETE_EVERY="10"
$env:NOOS_SMT_EVAL_PROOF_SAMPLES="50"
npm run benchmark:smt:evaluation:external-fixture

Running A Real Candidate

Use environment variables to point the harness at a candidate executable:

powershell
$env:NOOS_SMT_EVAL_EXTERNAL_CANDIDATE_COMMAND="C:\path\to\smt-candidate.exe"
$env:NOOS_SMT_EVAL_EXTERNAL_CANDIDATE_ARGS_JSON='["--vector","{vectorPath}"]'
npm run benchmark:smt:evaluation

If NOOS_SMT_EVAL_EXTERNAL_CANDIDATE_ARGS_JSON is unset, the harness calls:

text
<command> --vector <generated-vector-path>

The harness exits non-zero when the candidate root does not match the iden3 baseline. That is intentional. A report is still written, and the mismatch is a useful result because it distinguishes "fast but migration-only" candidates from drop-in-compatible candidates.

Nervos Benchmark Utility

The selected SMT sidecar path is Nervos. Benchmark utility work remains available for measuring the state-root engine boundary. Runtime development and production hardening target nervos-smt-v2 and the persistent Nervos sidecar documented in Nervos SMT Sidecar.

For a NOOSChain-shaped sidecar comparison, run:

powershell
npm run build:state-root-tools
npm run benchmark:state-root-engine

That benchmark applies an ordered block-style mutation batch and then rebuilds from final materialized leaves. It checks benchmark utility determinism and rebuild equivalence without changing consensus execution. The benchmark utility is external/state-root-sidecar-nervos-tools/, which wraps the maintained Rust sparse-merkle-tree crate. Its root does not match iden3, so Nervos is a new root scheme selected through the state-root engine activation/default path, not a transparent drop-in replacement for old iden3 chains.

Acceptance Gates

A candidate is not eligible for production unless it passes all gates:

  • roots match the current iden3 baseline for synthetic vectors;
  • requested proofs verify with zero failures;
  • replay-generated vectors match;
  • snapshot-generated vectors match;
  • Windows and Linux runs produce the same roots;
  • memory remains bounded for large vectors;
  • performance gain is large enough to justify consensus risk;
  • license and maintenance review are complete.

Any root mismatch is a rejection unless it is understood, documented, and handled as a protocol-versioned migration. Silent state-root changes are not allowed.

Current Finding

The current benchmark profiles show the hot path is inside iden3 mutation calls (update and fallback add), not NOOSChain hash-to-field conversion. Wrapper conversion is below one percent in the measured 1k and 5k profiles. The next useful work is therefore candidate comparison, not more local conversion tuning.

Audience-first NOOSChain documentation.