New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@fairseal/verify

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fairseal/verify

Independent verification for VEO-2 objects — structure, integrity, Ed25519 signatures, and on-chain Merkle anchors. Zero dependencies beyond @fairseal/core.

Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
22
-89.27%
Maintainers
1
Weekly downloads
 
Created
Source

@fairseal/verify

Part of FairSeal — formerly OpenRNG.

Independent verification for VEO-2 (Verifiable Execution Object) records.

A VEO is only worth something if a third party can check it without trusting the party that issued it. This package is that checker. It has zero dependencies beyond @fairseal/core — an independent verifier shouldn't require you to install more than the thing it verifies.

npm install @fairseal/verify

Quick Start

import { verifyVEO } from '@fairseal/verify';

const result = verifyVEO(veo, { trustedKeys: [OUR_PUBLIC_KEY] });
if (!result.valid) console.error(result.errors);

Looking to verify a Committed Selection Receipt (CSReceipt)? That lives in @fairseal/commit — use its verifyReceipt(receipt), which returns status: 'VALID' | 'PARTIAL' | 'INVALID'. This package (@fairseal/verify) verifies VEO objects — structure, integrity, signature, and on-chain anchor.

Four separate questions

FunctionQuestion it answersNetwork?
verifyStructure(veo)Is this a well-formed VEO-2?no
verifyIntegrity(veo)Has it been modified since it was signed?no
verifySignature(veo, trustedKeys?)Was it signed by a key I trust?no
verifyAnchor(veo, rpcUrl?)Is its Merkle root really on chain?yes

verifyVEO() runs the first three together and is what most callers want.

Quick start

import { verifyVEO } from '@fairseal/verify';

const result = verifyVEO(veo, { trustedKeys: [OUR_PUBLIC_KEY] });

if (result.valid) {
  console.log('verified');
} else {
  console.error(result.errors);
  console.error(result.checks); // per-check pass / fail / skipped
}

verifyVEO() is synchronous and never touches the network, so it is safe to run on untrusted input inside a request handler.

verifyVEO(veo, options?)

interface VerifyOptions {
  trustedKeys?: string[];      // PEM or raw 32-byte hex
  requireSignature?: boolean;  // default: true
}

interface VerificationResult {
  valid: boolean;
  checks: {
    structure: { status: 'pass' | 'fail' | 'skipped'; detail?: string };
    integrity: { status: 'pass' | 'fail' | 'skipped'; detail?: string };
    signature: { status: 'pass' | 'fail' | 'skipped'; detail?: string };
  };
  errors: string[];    // why it failed
  warnings: string[];  // what the result does *not* prove
}

Defaults are fail-closed. An unsigned object is not valid unless you pass { requireSignature: false }, and an empty trustedKeys array trusts nobody.

What a signature actually proves

This is the part most verifiers get wrong, so the API is explicit about it:

// Proves: not modified since signing.
// Does NOT prove: who signed it. Anyone can generate a keypair.
verifyVEO(veo);
// → valid: true, warnings: ['Signature was verified against the public key
//    embedded in the object…']

// Proves: signed by a key you decided to trust, and not modified since.
verifyVEO(veo, { trustedKeys: [OUR_PUBLIC_KEY] });
// → valid: true, warnings: []

If you are verifying someone else's VEO, always pass trustedKeys. A VEO that verifies against its own embedded key is self-consistent, not authentic.

verifyAnchor(veo, rpcUrl?)

Anchored VEOs (class VEO-2C) claim "this Merkle root was written to chain X in transaction Y". A signature over that claim only proves the issuer said so — confirming it means reading the chain back.

import { verifyAnchor } from '@fairseal/verify';

const result = await verifyAnchor(veo);                        // public RPC for the chain
const result = await verifyAnchor(veo, 'https://my-rpc.example'); // your own node
const result = await verifyAnchor(veo, { offline: true });     // local checks only

Three independent checks, strongest last:

  • merkleProof — the object's leaf hashes up to anchor.merkle_root (local, no network).
  • transaction — the anchor transaction succeeded and emitted a BatchAnchored event carrying that exact root, from the expected contract.
  • contractState — getBatchRoot(anchor.batch_id) on the contract still returns that root. Skipped when batch_id is absent from the anchor record.
interface AnchorVerifyOptions {
  rpcUrl?: string;      // defaults to a public endpoint for anchor.chain
  offline?: boolean;    // skip all network calls
  timeoutMs?: number;   // per request, default 15000
  fetch?: FetchLike;    // inject a transport (tests, proxies)
  leafHash?: string;    // defaults to metadata._content_hash, then entropy_hash
}

verifyAnchor() never throws on network failure. An unreachable RPC yields valid: false with the check marked skipped, so you can tell "could not check" apart from "checked and wrong":

if (!result.valid && result.checks.transaction.status === 'skipped') {
  // RPC problem, not a bad anchor — retry later.
}

Supported chain

Anchoring currently runs on Polygon Amoy testnet against the MerkleAnchor contract at 0xA79E149C35Ad47Ed270Bf4b16B80170eBF7B88F8. Mainnet deployment is planned. See the root README for the full anchoring architecture.

Default RPC endpoints (DEFAULT_RPC_URLS) are provided for polygon-amoy and polygon-mainnet. For any other chain, pass rpcUrl explicitly.

Merkle helpers

Exported for building your own tooling:

import { verifyMerklePath, computeMerkleRoot } from '@fairseal/verify';

verifyMerklePath(leafHash, [{ hash: sibling, position: 'right' }], root);

Nodes are lowercase hex strings, and a parent is sha256(leftHex + rightHex) over the concatenated hex text — matching FairSeal's tree construction. position names the side the sibling sits on.

Verifying without this package

Everything here is deliberately reproducible from the spec. A verifier in another language needs: SHA-256, Ed25519, canonical JSON (sorted keys, undefined dropped), and an Ethereum JSON-RPC client. See docs/rfc/RFC-0002-VEO2.md and packages/core/veo-2.schema.json.

License

MIT

Keywords

openrng

FAQs

Package last updated on 19 Aug 2026

Related posts