Skip to content

InclusionProofV2.Verify is missing SDK shard and network binding checks #185

Description

@ristik

Summary

pkg/api.InclusionProofV2.Verify omits two checks performed by the JavaScript, Java, and Rust state-transition SDK verifiers:

  1. the state ID must belong to the shard named by the UC's ShardTreeCertificate; and
  2. the UC seal network ID must equal the trust-base network ID.

As a result, the published Go verifier accepts a validly certified leaf from the wrong shard when the caller supplies that shard as VerifierContext.ExpectedShardID. It also accepts a seal whose NetworkID differs from TrustBase.GetNetworkID() when the same validator keys can satisfy the trust base.

This supersedes the Yellowpaper-driven remediation proposed in #183. The SDK implementations are the compatibility target here and do not require a partition-description or sharding-scheme input.

SDK behavior

All three SDKs independently enforce the same relation:

  • derive the state ID from certification/transaction data;
  • verify the SMT path against UC.IR.h;
  • require UC.ShardTreeCertificate.Shard to be a prefix of the state ID;
  • require UC.UnicitySeal.NetworkID == TrustBase.NetworkID; and
  • verify the UC root and quorum signatures.

Relevant implementations:

  • JS: src/transaction/verification/rule/InclusionProofVerificationRule.ts, ShardIdMatchesStateIdRule.ts, and api/bft/verification/UnicityCertificateVerifier.ts
  • Java: transaction/verification/InclusionProofVerificationRule.java, ShardIdMatchesStateIdRule.java, and api/bft/verification/UnicityCertificateVerification.java
  • Rust: src/verify/mod.rs::verify_inclusion_proof_for and verify_unicity_certificate

Current Go behavior

InclusionProofV2.Verify derives the SMT key from v2.StateID and verifies the path, then calls:

uc.Verify(vctx.TrustBase, crypto.SHA256, vctx.PartitionID, vctx.ExpectedShardID, vctx.ShardConfHash)

The BFT library checks only that the certificate shard equals the caller-supplied ExpectedShardID. It does not check that the shard prefix matches the state ID. UnicitySeal.Verify validates quorum signatures but does not compare the seal and trust-base network IDs.

The existing BFT sharding integration test derives ExpectedShardID from the endpoint that served the proof, so it does not cover a key committed under the wrong shard's otherwise valid UC.

Impact

The three state-transition SDKs are not affected. The affected surface is external users of the published Go pkg/api verifier.

In a multi-shard deployment, a faulty or Byzantine shard quorum can certify a state ID owned by another shard. A caller that uses the serving endpoint or UC to choose ExpectedShardID will accept the proof. Uniqueness is per shard tree, so the same state ID may then have accepted proofs in two shards.

The network mismatch is a domain-separation failure. It is exploitable when validator keys are reused across trust bases with different network IDs.

There are currently no non-test callers of InclusionProofV2.Verify inside this repository. Internal service paths use the deliberately local-only verifier in internal/proofverify/local.go.

Proposed fix

Bring the Go verifier into parity with the SDKs without changing VerifierContext:

  1. Validate that v2.StateID is derived from the request certification data.
  2. Require the proof certification data fields used to derive the state ID to match the request.
  3. After decoding the UC, require uc.ShardTreeCertificate.Shard.Comparator()(key).
  4. Require uc.UnicitySeal.NetworkID == vctx.TrustBase.GetNetworkID().
  5. Retain ExpectedShardID as an additional caller policy check for API compatibility.
  6. Add regression tests for a fully signed wrong-shard proof and for a signed seal with a mismatched network ID.

No full sharding scheme or partition descriptor is needed to match the SDK verifier behavior, and no public API break is required.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions