Fingerprint Verification

Purpose

Scope: Tasks from the Binance Booster Campaign.

Goal: Let contributors independently verify that their valid data contributions were correctly, completely, and tamper-proof recorded on-chain by comparing data fingerprints for consistency.


Preparation

Retrieve your on-chain fingerprint via the block explorer

Steps

  • Enter parameters:

    • user: your wallet address

    • page: page index, enter 0

    • size: items per page, enter 1000

  • Click Query to get the result:

    • rets: an array that may contain multiple records, in the shape [[submissionID, fingerprint]], where:

      • submissionID: e.g., 2025082903351000xxxxxx

      • fingerprint: e.g.,0x3f287de1fac99c807b8b23e67fa41b6e8547c45a7c37868f71457b1400xxxxxx

    • end: whether the query is finished

      • true: finished

      • false: not finished — increase page and repeat until end is true.

Note:

  • 1 fingerprint = 1 valid contribution.

  • The number of fingerprints equals the number of valid contributions recorded for that address.


Aggregate your contribution data

Your contribution consists of X-Data and Y-Data.

  • X-Data: original/raw data

  • Y-Data: annotated/label data

Example (food labeling task)

  • X-Data

    • Image (the original food image you uploaded)

  • Y-Data

    • Food Name

    • Food Category

    • Brand / Store

    • Region

    • Quantity of food

All of the above are user-submitted. You can reconstruct and save them yourself.Fill the template exactly as originally submitted

(replace the values in <>; if it was empty, use an empty string ""). Case, spaces, punctuation, and brackets must match exactly.

{
  "brand": "<brand/store at the time; empty string if none>",
  "images": [
    {
      "hash": "e6b024a0a5b3f202667300f3621190e666a52cadfd715664cd2e082cb0d3e03a"
    }
  ],
  "region": "the region you selected, e.g. PK",
  "foodName": "the Food Name you entered at the time",
  "quantity": "the exact dropdown text, e.g. Individual (1 person)",
  "foodCategory": "the exact category text you selected"
}

Image hashing: Because raw images are large, we typically include their SHA-256 hash in the fingerprint input.

  • Use an online tool (drag the image to the input box to get a SHA-256 hash), or

  • Compute it yourself with a script/tool of your choice.


Collect auxiliary fields

Alongside the contribution JSON, two auxiliary fields are used to generate the fingerprint:

  • Address* — your on-chain wallet address (identity).

  • Quality — the rating of your contribution. After task review, the Codatta platform evaluates authenticity/completeness and assigns a rating. Only rated contributions are considered valid and recorded. For the food labeling example, ratings (high → low) are: S, A, B, C, D.

Notes & strictness

  • Key names must mirror the task form exactly (e.g., foodName, foodCategory, region, quantity). Case and spelling must match the original form labels.

  • Include all fields you completed on the task form. If you filled fields not listed in the template, add them with the exact original labels and values.

  • Strict equality: any difference in key names / values / order (including spaces, case, punctuation) will change the fingerprint.

  • If you forgot your original entries, you may look them up on the Codatta platform (if available).


Generate the fingerprint (JCS → ABI.encode → keccak256)

Reconstruct the exact JSON from what you originally entered/uploaded in the form, then recompute the fingerprint locally using the public rules and compare it with the on-chain fingerprint, entry by entry, to complete independent verification.

Step 1 | JCS-canonicalize the contribution JSON → produce submissionData

Take the self-assembled raw JSON and canonicalize it using JCS. The canonicalized string is referred to as submissionData. You can follow the https://github.com/codatta/submission-data-fingerprint/blob/main/tools/jcs.js to implement this.

Step 2 | ABI-encode the contribution data together with the auxiliary fields (Solidity) → produce encodedData

Encode the tuple using Solidity ABI. You can implement this with ethers.js; an example is shown below (running it will output encodedData).

const encodedData = ethers.AbiCoder.defaultAbiCoder().encode(
        ["address", "string", "string"],
        [address, quality, submissionData]
    );

quality accepts "S","A","B","C","D"," (use empty string "" if the task had no rating)You can follow the https://github.com/codatta/submission-data-fingerprint/blob/main/tools/fingerprint.js#L8 to implement this。

Step 3 | Compute keccak256 → obtain the local fingerprint localFingerprint

Compute it with the following ethers.js code.

const hash = ethers.keccak256(encodedData);

The calculation yields a 0x… value — that is the localFingerprint. You can follow the https://github.com/codatta/submission-data-fingerprint/blob/main/tools/fingerprint.js#L14 to implement this。

Step 4 | Verify

Using the on-chain fingerprint obtained in Retrieve your on-chain fingerprint via the block explorer, compare it with localFingerprint:

Result semantics

  • localFingerprint == onChainFingerprintVerification successful

    This JSON matches the fingerprint recorded on-chain; your data has not been tampered with.

  • No on-chain fingerprint found for the specified address / submission → This address has no contribution attested on-chain.

  • localFingerprint != onChainFingerprintVerification failed

    A step may be incorrect; please recheck your JSON/address/quality or contact support.

When your locally recomputed fingerprints match the on-chain records entry by entry, it proves that all corresponding contributions have been completely, correctly, and immutably recorded on-chain.

Verify Fingerprint

https://onchain-data-verify.codatta.io/

Last updated

Was this helpful?