Making a Basic NFT zkRollup: How-To Guide

Table of Contents
Zero-Knowledge Rollups (ZK-rollups) is the endgame but do you really know how to explore it in a right way? These layer 2 scaling solutions enhance Ethereum's Mainnet throughput by moving computation and state storage off-chain. In this exploration, we delve into the exciting realm of ZK-rollups and uncover the process of creating Non-Fungible Tokens (NFTs) within this framework.

I. Implementation Basics

Introduction to the Foundations
Before diving into the intricacies of creating Non-Fungible Tokens (NFTs) within the Zero-Knowledge Rollups (ZK-rollups) framework, let's establish a solid understanding of the foundational elements that form the backbone of this innovative approach.
Prerequisites: ZKP, Circom, SnarkJS
Zero-Knowledge Proofs (ZKPs) serve as the cornerstone of our exploration. These cryptographic protocols allow one party, the prover, to convince another party, the verifier, that a particular statement is true without revealing any information about the statement itself. In our context, ZKPs play a pivotal role in ensuring the privacy and security of NFT transactions within the ZK-rollup ecosystem.
Accompanying ZKPs are two essential tools - Circom and SnarkJS. Circom, a domain-specific language, facilitates the creation of arithmetic circuits, while SnarkJS provides a JavaScript library for zk-SNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge). Together, these tools empower developers to construct and verify complex zero-knowledge proofs efficiently.
Sparse Merkle Trees for Storage
With our cryptographic toolbox in hand, we delve into the concept of Sparse Merkle Trees (SMT), a key component for efficient storage within the ZK-rollup framework.
Unlike the more intricate Merkle Patricia Trie, the Sparse Merkle Tree offers a simpler binary tree structure. Think of it as a streamlined version, where each parent node stores the hash of its children, and the stored values are the leaf elements. This structure becomes a key/value storage mechanism by having the child elements' paths determined by the key bits.
For example, a two-bit key directs us through the tree - if the key's bit is 0, we go left, and if it's 1, we go right. The efficiency of the Sparse Merkle Tree lies in its ability to store fewer values than its capacity, thanks to a process known as "pruning" the binary tree. This pruning ensures that the elements are stored with optimal efficiency, crucial for our rollup's performance.
The distinctive advantage of Sparse Merkle Trees over their general Merkle tree counterparts is the ability to provide both inclusion and exclusion proofs. This means not only can we prove that a value exists for a given key, but we can also prove that a value does not exist. This feature becomes a linchpin for our rollup, enabling robust proofs for various operations such as insert, delete, and update.
Fortuitously, the implementation of Sparse Merkle Trees is streamlined, thanks to existing libraries like Circomlib (and CircomlibJS). This allows us to focus on the high-level intricacies of our rollup design without delving into the nitty-gritty details of SMT implementation.
In summary, our journey into ZK-rollup implementation begins with a strong foundation in Zero-Knowledge Proofs, supported by the essential tools of Circom and SnarkJS. The use of Sparse Merkle Trees ensures an efficient and secure storage mechanism, laying the groundwork for the subsequent development of our NFT rollup system.

II. NFT Management in ZK-Rollup

Storing NFTs in a Secure Realm
Now that we've grasped the fundamentals, let's shift our focus to the heart of our endeavor - managing Non-Fungible Tokens (NFTs) within the Zero-Knowledge Rollups (ZK-rollups) framework.
Storing NFTs in an SMT
Our journey into the world of ZK-rollups involves housing NFTs within a Sparse Merkle Tree (SMT). This cryptographic structure acts as our digital garden, where each NFT's identifier becomes a unique key, and the corresponding value represents the current owner's public key.
Consider it as an organized repository where NFTs find their place in a binary tree. The tree's architecture efficiently accommodates the NFTs, with each branch and leaf contributing to a streamlined and secure storage solution. The beauty of the SMT lies in its ability to offer not just inclusion proofs but also exclusion proofs, a crucial aspect of our rollup's functionality.
For every NFT transfer, the owner must produce a digitally signed transaction, a testament to their intention to shift ownership. This transaction, carrying the new owner's public key and the NFT's identifier, acts as a key catalyst for the subsequent modifications in our SMT.
NFT Transfer Mechanism
The transfer of NFTs within our ZK-rollup system is a multi-step dance, ensuring both security and efficiency. The owner's signed transaction sets the rhythm, containing essential elements - the NFT's identifier, the destination address, and a nonce, a counter crucial for uniqueness.
The owner, in proving their mettle, must establish two critical facts: first, that they indeed signed the transaction, and second, that they are the legitimate owner of the NFT, backed by the presence of their public key within the SMT alongside the NFT's ID.
Once these proofs find validation, the ownership baton gracefully transitions to the new holder. The sequencer, a conductor in our orchestrated ballet, collects these NFT transfer transactions, calculates the Merkle root based on these movements, and sends this new root, along with the transaction list and a zero-knowledge proof, to a smart contract.
Sequencer and Smart Contract
The sequencer, an integral player in our ZK-rollup symphony, orchestrates the compilation of NFT transfer transactions. Its role is to harmonize these transactions into a coherent list, calculate the Merkle root that encapsulates the changes, and present this transformative ensemble to the smart contract.
This smart contract, the vigilant adjudicator of the rollup performance, scrutinizes the zero-knowledge proof accompanying the transactions. Upon successful verification, the smart contract updates the root, signifying a seamless transition of NFT ownership. This elegant dance between the sequencer and the smart contract ensures the accuracy and integrity of NFT transfers within our ZK-rollup.
In essence, our NFT management system within the ZK-rollup relies on a choreography of digital signatures, Merkle trees, and zero-knowledge proofs. Each element plays a crucial role, contributing to the secure and efficient movement of NFTs within our rollup ecosystem.

