Skip to content

Commit the round reference time in the SMT leaf value #81

Description

@ristik

Background

Yellowpaper commit 407b07f ("commit reference time in the SMT leaf value") changes the Unicity Service SMT leaf value from the transaction hash alone to H(txhash, τ), where τ is the reference time of the round the request was validated in (UC.IR.t).

Predicate evaluation already takes τ as an argument, but τ was recoverable only from the inclusion proof, as UC.IR.t. The SMT is append-only, so a leaf can be certified afresh against any later root, and a later proof carries a later round's IR.t. Reference time was therefore a property of the proof rather than of the leaf, and re-presenting a leaf changed the predicate evaluation outcome. Binding τ into the leaf value fixes the value the transition was validated under, for any proof of that leaf.

τ cannot go into txhash: it is chosen by the Aggregator after the sender has signed. The leaf value is the first field written once τ is known, and it is the one field re-presentation preserves verbatim.

Affected yellowpaper sections: platform.tex (Unicity Service Request, request validation, SMT leaf structure, inclusion proof), execution-layer.tex (mint/transfer transaction structure and verification, sec:time-extraction, Unicity Service processing), appendix-hashtrees.tex (ZK-compressed consistency proof).

Normative encodings

These must be byte-identical across aggregator-go, rugregator, bft-core, and the three SDKs.

Symbol Meaning Type
τ Round reference time: UC.InputRecord.Timestamp of the round the leaf was certified in. BFT Core requires it to equal the previous round's Unicity Seal timestamp. uint64, Unix seconds
τ_Q Exclusive request timeout, chosen by the sender uint64, Unix seconds

Transaction hash. τ_Q is the last element of the transaction's own deterministic CBOR array, so

txhash = SHA-256( <transaction CBOR, ending in τ_Q> )

is unchanged in form and is exactly appendix-token.tex's SHA-256(CBOR(…, τ_Q)). Keeping τ_Q inside the transaction rather than beside it (as the appendix's four-element certified transaction does) means the request, the certified transaction and the hash preimage cannot disagree about it, and the unlock script signs it along with the rest of the transaction.

SMT leaf value.

v = SHA-256( CBOR([ txhash, τ ]) )     // 32 raw bytes

txhash enters as a CBOR byte string of the raw 32-byte digest (no algorithm-id prefix), τ as a CBOR unsigned integer. This is the same construction already used for StateID and for the signature preimage.

Shared test vector:

txhash = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
τ      = 1755000000
preimage = 825820000102…1e1f 1a689b2cc0
v      = 0235bd52cfa10c9785dfa01942bc396f201fe715dbc3896ee117a97e895e1e36

Certification request. CertificationData carries τ_Q between the transaction hash and the witness, matching Q = (ρ, sthash, txhash, τ_Q, u). The aggregator never sees the transaction, so it needs the value explicitly to enforce expiry.

Inclusion proof. Carries τ. A verifier cannot recover it from the certificate chain, because an aggregator serves proofs against the current certified root rather than the one the leaf was created under.

Certified transaction. [ transaction, τ, inclusionProof ]. τ_Q is already inside element 0.

Admission rule. A request may be inserted only in a round whose reference time satisfies τ < τ_Q.

Scope in this SDK

Reference time is carried, not read off the proof

τ used to be recoverable as inclusionProof.unicityCertificate.inputRecord.timestamp. That is correct only for the proof issued in the transition's own round: the SMT is append-only, an aggregator may serve a proof against any later certified root, and such a proof carries a later round's IR.t. τ becomes a field of the certified transaction, fixed at the moment the transaction is bound to its first proof, and every later verification uses the carried value.

Changes

  • Inclusion proof gains the round reference time returned by the aggregator, so a client can learn τ when it first fetches a proof.
  • Inclusion proof verification takes τ as an argument and reconstructs the root from the leaf value SHA-256(CBOR([txhash, τ])) instead of from the bare transaction hash. A mismatch fails the proof, which is the yellowpaper's require H(txhash, τ) = π.v.
  • Certified mint and transfer transactions carry τ and expose it. Callers that bind a transaction to a proof take τ from the proof they are binding to; callers that re-verify an existing token use the carried τ.
  • Predicate evaluation receives the carried τ rather than one derived from whichever proof is attached.

Wire format

InclusionProof         [version, certificationData, τ, inclusionCertificate, unicityCertificate]
certified transaction  [transaction, τ, inclusionProof]

Notes

Non-backward-compatible. There is no mainnet, so no migration path is required, but tokens serialised before the change will not verify afterwards.

Acceptance criteria

  • Verification of a token never reads τ from a unicity certificate.
  • A token whose carried τ does not reproduce the certified leaf value is rejected.
  • A proof fetched against a later root still verifies a transition certified earlier.
  • Leaf-value encoding pinned by a test vector shared with the other implementations.

Touch points

api/InclusionProof.java, api/CertificationData.java, transaction/verification/InclusionProofVerificationRule.java, transaction/CertifiedMintTransaction.java, transaction/CertifiedTransferTransaction.java, transaction/Token.java, util/InclusionProofUtils.java, predicate/verification/PredicateVerifierService.java.


Cross-repository change. The same encoding lands in aggregator-go, rugregator, bft-core (branch l1, consistency proof only) and the three state transition SDKs, and is switched on across the deployment in one coordinated step. Cross-implementation test vectors are part of the work.

Companion issues

Repository Reference time in the leaf value Request timeout
aggregator-go unicitynetwork/aggregator-go#176 unicitynetwork/aggregator-go#177
rugregator ristik/rugregator#3 ristik/rugregator#4
bft-core (branch l1) unicitynetwork/bft-core#23 (RSMT), unicitynetwork/bft-core#24 (ZK) out of scope
state-transition-sdk-js unicitynetwork/state-transition-sdk-js#144 unicitynetwork/state-transition-sdk-js#145
state-transition-sdk-java #81 #82
state-transition-sdk-rust unicitynetwork/state-transition-sdk-rust#16 unicitynetwork/state-transition-sdk-rust#17

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions