← Back to Documentation
FeedOracle

Evidence Verification Guide

Schema: treasury-audit/2.5 + treasury-scenarios/1.2 · Independent 6-step verification

📦 Verifier Kit (Download)

verify_response.py verify_response.js Test Vector (Response) Test Vector (Request) Expected Hash RELEASE.json Release Signature py.sha256 js.sha256 response.sha256

Python: pip install ecdsa · Node.js: zero dependencies (built-in crypto)

1 Get a response

curl -s -X POST https://api.feedoracle.io/api/v2/risk/treasury-audit \
  -H "Content-Type: application/json" \
  -d '{"holdings":{"USDT":5000000,"USDC":3000000}}' \
  -o response.json

Or use the static test vector for offline verification.

2 Remove /evidence + /manifest_id

Per hash_scope.exclude_paths: ["/evidence", "/manifest_id"], strip evidence and manifest_id keys.

body = {k: v for k, v in response.items() if k not in ("evidence", "manifest_id")}

3 JCS Canonicalize (RFC 8785)

Sort keys, no whitespace.

# Python
canon = json.dumps(body, sort_keys=True, separators=(",",":"))

// Node.js — recursive key sort
function jcs(obj) {
  if (obj === null || typeof obj !== 'object') return JSON.stringify(obj);
  if (Array.isArray(obj)) return '[' + obj.map(jcs).join(',') + ']';
  return '{' + Object.keys(obj).sort()
    .map(k => JSON.stringify(k) + ':' + jcs(obj[k])).join(',') + '}';
}

4 SHA-256 → must match evidence.content_hash.hex

computed = hashlib.sha256(canon.encode()).hexdigest()
assert computed == response["evidence"]["content_hash"]["hex"]

If MATCH — the response body has not been tampered with.

5 Load public key from JWKS

curl -s https://feedoracle.io/.well-known/jwks.json

Select key matching evidence.key_id (feedoracle-prod-2026). Curve: secp256k1.

6 Verify ECDSA signature

Signature is raw r||s hex (64 bytes) over the SHA-256 digest from Step 4.
signed_over.field: /evidence/content_hash/hex

# Python (pip install ecdsa)
vk.verify_digest(sig_bytes, digest)

// Node.js (built-in crypto)
crypto.verify('sha256', Buffer.from(canon), pubKey, derSig)

If SIGNATURE VALID — the response was produced by FeedOracle's signing key.

Quick Run: Download the verifier kit and run:
python3 verify_response.py test_response.json or node verify_response.js test_response.json
Both produce HASH MATCH Yes + SIGNATURE VALID Yes. Works with both /treasury-audit and /scenarios responses.
Applies to both endpoints:
POST /api/v2/risk/treasury-audit (schema: treasury-audit/2.5)
POST /api/v2/risk/treasury-audit/scenarios (schema: treasury-scenarios/1.2)
Same evidence structure, same verification procedure, same signing key.

7 Verify the Verifier Kit (Supply Chain)

The entire kit is a signed release. Download and verify locally:

python3 verify_response.py --verify-release .
node verify_response.js --verify-release .

This checks: manifest hash, ES256K signature via JWKS, and every file hash + size.

Result: ALL VERIFIED = the kit is exactly what FeedOracle published.

RELEASE.json · SHA-256 · Signature