{
  "tool_id": "art-605-merkle-airdrop-proof-verifier",
  "tool_version": "1.0.0",
  "display_name": "Merkle Airdrop-Proof Verifier",
  "mcp_name": "verify_merkle_airdrop_proof",
  "mandate_type": "payment_policy",
  "wave": 99,
  "gpu": false,
  "url": "https://ainumbers.co/chaingraph/art-605-merkle-airdrop-proof-verifier.html",
  "description": "Recomputes a Merkle airdrop-claim proof from caller-declared leaf fields (address, uint256 amount, encoding_variant) and a sibling path, OpenZeppelin MerkleProof.verify shape (processProof/_hashPair over chaingraph/kernels/_noble-secp256k1.bundle.mjs's already-vendored keccak256, no new vendoring, no hand-rolled hashing). Leaf derivation follows OpenZeppelin StandardMerkleTree's (address,uint256) convention: encoding_variant selects the double-hash leaf (keccak256(keccak256(abi.encode(address,amount))), the default, second-preimage-resistant) or a single-hash variant some deployed contracts use instead -- never assumed, always a declared param. Sibling-pair hashing is sorted/commutative (OpenZeppelin's default _hashPair, pair_sort:true) or explicit per-step left/right position (pair_sort:false) -- also a declared param, never an assumption. Given an optional claimed_path (a prior run's per-step running hashes), re-verifies and reports the earliest step at which the recompute diverges, instead of only a final match/no-match. This node never reads any chain: it cannot know whether claimed_root is the root actually recorded on-chain, whether the leaf's allocation was already claimed or redeemed, or whether the underlying tree was built correctly from the full allocation list -- it only recomputes hashes from what the caller supplies.",
  "input_schema_ref": "chaingraph/art-605-merkle-airdrop-proof-verifier.html#manifest",
  "consumes": [],
  "feeds": [],
  "status": "live",
  "conformance_fixtures": true,
  "compute_capability": "server",
  "compute_images": [{"system":"sha256-source","image_id":"sha256:b4ca349f69674d520b252804bfdcfb4e76d917db449c46bfdfa2ac1632ea2763","valid_from":"2026-07-10"},{"system":"risc0","image_id":"sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6","valid_from":"2026-08-12"}],
  "export_capability": [
    "json"
  ],
  "compute_proof": {
    "type": "ZkVmReceipt",
    "system": "risc0",
    "receiptFormat": "groth16-bn254",
    "imageId": "sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6",
    "seal": "EnwShRVRCe+EokZO0qY2LVcVEbroE7yRTJRzYaLSVH8vkHTMuvigICDkBaNa9vtNp+D1DLxvHhLF5S0SX/bsgxQlqSfp2F3qSP6KsLLdodCCY400ejNUVEFl292yHo8vGiQpqKzyHwOCd/8jycj3c1fr5QqPAVuhF+K6S+AoccYQKEO1YS3X65fuMOEnynhOeQrthZUGEM6hR1QBekavcCb26zOIUshCJYgLFJWWjVmnfZU1i7BfjwX0b+kTp90GCGqNPMfTQs4sgNyDf6SwWAQB7WNeJf9f4en1DXjnlEIr7WomnE0R+C1BCvin35UENE5+6KrWhDXV3sk4eZmyPg==",
    "journal": {
      "chaingraph_version": "0.4.0",
      "kernel_digest": "sha256:b4ca349f69674d520b252804bfdcfb4e76d917db449c46bfdfa2ac1632ea2763",
      "output": {
        "computed_root": "0xb38ec842db1cd54e5e5ce48491f1a404551e9726ebda349d0478e189e0996dd4",
        "encoding_variant_used": "double-hash",
        "first_divergent_step": null,
        "leaf": "0xb38ec842db1cd54e5e5ce48491f1a404551e9726ebda349d0478e189e0996dd4",
        "note": "Pure hash recomputation over caller-declared leaf fields and sibling path -- OpenZeppelin MerkleProof.verify shape (leaf, then _hashPair per proof step, compared to claimed_root). This kernel does NOT know whether claimed_root is the root actually recorded on any chain, whether this leaf's airdrop allocation has already been claimed/redeemed, whether the underlying Merkle tree was constructed correctly from the full allocation list, or who controls the address. It only reports whether the supplied leaf + proof recompute to claimed_root, and (when a claimed_path is supplied for re-verification) the earliest step at which the recompute diverges from that claim.",
        "pair_sort_used": true,
        "path": [],
        "path_intact": null,
        "reasons": [],
        "root_matches_claimed": true
      }
    }
  }
}
