PAPH
The library @pixagram/paph-js 5.3.1 is published on npm (repository at commit 8959a08, 2026-10-06); nothing on pixagram.com uses it today, and no production use is planned with a date.
PAPH is Pixagram's perceptual hash for pixel art: a fixed-size fingerprint of an image and a comparator that decides whether two fingerprints come from the same work, including after rotation, mirroring, colour inversion, tone shifts, nearest-neighbour upscaling or pasting into another picture. This page describes what the published library computes, how it compares, how it is versioned and calibrated, and where it stands: it is a reference implementation with a provisional calibration, and nothing on pixagram.com runs it. Readers who want copy detection on the platform should read the last section first.
What it is for
A cryptographic hash such as pixahash changes completely when one pixel changes; it answers "are these bytes identical?". A perceptual hash answers "is this the same picture?", so that a copy of an artwork can be recognised even after the copier flipped it, inverted its colours or scaled it up. PAPH is built for pixel art specifically: small images, flat colours, hard edges and repetition, which defeat the perceptual hashes made for photographs.
The intended use, stated in the repository and on pixa.org, is plagiarism detection before an artwork is published or sold. That use is not implemented: the app does not import the library (Search), and the pixa.org library page's sentence "used for plagiarism detection before an image becomes an NFT" describes an intention, not a running system.
What it computes
hash(rgbaPixels, width, height) takes an RGBA byte buffer and returns two tiers (README.md, SPEC-005.1.md §2):
| Tier | Size | Contents | Use |
|---|---|---|---|
Tier 1 (t1) |
2,560 bytes, fixed | Sectioned structural channels of the whole image, with a CRC-32 | Index search and the fast screen(a, b) pre-check |
Tier 2 (t2) |
32 + 32 × n bytes, n ≤ 512 | Keypoint records: position, pyramid level, orientation, strength, region and a 128-bit descriptor in two 64-bit planes, with CRC-32s linking it to Tier 1 | Geometric evidence in compare |
Extraction follows a frozen profile, PAPH5-E03: luma (54r + 183g + 19b + 128) >> 8, matte folding for images on a flat border, detection and removal of exact k×k upscales, a 5551 palette, a FAST corner detector with threshold 18, non-maximum suppression 4 and a pyramid with a 10/13 ladder. Everything is integer arithmetic: the same bytes in give the same bytes out on every platform, which is what lets fingerprints computed by different programs be compared and stored.
How it compares
compare(a, b) returns a report with a verdict and the evidence behind it (SPEC-005.1.md §3-§7):
| Verdict | Meaning |
|---|---|
Identical |
The same image |
Copy |
The same work, transformed |
Related |
Shared structure beyond chance |
Suspected |
Evidence that needs a human look |
Unrelated |
Different works (the specification calls this verdict Distinct; the code says Unrelated) |
Indeterminate |
The comparison could not be made: corrupt tiers, too few keypoints, or an image outside the method's reach |
The evidence comes from three axes, each scored on a 0 to 10,000 scale: structure (seven channels over Tier 1), geometry (a staged search over the eight D4 transforms, rotations and mirrors, with an inversion family, matching Tier 2 keypoints) and diversity, which demotes matches driven by repetition, a tiled pattern matching another tiled pattern. The report also carries an evidenceClass and an assetRisk level; the TypeScript declarations name the middle level ELEVATED and the code emits POSSIBLE, one of the discrepancies listed below.
The comparator is specified to survive, alone or combined: all eight D4 transforms, colour inversion, tone shifts, nearest-neighbour upscales, and crops pasted into new compositions. Its conformance suite covers 19 verdict scenarios and 13 frozen golden vectors, which the repository names as the contract any other implementation, such as a planned Rust and WebAssembly engine, must meet.
Versions, calibration and performance
| Aspect | Value |
|---|---|
| Package | @pixagram/paph-js 5.3.1, MIT, © Pixagram SA; Node 18 or later; CommonJS and ES module entry points; subpaths /wire and /comparator |
| Wire format | 5 |
| Comparator | 51 |
| Extraction profile | PAPH5-E03 |
| Specification | docs/SPEC-005.1.md in the repository; there is no SPEC-006 |
| Calibration | CAL-051-PROVISIONAL: thresholds and lookup tables set from the conformance fixtures, "honest about not having seen a production corpus". tools/calibrate.cjs fits a real profile from a labelled corpus and refuses to bless one below the specification's gates: at least 24 image families, 60 images, 60 positive pairs and 10 measurable positives per channel. |
| Browser build | dist/paph53.browser.js, no dependencies, attaches PAPH53 to the global object; the README still says PAPH51 |
| Performance | CHANGELOG 5.3.0: a 150×110 image hashes in about 21.8 ms and a pair compares in about 36.8 ms (median, JavaScript, the project's build container); the specification's informative figures, 95 ms and 117 ms, predate that release |
Because the calibration is provisional, the verdict thresholds have not been fitted to real Pixagram artworks. A deployment would start by building a labelled corpus and running the calibration tool; until then, verdicts are the fixtures' verdicts.
The API
JavaScriptimport { hash, compare, screen, parseT1, parseT2, cal, profileEncode, profileDecode } from '@pixagram/paph-js';
const a = hash(pixelsA, widthA, heightA); // { t1, t2, detail }
const b = hash(pixelsB, widthB, heightB);
screen(a, b); // Tier 1 only: fast rejection
const report = compare(a, b); // verdict, evidenceClass, assetRisk, channels, geometry
compare(a, b, { profile: profileDecode(bytes) }); // with a fitted calibration
hash also accepts an ImageData object. The input must be RGBA, 4 bytes per pixel, or the call throws. Fingerprints are plain byte arrays, so they can be stored next to a post's permlink, in a database or in a post's json_metadata; nothing in the chain's rules knows them.
What exists and what does not
| Aspect | State |
|---|---|
| The library, its specification, tests and golden vectors | Published |
| A production calibration | Not done; the profile is provisional |
| Use in the app at publication time | Not implemented. The app bundles @pixagram/pixahash for content hashing only (Search) |
| Use in the operator's search service | Not visible from the app; the service's code is not published |
| An index of fingerprints for every artwork on chain, and a similarity search over it | Not built. No code or specification exists; the planned pages of this section stay planned until it does (Search and indexing) |
| A chain rule that reads or stores fingerprints | None, and none planned; the chain stores posts, not judgements about them (Data Model) |
What this means for an artist today: nothing stops a copy of an artwork from being published as a new post, and nothing marks it. Provenance comes from the chain's order of events, the original being in an earlier block, and from the community's eyes (Permanence and Provenance). A program that wanted to detect copies could do it now with this library and the public API: hash every artwork from bridge.get_ranked_posts as it appears, keep the Tier 1 fingerprints, and screen new ones against them.
Discrepancies in the repository
Recorded so that nobody is surprised by them; none affects the computed bytes.
- The README's title says "PAPH 5.1" and names the browser global
PAPH51; the package is 5.3.1 and the bundle attachesPAPH53. - The specification's verdict lattice says
Distinct; the code and README sayUnrelated. index.d.tsdeclares the asset-risk levelsLOW | ELEVATED | HIGH; the code emitsPOSSIBLEfor the middle one.- The CHANGELOG stops at 5.3.0 (2026-08-28); the published 5.3.1 has no entry.
- pixa.org's library page lists version 5.3.0 and describes production use that does not exist.
Inherited → changed
Hive has no perceptual hashing in its protocol or its reference front ends; copy detection, where it exists, is done by community curation projects outside the chain. Pixa's chain is the same in this respect. PAPH is a library in the Pixagram ecosystem, not a chain feature.
Sources
- Repository
pixagram-blockchain/paph-jsat commit8959a08:README.md,docs/SPEC-005.1.md,CHANGELOG.md,index.d.ts,src/paph-js.cjs:1308(POSSIBLE),dist/paph53.browser.js:3205(PAPH53),package.json. - npm:
@pixagram/paph-js, version 5.3.1 on 2026-10-08. - App at commit
ca1d157: no import of@pixagram/paph-js;@pixagram/pixahashinpng-db.js:1. - pixa.org: the library page and the interface page, read on 2026-10-07.