Asset Signature Verification

Cryptographic digital signatures in Numbers

The Numbers Protocol employs the Asset Tree Signature to ensure the integrity of on-chain asset tree data. Furthermore, it utilizes the Creator Signature, generated with the creator's integrity wallet key, to strengthen the provenance and authenticity of the asset.

Asset Tree Signature Verification

The most simple way to retrieve on-chain commit data which includes Asset Tree and Asset Tree Signature is install the Nit CLI tool, initialize the Nit config following the repository's readme to use Numbers mainnet, and use the nit log <nid> command to list all commit data found on Numbers mainnet.

yarn global add @numbersprotocol/nit

# Run this if you don't have yarn global bin in your PATH
echo 'export PATH="$(yarn global bin):$PATH"' >> ~/.bashrc
source ~/.bashrc

nit init

Example nit log command:

$ nit log bafkreifsitvutdqggqt2i3ag32tvw6g67bweszkrdtbm44vebfxpqs55m4                                                                                                         19:30:20 
Total Commit number: 1

block number: 387179
tx: 0x7ec4c829f6ebf104443b251356586fe5016b26268538bc4d81d61f128f192d80
{
  "assetTreeCid": "bafkreigdpjluexw5ponbonhw5tnqltp3ijrbak2ouja5xjpoh23exj3hmm",
  "assetTreeSha256": "c37a57425edd7b9a1734f6ecdb05cdfb4262102b4ea241dba5ee3eb64ba76763",
  "assetTreeSignature": "0x62fc4e51d51cf5627bb096acc7a5ab404df2a70fea9bcf902d4959dbf69accf102c714c90a3262001aa552cd7d95d5299ecd954dda4aae010e0628a6131691471c",
  "author": "0x114e5E0dce98180c98ADC62E9Ac6Ea7184417ecd",
  "committer": "0x51130dB91B91377A24d6Ebeb2a5fC02748b53ce1",
  "provider": "bafkreigrt5tepycewppysdwcjccdkdvvc2ztelqv64idgautq52g3vfh4i",
  "action": "bafkreicptxn6f752c4pvb6gqwro7s7wb336idkzr6wmolkifj3aafhvwii",
  "actionResult": "https://bafkreigdpjluexw5ponbonhw5tnqltp3ijrbak2ouja5xjpoh23exj3hmm.ipfs.dweb.link",
  "abstract": "Asset was created by 0xB36BcD7ce1940814DB3cBBb228e8CD78D776748E.",
  "timestampCreated": 1717064256,
  "actionName": "action-initial-registration-jade"
}

By using the committer, assetTreeSha256 and assetTreeSignature the identify of the committer could be verified by verifying the Asset Tree Signature is created by the committer's private key. Below is the minimal example code to perform the verification for Asset Tree Signature.

import * as nit from "@numbersprotocol/nit";

async function verifySignature(committer, assetTreeSha256, assetTreeSignature) {
  const recoveredAddress = await nit.verifyIntegrityHash(
    assetTreeSha256,
    assetTreeSignature
  );

  if (recoveredAddress === committer) {
    console.log("Signature is valid!");
  } else {
    console.log("Signature is invalid.");
  }
}

const committer = "0x51130dB91B91377A24d6Ebeb2a5fC02748b53ce1";
const assetTreeSha256 =
  "8632694ee8a9f8a5a238105512bd2b0407088a64370ebce2b583ce4025199731";
const assetTreeSignature =
  "0x7ff29ac295947eb5d5a7e1c104fe34f4064434c0cbcb635443f0aeee627f31304a8ad2cfb5885cacd4129dfd006f0dbafd4d92db0d8f81bd46c4802c3d055d1a1b";
verifySignature(committer, assetTreeSha256, assetTreeSignature);

Creator Signature Verification

To verify Creator Signature, obtain the signed_metadata and signature following the steps in Query Assets section. The below example code demonstrate the verification steps.

import * as nit from "@numbersprotocol/nit";
import { ethers } from "ethers";

async function verifySignature(signedMetadataJSON, signatureJSON) {
  const signatureObject = JSON.parse(signatureJSON);
  const integritySha = await nit.getIntegrityHash(
    ethers.toUtf8Bytes(signedMetadataJSON)
  );
  if (integritySha === signatureObject.integritySha) {
    console.log("integritySha is correct!");
  } else {
    console.log("integritySha is incorrect.");
  }

  const recoveredAddress = await nit.verifyIntegrityHash(
    signatureObject.integritySha,
    signatureObject.signature
  );

  if (recoveredAddress === signatureObject.publicKey) {
    console.log("Signature is valid!");
  } else {
    console.log("Signature is invalid.");
  }
}

// Replace these value with your actual signed_metadata and signature
const signedMetadataJSON = `{
  "asset_mime_type": "image/png",
  "caption": "",
  "created_at": 1701688997,
  "proof_hash": "01b0d72b491486379e9657eaf960e1ab114fbe6479a757fdaf2144dc9d654d58",
  "recorder": "Capture",
  "spec_version": "2.0.0"
}`;
const signatureJSON =
  '{"proofHash":"01b0d72b491486379e9657eaf960e1ab114fbe6479a757fdaf2144dc9d654d58","provider":"ExampleCaptureSignatureProvider","signature":"0xa6615b4a6a563eaf89e000c6f7b46bcb3f4fabb90438cc44e46c9ff282e4ef857352735e051637f2737d7d30d8f8a3dd9d048b102413751ac06a96376042e3061b","publicKey":"0x114e5E0dce98180c98ADC62E9Ac6Ea7184417ecd","integritySha":"39c8352f98872ce41fc79c2446f2fa6903fa68f73d6b2cb99f843844e5e01291"}';

verifySignature(signedMetadataJSON, signatureJSON);

The implementation detail of nit.verifyIntegrityHash can also be found on the Nit Github Repository page.

Last updated