III. Code Implementation and Verification

Generating Wallet Accounts: A Prelude to Possession
Before delving into the intricacies of code implementation, let's set the stage by creating the protagonists of our digital narrative - the wallet user accounts. Each Rollup account, akin to its Ethereum counterpart, possesses a private key, a public key, and an address. However, in our innovative twist, we employ EDDSA for the digital signing of transactions, a ZKP-friendly digital signature format.
The script to bring these characters to life involves the random generation of private keys, followed by the derivation of public keys and addresses. The Poseidon Hash, a ZKP-friendly hash algorithm, aids in this creative process. The code snippet weaves these elements together, birthing five test accounts with a stroke of computational artistry.
```javascript
for (let i = 0; i < 5; i++) {
  // generate private and public eddsa keys, 
  // the public address is the poseidon hash of the public key
  const prvKey = randomBytes(32);
  const pubKey = eddsa.prv2pub(prvKey);
  accounts[i] = {
    prvKey: prvKey,
    pubKey: pubKey,
    address: trie.F.toObject(poseidon(pubKey))
  }
}
```
These wallet accounts, now in possession of their digital identities, are ready to engage in the NFT spectacle within our ZK-rollup.
Creating NFTs and Transfers: The Dance of Digital Possession
With our cast of characters established, the next act unfolds in the creation and transfer of Non-Fungible Tokens (NFTs). The stage is set with the generation of five NFTs, each assigned to the first account. Our Sparse Merkle Tree (SMT) becomes the canvas where the NFTs find their place, the key being the NFT ID, and the value representing the current owner's address.
```javascript
// generate 5 NFTs, and set the first account as owner
for (let i = 1; i <= 5; i++) {
  await trie.insert(i, accounts[0].address)
  await nonceTrie.insert(i, 0)
}
```
The plot thickens as we venture into the creation of a transfer request - a crucial act in the NFT ballet. This request encapsulates the NFT ID, the destination address, and a nonce, all orchestrated into a Poseidon hash. The owner's digital signature seals this request, a testament to their authority in the transfer.
```javascript
const createTransferRequest = (owner: Account, target: Account, 
  nftID: number, nonce: number): TransferRequest => {
  const transactionHash = poseidon([
    buffer2hex(target.address), nftID, buffer2hex(nonce)
  ])
  const signature = eddsa.signPoseidon(owner.prvKey, 
    transactionHash);
  return {
    ownerPubKey: owner.pubKey,
    targetAddress: target.address,
    nftID: nftID,
    nonce: nonce,
    signature: signature
  }
}
```
Now, the stage is set, the actors are in their positions, and the ballet of NFT transfers can commence.
Rollup Circuit and Verification: Ensuring Harmony
As we step into the grand finale of our code symphony, we encounter the Rollup Circuit, the maestro orchestrating the harmonious execution of NFT transfers. The proof of the pudding lies in its ability to seamlessly validate transactions and update the state roots. Our verification process ensures that the baton of ownership gracefully moves from one account to another, backed by cryptographic precision.
```javascript
const transferNFT = async (from: Account, to: Account, nftID: number) => {
  // get the nonce for the NFT
  const nonce = BigNumber.from(
    nonceTrie.F.toObject((await nonceTrie.find(nftID)).foundValue)
  ).toNumber()
  // creating transfer request
  const transferRequest = await createTransferRequest(from, to, nftID, nonce)
  // move the NFT to the new owner
  const nft_res = await trie.update(nftID, transferRequest.targetAddress)
  // increase nonce for the NFT
  const nonce_res = await nonceTrie.update(nftID, transferRequest.nonce + 1)
  // generate and check zkp
  let nft_siblings = convertSiblings(nft_res.siblings)
  let nonce_siblings = convertSiblings(nonce_res.siblings)
  const inputs = {
    targetAddress: buffer2hex(transferRequest.targetAddress),
    nftID: transferRequest.nftID,
    nonce: buffer2hex(transferRequest.nonce),
    Ax: eddsa.F.toObject(transferRequest.ownerPubKey[0]),
    Ay: eddsa.F.toObject(transferRequest.ownerPubKey[1]),
    R8x: eddsa.F.toObject(transferRequest.signature.R8[0]),
    R8y: eddsa.F.toObject(transferRequest.signature.R8[1]),
    S: transferRequest.signature.S,
    oldRoot: trie.F.toObject(nft_res.oldRoot),
    siblings: nft_siblings,
    nonceOldRoot: trie.F.toObject(nonce_res.oldRoot),
    nonceSiblings: nonce_siblings
  }
  const w = await verifyRollupTransactionCircuit.calculateWitness(
    inputs, true
  );
  await verifyRollupTransactionCircuit.checkConstraints(w);
  await verifyRollupTransactionCircuit.assertOut(w, {
    newRoot: trie.F.toObject(nft_res.newRoot),
    nonceNewRoot: trie.F.toObject(nonce_res.newRoot)
  });
}
```
This dance of digital possession, encoded in the Rollup Circuit, ensures a seamless and secure transfer of NFTs within our ZK-rollup. The verification process, a vigilant guardian, scrutinizes each move, guaranteeing the integrity of the NFT ownership transitions. Our code implementation and verification process, like a well-choreographed ballet, showcases the prowess of ZK-rollups in managing NFTs with finesse and cryptographic precision.

