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 CHANGED
@@ -1,8 +1,18 @@
1
1
  {
2
2
  "name": "twzrd-receipt-verifier",
3
- "version": "1.0.5",
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": ["twzrd", "x402", "solana", "ed25519", "keccak256", "receipt", "verifier", "agent", "attestation"],
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"
@@ -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 domain = Buffer.from(isAttention ? 'TWZRD:AO_ATTENTION_RECEIPT_V5' : 'TWZRD:AO_REPUTATION_RECEIPT_V5', 'ascii');
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 msg = Buffer.concat([
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
- return Buffer.from(keccak256.arrayBuffer(msg));
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) {