# Immutable JSON / CIP25

**URL:** <https://forums.counterparty.io/t/immutable-json-cip25/6428>\
**Category:** Counterparty\
**Created:** [September 14, 2022, 7:02am UTC](https://forums.counterparty.io/t/immutable-json-cip25/6428 "2022-09-14T07:02:56Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![JPJA](https://yyz2.discourse-cdn.com/flex004/user_avatar/forums.counterparty.io/jpja/32/1324_2.png) [@JPJA](https://forums.counterparty.io/u/JPJA)\
**Post date:** [September 14, 2022, 7:02am UTC](https://forums.counterparty.io/t/immutable-json-cip25/6428/1 "2022-09-14T07:02:56Z")

</div>

For the upcoming [CIP25](https://gist.github.com/jdogresorg/a8b3aa5e4d48e5e9a9324f9e41010346) (Enhanced Asset Information Spec) I suggest a standard for immutable content.

For files, add a `sha256` field. Example;

```auto
"images": [{
        "type": "icon",
        "size": "128x128",
        "data": "https://domain.com/icon128.png",
        "sha256": "8031025a667824a188dd5479ca5cb20c5306be06ed01875f7bcc11ecb48251be"
    },{
        "type": "large",
        "data": "https://domain.com/image_large.png",
        "sha256": "2bca95eb91e6be1e9ae5b23de5f8373952987f0cdebbd7f6b0d484821951f486"
    }],

```

It is essential to have an onchain hash too _(believe me, I found this mistake repeatedly when I ran [the archiver](https://jpjanssen.com/back-up-your-bitcoin-nfts/))_. A practical solution would be to put a hash inside the asset description together with the json url.

I recommend a truncated sha256 hash of at least 24 hex characters or 16 [base64url](https://base64.guru/standards/base64url) characters\*. This hash is of the json file, meaning a token issuer who wants immutability must provide both:

1. Hash of files inside the json file
2. Hash of json file in asset description

Advantages of this approach

- Easy to add manually for issuers
- Easy to add automatically for issuers
- Easy to verify manually
- Easy to verify algorithmically
- Wallets/explorers/[archives](https://github.com/Jpja/XDP-Image-Archive) can affordably keep the records they want (e.g json files and icons for all assets but ignore high resolution images)
- No need to look up url if you have a local version
- If url dies, the files with matching hashes are sufficient to recreate the asset (big deal for token issuers so they won’t need to trust services such as easyassets etc to remain online)
- Truncated hash means asset url+hash should fit op\_return

Examples of possible immutable asset descriptions:

1. [jpjanssen.com/i/asset/2bca95eb91e6be1e9ae5b23d.json](http://jpjanssen.com/i/asset/2bca95eb91e6be1e9ae5b23d.json)
2. easyasset.art/j/QKr-5saazd\_jXi8R/SOMEASSET.json
3. [myurl.net/x/asset.json;JTh/QRy27yRYi1CkQKI8bg\_rX3omgtNf3VkP9rgRJz8](http://myurl.net/x/asset.json;JTh/QRy27yRYi1CkQKI8bg_rX3omgtNf3VkP9rgRJz8)

The rules that would apply:

- If protocol not specified, assume https://
- Anything before semicolon “;” is potentially a url
- Url must end with “.json”
- Check for the first lowercase hex string of at least 24 char (regex: `[0-9a-f]{24}`) or base64url of at least 16 chars (regex: `[0-9a-zA-Z-_]{16}`)
  - If found, verify that downloaded json matches hash
  - If url does _not_ match, but a file exists that does match, the matching file has priority
  - If url does not match and no matching file exists either, display url content

A best practice is to keep the description at 52 char max (this is the maximum to fit op\_return). For subassets the limit is less (exactly how much?) so in those cases you either need to make a shorter url, a short sub-name or just pay the extra btc fees.

\*_Notes on truncated hash:_

- 24 hex character or 16 base64 characters both correspond to 96 bits. Accidental collisions will never happen. An attacker who deliberately tries to make a collision will not be able to do so either. 96 bits means there are 2^96 possible values;  
`= 79228162514264337593543950336`  
Attacker with a billion trials/sec over 100 years, 100 \* 365 \* 24 \* 3600 \* 1e9;  
`= 3153600000000000000`  
Even in a hundred years, attacker has something like a one in a billion chance of making a collision. And (theoretically) if he did manage, the earliest file with a matching hash should get priority.

_Notes on immutability mistakes:_

- With the archiver, I found several json files with proofs inside the json but with no onchain hash. It’s impossible to know if the json file has been tampered with, thus “proof” is worthless. This applies to easyasset links afaik. I strongly suggest they look into this.
- MD5 hash is useless. Read [this](https://emaragkos.gr/infosec-adventures/create-your-own-md5-collisions/); it took 18 hours / $11.70 to make a collision.
- Ipfs links are often “broken”. I don’t think there’s anything wrong with ipfs but the _users_ have failed to use it correctly. Yet, these can always be recreated later as they do have a hash inside the url. Why I’m _not_ suggesting ipfs are 1) unnecessary to rely on one specific standard, and 2) links are too long for op\_return.

---

<div class="post-metadata">

**Author:** ![NotJon](https://avatars.discourse-cdn.com/v4/letter/n/8c91f0/32.png) [@NotJon](https://forums.counterparty.io/u/NotJon)\
**Post date:** [October 11, 2022, 2:39pm UTC](https://forums.counterparty.io/t/immutable-json-cip25/6428/2 "2022-10-11T14:39:06Z")

</div>

Having a hash prevents the file being linked to from being modified - but what if you have a malicious json host ? it does not prevent the malicious host from changing both the the files and its hash, so to prevent that we could sign our hashes with our private key

“type”: “large”,  
“data”: “[https://domain.com/image\_large.png](https://domain.com/image_large.png)”,  
“sha256”: “2bca95eb91e6be1e9ae5b23de5f8373952987f0cdebbd7f6b0d484821951f486”  
“sig”: “IAy9WmzdJvfqq/0IQg6baNsZqLv1IkBKo3xt97EzjNvBM1ueEM93aPk5xC62ldCE5GWE8kM+BepSWRcOCTQVSw=”

Obviously the private key that is the asset owner would need to be the one that is used

I am just throwing this idea out there

---

<div class="post-metadata">

**Author:** ![JPJA](https://yyz2.discourse-cdn.com/flex004/user_avatar/forums.counterparty.io/jpja/32/1324_2.png) [@JPJA](https://forums.counterparty.io/u/JPJA)\
**Post date:** [October 13, 2022, 7:50am UTC](https://forums.counterparty.io/t/immutable-json-cip25/6428/3 "2022-10-13T07:50:42Z")

</div>

If the file and/or the `sha256` property is modified by a malicious host, the onchain hash will no longer match the content.  
A `sig` field may serve the same purpose as `sha256` for **immutable** content at the expensive of more complicated verification. The onchain hash serves as signature, making the `sig` field redundant.

For a **mutable** asset, where content may be updated, the `sig` property is preferable as it proves the origin + eliminates the need for further onchain tx’s. In such cases no onchain hash should be used.

IMO:

- `sha256` inside json + onchain hash is best practice for **immutable** asset.
- `sig` inside json with no onchain hash is best practice for **mutable** asset.

For CIP25 I recommend both `sha256` and `sig` as optional fields.
