Skip to content

@odatano/nightgate v0.10.0

Choose a tag to compare

@maxalexweber1 maxalexweber1 released this 24 Jul 13:23
· 14 commits to main since this release
435f0de

@odatano/nightgate 0.10.0 (2026-07-24)

  • AttestationVault passport hardening in ONE contract change (one redeploy):
    bindPassport rebind-takeover guard + registrar-gated pre-registration
    (registerPassport) against first-bind squatting.
  • Deterministic batch apply order: submitContractCallBatch rewrites segment
    ids into call order before proving, so DEPENDENT calls run as one
    transaction. Lifts the 0.9.3 order-independence restriction.

Highlights

bindPassport rebind-takeover guard

  • passport_bindings.insert overwrites and only payload_hash ownership was
    checked, so any attester could re-bind a bound passportId onto their own
    attestation and hijack the QR resolution (same takeover class as the 0.6.1
    attest() fix). An already-bound, unregistered id now re-binds only for
    the owner of its currently bound attestation; same-owner rebinding stays
    allowed.

Registrar-gated pre-registration (registerPassport)

  • A new constructor locks the DEPLOYER's attester identity as registrar;
    the registrar-only circuit registerPassport(passportId, owner_id) fills
    passport_owners. Registered ids bind/re-bind ONLY for their registered
    attester: blocks first-bind squatting and recovers a squatted id (registrar
    re-points it, the owner rebinds over the foreign binding). Unregistered ids
    stay first-come-first-served (squattable by design).
  • New OData action registerPassport(...): async job like
    grant/revokeDisclosure (30/h per session), result
    { passportId, ownerId, contractAddress, txHash }. Browser helper
    prepareRegisterPassport.

Deterministic batch apply order (submitContractCallBatch)

  • The SDK randomizes each call's segment id while the ledger applies merged
    intents in ascending segment order, so a dependent batch only landed by
    luck (~1/3). NIGHTGATE now rewrites the batch's existing segment ids into
    call order before proving (ledger-v8 recomputes binding);
    attest -> bindPassport -> anchorContentRoot runs as ONE tx.
  • Fail-closed: if the ordering cannot be established for a multi-call batch,
    the submission aborts BEFORE proving (nothing submitted) instead of
    silently proving in randomized order. Duplicate circuit names keep a random
    relative order among themselves. New srv/midnight/batch-segment-order.ts.

Notes

  • Recompiled managed/ artifact (compactc 0.31.0), now 9 circuits
    (anchorContentRoot/proveFieldPredicate keys shifted too). No CDS schema
    change. The deploying session's secret defines the registrar: deploy from
    the session that should manage passport ownership.
  • Consumer action (NIGHTPASS): redeploy the vault. A redeployed vault
    starts with an EMPTY ledger:
    switch the contract address AND re-create
    needed state (attest, bindPassport, anchorContentRoot, grants), ideally
    registering known passport ids first, otherwise QR resolution appears
    lost.
  • Job-pool fix: grantDisclosure/revokeDisclosure/registerPassport now
    run in the HEAVY pool (full ZK proof generation; light since 0.9.0 was an
    oversight).
  • Verified: 68 suites / 1231 tests + 34-check contract regression script,
    and TWO full live rounds on preprod (fresh vaults 81576468…/da9b0bcf…):
    deploy, first-try dependent 3-call batch with on-chain SUCCESS
    (txs 86bc9a0b…/4db4dea6…), registerPassport, bind on the registered
    id. Two first-try batches had ~11% combined odds under the old randomized
    order; the statistical 6/6-vs-0/6 stress proof runs consumer-side.