> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/apps/0145.md).

# Registry-Free Typed Content Anchor with On-Chain Code Provenance

RexStarBSV (<294282606+RexStarBSV@users.noreply.github.com>)

## Abstract

This BRC specifies a **registry-free typed content anchor**: a deterministic scheme for committing to *typed* content with a single 32-byte anchor and no central registry. An anchor is `SHA-256(INKAN_DOMAIN || u8(len(kind)) || kind || data)`: a fixed domain string separates these digests from every other SHA-256 usage, a one-byte length prefix makes the `kind`/`data` boundary unambiguous for all inputs, and the `kind` string is *inside* the digest so two anchors of different types never collide even when the underlying `data` is identical. Because the type is carried in the digest and the type namespace is content-derived, third parties assign their own kinds and tiers (`[namespace:]name[@t1|t2|t3]`) without asking anyone, and the same kind renders and verifies identically on every device, forever. Anchors serialize to self-identifying **`ik1` codes** whose version prefix keeps the construction hash-agile. The same primitive produces **software/build provenance**: a per-adopter tamper fingerprint over running code, published on-chain as an immutable data record or a 1-of-1 (1Sat) code-provenance ordinal that any client re-verifies against the build it is executing. This BRC defines the anchor construction, the code format, the open kind system, the tamper fingerprint, and the on-chain provenance record, in enough detail for an independent second implementation to interoperate byte-for-byte.

In plain terms: this standard describes a way to take any piece of digital content (an address, a document, a contract, a software release) and produce a short, permanent fingerprint for it that also records what kind of thing it is. Two different kinds of content can never share a fingerprint, even when their raw bytes are identical, and anyone can invent a new kind for their own application without asking a registry, a committee, or this document. The fingerprint writes out as a compact text code, renders as a deterministic visual seal that looks the same on every device forever, and can be published on the BSV chain as a permanent, timestamped record. The same mechanism lets a software project publish the fingerprint of a released build on chain, so any user can check that the code they are running is exactly the code that was released. The scheme is published as the **Inkan Standard v1.0** (frozen) by RexStarBSV, with a complete Python reference implementation and JavaScript and Kotlin ports proven byte for byte against a shared vector suite for the layers each implements.

## Motivation

Bitcoin SV applications routinely need to commit to a piece of content (an address, an identity key, an account, a contract, a build artifact) in a way that is (a) deterministic across languages and devices, (b) *typed*, so a commitment to one kind of thing cannot be confused with a commitment to another, and (c) coordinated without a registry, so any party can introduce a new type without a gatekeeper.

The existing BRC stack does not provide this primitive:

* **BRC-42 / BRC-43 (BSV key derivation, invoice numbering / protocol IDs)** namespace *keys* by protocol and key IDs that two parties must already share. They are a coordination convention for derivation, not a general typed content-commitment, and they presuppose the counterparties agree on the protocol string out of band.
* **BRC-100 (wallet-to-application interface)** and its `createAction` give an application a way to *write* arbitrary bytes to the chain, but say nothing about how to canonically commit to typed content before writing it. Two apps that both "hash the thing and put it in an `OP_RETURN`" produce incompatible, type-blind, domain-unseparated digests.
* **Overlay-network discovery (topic managers / lookup services)** solves coordination by introducing exactly the registry this scheme is designed to avoid: a topic string must be recognized by an overlay to be meaningful.
* **Visual-hash / identicon conventions** (LifeHash, jdenticon, blockies) are presentation-only. They render a digest but define neither a typed, domain-separated digest nor a self-describing, version-tagged code, and none binds the *type* of the content into the commitment.

No existing BRC covers a **registry-free typed content commitment** or **software/build provenance published on-chain**. A bare `SHA-256(content)` has three defects this BRC fixes: it is not domain-separated (the same digest can mean anything, inviting cross-protocol confusion), it is not type-bound (a hash of an "address" equals a hash of the same bytes labelled "contract"), and it has no in-band version of the hash function (a future migration off SHA-256 is silent and dangerous). The scheme defined here closes all three while remaining a plain SHA-256 that any language computes with its standard library.

## Relationship to related work

NotaryHash (Gregory Ward, SmartLedger; merged as BRC-220) and this proposal overlap in two ways: both anchor a content commitment on chain, and both derive that commitment from a deterministic length-prefixed binary encoding, so any language reproduces identical bytes. They answer different questions. NotaryHash standardizes a notarization certificate: a signer proves, SPV-verifiable against block headers alone, that they signed one specific `SHA-256(content)` at the block where it was mined, and the document itself never leaves the client. That is the right tool when what matters is who signed a given hash and when. This proposal standardizes a registry-free *typed* content commitment. The `kind` of the thing being committed to is folded into the digest by a fixed domain string and a one-byte length prefix, so a commitment to an address and a commitment to a contract over identical bytes produce different anchors that cannot collide, and no central authority allocates or arbitrates the type namespace. Around that anchor it adds a self-versioning code format that keeps the construction hash-agile, plus a per-adopter fingerprint used for running-code and build provenance. The two layers compose cleanly: a typed anchor computed here can itself be the hash a NotaryHash certificate signs. Cite NotaryHash for the bare signed-hash anchoring case; the contribution here is the typed-commitment and type-system layer above it.

## Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as in RFC 2119.

### 1. Constants

All multi-byte integers below are big-endian unless stated otherwise. `u8(n)` denotes the single unsigned byte `n` (`0 ≤ n ≤ 255`). `||` denotes byte concatenation. Text is encoded to bytes with UTF-8 (RFC 3629). "NFC" denotes Unicode Normalization Form C (UAX #15). `hex(x)` denotes lower-case, zero-padded hexadecimal.

| Name             | Value                            | Bytes (hex)                                  | Role                                     |
| ---------------- | -------------------------------- | -------------------------------------------- | ---------------------------------------- |
| `INKAN_DOMAIN`   | ASCII `"inkan/v1"` + `0x00`      | `69 6e 6b 61 6e 2f 76 31 00`                 | glyph/anchor domain (9 bytes)            |
| `CODE_PREFIX`    | `"ik1"`                          | `69 6b 31`                                   | self-identifying code prefix             |
| `SHORT_CODE_LEN` | `16`                             | n/a                                          | hex chars in a short code body (64 bits) |
| `KIND_DOMAIN`    | ASCII `"inkan/kind/v1"` + `0x00` | `69 6e 6b 61 6e 2f 6b 69 6e 64 2f 76 31 00`  | open-kind derivation domain (14 bytes)   |
| `FP_SUFFIX(v)`   | `"/inkan/v" + dec(v) + 0x00`     | e.g. `v=1` → `2f 69 6e 6b 61 6e 2f 76 31 00` | tamper-fingerprint domain suffix         |
| `MARKER`         | ASCII `"INKANC1"`                | `49 4e 4b 41 4e 43 31`                       | on-chain signed-record marker (7 bytes)  |

Open-kind resolution constants (§4):

* `TIER_CELLS = { "t1": 72, "t2": 48, "t3": 24 }`; default tier is `t2`.
* `KMAX = { 72: 2, 48: 4, 24: 7 }`.
* `ORBIT_REPS = (0, 1, 3, 5, 7, 9, 11, 13, 15, 21, 23, 27, 31, 63)`, 14 rotation-distinct 6-bit frame representatives.

`INKAN_DOMAIN`, `CODE_PREFIX`, and `KIND_DOMAIN` are permanent. An implementation MUST NOT alter any of them; changing `INKAN_DOMAIN` or `CODE_PREFIX` invalidates every anchor ever computed and is a new version namespace, not a revision (§9).

### 2. The anchor

Given `data` (an octet string, or text) and `kind` (a string):

1. If `data` is text, set `data_bytes = utf8(NFC(data))`. If `data` is raw octets, set `data_bytes = data` **verbatim** (raw bytes MUST NOT be normalized, they are not text).
2. Set `kind_bytes = utf8(NFC(kind))`. The implementation MUST reject `kind` with `len(kind_bytes) > 255`.
3. The **glyph seed** is:

```
seed = INKAN_DOMAIN || u8(len(kind_bytes)) || kind_bytes || data_bytes
```

4. The **anchor** is `SHA-256(seed)`, exactly 32 octets (FIPS 180-4).

The anchor is the sole basis for trust: it is what a receipt commits to, the input to every presentation, and the value re-derived during verification. Any visual or other presentation of an anchor is a convenience; the anchor, never the presentation, is trusted.

**Why the length prefix (normative rationale).** Without `u8(len(kind_bytes))` between `kind_bytes` and `data_bytes`, the concatenation `kind_bytes || data_bytes` is ambiguous: `kind="address", data="X"` and `kind="", data="addressX"` produce the same trailing bytes and therefore the same anchor. The one-byte length prefix makes the boundary unambiguous for every possible `(kind, data)` pair (see Test Vector 5). An implementation MUST include it exactly as specified.

**Why the type is in the digest (registry-free typing).** Because `kind_bytes` is inside `seed`, an anchor for `(data, kindA)` and an anchor for the *same* `data` under `kindB` differ whenever `kindA ≠ kindB`. Type collisions are therefore cryptographically excluded rather than administratively prevented, so no allocation authority or registry is required to keep two adopters' types apart.

### 3. Codes (`ik1`)

An anchor serializes to a self-identifying ASCII string:

```
full = CODE_PREFIX || hex(anchor) # "ik1" + 64 hex chars = 67 chars
short = CODE_PREFIX || hex(anchor)[:16] # "ik1" + 16 hex chars = 19 chars
```

* The literal `ik` marks an anchor code; the trailing digit is the **code-format / hash version**. `1` denotes SHA-256 over glyph domain `inkan/v1`.
* The hex body of a code is a genuine prefix of the full anchor, so any code (including a short code) is auditable by recomputing the anchor and checking the prefix. The short code's 16 hex chars are 64 bits: collision-safe to billions of items and forgery-resistant, while remaining short enough for filenames and display. A short code is a **label only**; trust decisions MUST use the full 32-byte anchor.
* **Version handling (MUST).** A reader parsing a code MUST verify the version prefix. If a code begins with `ik` but not with a version this implementation supports (e.g. a future `ik2`), the reader MUST reject it rather than assume SHA-256. The reference parse is: reject if the string does not start with `ik`; reject if it does not start with the supported `CODE_PREFIX`; otherwise the digest hex is the remainder after `CODE_PREFIX`. This is what keeps the anchor hash-agile: a hash migration is a new prefix (`ik2…`), unambiguously distinguishable at parse time.

### 4. Kinds, open, tier-weighted, third-party assignable

A `kind` is any UTF-8 string of at most 255 bytes. By convention it is written `[namespace:]name[@tier]` (e.g. `address`, `acme:invoice@t3`, `acme:vault@t1`) but the anchor (§2) treats it as an opaque byte string, so any string that encodes as valid UTF-8 is a valid kind. Namespacing (`ns:`) lets adopters avoid clashing without coordination; because the whole string is inside the digest, `acme:invoice` and `beta:invoice` are distinct anchors even over identical data.

A value that cannot be encoded as valid UTF-8 is **not** a kind: an implementation MUST reject it and MUST NOT substitute replacement characters. Substitution is not a lenient reading of this rule, it is a collision. Every unpaired surrogate encodes to the same replacement bytes, so two distinct kinds that differ only in their ill-formed portion would derive one anchor, and a commitment to one would verify against the other.

Presentations (the visual seal, §5) require a `kind` to resolve to geometry parameters `(cells, k, motif)`, where `cells ∈ {24, 48, 72}` is the tier's cell count, `k ∈ 1..7` is a rotational-symmetry order, and `motif` is a 6-bit frame code. Resolution is:

**4.1 Reserved kinds.** If `kind` is a key of the reserved table below, use its curated entry directly:

| kind                   | cells | k | motif |
| ---------------------- | ----- | - | ----- |
| `""` (empty / default) | 48    | 2 | 63    |
| `identity`             | 48    | 4 | 56    |
| `account`              | 48    | 3 | 36    |
| `address`              | 72    | 1 | 51    |
| `vault`                | 72    | 1 | 61    |
| `signer`               | 72    | 2 | 54    |
| `contract`             | 72    | 2 | 60    |
| `code`                 | 24    | 7 | 42    |
| `report`               | 24    | 6 | 44    |
| `collection`           | 24    | 5 | 48    |
| `backup`               | 24    | 4 | 32    |
| `custom/24`            | 24    | 1 | 52    |
| `custom/48`            | 48    | 1 | 52    |
| `custom/72`            | 72    | 1 | 52    |

**4.2 Derivation (any other kind).** If `kind` is not reserved, derive `(cells, k, motif)` deterministically:

1. **Tier.** If `kind` ends with the literal suffix `@t1`, `@t2`, or `@t3`, that selects the tier; otherwise the tier defaults to `t2`. (The reference tests the suffixes in the order `t1, t2, t3` and takes the first match.) `cells = TIER_CELLS[tier]`.
2. **Kind hash.** `kh = SHA-256(KIND_DOMAIN || utf8(kind))`, where `kind` is the kind string **as provided** (see the normalization note below).
3. **Symmetry.** `k = 1 + (kh[0] mod KMAX[cells])`.
4. **Frame motif.** `motif = ORBIT_REPS[ kh[1] mod 14 ]`.

Because the tier is part of the kind string and the kind is part of the anchor, the same kind renders identically everywhere and namespaced kinds never collide between adopters, **no registry is needed** for either the anchor or the presentation.

> **Normalization note (MUST-for-interop).** The anchor (§2) NFC-normalizes `kind` before hashing; the reference presentation-derivation in §4.2 hashes the kind bytes **as provided** (no explicit NFC step) and performs the reserved-table lookup and suffix test on the string as provided. For an ASCII kind (all reserved kinds are ASCII) the two layers are identical. To keep the anchor and the presentation consistent for non-ASCII kinds, callers SHOULD pass kinds already in NFC. An implementation aiming for byte-exact parity with the reference presentation MUST NOT insert an NFC step into §4.2.

**Tiers and exposure.** Tiers `t1/t2/t3` map to cell profiles `72/48/24`. More cells means more visible entropy and a costlier forgery (§ Security Considerations); value-at-risk kinds (e.g. `address`, `vault`) SHOULD use `t1`. The resolution parameters affect only the presentation; **the anchor never depends on `(cells, k, motif)`**, it depends only on the exact `kind` string. Two distinct kind strings that happen to resolve to the same `(cells, k, motif)` still produce distinct anchors.

### 5. Deterministic presentation (the seal)

An anchor MAY be rendered to a deterministic visual **seal** so a human notices when a trusted value changes. The seal is optional to this BRC's interoperability core (anchor + code + kind, §2-§4). Its full pixel-level construction is out of scope here; an implementation that renders seals MUST match the reference conformance vectors byte-for-byte at the RGB level. The seal's normative contract is:

* **Deterministic and float-free.** Geometry and palette are integer tables, so all implementations agree byte-for-byte by construction, not by luck. Seal renderer version is `SEAL_VERSION = 3`.
* **The kind selects symmetry and frame.** `(cells, k, motif)` from §4 fix the rotational symmetry order and the 6-bit frame, so a seal of one kind cannot be confused with a seal of another.
* **A visible distance floor.** Interior cells carry 2 bits each from bit-interleaved extended Golay \[24,12,8] blocks; any two distinct seals of the same profile differ in at least 8 cells (Golay minimum weight), a floor verified tight over all 4096 code words.
* **Byte-deterministic PNG.** The canonical seal is an 8-bit indexed PNG whose chunks are exactly `IHDR`, `PLTE`, `IDAT`, `IEND`, with **no ancillary chunks**. The cross-language invariant is the decoded RGB pixel content, not the compressed bytes (deflate output is per-implementation). A **tagged** export additionally embeds `iTXt` chunks (keyword `inkan-code` carrying the full `ik1` code, keyword `inkan-kind` carrying the kind) making the image self-describing. The embedded code is an **untrusted hint**: a verifier MUST recompute the anchor and compare pixels, treating the tag only as a cross-check.

`iTXt` body layout used by the reference tagged export, for a `keyword` and UTF-8 `text`:

```
keyword(latin-1) || 0x00 || 0x00(comp flag) || 0x00(comp method) || 0x00(empty lang) || 0x00(empty translated keyword) || utf8(text)
```

**Verification of a presented seal.** To verify a seal claimed to be `(data, kind)`: recompute the anchor and the canonical seal; decode the presented PNG to native RGB; if it is an exact integer multiple of the canonical size, integer-downscale it, otherwise reject; compare pixel-for-pixel. Result is GENUINE iff equal. Re-encoding and integer upscales are tolerated; a resampled, cropped, or otherwise different image is rejected. Verification MUST NOT trust embedded metadata.

**Downscaling is a check, not a resize.** When the presented image is an integer upscale by factor *s*, the verifier MUST confirm that every pixel of each *s×s* block is identical before reducing that block to one pixel. Sampling one pixel per block and discarding the rest satisfies a pixel-for-pixel comparison of the reduced image while leaving *s²−1* of every *s²* pixels unexamined and under the presenter's control: at *s* = 8 that is 63 of every 64 pixels, 98.44% of what the viewer actually sees, free to carry a different mark entirely. A block whose pixels are not uniform MUST be reported as a verification failure in its own right, never as a size error and never as GENUINE.

**Rendering-affecting chunks MUST be rejected.** A presented PNG carrying `tRNS`, `gAMA`, `iCCP`, `sRGB`, `cHRM`, `sBIT`, `bKGD`, or the APNG chunks `acTL`, `fcTL`, `fdAT` MUST be rejected. These change what a conformant viewer draws without changing the stored pixel values the comparison reads, so an image that is byte-identical under comparison can present as a different mark. The constraint above on the canonical seal binds what a writer emits; this binds what a verifier accepts, and the two are not the same requirement. Chunks that cannot alter rendering (`tEXt`, `iTXt`, `pHYs`, `tIME`) remain tolerated.

### 6. Tamper fingerprint (build / running-code provenance digest)

The per-adopter tamper fingerprint of an octet payload (a build's bytes, an asset, a config) is:

```
domain_prefix = u8(len(adopter_bytes)) || adopter_bytes || FP_SUFFIX(version)
 = u8(len(adopter_bytes)) || adopter_bytes || "/inkan/v" || dec(version) || 0x00
fingerprint = SHA-256(domain_prefix || payload)
```

where `adopter_bytes = utf8(NFC(adopter))`, `len(adopter_bytes) ≤ 255` (reject otherwise), and `version` defaults to `1`. `fingerprint_hex` is the lower-case hex of the 32-byte digest.

The length-prefixed, per-adopter domain namespaces each project: identical payloads yield **distinct** fingerprints across adopters while every adopter shares the same universally verifiable scheme, and no adopter needs to register its name. A one-byte change in `payload` changes the whole digest (avalanche). This fingerprint is the digest used for **software/build provenance**: the fingerprint of the running build.

### 7. On-chain provenance

An anchor or a fingerprint (§2, §6) MAY be committed to the chain to obtain an immutable, timestamped, non-retractable record. This BRC defines two on-chain forms; both are self-verifying (a client re-derives everything offline and trusts the chain only for immutability and time-ordering).

**7.1 Signed-record data output (reference `OP_RETURN` form).** A signed statement (the reference case is a warrant/compromise **canary**, but the container is general) is carried as a data output whose locking script is:

```
OP_RETURN
push( MARKER) # "INKANC1", 7 bytes
push( canonical_record_bytes) # §7.2
push( der_signature) # secp256k1 ECDSA, DER
push( public_key) # 33-byte compressed secp256k1 point
```

Each `push(blob)` is minimal Bitcoin script pushdata: for `n = len(blob)`,

* `n < 0x4C` → `u8(n) || blob`
* `0x4C ≤ n ≤ 0xFF` → `0x4C || u8(n) || blob`
* `0x100 ≤ n ≤ 0xFFFF` → `0x4D || u16le(n) || blob`
* otherwise → `0x4E || u32le(n) || blob`

A reader parses the script by matching `OP_RETURN` then reading four pushes in order; it MUST reject the output if the first push is not exactly `MARKER` or if any push is truncated. Everything a verifier needs (the record, the signature, and the public key) is on-chain, so the output is checked entirely offline (§7.3). The reader MUST NOT trust the parsed bytes; it re-verifies them.

**7.2 Canonical record and signature.** A signed record is a JSON object serialized canonically: keys sorted lexicographically, no insignificant whitespace (`separators` `,` and `:`), UTF-8, non-ASCII left un-escaped. The reference canary record has fields:

| field          | type       | meaning                                         |
| -------------- | ---------- | ----------------------------------------------- |
| `v`            | int        | record version (`1`)                            |
| `domain`       | string     | operator/publisher identifier                   |
| `seq`          | int        | monotonic sequence number                       |
| `date`         | string     | `YYYY-MM-DDTHH:MM:SSZ` (UTC)                    |
| `block_height` | int        | a recent chain-tip height (anti-backdate proof) |
| `block_hash`   | hex string | that tip's block hash                           |
| `statement`    | string     | the human-readable assertion                    |

The message to sign/verify is `SHA-256(canonical_record_bytes)`. The signature scheme is secp256k1 ECDSA, DER-encoded, deterministic per RFC 6979, low-S. A signature-algorithm identifier is reserved for a future post-quantum migration. The `block_height`/`block_hash` pair binds the record to a chain tip so it cannot have been pre-signed before that block existed.

**7.3 Status.** A verifier reports exactly one of:

* `INVALID`, the signature does not verify against the published key over `SHA-256(canonical_record_bytes)`.
* `STALE`, signature valid but the record is outside the freshness window: with `now`, `max_age_days` (reference default 35), and `date` parsed as UTC, the record is fresh iff `-86400 ≤ (now − date_seconds) ≤ max_age_days · 86400` (i.e. not expired and not implausibly future-dated by more than one day).
* `OK`, signature valid and fresh.

For a canary, absence, `STALE`, or `INVALID` is itself the warning.

**7.4 1-of-1 ordinal form (code-provenance ordinal).** A build's provenance MAY instead be published as a 1-of-1 (1Sat) ordinal whose inscription content is the canonical **tagged** seal PNG (§5) of the build's fingerprint (§6). The `iTXt` `inkan-code` / `inkan-kind` tags make the inscription self-describing; the ordinal's single-satoshi custody model conveys and transfers the mark. The inscription envelope and transfer follow the 1Sat Ordinals convention (referenced, not redefined here). A client verifies a running build by recomputing the build's fingerprint, forming its `ik1` code, and comparing against the on-chain code-provenance ordinal for that release; the displayed seal *is* the on-chain-committed mark, so a tampered build cannot reproduce it.

**7.5 Broadcast interoperability (BRC-100, informative).** The reference publishes §7.1 outputs through a BRC-100 wallet: it runs `getVersion → getNetwork → isAuthenticated → getPublicKey → createAction`, funding a single `OP_RETURN` output (`satoshis: 0`) carrying the §7.1 script. The wallet only funds and broadcasts; it never signs the record (the operator signs offline with the bare secp256k1 key), so verification is never coupled to a wallet. An implementation MAY use any broadcast path; the on-chain bytes (§7.1) are what matters. Implementations that broadcast SHOULD default to a test network and require explicit operator opt-in for mainnet, so real funds are the last step, never the first.

### 8. Verification requirements (summary)

* An anchor is re-derived, never received: a verifier presented with `(data, kind)` and a claimed code/seal MUST recompute `SHA-256(seed)` per §2 and compare, and MUST NOT trust any embedded code or metadata.
* A code MUST be version-checked before its body is interpreted as a SHA-256 digest (§3).
* A value that is not valid UTF-8 MUST be rejected as a kind, never substituted; substitution collapses distinct kinds onto one anchor (§4).
* An integer upscale MUST be reduced only after confirming every pixel of each block is identical; sampling one pixel per block leaves the rest unexamined and presenter-controlled (§5).
* A presented image carrying a rendering-affecting ancillary chunk MUST be rejected, because it changes what is drawn without changing the pixels compared (§5).
* An on-chain record MUST be re-verified offline (signature + freshness) after parsing; the chain is trusted only for immutability and timestamp ordering (§7).

### 9. Versioning and parity

* **Anchor** (`inkan/v1`, SHA-256, code `ik1`): permanent. A new hash is a new version namespace (`ik2…`), not a revision. Changing the anchor domain invalidates every anchor ever computed.
* **Presentation** (`SEAL_VERSION`): swappable without touching any anchor. Swapping a presentation never invalidates an anchor, the property that lets an on-chain-anchored digest outlive any renderer. Two surfaces that compare seals MUST share `SEAL_VERSION`.
* **Fingerprint domain** (`FP_SUFFIX` version): per-adopter and independently versioned.

## Test Vectors

All values below are produced by the reference implementation and are reproducible with a SHA-256 and UTF-8 alone (except the ECDSA signature in TV7).

### TV1, anchor of text, default kind

```
data = "Hello" (text) kind = ""
seed (hex) = 696e6b616e2f7631000048656c6c6f
 = INKAN_DOMAIN || 00 (len kind = 0) || "Hello"
anchor = ae63a28a7b3fbae640f24ab4003d285a453e5493b89741326a7fbcc36a2a6a44
code = ik1ae63a28a7b3fbae640f24ab4003d285a453e5493b89741326a7fbcc36a2a6a44
short code = ik1ae63a28a7b3fbae6
resolve_kind("") = (cells=48, k=2, motif=63) [reserved]
```

### TV2, anchor of a typed address (reserved kind `address`)

```
data = "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2" kind = "address"
seed (hex) = 696e6b616e2f7631000761646472657373314276424d53455973745765747154466e354175346d3447466737784a614e564e32
 = INKAN_DOMAIN || 07 (len "address") || "address" || "1BvB…VN2"
anchor = 12cf1aaca7ef50793d990e94c9ae889af6f9e8fdfc28b2f9a72d4028bde05dcd
code = ik112cf1aaca7ef50793d990e94c9ae889af6f9e8fdfc28b2f9a72d4028bde05dcd
resolve_kind("address") = (cells=72, k=1, motif=51) [reserved, tier t1]
```

### TV3, open-kind derivation (no registry): `acme:invoice@t3`

```
kind = "acme:invoice@t3" (not reserved)
tier = t3 (suffix "@t3") -> cells = 24
kh = SHA-256( "inkan/kind/v1\0" || "acme:invoice@t3")
kh[0] = 137, kh[1] = 93
k = 1 + (137 mod KMAX[24]=7) = 1 + 4 = 5
motif = ORBIT_REPS[ 93 mod 14 = 9 ] = 21
resolve_kind("acme:invoice@t3") = (cells=24, k=5, motif=21)
```

This resolves identically on any device with no allocation authority, demonstrating the registry-free kind system. (`myapp:thing` → `(48, 4, 11)` and `acme:vault@t1` → `(72, 2, 27)` resolve the same way.)

### TV4, NFC normalization stability

```
kind entered as "café" with é = U+00E9 (NFC)
kind entered as "café" with e + U+0301 (NFD)
data = "x"
Both anchors = ik188858a890fa01bf5a463e0e4ca0181d18fe261f34799fe5c5d0ab76e0647f6af (equal)

Derived kind "café@t2" (NFC): utf8 = 63 61 66 c3 a9 40 74 32 (8 bytes)
resolve_kind("café@t2") = (cells=48, k=3, motif=1)
```

### TV5, length-prefix collision resistance

```
kind = "address", data = "X" -> ik1b49a32c4d99c6b80b331223166711da0a91105d1aea989430b8dc22e073c97fd
kind = "", data = "addressX" -> ik13780ad6190697cc754df1159766f9c9781aa610529d0654a197a9a31c691a7f7
distinct: TRUE
```

Without the `u8(len(kind))` prefix both would hash `… "addressX"` and collide. The length prefix (`07` vs `00`) makes the boundary unambiguous.

### TV6, tamper fingerprint / build provenance (per-adopter namespacing)

```
domain_prefix("acme", v=1) = 04 61636d65 2f696e6b616e2f7631 00
 = 0461636d652f696e6b616e2f763100
fingerprint("build-bytes-v1", adopter="acme") = d88657e80e283d5a44bd29b83cf8a93ec60729ec635e642b5454b8829bd3e3c6
fingerprint("build-bytes-v1", adopter="otherapp") = 1847961553e04828204efb7322f1763b8ade6faa14f6f78e30b43957a0c24ab1
```

Same payload, different adopter → different digest, with no registration.

### TV7, on-chain signed record and `OP_RETURN` script (§7)

```
record (fields) = { v:1, domain:"acme", seq:7, date:"2026-06-30T00:00:00Z",
 block_height:870000,
 block_hash:"00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff",
 statement:"No warrant, gag, key compromise or coercion." }

canonical_record_bytes (222 bytes, keys sorted, no whitespace) =
 {"block_hash":"00ff...00ff","block_height":870000,"date":"2026-06-30T00:00:00Z",
 "domain":"acme","seq":7,"statement":"No warrant, gag, key compromise or coercion.","v":1}
message_hash = SHA-256(canonical_record_bytes)
 = 7b0991a1ab13b4b17384e1c6acd0017edb77bd563cdea59cdc776993d8c99362

pubkey = 031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f
der_sig = 3045022100d336085483c2dea86794ef3404d7dc7beef56368fd380000e4d0d8f3ac3fe50c
 02200a4fff49ba1173d1b66f8d4a335cb587c221db79280df23fc2b495b081c65e11
verify(record, der_sig, pubkey) = true (secp256k1 ECDSA over message_hash)

OP_RETURN script (339 bytes) begins:
 6a OP_RETURN
 07 494e4b414e4331 push "INKANC1"
 4c de 7b22626c6f636b5f68617368... push canonical_record_bytes (0xde = 222 bytes)
... push der_sig, push pubkey
```

Round-tripping the script recovers `record`, `der_sig`, and `pubkey` for offline re-verification. The keys in this vector are deterministic **test** values; production issuer keys and the first live record are minted at launch and never appear in test material.

## Implementations

The reference implementation is **Inkan**, an offering by RexStarBSV: a frozen v1.0 standard carrying three reference implementations and a pinned conformance-vector suite, from which every value in the Test Vectors above is reproduced.

* **Reference implementation** (Python): `seed`/anchor and code construction (`inkan_digest`, `inkan_code`, `inkan_short_code`, `code_to_digest_hex`), open-kind resolution and the Seal v3 renderer (`resolve_kind`, `seal_rgb`, `seal_png`, reserved `KINDS` table and derivation constants), the tamper fingerprint (`domain_prefix`, `fingerprint_digest`, `fingerprint_hex`), the signed-record/canary module (`canonical_bytes`, `message_hash`, `sign`, `verify`, `status`), and the on-chain anchoring module (`build_canary_script`, `parse_canary_script`, and a BRC-100 `createAction` broadcast path with a testnet default guard). Stdlib-only for everything except secp256k1 signing/verification.
* **JavaScript port**: a dependency-free, synchronous, browser-and-Node port of the anchor, code, kind resolution, seal renderer, and fingerprint, proven byte-for-byte against the Python reference by the shared vectors.
* **Kotlin port**: the mobile/desktop rendering path, likewise held to the shared vectors.
* **Conformance vectors**: a fingerprint/canary/glyph vector set and a Seal v3 vector set (sampled fields, RGB SHA-256s, and constructed minimum-distance pairs) let any implementation prove parity. An implementation conforms iff it reproduces both.
* **Standalone verifier and creator**, offered by RexStarBSV: a command-line verifier with `seal`, `fingerprint`, `canary`, and `selftest` subcommands (the verifier reproduces the pinned vectors before it trusts itself), plus creation of anchors, codes, and seals from any `(data, kind)` pair through the same package.

The reference sources and the full conformance-vector suite are maintained by RexStarBSV, with public release of the Inkan Standard forthcoming; this BRC is written so that a second, independent implementation can be built from the Specification and Test Vectors above without access to them. The optional seal presentation layer (§5) additionally requires the released conformance vectors for byte-level parity; the interoperability core (§2-§4, §6-§7) is fully specified here.

## Mathematical and cryptographic basis

The commitment folds the type into the digest. The anchor is SHA-256 over a fixed, versioned domain string terminated by a zero byte, then the length-prefixed kind, then the content (§2). Because the kind sits inside the preimage, two records of different kinds coincide only if SHA-256 itself collides. The length prefix makes the concatenation injective: given the fixed domain, there is exactly one way to split a preimage back into (kind, content), so no two distinct field assignments produce the same bytes. This is what removes the need for a central type registry, since type distinctness is a property of the hash rather than of a lookup table. Authenticity of the anchoring party, where a use requires it, is a separate signature over the same digest and does not change the commitment.

## Security Considerations

* **The anchor is the trust root; the image is not.** Every verifier MUST re-derive the anchor from `(data, kind)` and MUST NOT trust a presented code, seal, or embedded metadata. A phishing lookalike fails because it is not the byte-exact render of the recomputed anchor.
* **Domain separation and length prefixing.** The fixed `INKAN_DOMAIN` prevents an anchor digest from being mistaken for, or manufactured from, any other SHA-256 usage. The `u8(len(kind))` prefix (§2) and the `u8(len(adopter))` prefix (§6) each close a boundary-ambiguity collision class; both MUST be implemented exactly, as an implementation that drops either re-opens a real collision (TV5).
* **Type binding without a registry.** Because `kind` is inside the digest, cross-type confusion is cryptographically excluded, not administratively prevented. This removes the registry as both a coordination burden and a single point of failure/censorship, but it also means there is no authority to revoke or arbitrate a namespace; adopters MUST choose namespaces they control (e.g. a domain-like `ns:`).
* **Hash agility.** The `ik1` version prefix makes a future migration off SHA-256 explicit and non-silent. A reader that assumes SHA-256 for an unrecognized version (e.g. `ik2`) would mis-verify; readers MUST reject unknown versions (§3).
* **Seal forgery economics.** Visible entropy scales with tier: a perfect visual collision costs on the order of `2^16 / 2^28 / 2^40` renders (birthday) for `t3 / t2 / t1`. Low-tier seals therefore have *findable* perfect collisions **by design** (value-at-risk kinds SHOULD use `t1`, and in all cases the 32-byte anchor, not the image, is the trust root). The 6-bit frame yields 14 distinct frames per configuration; beyond that, open kinds may share a frame. This is defence-in-depth, not a break, since different kinds over the same data always differ in the interior and always differ in the anchor.
* **Honest perceptual limits.** All perceptual-distance figures are model outputs, not measurements of people; no human study has been run, so no accessibility or "phishing-proof" claim is made. Implementers MUST NOT market a seal as human-proof.
* **On-chain records are self-verifying and non-retractable.** A signed record (§7) carries its own record, signature, and public key, so it is checked entirely offline; the chain is trusted only for immutability and timestamp ordering. The `block_height`/`block_hash` binding is an anti-backdate proof. A verifier MUST treat absence, `STALE`, or `INVALID` as the warning (fail-closed), and MUST NOT trust the parsed on-chain bytes without re-verifying the signature and freshness. `INVALID` means a signature check was performed and failed; a verifier whose signature backend is unavailable MUST raise an explicit error and MUST NOT report `INVALID` or `OK`, since a fabricated verdict is a silent false alarm in one direction and a silent pass in the other.
* **Key custody.** The signing key MUST be the operator's own key held offline; the broadcast wallet (§7.5) funds but never signs, so a compromised or coerced broadcast path cannot forge a record. The test-network default (§7.5) keeps real funds as the last step, never the first.
* **Metadata hygiene / privacy.** The canonical seal and the fingerprint image writers emit no ancillary PNG chunks (no author, software, timestamp, or physical-dimension metadata). Implementations MUST preserve this and MUST NOT embed identifying information (public key, fingerprint, name, paymail, timestamp) in a seal's filename; a seal image should reveal nothing about the machine, build, time, or subject beyond the anchor itself. The optional `iTXt` tags carry only the (already public) `ik1` code and kind, and remain untrusted hints.
* **Presentation/anchor consistency for non-ASCII kinds.** The anchor NFC-normalizes `kind` while the reference presentation derivation does not (§4.2 note); callers SHOULD pass NFC kinds so both layers agree.

## References

* FIPS 180-4, Secure Hash Standard (SHA-256).
* RFC 2119, Key words for requirement levels.
* RFC 3629, UTF-8.
* Unicode Standard Annex #15, Unicode Normalization Forms (NFC).
* RFC 6979, Deterministic ECDSA.
* SEC 2 / secp256k1, the ECDSA curve used for on-chain signed records.
* BRC-42, BSV Key Derivation Scheme (protocol/key-ID namespacing contrast).
* BRC-43, Security Levels, Protocol IDs, Key IDs, and Counterparties.
* BRC-100, Wallet-to-Application interface (`createAction` broadcast path used by the optional on-chain anchoring).
* BRC-220, NotaryHash, privacy-preserving signed-hash notarization; the signed-hash counterpart this typed commitment composes with.
* 1Sat Ordinals, 1-of-1 ordinal inscription convention (used, not redefined, by §7.4).
* Golay, M. J. E., Notes on digital coding (extended Golay \[24,12,8], the seal's distance floor).
* The Inkan Standard, version 1.0 (frozen), by RexStarBSV, and its conformance vectors, from which this BRC is drawn.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bsv.brc.dev/apps/0145.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
