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:
{
"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:
{
"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.
npm run benchmark:smt:evaluation:external-fixtureLarger profile:
$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-fixtureRunning A Real Candidate
Use environment variables to point the harness at a candidate executable:
$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:evaluationIf NOOS_SMT_EVAL_EXTERNAL_CANDIDATE_ARGS_JSON is unset, the harness calls:
<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:
npm run build:state-root-tools
npm run benchmark:state-root-engineThat 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.