twzrd-receipt-verifier 1.0.5 → 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/package.json +12 -2
- package/verify_twzrd_receipt.js +35 -4
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
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
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"twzrd",
|
|
7
|
+
"x402",
|
|
8
|
+
"solana",
|
|
9
|
+
"ed25519",
|
|
10
|
+
"keccak256",
|
|
11
|
+
"receipt",
|
|
12
|
+
"verifier",
|
|
13
|
+
"agent",
|
|
14
|
+
"attestation"
|
|
15
|
+
],
|
|
6
16
|
"homepage": "https://intel.twzrd.xyz",
|
|
7
17
|
"bugs": {
|
|
8
18
|
"url": "https://github.com/twzrd-sol/wzrd-final/issues"
|
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) {
|