(written for 0xPARC applied ZK learning group final project proposal)
A spec for NFTs with default private ownership. Can easily be made ERC721 compliant.
NFTs come in two types:
ownerOf()
return contract addressZK NFTs can also be implemented as wrappers around existing ERC721 contracts.
uint256[] ids
MerkleTree utxoHashes
uint256[] nullifiers
mapping(uint256 => address) knownOwners
UTXOs are ownerAddress | nftID | salt
mint(id, address)
:
id
and public owner address
id
not already mintedid
is appended to ids
knownOwners[id] = address
(optional) mintShielded(id, utxoHash, proof)
:
id
and private owner (and private salt)utxoHash
is H(ownerAddress | nftID | salt)
.id
is appended to ids
utxoHash
is added to utxoHashes
proof
is ZKP that utxoHash
is indeed the hash of a secret ownerAddress
and secret salt
and publicly-declared id
.transferShielded(nullifier, newUtxoHash, proof)
:
nullifier
is not already in nullifiers
, then appends it to the end of listnewUtxoHash
doesn't already exist (would mean salt
is reused, which is bad)proof
is ZKP (provided by recipient) that recipient knows five secret values: oldOwner
, newOwner
, oldSalt
, newSalt
, id
such that H(oldOwner | id | oldSalt)
is in utxoHashes
(merkle proof), G(oldOwner | id | oldSalt) = nullifier
, and H(newOwner | id | newSalt) = newUtxoHash
unshield(address, id, salt, merkleIdx)
:
address
owns NFT with id id
, turning it into an unshielded NFTG(address, id, salt)
(nullifier) and verifies it is not in nullifier set already (so this UTXO is not already spent). then appends it to nullifier setH(address, id, salt) == utxoHashes[merkleIdx]
(merkleIdx
is provided for fast lookup)knownOwners[id] = address
shield(address, id, utxoHash, proof)
:
address != 0
knownOwners[id] == address
, then set it to 0
proof
is ZKP that i know secret value salt
such that H(address | id | salt) = utxoHash
utxoHash
doesn't already exist (would mean salt
is reused, which is bad)utxoHash
to utxoHashes
(optional) proveOwnershipOfSomeNFT(address, stateRoot, proof)
:
stateRoot
, which is hopefully a recent state). proofs can be augmented to prove additional properties as well about the NFT ownedaddress
and secret id
, when hashed with each possible salt, is not any of the nullifiers (nullifier set size * valid salt set size).[0, ..., MAX_SALT]
, the value associated with key hash(address, id, salt)
in your merkelized mapping is false. but now your merkelized mapping must have a root corresponding to a root tracked in the contractshielded NFTs can be auctioned, with transfer and payment occurring in the same atomic transaction. these contracts will require ZKPs as well that are proxied to the shieldedTransfer
function that is called internally
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing