twzrd-receipt-verifier 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -14
- package/package.json +2 -3
- package/verify_twzrd_receipt.js +36 -10
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# TWZRD Receipt Verifier (standalone)
|
|
2
2
|
|
|
3
|
-
Verify a
|
|
4
|
-
|
|
3
|
+
Verify a TWZRD **AO-Receipt V5** offline, trusting **nothing from TWZRD's servers
|
|
4
|
+
or codebase** - only the receipt, TWZRD's published public key, and two
|
|
5
5
|
widely-audited crypto libraries.
|
|
6
6
|
|
|
7
7
|
A TWZRD trust receipt has two layers:
|
|
@@ -32,16 +32,6 @@ npx twzrd-receipt-verifier receipt.json --pubkey 9V6Pn19kiUA5Rn6JpQfNduanvGt2aXG
|
|
|
32
32
|
npx twzrd-receipt-verifier receipt.json --pubkey 9V6Pn19kiUA5Rn6JpQfNduanvGt2aXGwsarosNfa2Ldf --max-age 60
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
## Ingest the corpus
|
|
36
|
-
|
|
37
|
-
The receipts this tool verifies are issued from the only live cross-facilitator x402
|
|
38
|
-
payer corpus on Solana. Pull the scored signal population as a feed (no auth, paginated):
|
|
39
|
-
|
|
40
|
-
curl -s 'https://intel.twzrd.xyz/v1/intel/corpus_feed?limit=5' | jq .
|
|
41
|
-
|
|
42
|
-
Browser demo: https://twzrd.xyz/demo/ingest/ · schema: https://intel.twzrd.xyz/docs ·
|
|
43
|
-
ingestion pilots: https://twzrd.xyz/grants (email privacy@twzrd.xyz).
|
|
44
|
-
|
|
45
35
|
## The published signing key
|
|
46
36
|
|
|
47
37
|
| field | value |
|
|
@@ -60,8 +50,8 @@ Also published, machine-readable, at:
|
|
|
60
50
|
|
|
61
51
|
## Get a receipt to verify
|
|
62
52
|
|
|
63
|
-
Any
|
|
64
|
-
|
|
53
|
+
Any TWZRD V5 receipt works. To mint a fresh one, pay the trust endpoint (x402,
|
|
54
|
+
0.05 USDC on Solana mainnet) - e.g. via AgentCash:
|
|
65
55
|
|
|
66
56
|
```bash
|
|
67
57
|
npx agentcash@latest fetch https://intel.twzrd.xyz/v1/intel/trust/<PUBKEY> > resp.json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twzrd-receipt-verifier",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Standalone offline verifier for TWZRD AO-Receipt V5 (Ed25519-signed keccak256 leaf). No trust in TWZRD servers or code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twzrd",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"LICENSE"
|
|
34
34
|
],
|
|
35
35
|
"scripts": {
|
|
36
|
-
"verify": "node verify_twzrd_receipt.js"
|
|
37
|
-
"test": "node --test test/*.test.js"
|
|
36
|
+
"verify": "node verify_twzrd_receipt.js"
|
|
38
37
|
},
|
|
39
38
|
"engines": {
|
|
40
39
|
"node": ">=16"
|
package/verify_twzrd_receipt.js
CHANGED
|
@@ -37,6 +37,29 @@ function b58decode(s) { return Buffer.from(bs58.decode(s)); }
|
|
|
37
37
|
|
|
38
38
|
function u16le(n) { const b = Buffer.alloc(2); b.writeUInt16LE(n & 0xffff, 0); return b; }
|
|
39
39
|
function u64le(n) { const b = Buffer.alloc(8); b.writeBigUInt64LE(BigInt(n), 0); return b; }
|
|
40
|
+
function i64le(n) { const b = Buffer.alloc(8); b.writeBigInt64LE(BigInt(n), 0); return b; }
|
|
41
|
+
|
|
42
|
+
// V6 reputation block: 1-byte presence flag (0x00 null / 0x01 present) + fixed-width
|
|
43
|
+
// value when present. reputation_score is i64 LE (null-vs-0 safe); version/quality
|
|
44
|
+
// are u16-len-prefixed UTF-8; feature_window is u64 LE. "" is present (distinct from
|
|
45
|
+
// null). Mirrors the issuer's RECEIPT_V6_LEAF_SPEC.md byte layout exactly.
|
|
46
|
+
function encodeReputationBlockV6(pre) {
|
|
47
|
+
const optInt = (v, enc) => (v === null || v === undefined)
|
|
48
|
+
? Buffer.from([0x00])
|
|
49
|
+
: Buffer.concat([Buffer.from([0x01]), enc(v)]);
|
|
50
|
+
const optStr = (v) => {
|
|
51
|
+
if (v === null || v === undefined) return Buffer.from([0x00]);
|
|
52
|
+
const raw = Buffer.from(String(v), 'utf8');
|
|
53
|
+
return Buffer.concat([Buffer.from([0x01]), u16le(raw.length), raw]);
|
|
54
|
+
};
|
|
55
|
+
return Buffer.concat([
|
|
56
|
+
optInt(pre.reputation_score, i64le),
|
|
57
|
+
optInt(pre.reputation_confidence_bps, u16le),
|
|
58
|
+
optStr(pre.reputation_score_version),
|
|
59
|
+
optInt(pre.reputation_feature_window_start_unix, u64le),
|
|
60
|
+
optStr(pre.reputation_data_quality),
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
40
63
|
|
|
41
64
|
function payer32(payer) {
|
|
42
65
|
try { const raw = b58decode(payer); if (raw.length === 32) return raw; } catch (_) {}
|
|
@@ -51,12 +74,19 @@ function anchor32(tx) {
|
|
|
51
74
|
}
|
|
52
75
|
|
|
53
76
|
function recomputeLeaf(pre) {
|
|
77
|
+
// Use the exact domain the receipt carries. V6 binds reputation_* into the leaf
|
|
78
|
+
// (V5 left them unsigned/forgeable); a V6 receipt verified with V5 rules would
|
|
79
|
+
// fail on a legitimate receipt, so the block is appended whenever domain is _V6.
|
|
54
80
|
const dom = String(pre.domain || '').toUpperCase();
|
|
81
|
+
const isV6 = dom.includes('_V6');
|
|
55
82
|
const isAttention = dom.includes('ATTENTION');
|
|
56
|
-
const
|
|
83
|
+
const domainStr = isAttention
|
|
84
|
+
? (isV6 ? 'TWZRD:AO_ATTENTION_RECEIPT_V6' : 'TWZRD:AO_ATTENTION_RECEIPT_V5')
|
|
85
|
+
: (isV6 ? 'TWZRD:AO_REPUTATION_RECEIPT_V6' : 'TWZRD:AO_REPUTATION_RECEIPT_V5');
|
|
86
|
+
const domain = Buffer.from(domainStr, 'ascii');
|
|
57
87
|
const score = isAttention ? (pre.attention_score || 0) : (pre.score || 0);
|
|
58
88
|
const agent = Buffer.from(pre.agent_id, 'utf8');
|
|
59
|
-
const
|
|
89
|
+
const parts = [
|
|
60
90
|
domain,
|
|
61
91
|
u16le(agent.length), agent,
|
|
62
92
|
u16le(score),
|
|
@@ -64,8 +94,9 @@ function recomputeLeaf(pre) {
|
|
|
64
94
|
u64le(pre.timestamp_unix),
|
|
65
95
|
payer32(pre.payer),
|
|
66
96
|
anchor32(pre.settlement_tx || pre.settlement_anchor),
|
|
67
|
-
]
|
|
68
|
-
|
|
97
|
+
];
|
|
98
|
+
if (isV6) parts.push(encodeReputationBlockV6(pre));
|
|
99
|
+
return Buffer.from(keccak256.arrayBuffer(Buffer.concat(parts)));
|
|
69
100
|
}
|
|
70
101
|
|
|
71
102
|
function fetchPublishedPubkey(baseUrl) {
|
|
@@ -220,9 +251,4 @@ key source: ${DEFAULT_BASE_URL}/.well-known/x402`;
|
|
|
220
251
|
process.exit(ok ? 0 : 1);
|
|
221
252
|
}
|
|
222
253
|
|
|
223
|
-
|
|
224
|
-
if (require.main === module) {
|
|
225
|
-
main().catch((e) => { console.error('error:', e.message); process.exit(1); });
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
module.exports = { verify, recomputeLeaf, b58decode, payer32, anchor32 };
|
|
254
|
+
main().catch((e) => { console.error('error:', e.message); process.exit(1); });
|