# Proof of Integrity

We publicly introduced the concept of ***Proof of Integrity*** along with our first release of PSA Graded Pokémon cards as Connected Collectibles. In short, a Proof of Integrity acts like a tamper-proof seal and establishes that every Courtyard NFT is provably linked to a unique matching physical item stored in our vaults. If someone tries to alter the NFT's fingerprint (i.e. its *identity*), the Proof of Integrity will show that the token is corrupted.

### 1. Item identity and fingerprints

Every item that is stored at Courtyard is identified by an accurate, human readable description and a unique ID. While the description allows anyone to quickly identify the item visually, the unique ID brings further differentiation when we store multiple copies of the same item. Some items, like graded caards, already have a unique ID imprinted on them. WHen an item does not already have a unique identifier, we create one for it and include it on the IRL picture of the item that is associated with the NFT. The accurate description of the asset and the unique ID are used together to form the fingerprint of the asset, which is both unique and human readable at the same time:

{% code overflow="wrap" %}

```
Graded Pokemon TCG | PSA 23303316 | 1999 Pokemon Base Set Shadowless 1st Edition Red Cheeks Pikachu #58 | PSA 9 MINT
```

{% endcode %}

Before storing an asset, we always take a picture of it and make sure that the unique ID that differentiates it from other similar items is shown in the picture, and we include a link to that picture in the metadata of the NFT, along with the 3D rendering:

<figure><img src="/files/b2lN9jQIOKTsJeyvKYFl" alt="" width="188"><figcaption><p><em>IRL picture of the vaulted item</em></p></figcaption></figure>

<div align="center"><figure><img src="/files/YbSb6n2DLgH9mU7ECaip" alt="" width="563"><figcaption><p><em>NFT 3D rendering</em></p></figcaption></figure></div>

### **2.** From a fingerprint to a Proof of Integrity

Because the fingerprint of an item has an arbitrary length, we encode it using a **cryptographic function** called `keccak256`, which is widely used on the Ethereum blockchain as a standard way to securely encode sensitive data. The result of this encoding is what we call the Proof of Integrity. It is a string starting with `0x`, followed by 64 hexadecimal characters that uniquely represents the corresponding physical item:

{% code overflow="wrap" %}

```
0x0b58386d08014f001c1a37ca6b11afd2f3f3e3a578e69a8ed7e7acf68103258e
```

{% endcode %}

The on-chain function that is used to calculate the Proof of Integrity is the following:

{% code lineNumbers="true" %}

```solidity
/**
 * @dev Generates a Proof Of Integrity as the keccak256 hash of a {fingerprint} and a {salt} value.
 *  - the fingerprint is a unique, human readable description of an item.
 *  - the salt value is a random number used to bring some further functionalities, like creating NFTs that can provably exist but remain "unrevealed" until the salt value is made public.
 */
function generateProofOfIntegrity(string memory fingerprint, uint256 salt) public pure returns (bytes32) {
    return keccak256(abi.encodePacked(fingerprint, salt));
}
```

{% endcode %}

A useful property of the `keccak256` function is that if the fingerprint changes by a single character, the resulting Proof of Integrity would be a completely different value, that has nothing to do with the original one. This is how we can tell if a fingerprint has been altered.

{% hint style="info" %}
A useful property of the `keccak256` function is that if the fingerprint changes by a single character, the resulting Proof of Integrity would be a completely different value, that has nothing to do with the original one. This is how we can tell if a fingerprint has been altered.
{% endhint %}

{% hint style="info" %}
In addition to the human readable `fingerprint`, we also use a `salt` value when generating the `Proof of Integrity`. The `salt` is a random number that we use to prevent people from reverse-engineering a fingerprint from a Proof of Integrity when we organize events such as drops with sealed packs, where we're making the Proof of Integrity of each pack public, but want to keep the actual fingerprint hidden until the pack is open.
{% endhint %}

**Example:**

<table><thead><tr><th width="368">Fingerprint</th><th>Proof of Integrity (using salt = 834659742360)</th></tr></thead><tbody><tr><td><strong>G</strong>raded Pokemon TCG | PSA 23303316 | 1999 Pokemon Base Set Shadowless 1st Edition Red Cheeks Pikachu #58 | PSA 9 MINT</td><td><code>0x0b58386d08014f001c1a37ca6b11afd2f3f3e3a578e69a8ed7e7acf68103258e</code></td></tr><tr><td><strong>g</strong>raded Pokemon TCG | PSA 23303316 | 1999 Pokemon Base Set Shadowless 1st Edition Red Cheeks Pikachu #58 | PSA 9 MINT</td><td><code>0x3533294d06d102c4e6c1c93b28d4dd9cfb62c80111053363950af2af9eebdd91</code></td></tr></tbody></table>

### 3. How does a Proof of Integrity relate to an NFT?

Once we obtained the Proof of Integrity of an item, we can use it to generate the corresponding NFT. We create the NFT using the Proof of Integrity as its token ID.

> **But wait... aren't token IDs on Ethereum numbers, and not hexadecimal strings?**

*Exactly!* And this is where something special happens. We already established that a Proof of Integrity is a unique hexadecimal value of 64 characters. However, hexadecimal values are nothing more than numbers encoded in a way to save space on a computer. And as such, to every hexadecimal value corresponds an actual decimal number. For instance, the following hexadecimal value:

{% code overflow="wrap" %}

```
0x0b58386d08014f001c1a37ca6b11afd2f3f3e3a578e69a8ed7e7acf68103258e
```

{% endcode %}

corresponds to the very long number:

{% code overflow="wrap" %}

```
5131313313389071742384083343855484226773370949666220711435372176261821703566
```

{% endcode %}

We store that number on-chain and use as the token ID of the NFT.

{% hint style="success" %}
The tokenId and the Proof of Integrity are the same thing, just written differently. An NFT's token ID corresponds exactly to a Proof of Integrity that identifies a unique physical item stored at Courtyard, and vice-versa.
{% endhint %}

### 4. How is this tamperproof, and why does it matter?

On the blockchain side, it is well established that the token ID of an NFT, once recorded on-chain, is there to stay forever, unchanged. However, we cannot say as much of the metadata of that NFT, which may or may not be stored in decentralized storage, and may or may not be subject to evolve over-time, either because the creators of the NFT want to regularly provide a richer experience to the holder of the NFT, or because a malicious actor came and was able to alter the metadata and completely change the nature of the NFT.

The Proof of Integrity is Courtyard's way of making the NFT really tamperproof by using the 3 following properties:

* Once an NFT's token ID is recorded on-chain, it will never change.
* A Proof of Integrity of an NFT is exactly the same thing as its token ID, and so it will never change either.
* The unique, human readable fingerprint of a physical asset stored with Courtyard corresponds exactly to the Proof of Integrity, and only *that* fingerprint corresponds to it.

{% hint style="success" %}
Together, these 3 properties ensure that if the metadata changes as the result of a malicious attack to alter the identity of the underlying physical asset, the seal of integrity will be "broken", meaning that the Proof of integrity will invalidate the NFT.
{% endhint %}


---

# Agent Instructions: 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:

```
GET https://docs.courtyard.io/courtyard/technology/proof-of-integrity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
