iden3 State-Root Contract
This page documents the iden3-v1 state-root engine contract that NOOSChain keeps for legacy histories, replay, snapshots, migration tests, and explicit compatibility checks.
Unlike the Nervos contract, iden3-v1 is not a sidecar protocol. It is the legacy TypeScript adapter around @iden3/js-merkletree.
Frozen Identifiers
| Field | Frozen value |
|---|---|
| Engine id | iden3-v1 |
| Migration model | same_root_scheme |
| Implementation | @iden3/js-merkletree through the NOOSChain adapter |
| Runtime process | TypeScript/Node.js process |
| Tree max levels | 253 |
| State key input | 64-character SHA-256 hex string |
| Value hash input | 64-character SHA-256 hex string |
| Key domain separator | NOOS_SMT_KEY: |
| Value domain separator | NOOS_SMT_VALUE: |
| Key conversion | sha256("NOOS_SMT_KEY:" + stateKey) reduced modulo iden3 FIELD_SIZE |
| Value conversion | sha256("NOOS_SMT_VALUE:" + valueHash) reduced modulo iden3 FIELD_SIZE |
| Root encoding | root.hex() from iden3 |
| Proof encoding | iden3 proof JSON from proof.toJSON() |
Changing any value that affects key conversion, value conversion, tree structure, root extraction, mutation behavior, or proof semantics changes the iden3-v1 root scheme.
Consensus-Critical Inputs
The iden3 adapter receives the same logical state-root mutations as other engines:
set(stateKey, valueHash)delete(stateKey)
For iden3-v1, the following are consensus-critical:
stateKeymust be a 64-character SHA-256 hex string;valueHashmust be a 64-character SHA-256 hex string;- keys are domain-separated with
NOOS_SMT_KEY:; - values are domain-separated with
NOOS_SMT_VALUE:; - the domain-separated SHA-256 hashes are reduced modulo iden3
FIELD_SIZE; - iden3
add,update, anddeletebehavior defines tree mutation; - root extraction uses iden3
root().hex(); - mutation order must match the block state-change order emitted by NOOSChain.
Raw NOOSChain hashes are never interpreted as iden3 fields directly. The domain-separation step is part of the engine contract.
Delete Behavior
The iden3 adapter attempts native iden3 delete for leaf removals. If the persistent iden3 storage path fails a native delete and a rebuild callback is available, NOOSChain rebuilds the iden3 tree from audit state_leaves.
That fallback is a correctness path for the legacy engine. Normal updates still apply incrementally, and state_leaves remains the audit/current leaf set used to reconstruct the tree when needed.
Storage
iden3-v1 can run against:
- in-memory iden3 storage for replay, snapshot verification, benchmarks, and isolated checks;
- PostgreSQL-backed storage through
Iden3PostgresSmtDbduring persistent execution.
Persistent SMT nodes are stored below state_smt_kv. Current consensus leaves are stored in state_leaves as state key, namespace, entity id, value hash, and updated height.
Proofs
The iden3 proof path returns iden3 proof JSON plus the iden3 proof value and root. Verification reconstructs the iden3 proof object with Proof.fromJSON, converts the NOOSChain state key and value hash through the same field-element mapping, and calls iden3 verifyProof.
These proof semantics apply only to iden3-v1 roots.
What Requires A New Engine Id
Use a new engine id instead of silently changing iden3-v1 if any of the following changes:
- domain separators;
- SHA-256 validation rules;
- field-element conversion;
- tree max levels;
- iden3 library behavior that changes roots;
- root encoding;
- mutation ordering;
- delete/rebuild behavior that changes observable roots;
- proof format or proof verification semantics.
Old iden3-v1 blocks must remain replayable with the original root scheme.
Validation
The iden3 path is exercised by replay, snapshot, migration, readiness, and benchmark coverage:
- replay verification for legacy or pre-activation blocks;
- snapshot verification/import for
iden3-v1snapshots; - state-root activation readiness checks proving iden3 does not require the Nervos sidecar;
- state-root engine comparison benchmarks;
- migration tests proving iden3-to-Nervos continuation is rejected without an activation boundary.