IV. Performance and Future Considerations

Gas Efficiency and Benefits
Comparing our rollup solution to traditional on-chain NFT contracts reveals remarkable gas efficiency. Our 64-element batch rollup costs only a fraction of the on-chain equivalent. The benefits extend beyond cost, as ZKP validation remains consistent regardless of transaction volume, promising increased efficiency and space savings on the blockchain.
Implementation Challenges
While our implementation showcases exciting potential, challenges emerge. Compiling large circuits demands significant computational resources, presenting a current hurdle. The time-consuming nature of proof generation and the need for optimization point to areas for improvement.
Future Improvements and Scalability
Looking ahead, the future holds promise for improved efficiency and scalability. Advancements in proof generation technologies, such as rapidsnark, and potential GPU or ASIC-based solutions could address current challenges. Optimizing data storage within the rollup and enabling NFT movement between the rollup and the blockchain stand as areas for future refinement.

Conclusion

In the dynamic landscape of blockchain technology, our exploration of NFTs within ZK-rollups unveils a powerful blend of security, efficiency, and scalability. As we navigate the complexities and challenges, the potential for transformative advancements in decentralized systems becomes increasingly evident. The journey towards a more efficient and decentralized blockchain future is underway, with ZK-rollups leading the way.

About Orochi Network

Orochi Network is a cutting-edge zkOS (An operating system based on zero-knowledge proof) designed to tackle the challenges of computation limitation, data correctness, and data availability in the Web3 industry. With the well-rounded solutions for Web3 Applications, Orochi Network omits the current performance-related barriers and makes ways for more comprehensive dApps hence, becoming the backbone of Web3's infrastructure landscape.
Categories
Event Recap
3
Misc
56
Monthly Report
1
Oracles
4
Orand
3
Orosign
19
Partnership
20
Verifiable Random Function
9
Web3
86
Zero-Knowledge Proofs
33
Top Posts
Tag
Orand
NFT
Misc
Web3
Partnership Announcement
Layer 2
Event Recap
Immutable Ledger
Oracles
Verifiable Random Function
Zero-Knowledge Proofs
Multisignature Wallet

Orosign Wallet

Manage all digital assets safely and securely from your mobile devices

zkDatabaseDownload Orosign Wallet
Coming soon
Orochi

zkOS for Web3

© 2021 Orochi