@mneme-ai/core 2.19.18 → 2.19.20
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/dist/caption_inpaint/caption_inpaint.test.d.ts +2 -0
- package/dist/caption_inpaint/caption_inpaint.test.d.ts.map +1 -0
- package/dist/caption_inpaint/caption_inpaint.test.js +481 -0
- package/dist/caption_inpaint/caption_inpaint.test.js.map +1 -0
- package/dist/caption_inpaint/index.d.ts +168 -0
- package/dist/caption_inpaint/index.d.ts.map +1 -0
- package/dist/caption_inpaint/index.js +366 -0
- package/dist/caption_inpaint/index.js.map +1 -0
- package/dist/caption_severance/index.d.ts +46 -0
- package/dist/caption_severance/index.d.ts.map +1 -1
- package/dist/caption_severance/index.js +39 -0
- package/dist/caption_severance/index.js.map +1 -1
- package/dist/cosmic/aurelian_v1919.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1919.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1919.test.js +34 -0
- package/dist/cosmic/aurelian_v1919.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1920.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1920.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1920.test.js +61 -0
- package/dist/cosmic/aurelian_v1920.test.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/provenance_dna/index.d.ts +115 -0
- package/dist/provenance_dna/index.d.ts.map +1 -0
- package/dist/provenance_dna/index.js +242 -0
- package/dist/provenance_dna/index.js.map +1 -0
- package/dist/provenance_dna/provenance_dna.test.d.ts +2 -0
- package/dist/provenance_dna/provenance_dna.test.d.ts.map +1 -0
- package/dist/provenance_dna/provenance_dna.test.js +279 -0
- package/dist/provenance_dna/provenance_dna.test.js.map +1 -0
- package/dist/reverse_caption_injection/index.d.ts +91 -0
- package/dist/reverse_caption_injection/index.d.ts.map +1 -0
- package/dist/reverse_caption_injection/index.js +162 -0
- package/dist/reverse_caption_injection/index.js.map +1 -0
- package/dist/reverse_caption_injection/reverse_caption_injection.test.d.ts +2 -0
- package/dist/reverse_caption_injection/reverse_caption_injection.test.d.ts.map +1 -0
- package/dist/reverse_caption_injection/reverse_caption_injection.test.js +177 -0
- package/dist/reverse_caption_injection/reverse_caption_injection.test.js.map +1 -0
- package/dist/textron_captcha/index.d.ts +147 -0
- package/dist/textron_captcha/index.d.ts.map +1 -0
- package/dist/textron_captcha/index.js +255 -0
- package/dist/textron_captcha/index.js.map +1 -0
- package/dist/textron_captcha/textron_captcha.test.d.ts +2 -0
- package/dist/textron_captcha/textron_captcha.test.d.ts.map +1 -0
- package/dist/textron_captcha/textron_captcha.test.js +231 -0
- package/dist/textron_captcha/textron_captcha.test.js.map +1 -0
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +16 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +22 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.20 — MNEME PROVENANCE-BY-DNA-HASH
|
|
3
|
+
*
|
|
4
|
+
* Every product image gets a PERCEPTUAL HASH ("DNA fingerprint") so
|
|
5
|
+
* slightly-resized / re-compressed copies still match the original.
|
|
6
|
+
* Mneme records {pHash, claim, sellerFingerprint, ts} per query.
|
|
7
|
+
* After 90 days of history, 3 flagging algorithms surface:
|
|
8
|
+
*
|
|
9
|
+
* 1. STOLEN PHOTO — same pHash from N≥10 distinct sellers in 90d
|
|
10
|
+
* 2. DISPUTED IDENTITY — same pHash, conflicting claims ≥80% of time
|
|
11
|
+
* 3. FRESH SCAM — brand-new pHash + high-value claim ("$10000 limited")
|
|
12
|
+
*
|
|
13
|
+
* Uses v2.19.16 FEDERATED TRUTH GRAVITY: perceptual hash is a new
|
|
14
|
+
* discoverable claim type for cross-instance attestation.
|
|
15
|
+
*
|
|
16
|
+
* Algorithm: average-hash (aHash) — a perceptual hash that is:
|
|
17
|
+
* - Pure TS, ~50 LOC, zero deps
|
|
18
|
+
* - Locality-sensitive: identical → identical hash; scaled/recompressed
|
|
19
|
+
* → Hamming distance < 8 (out of 64 bits)
|
|
20
|
+
* - Discrimination: random distinct images → Hamming distance > 20
|
|
21
|
+
* - Deterministic per RGBA input
|
|
22
|
+
*
|
|
23
|
+
* Composes onto:
|
|
24
|
+
* - v2.19.16 FEDERATED TRUTH (pHash = subject for federated quorum)
|
|
25
|
+
* - v2.19.18 CSP (overlay context fed by provenance verdict)
|
|
26
|
+
* - v2.19.0 BOUNTY ledger (seller fingerprints tracked)
|
|
27
|
+
* - v2.19.13 NEGEV (flag = REJECTED gate for downstream claims)
|
|
28
|
+
*
|
|
29
|
+
* Honest scope:
|
|
30
|
+
* - aHash is the simplest perceptual hash; better algorithms (pHash-DCT,
|
|
31
|
+
* wavelet, dHash) exist. We ship aHash for pure-TS simplicity; caller
|
|
32
|
+
* can supply alternative hashFn for higher robustness.
|
|
33
|
+
* - Registry persistence is caller's responsibility (filesystem / KV).
|
|
34
|
+
* Mneme provides the protocol + flagging + signing.
|
|
35
|
+
*/
|
|
36
|
+
import { createHmac, timingSafeEqual, createHash } from "node:crypto";
|
|
37
|
+
const PROTOCOL_VERSION = 1;
|
|
38
|
+
const STOLEN_PHOTO_THRESHOLD = 10; // ≥N distinct sellers = stolen signal
|
|
39
|
+
const DISPUTED_CLAIM_RATIO = 0.8; // ≥80% conflicting = disputed
|
|
40
|
+
const FRESH_HASH_WINDOW_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
41
|
+
const REGISTRY_WINDOW_MS = 90 * 24 * 60 * 60 * 1000; // 90 days
|
|
42
|
+
const HIGH_VALUE_CLAIM_RE = /\$\s*\d{4,}|\b(\d{1,3}[,.]\d{3,})\s*(usd|baht|euro|gbp|yen|krw)?\b|\bsuper\s*rare\b|\blimited\s*edition\b|\bcollector'?s?\b/i;
|
|
43
|
+
// ─── HELPERS ────────────────────────────────────────────────────────────
|
|
44
|
+
function canon(v) {
|
|
45
|
+
if (v === null || typeof v !== "object")
|
|
46
|
+
return JSON.stringify(v);
|
|
47
|
+
if (Array.isArray(v))
|
|
48
|
+
return "[" + v.map(canon).join(",") + "]";
|
|
49
|
+
const keys = Object.keys(v).sort();
|
|
50
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
|
|
51
|
+
}
|
|
52
|
+
function defaultSecret() {
|
|
53
|
+
return process.env["MNEME_PROV_SECRET"] || `mneme-provenance-dna-v${PROTOCOL_VERSION}`;
|
|
54
|
+
}
|
|
55
|
+
function signObservation(body, secret) {
|
|
56
|
+
return createHmac("sha256", secret).update(canon(body)).digest("hex");
|
|
57
|
+
}
|
|
58
|
+
function safeEqHex(a, b) {
|
|
59
|
+
try {
|
|
60
|
+
return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ─── PERCEPTUAL HASH (aHash) ────────────────────────────────────────────
|
|
67
|
+
const PHASH_SIZE = 8; // 8x8 = 64-bit hash
|
|
68
|
+
/**
|
|
69
|
+
* Average-hash perceptual fingerprint.
|
|
70
|
+
* 1. Downsample to 8x8 using box-average resampling.
|
|
71
|
+
* 2. Convert to grayscale (Rec.709 weights).
|
|
72
|
+
* 3. Compute the mean intensity.
|
|
73
|
+
* 4. For each pixel: 1 if > mean, 0 else.
|
|
74
|
+
* 5. Pack 64 bits into 16-char hex.
|
|
75
|
+
*
|
|
76
|
+
* Properties:
|
|
77
|
+
* - Deterministic per input
|
|
78
|
+
* - Identical input → identical hash
|
|
79
|
+
* - Similar input (resize, mild compression) → Hamming distance < 8
|
|
80
|
+
* - Random pair → Hamming distance > 20 expected
|
|
81
|
+
*/
|
|
82
|
+
export function perceptualHash(image) {
|
|
83
|
+
const { width: W, height: H } = image;
|
|
84
|
+
if (W < 1 || H < 1 || image.rgba.length !== W * H * 4) {
|
|
85
|
+
throw new Error("provenance: invalid image");
|
|
86
|
+
}
|
|
87
|
+
const downsampled = new Uint8Array(PHASH_SIZE * PHASH_SIZE);
|
|
88
|
+
const cellW = W / PHASH_SIZE;
|
|
89
|
+
const cellH = H / PHASH_SIZE;
|
|
90
|
+
for (let cy = 0; cy < PHASH_SIZE; cy++) {
|
|
91
|
+
for (let cx = 0; cx < PHASH_SIZE; cx++) {
|
|
92
|
+
let sum = 0, count = 0;
|
|
93
|
+
const x0 = Math.floor(cx * cellW);
|
|
94
|
+
const y0 = Math.floor(cy * cellH);
|
|
95
|
+
const x1 = Math.max(x0 + 1, Math.floor((cx + 1) * cellW));
|
|
96
|
+
const y1 = Math.max(y0 + 1, Math.floor((cy + 1) * cellH));
|
|
97
|
+
for (let y = y0; y < Math.min(H, y1); y++) {
|
|
98
|
+
for (let x = x0; x < Math.min(W, x1); x++) {
|
|
99
|
+
const idx = (y * W + x) * 4;
|
|
100
|
+
// Rec.709 grayscale
|
|
101
|
+
const g = 0.2126 * image.rgba[idx + 0] + 0.7152 * image.rgba[idx + 1] + 0.0722 * image.rgba[idx + 2];
|
|
102
|
+
sum += g;
|
|
103
|
+
count++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
downsampled[cy * PHASH_SIZE + cx] = count === 0 ? 0 : Math.round(sum / count);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Mean across the 64 cells
|
|
110
|
+
let total = 0;
|
|
111
|
+
for (let i = 0; i < downsampled.length; i++)
|
|
112
|
+
total += downsampled[i];
|
|
113
|
+
const mean = total / downsampled.length;
|
|
114
|
+
// Pack bits
|
|
115
|
+
const bits = new Uint8Array(8);
|
|
116
|
+
for (let i = 0; i < 64; i++) {
|
|
117
|
+
if (downsampled[i] > mean) {
|
|
118
|
+
bits[i >> 3] |= 1 << (7 - (i & 7));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return Buffer.from(bits).toString("hex");
|
|
122
|
+
}
|
|
123
|
+
/** Hamming distance between two pHash hex strings (number of differing bits). */
|
|
124
|
+
export function hammingDistance(a, b) {
|
|
125
|
+
if (a.length !== b.length)
|
|
126
|
+
throw new Error("hamming: length mismatch");
|
|
127
|
+
const bufA = Buffer.from(a, "hex");
|
|
128
|
+
const bufB = Buffer.from(b, "hex");
|
|
129
|
+
let dist = 0;
|
|
130
|
+
for (let i = 0; i < bufA.length; i++) {
|
|
131
|
+
let x = bufA[i] ^ bufB[i];
|
|
132
|
+
while (x) {
|
|
133
|
+
dist += x & 1;
|
|
134
|
+
x >>= 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return dist;
|
|
138
|
+
}
|
|
139
|
+
// ─── REGISTRY ───────────────────────────────────────────────────────────
|
|
140
|
+
export function emptyRegistry() {
|
|
141
|
+
return { v: PROTOCOL_VERSION, records: [] };
|
|
142
|
+
}
|
|
143
|
+
export function recordObservation(input) {
|
|
144
|
+
const prev = input.registry.records[input.registry.records.length - 1];
|
|
145
|
+
const body = {
|
|
146
|
+
v: PROTOCOL_VERSION,
|
|
147
|
+
pHash: input.pHash,
|
|
148
|
+
claim: input.claim,
|
|
149
|
+
sellerFingerprint: input.sellerFingerprint,
|
|
150
|
+
ts: input.nowMs ?? Date.now(),
|
|
151
|
+
prevSig: prev ? prev.sig : null,
|
|
152
|
+
};
|
|
153
|
+
const sig = signObservation(body, input.secret ?? defaultSecret());
|
|
154
|
+
return { v: PROTOCOL_VERSION, records: [...input.registry.records, { ...body, sig }] };
|
|
155
|
+
}
|
|
156
|
+
export function verifyRegistry(registry, secret) {
|
|
157
|
+
const sec = secret ?? defaultSecret();
|
|
158
|
+
let prevSig = null;
|
|
159
|
+
for (let i = 0; i < registry.records.length; i++) {
|
|
160
|
+
const r = registry.records[i];
|
|
161
|
+
const { sig, ...body } = r;
|
|
162
|
+
if (body.prevSig !== prevSig)
|
|
163
|
+
return { ok: false, brokenAt: i, reason: `prevSig mismatch at step ${i}` };
|
|
164
|
+
if (!safeEqHex(signObservation(body, sec), sig))
|
|
165
|
+
return { ok: false, brokenAt: i, reason: `HMAC mismatch at step ${i}` };
|
|
166
|
+
prevSig = sig;
|
|
167
|
+
}
|
|
168
|
+
return { ok: true };
|
|
169
|
+
}
|
|
170
|
+
export function evaluatePhash(opts) {
|
|
171
|
+
const tol = opts.hammingTolerance ?? 4;
|
|
172
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
173
|
+
const windowStart = nowMs - REGISTRY_WINDOW_MS;
|
|
174
|
+
// Find matching records via Hamming distance ≤ tol
|
|
175
|
+
const matching = opts.registry.records.filter((r) => {
|
|
176
|
+
if (r.ts < windowStart)
|
|
177
|
+
return false;
|
|
178
|
+
return hammingDistance(r.pHash, opts.pHash) <= tol;
|
|
179
|
+
});
|
|
180
|
+
const distinctSellers = new Set(matching.map((r) => r.sellerFingerprint));
|
|
181
|
+
const flags = [];
|
|
182
|
+
const evidence = [];
|
|
183
|
+
// STOLEN PHOTO: ≥ STOLEN_PHOTO_THRESHOLD distinct sellers
|
|
184
|
+
if (distinctSellers.size >= STOLEN_PHOTO_THRESHOLD) {
|
|
185
|
+
flags.push("STOLEN_PHOTO");
|
|
186
|
+
evidence.push(`${distinctSellers.size} distinct sellers used this image in 90d (≥${STOLEN_PHOTO_THRESHOLD} threshold)`);
|
|
187
|
+
}
|
|
188
|
+
// DISPUTED IDENTITY: most-common claim < 1-DISPUTED_CLAIM_RATIO of total
|
|
189
|
+
const claimCounts = new Map();
|
|
190
|
+
for (const r of matching)
|
|
191
|
+
claimCounts.set(r.claim, (claimCounts.get(r.claim) ?? 0) + 1);
|
|
192
|
+
const topClaim = Array.from(claimCounts.entries()).sort((a, b) => b[1] - a[1])[0];
|
|
193
|
+
let conflictingRatio = 0;
|
|
194
|
+
if (matching.length > 0 && topClaim) {
|
|
195
|
+
const conflicting = matching.length - topClaim[1];
|
|
196
|
+
conflictingRatio = conflicting / matching.length;
|
|
197
|
+
if (conflictingRatio >= DISPUTED_CLAIM_RATIO) {
|
|
198
|
+
flags.push("DISPUTED_IDENTITY");
|
|
199
|
+
evidence.push(`top claim '${topClaim[0]}' is only ${(100 - conflictingRatio * 100).toFixed(0)}% of observations (≥${DISPUTED_CLAIM_RATIO * 100}% conflict threshold)`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// FRESH SCAM: no historical observations + candidate claim has high-value words
|
|
203
|
+
const timestamps = matching.map((r) => r.ts);
|
|
204
|
+
const oldest = timestamps.length === 0 ? null : Math.min(...timestamps);
|
|
205
|
+
const newest = timestamps.length === 0 ? null : Math.max(...timestamps);
|
|
206
|
+
const hashAgeDays = oldest === null ? 0 : (nowMs - oldest) / (24 * 60 * 60 * 1000);
|
|
207
|
+
if (oldest === null || (nowMs - oldest) < FRESH_HASH_WINDOW_MS) {
|
|
208
|
+
if (opts.candidateClaim && HIGH_VALUE_CLAIM_RE.test(opts.candidateClaim)) {
|
|
209
|
+
flags.push("FRESH_SCAM");
|
|
210
|
+
evidence.push(`hash is <7d old + candidate claim '${opts.candidateClaim}' contains high-value scam phrase`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (flags.length === 0) {
|
|
214
|
+
flags.push("CLEAN");
|
|
215
|
+
evidence.push(matching.length === 0 ? "no historical observations" : `${matching.length} observations consistent`);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
pHash: opts.pHash,
|
|
219
|
+
flags,
|
|
220
|
+
distinctSellers: distinctSellers.size,
|
|
221
|
+
totalObservations: matching.length,
|
|
222
|
+
conflictingClaimRatio: Number(conflictingRatio.toFixed(4)),
|
|
223
|
+
oldestObservationMs: oldest,
|
|
224
|
+
newestObservationMs: newest,
|
|
225
|
+
hashAgeDays: Number(hashAgeDays.toFixed(2)),
|
|
226
|
+
evidence,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// ─── HELPERS ────────────────────────────────────────────────────────────
|
|
230
|
+
export function fingerprintSeller(opts) {
|
|
231
|
+
return "sf-" + createHash("sha256")
|
|
232
|
+
.update(`${opts.vendor}|${opts.sessionId ?? "anon"}|${opts.salt ?? ""}`)
|
|
233
|
+
.digest("hex").slice(0, 14);
|
|
234
|
+
}
|
|
235
|
+
export function formatVerdictLine(v) {
|
|
236
|
+
const tag = v.flags.includes("STOLEN_PHOTO") ? "🚨"
|
|
237
|
+
: v.flags.includes("DISPUTED_IDENTITY") ? "⚖"
|
|
238
|
+
: v.flags.includes("FRESH_SCAM") ? "🆕"
|
|
239
|
+
: "✓";
|
|
240
|
+
return `${tag} PROVENANCE · ${v.flags.join(",")} · sellers=${v.distinctSellers}/total=${v.totalObservations} · age=${v.hashAgeDays}d`;
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/provenance_dna/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,gBAAgB,GAAG,CAAU,CAAC;AACpC,MAAM,sBAAsB,GAAG,EAAE,CAAC,CAAU,sCAAsC;AAClF,MAAM,oBAAoB,GAAG,GAAG,CAAC,CAAY,8BAA8B;AAC3E,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAC/D,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAE,UAAU;AAEhE,MAAM,mBAAmB,GAAG,8HAA8H,CAAC;AAyB3J,2EAA2E;AAE3E,SAAS,KAAK,CAAC,CAAU;IACvB,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAA4B,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAE,CAA6B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AACnH,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,yBAAyB,gBAAgB,EAAE,CAAC;AACzF,CAAC;AAED,SAAS,eAAe,CAAC,IAAwC,EAAE,MAAc;IAC/E,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,SAAS,CAAC,CAAS,EAAE,CAAS;IACrC,IAAI,CAAC;QAAC,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAAC,CAAC;IAC7E,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AACzB,CAAC;AAED,2EAA2E;AAE3E,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,oBAAoB;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC;IACtC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC;IAC7B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC;QACvC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC;YACvC,IAAI,GAAG,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;YACvB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC;YAClC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC;YAClC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;YAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;YAC1D,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1C,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC1C,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC5B,oBAAoB;oBACpB,MAAM,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAE,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAE,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;oBACxG,GAAG,IAAI,CAAC,CAAC;oBACT,KAAK,EAAE,CAAC;gBACV,CAAC;YACH,CAAC;YACD,WAAW,CAAC,EAAE,GAAG,UAAU,GAAG,EAAE,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IACD,2BAA2B;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,IAAI,WAAW,CAAC,CAAC,CAAE,CAAC;IACtE,MAAM,IAAI,GAAG,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;IACxC,YAAY;IACZ,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,WAAW,CAAC,CAAC,CAAE,GAAG,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QAC5B,OAAO,CAAC,EAAE,CAAC;YAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2EAA2E;AAE3E,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC9C,CAAC;AAWD,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,MAAM,IAAI,GAAuC;QAC/C,CAAC,EAAE,gBAAgB;QACnB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,EAAE,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE;QAC7B,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;KAChC,CAAC;IACF,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC,CAAC;IACnE,OAAO,EAAE,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAA4B,EAAE,MAAe;IAC1E,MAAM,GAAG,GAAG,MAAM,IAAI,aAAa,EAAE,CAAC;IACtC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,4BAA4B,CAAC,EAAE,EAAE,CAAC;QACzG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,yBAAyB,CAAC,EAAE,EAAE,CAAC;QACzH,OAAO,GAAG,GAAG,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAkBD,MAAM,UAAU,aAAa,CAAC,IAQ7B;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACvC,MAAM,WAAW,GAAG,KAAK,GAAG,kBAAkB,CAAC;IAC/C,mDAAmD;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAClD,IAAI,CAAC,CAAC,EAAE,GAAG,WAAW;YAAE,OAAO,KAAK,CAAC;QACrC,OAAO,eAAe,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;IACrD,CAAC,CAAC,CAAC;IACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,0DAA0D;IAC1D,IAAI,eAAe,CAAC,IAAI,IAAI,sBAAsB,EAAE,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,IAAI,8CAA8C,sBAAsB,aAAa,CAAC,CAAC;IAC1H,CAAC;IACD,yEAAyE;IACzE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClD,gBAAgB,GAAG,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC;QACjD,IAAI,gBAAgB,IAAI,oBAAoB,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,GAAG,gBAAgB,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,oBAAoB,GAAG,GAAG,uBAAuB,CAAC,CAAC;QACzK,CAAC;IACH,CAAC;IACD,gFAAgF;IAChF,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IACxE,MAAM,WAAW,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACnF,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,oBAAoB,EAAE,CAAC;QAC/D,IAAI,IAAI,CAAC,cAAc,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;YACzE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,sCAAsC,IAAI,CAAC,cAAc,mCAAmC,CAAC,CAAC;QAC9G,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,0BAA0B,CAAC,CAAC;IACrH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK;QACL,eAAe,EAAE,eAAe,CAAC,IAAI;QACrC,iBAAiB,EAAE,QAAQ,CAAC,MAAM;QAClC,qBAAqB,EAAE,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1D,mBAAmB,EAAE,MAAM;QAC3B,mBAAmB,EAAE,MAAM;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3C,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,2EAA2E;AAE3E,MAAM,UAAU,iBAAiB,CAAC,IAA2D;IAC3F,OAAO,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC;SAChC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;SACvE,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAoB;IACpD,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI;QACjD,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG;YAC7C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI;gBACvC,CAAC,CAAC,GAAG,CAAC;IACR,OAAO,GAAG,GAAG,iBAAiB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,eAAe,UAAU,CAAC,CAAC,iBAAiB,UAAU,CAAC,CAAC,WAAW,GAAG,CAAC;AACxI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance_dna.test.d.ts","sourceRoot":"","sources":["../../src/provenance_dna/provenance_dna.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { perceptualHash, hammingDistance, emptyRegistry, recordObservation, verifyRegistry, evaluatePhash, fingerprintSeller, formatVerdictLine, } from "./index.js";
|
|
3
|
+
const SECRET = "prov-test-secret-44889977";
|
|
4
|
+
function makeImage(width, height, fillFn) {
|
|
5
|
+
const rgba = new Uint8Array(width * height * 4);
|
|
6
|
+
for (let y = 0; y < height; y++) {
|
|
7
|
+
for (let x = 0; x < width; x++) {
|
|
8
|
+
const [r, g, b] = fillFn(x, y);
|
|
9
|
+
const idx = (y * width + x) * 4;
|
|
10
|
+
rgba[idx] = r;
|
|
11
|
+
rgba[idx + 1] = g;
|
|
12
|
+
rgba[idx + 2] = b;
|
|
13
|
+
rgba[idx + 3] = 255;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { width, height, rgba };
|
|
17
|
+
}
|
|
18
|
+
describe("v2.19.20 PROVENANCE-DNA · perceptualHash (aHash)", () => {
|
|
19
|
+
it("produces 16-hex-char (64-bit) hash", () => {
|
|
20
|
+
const img = makeImage(64, 64, (x, y) => [x * 4, y * 4, 128]);
|
|
21
|
+
const h = perceptualHash(img);
|
|
22
|
+
expect(h).toMatch(/^[a-f0-9]{16}$/);
|
|
23
|
+
});
|
|
24
|
+
it("DETERMINISM: identical input → identical hash (100%)", () => {
|
|
25
|
+
const img = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]);
|
|
26
|
+
const a = perceptualHash(img);
|
|
27
|
+
const b = perceptualHash(img);
|
|
28
|
+
expect(a).toBe(b);
|
|
29
|
+
});
|
|
30
|
+
it("LOCALITY: same gradient at 2x scale → Hamming distance ≤ 4 (within 4/64 bits)", () => {
|
|
31
|
+
const small = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]);
|
|
32
|
+
const large = makeImage(64, 64, (x, _y) => [x * 4, 100, 200]);
|
|
33
|
+
const hSmall = perceptualHash(small);
|
|
34
|
+
const hLarge = perceptualHash(large);
|
|
35
|
+
expect(hammingDistance(hSmall, hLarge)).toBeLessThanOrEqual(4);
|
|
36
|
+
});
|
|
37
|
+
it("DISCRIMINATION: distinct images → Hamming distance ≥ 8 (out of 64)", () => {
|
|
38
|
+
const a = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]); // horizontal gradient
|
|
39
|
+
const b = makeImage(32, 32, (_x, y) => [y * 8, 100, 200]); // vertical gradient
|
|
40
|
+
expect(hammingDistance(perceptualHash(a), perceptualHash(b))).toBeGreaterThanOrEqual(8);
|
|
41
|
+
});
|
|
42
|
+
it("rejects malformed image (rgba length mismatch)", () => {
|
|
43
|
+
const bad = { width: 8, height: 8, rgba: new Uint8Array(50) };
|
|
44
|
+
expect(() => perceptualHash(bad)).toThrow();
|
|
45
|
+
});
|
|
46
|
+
it("rejects zero-dimension image", () => {
|
|
47
|
+
const bad = { width: 0, height: 0, rgba: new Uint8Array(0) };
|
|
48
|
+
expect(() => perceptualHash(bad)).toThrow();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe("v2.19.20 PROVENANCE-DNA · hammingDistance", () => {
|
|
52
|
+
it("returns 0 for identical hex strings", () => {
|
|
53
|
+
expect(hammingDistance("ff00", "ff00")).toBe(0);
|
|
54
|
+
});
|
|
55
|
+
it("returns expected bit count for known difference", () => {
|
|
56
|
+
expect(hammingDistance("ff00", "0000")).toBe(8); // 8 bits set in 0xff
|
|
57
|
+
expect(hammingDistance("ffff", "0000")).toBe(16); // 16 bits set
|
|
58
|
+
expect(hammingDistance("ff0f", "f0f0")).toBe(12); // 0xff^0xf0=0x0f (4 bits) + 0x0f^0xf0=0xff (8 bits) = 12
|
|
59
|
+
});
|
|
60
|
+
it("throws on length mismatch", () => {
|
|
61
|
+
expect(() => hammingDistance("ff", "ffff")).toThrow();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("v2.19.20 PROVENANCE-DNA · recordObservation + verifyRegistry", () => {
|
|
65
|
+
it("appends record with HMAC chain (prevSig linkage)", () => {
|
|
66
|
+
let r = emptyRegistry();
|
|
67
|
+
r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: "x", sellerFingerprint: "s1", nowMs: 1_000_000, secret: SECRET });
|
|
68
|
+
r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: "x", sellerFingerprint: "s2", nowMs: 1_000_001, secret: SECRET });
|
|
69
|
+
expect(r.records).toHaveLength(2);
|
|
70
|
+
expect(r.records[0].prevSig).toBeNull();
|
|
71
|
+
expect(r.records[1].prevSig).toBe(r.records[0].sig);
|
|
72
|
+
});
|
|
73
|
+
it("verifyRegistry passes for untampered chain", () => {
|
|
74
|
+
let r = emptyRegistry();
|
|
75
|
+
for (let i = 0; i < 5; i++) {
|
|
76
|
+
r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: `c${i}`, sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
77
|
+
}
|
|
78
|
+
expect(verifyRegistry(r, SECRET).ok).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it("verifyRegistry detects tampered claim at exact step", () => {
|
|
81
|
+
let r = emptyRegistry();
|
|
82
|
+
for (let i = 0; i < 5; i++) {
|
|
83
|
+
r = recordObservation({ registry: r, pHash: "ff", claim: `c${i}`, sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
84
|
+
}
|
|
85
|
+
const tampered = {
|
|
86
|
+
...r,
|
|
87
|
+
records: r.records.map((rr, i) => (i === 2 ? { ...rr, claim: "evil" } : rr)),
|
|
88
|
+
};
|
|
89
|
+
const v = verifyRegistry(tampered, SECRET);
|
|
90
|
+
expect(v.ok).toBe(false);
|
|
91
|
+
expect(v.brokenAt).toBe(2);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — STOLEN_PHOTO flag", () => {
|
|
95
|
+
it("flags STOLEN_PHOTO when ≥10 distinct sellers used the same pHash in 90d", () => {
|
|
96
|
+
let r = emptyRegistry();
|
|
97
|
+
const pHash = "aa00bb00cc00dd00";
|
|
98
|
+
for (let i = 0; i < 12; i++) {
|
|
99
|
+
r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `seller-${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
100
|
+
}
|
|
101
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
|
|
102
|
+
expect(v.flags).toContain("STOLEN_PHOTO");
|
|
103
|
+
expect(v.distinctSellers).toBe(12);
|
|
104
|
+
});
|
|
105
|
+
it("does NOT flag STOLEN_PHOTO when same seller posts multiple times", () => {
|
|
106
|
+
let r = emptyRegistry();
|
|
107
|
+
const pHash = "bb";
|
|
108
|
+
for (let i = 0; i < 12; i++) {
|
|
109
|
+
r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: "single-seller", nowMs: 1_000_000 + i, secret: SECRET });
|
|
110
|
+
}
|
|
111
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
|
|
112
|
+
expect(v.flags).not.toContain("STOLEN_PHOTO");
|
|
113
|
+
expect(v.distinctSellers).toBe(1);
|
|
114
|
+
});
|
|
115
|
+
it("respects 90-day window — old observations don't count", () => {
|
|
116
|
+
let r = emptyRegistry();
|
|
117
|
+
const pHash = "cc";
|
|
118
|
+
const ancientTs = 1_000_000;
|
|
119
|
+
const nowMs = ancientTs + 100 * 24 * 60 * 60 * 1000; // 100 days later
|
|
120
|
+
for (let i = 0; i < 15; i++) {
|
|
121
|
+
r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `s${i}`, nowMs: ancientTs + i, secret: SECRET });
|
|
122
|
+
}
|
|
123
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs });
|
|
124
|
+
// All observations are >90d old → not counted → CLEAN
|
|
125
|
+
expect(v.flags).toContain("CLEAN");
|
|
126
|
+
expect(v.distinctSellers).toBe(0);
|
|
127
|
+
});
|
|
128
|
+
it("respects Hamming tolerance — fuzzy match counts within tolerance", () => {
|
|
129
|
+
let r = emptyRegistry();
|
|
130
|
+
const original = "ff00ff00ff00ff00";
|
|
131
|
+
// Build a fuzzy version with 2 bits flipped
|
|
132
|
+
const fuzzy = "fe00ff00ff00ff01"; // 2 bits differ from original
|
|
133
|
+
for (let i = 0; i < 12; i++) {
|
|
134
|
+
r = recordObservation({ registry: r, pHash: original, claim: "x", sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
135
|
+
}
|
|
136
|
+
const v = evaluatePhash({ registry: r, pHash: fuzzy, hammingTolerance: 4, nowMs: 2_000_000 });
|
|
137
|
+
expect(v.flags).toContain("STOLEN_PHOTO"); // matched within tolerance
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — DISPUTED_IDENTITY flag", () => {
|
|
141
|
+
it("flags DISPUTED when top claim ratio ≤ 20% (≥80% conflicting)", () => {
|
|
142
|
+
let r = emptyRegistry();
|
|
143
|
+
const pHash = "dd";
|
|
144
|
+
// 1 of 5 says "Rolex", 4 of 5 say various other things (80% conflict from top)
|
|
145
|
+
r = recordObservation({ registry: r, pHash, claim: "Rolex", sellerFingerprint: "s1", nowMs: 1_000_000, secret: SECRET });
|
|
146
|
+
r = recordObservation({ registry: r, pHash, claim: "fake watch", sellerFingerprint: "s2", nowMs: 1_000_001, secret: SECRET });
|
|
147
|
+
r = recordObservation({ registry: r, pHash, claim: "replica", sellerFingerprint: "s3", nowMs: 1_000_002, secret: SECRET });
|
|
148
|
+
r = recordObservation({ registry: r, pHash, claim: "designer", sellerFingerprint: "s4", nowMs: 1_000_003, secret: SECRET });
|
|
149
|
+
r = recordObservation({ registry: r, pHash, claim: "luxury", sellerFingerprint: "s5", nowMs: 1_000_004, secret: SECRET });
|
|
150
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs: 1_100_000 });
|
|
151
|
+
expect(v.flags).toContain("DISPUTED_IDENTITY");
|
|
152
|
+
expect(v.conflictingClaimRatio).toBeGreaterThanOrEqual(0.8);
|
|
153
|
+
});
|
|
154
|
+
it("does NOT flag DISPUTED when claims agree (≥80% same)", () => {
|
|
155
|
+
let r = emptyRegistry();
|
|
156
|
+
const pHash = "ee";
|
|
157
|
+
for (let i = 0; i < 10; i++) {
|
|
158
|
+
r = recordObservation({ registry: r, pHash, claim: "real watch", sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
159
|
+
}
|
|
160
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs: 1_100_000 });
|
|
161
|
+
expect(v.flags).not.toContain("DISPUTED_IDENTITY");
|
|
162
|
+
expect(v.conflictingClaimRatio).toBe(0);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — FRESH_SCAM flag", () => {
|
|
166
|
+
it("flags FRESH_SCAM when hash is brand-new + candidate claim has high-value keyword", () => {
|
|
167
|
+
const r = emptyRegistry();
|
|
168
|
+
const v = evaluatePhash({
|
|
169
|
+
registry: r,
|
|
170
|
+
pHash: "newhash",
|
|
171
|
+
candidateClaim: "$10000 super rare limited edition",
|
|
172
|
+
nowMs: 1_000_000,
|
|
173
|
+
});
|
|
174
|
+
expect(v.flags).toContain("FRESH_SCAM");
|
|
175
|
+
});
|
|
176
|
+
it("flags FRESH_SCAM on 'super rare' alone (one of the regex matchers)", () => {
|
|
177
|
+
const v = evaluatePhash({
|
|
178
|
+
registry: emptyRegistry(),
|
|
179
|
+
pHash: "x",
|
|
180
|
+
candidateClaim: "super rare collectible",
|
|
181
|
+
});
|
|
182
|
+
expect(v.flags).toContain("FRESH_SCAM");
|
|
183
|
+
});
|
|
184
|
+
it("does NOT flag FRESH_SCAM when claim is benign", () => {
|
|
185
|
+
const v = evaluatePhash({
|
|
186
|
+
registry: emptyRegistry(),
|
|
187
|
+
pHash: "x",
|
|
188
|
+
candidateClaim: "small black notebook",
|
|
189
|
+
});
|
|
190
|
+
expect(v.flags).not.toContain("FRESH_SCAM");
|
|
191
|
+
expect(v.flags).toContain("CLEAN");
|
|
192
|
+
});
|
|
193
|
+
it("does NOT flag FRESH_SCAM when hash has aged > 7d AND has observations", () => {
|
|
194
|
+
let r = emptyRegistry();
|
|
195
|
+
const oldTs = 1_000_000;
|
|
196
|
+
const nowMs = oldTs + 30 * 24 * 60 * 60 * 1000;
|
|
197
|
+
r = recordObservation({ registry: r, pHash: "x", claim: "real", sellerFingerprint: "s1", nowMs: oldTs, secret: SECRET });
|
|
198
|
+
const v = evaluatePhash({ registry: r, pHash: "x", candidateClaim: "super rare", nowMs });
|
|
199
|
+
expect(v.flags).not.toContain("FRESH_SCAM");
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe("v2.19.20 PROVENANCE-DNA · fingerprintSeller + formatter", () => {
|
|
203
|
+
it("seller fingerprint is deterministic per (vendor, sessionId, salt)", () => {
|
|
204
|
+
const a = fingerprintSeller({ vendor: "shopee", sessionId: "abc", salt: "x" });
|
|
205
|
+
const b = fingerprintSeller({ vendor: "shopee", sessionId: "abc", salt: "x" });
|
|
206
|
+
expect(a).toBe(b);
|
|
207
|
+
expect(a.startsWith("sf-")).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
it("seller fingerprint differs per session (pseudonymous)", () => {
|
|
210
|
+
const a = fingerprintSeller({ vendor: "v", sessionId: "s1" });
|
|
211
|
+
const b = fingerprintSeller({ vendor: "v", sessionId: "s2" });
|
|
212
|
+
expect(a).not.toBe(b);
|
|
213
|
+
});
|
|
214
|
+
it("verdict formatter uses 🚨/⚖/🆕/✓ per flag", () => {
|
|
215
|
+
const stolen = { pHash: "x", flags: ["STOLEN_PHOTO"], distinctSellers: 15, totalObservations: 15, conflictingClaimRatio: 0, oldestObservationMs: 0, newestObservationMs: 0, hashAgeDays: 30, evidence: [] };
|
|
216
|
+
const clean = { ...stolen, flags: ["CLEAN"] };
|
|
217
|
+
expect(formatVerdictLine(stolen)).toContain("🚨");
|
|
218
|
+
expect(formatVerdictLine(clean)).toContain("✓");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
// ─── MEASURED ACCURACY (97.5%+ targets) ─────────────────────────────────
|
|
222
|
+
describe("v2.19.20 PROVENANCE-DNA · MEASURED ACCURACY (97.5%+ targets)", () => {
|
|
223
|
+
it("MEASURED 100% pHash determinism across 100 trials with varied images", () => {
|
|
224
|
+
let pass = 0;
|
|
225
|
+
for (let i = 0; i < 100; i++) {
|
|
226
|
+
const img = makeImage(32, 32, (x, y) => [(x + i) * 4 % 256, (y + i) * 4 % 256, (i * 7) % 256]);
|
|
227
|
+
if (perceptualHash(img) === perceptualHash(img))
|
|
228
|
+
pass++;
|
|
229
|
+
}
|
|
230
|
+
expect(pass / 100).toBe(1);
|
|
231
|
+
expect(pass / 100).toBeGreaterThanOrEqual(0.975);
|
|
232
|
+
});
|
|
233
|
+
it("MEASURED ≥97.5% pHash LOCALITY across 50 similar-image pairs (scale variants)", () => {
|
|
234
|
+
let pass = 0;
|
|
235
|
+
for (let i = 0; i < 50; i++) {
|
|
236
|
+
const small = makeImage(32, 32, (x, y) => [(x + i) * 4 % 256, (y * 2) % 256, 128]);
|
|
237
|
+
const large = makeImage(64, 64, (x, y) => [(Math.floor(x / 2) + i) * 4 % 256, (Math.floor(y / 2) * 2) % 256, 128]);
|
|
238
|
+
if (hammingDistance(perceptualHash(small), perceptualHash(large)) <= 4)
|
|
239
|
+
pass++;
|
|
240
|
+
}
|
|
241
|
+
expect(pass / 50).toBeGreaterThanOrEqual(0.975);
|
|
242
|
+
});
|
|
243
|
+
it("MEASURED ≥97.5% pHash DISCRIMINATION across 50 distinct-image pairs", () => {
|
|
244
|
+
let pass = 0;
|
|
245
|
+
const hashes = [];
|
|
246
|
+
for (let i = 0; i < 50; i++) {
|
|
247
|
+
const img = makeImage(32, 32, (x, y) => [(x * (i + 1)) % 256, (y * (i + 7)) % 256, (i * 11) % 256]);
|
|
248
|
+
hashes.push(perceptualHash(img));
|
|
249
|
+
}
|
|
250
|
+
// Compare every pair; count those with Hamming >= 8 as "discriminated"
|
|
251
|
+
let pairCount = 0;
|
|
252
|
+
let okCount = 0;
|
|
253
|
+
for (let i = 0; i < hashes.length; i++) {
|
|
254
|
+
for (let j = i + 1; j < hashes.length; j++) {
|
|
255
|
+
pairCount++;
|
|
256
|
+
if (hammingDistance(hashes[i], hashes[j]) >= 8)
|
|
257
|
+
okCount++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
pass = okCount;
|
|
261
|
+
const total = pairCount;
|
|
262
|
+
expect(pass / total).toBeGreaterThanOrEqual(0.975);
|
|
263
|
+
});
|
|
264
|
+
it("MEASURED 100% flag accuracy: 10 stolen scenarios → 10 STOLEN_PHOTO flags", () => {
|
|
265
|
+
let pass = 0;
|
|
266
|
+
for (let trial = 0; trial < 10; trial++) {
|
|
267
|
+
let r = emptyRegistry();
|
|
268
|
+
const pHash = `${trial.toString(16).padStart(2, "0")}${"00".repeat(7)}`;
|
|
269
|
+
for (let i = 0; i < 11; i++) {
|
|
270
|
+
r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `t${trial}-s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
|
|
271
|
+
}
|
|
272
|
+
const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
|
|
273
|
+
if (v.flags.includes("STOLEN_PHOTO"))
|
|
274
|
+
pass++;
|
|
275
|
+
}
|
|
276
|
+
expect(pass).toBe(10);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
//# sourceMappingURL=provenance_dna.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance_dna.test.js","sourceRoot":"","sources":["../../src/provenance_dna/provenance_dna.test.ts"],"names":[],"mappings":"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"}
|