Algorithm and Rules Explained for Neoverse NFT Series

Neo Global Development (NGD) recently announced plans for an NFT mint and collection event, Neoverse, to celebrate the launch of the Neo N3 MainNet and the Mass Migration program. NGD plans to distribute these collectible Neoverse NFTs in “blind boxes” via airdrops and purchases.

To help you get ready to get the most out of Neoverse while you wait for its launch, this article provides background about the algorithm design and contracts behind Neoverse NFTs.

Algorithm design: How N3 Collector’s Edition NFTs are minted

Neoverse includes a total of 27,000 blind boxes. Each blind box costs two GAS tokens, and two free blind boxes are available for every 10 blind boxes purchased. When you open (or destroy) a blind box, you’ll get access to a randomly selected set of N3 Element pieces in that box.

Nine types of N3 Element NFTs are available. Each has its own serial number, which can range from 1 to 3,000 (for example, Fragment A #733, Fragment I #2314, etc.). Once you collect all nine different N3 Element NFT pieces, you can mint a special N3 Collector’s Edition NFT by burning all nine Element NFTs — commemorating the fact that Neo N3 is the “all-in-one” blockchain infrastructure for the smart economy.

The outcome of your specific minting will largely depend on the sum of the serial numbers of the nine N3 Element pieces that are burned:

  • If the sum of the serial numbers of the 9 Element NFTs to be burnt is less than or equal to 4816, the mint is more likely to be a N-series.
  • If the sum is between 4817 and 6411, the mint is more likely to be an E-series.
  • The rest of the mints are more likely to be O-series.

Nine N3 Element pieces, one resulting Neoverse Collectible Edition NFT

The nine N3 Element pieces that you can collect represent the nine major features that are all available in one blockchain — Neo N3:

  1. Interoperability
  2. Native oracles
  3. Self-sovereign ID
  4. Decentralized storage
  5. Neo name service
  6. One block finality
  7. Best-in-class tooling
  8. Smart contracts
  9. Multi-language

Once you collect and burn all nine Element NFTs, your Collector’s Edition N3 NFT will be “all in one” — like Neo N3.

Market logic behind the N series and E series NFT numbers

You’ll be able to get N3 Element pieces in either of two ways:

  • Primary market: Get random N3 Element pieces via airdrops and auctions.
  • Secondary market: Trade your N3 Element pieces in the NFT marketplace.

The sum of the serial numbers of the N3 Element pieces will largely depend on the market activity. According to the Neoverse algorithm simulation, the sum of the serial numbers of N-series will be 900 when the market is most active and 8731 when it’s least active. Therefore, when the market is moderately active, the sum of the serial numbers will be 4816 for N series and 6411 for E series.

Contract development

Blind-box games are essentially a game of randomness. When choosing an approach to randomness, it’s important to consider how randomness is achieved, whether it is predictable, and whether it can be exploited by hackers. We explored six different types of contracts for potential use in the blind boxes in Neoverse. Here, NGD developers who worked hard to get Neoverse ready for launch have shared the process to show you how NGD selected the contract for the Neoverse blind boxes that has the best approach to randomness.

1. Bronze version

Every N3 block has a random, but fixed, field called Nonce. When opening a blind box, we took the Nonce of the current as a random number seed so we could get a random number (Nonce mod 3000)+1, ranging from 1 to 3,000. This operation seems simple, but it still has issues:

  1. All blind boxes opened in the same block may have the same outcome.
  2. Random numbers may have duplicates.

2. Silver version

In the Silver version contract, we solved the first problem of the Bronze version noted above. We first tried to obtain a random number seed by performing a XOR operation between Nonce and the transaction ID. However, in this case it was possible for the blind boxes opened in one transaction to have the same outcomes. This was obviously unacceptable.

We then tried getting a random number seed by hashing the Token ID of the blind box, converting it to a BigInteger, and performing a XOR operation with the current Nonce. Each blind box has its own Token ID; it thus will have a different hash so that no duplicate random numbers are possible. But NGD developer Li Chen determined that directly using the Nonce of the current block would pose exploitation risks in both Silver and Bronze contract versions:

  • A hacker could possibly deploy a contract A, invoke a blind box opening method in it, and evaluate the outcome. If the hacker didn’t like this outcome, they could throw an exception to interrupt the execution.
  • The hacker could also accomplish these steps by adding well-structured OpCode after the blind-box opening script.

3. Gold version

In the Gold version of the contract, random numbers are generated between the time when the blind box is purchased and when it is opened. This prevents users from predicting the future Nonce when buying blind boxes, while the outcomes are quite certain when opening. We designed the contract so that once the user buys a blind box, it records the index of the next block. Then later, when the user opens the box, the contract generates a random number by performing an XOR operation between the Nonce of that block and the hash of Token ID.

The Gold version thus removes the risk of hacking. But it doesn’t solve the second problem in the Bronze version: Two blind boxes may have the still same outcomes (for example, Fragment A #33).

4. Platinum version

The development team spared no effort in solving the problem of duplicate random numbers. We eventually came up with these potential solutions:

1. Store all unused random numbers (up to 27,000) in the storage area and delete each number as it is used. Next time, read the random array remaining in the storage area and take random numbers from it.

2. Alternatively, store all the used random numbers (up to 27,000) in the storage area. Next time, read the random number array in the storage area, find the unused ones, and take the random numbers from them.

Whether storing used or unused random numbers, the storage area plays an important role in these two nearly equivalent solutions. We determined that how the numbers are stored could be costly:

  • At 2 bytes per random number, it would cost 13.5 GAS tokens to write 54KB of data once, which is quite expensive.
  • We also considered the possibility of storing the data in bits: This approach would use a byte array of length 3375, where the subscript of each bit represents a random number, and the value of each bit (0 or 1) indicates whether that random number is used. The random numbers of nine N3 Element pieces are then stored separately by sharding — greatly reducing the cost of reading and writing. But given the huge amount of computation involved in reducing bits to arrays, this still incurs a significant fee.

To solve this problem, NGD developer Yin Wei proposed a new solution:

  • There are nine types of N3 Element NFTs and 3,000 of each Element type, with random numbers ranging from 1 to 3,000.
  • The storage area will store the subscript of the last random number and the process of extraction and replacement.

To picture this process, suppose a user extracts a random number with a subscript of 500:

  • We would assign the user the number 500 and record k:500,v:3000 in the storage area, indicating that the bit with the subscript 500 stores the random number 3,000.
  • After that, we would change the maximum random number subscript from 3,000 to 2,999.
  • Then, when another user extracts a random number with subscript 500, we would

1. Give the user 3,000 according to the previous record.

2. Update the record to k:500, v:2999; 3) change the maximum random number subscript from 2,999 to 2,998.

  • This process would continue for each subsequent user.

In more detail, the random number generation mechanism can be simply described as:

Looking back at the Gold version, you may have noticed that the outcomes of the blind boxes are determined regardless of the order in which a box is opened. But in the Platinum version, the opposite situation can occur, raising another problem to resolve: A hacker can pre-execute the contract locally and broadcast the transaction if the outcome is satisfactory. If the outcome is unsatisfactory, the hacker can wait until someone else finds the same NFT pieces. The hacker can then perform the pre-execution. In case of an initially unsatisfactory outcome, the hacker would be free to wait until they are satisfied before sending the transaction.

Additionally, there were further issues to resolve in the Platinum version: It still had the two problems that exist in the Silver version. This meant that more work was needed.

5. Diamond version

The Diamond version represented a breakthrough: This version takes advantage of Neo’s excellent, underlying random number generation algorithm, which NGD engineer Steven Liu introduced before the release of Neo N3. This algorithm wasn’t yet available when the NGD team worked on the previous contract versions.

This algorithm can guarantee perfect randomness, non-duplication, and unpredictability (different random numbers for pre-execution and on-chain execution). The Diamond version contract also makes it simple to get random numbers with the interoperability service (Runtime.GetRandom()). Combining these capabilities with the Platinum version makes it possible to get non-repeating random numbers ranging from 1 to 3,000 at a time. This makes the random number generation mechanism nearly perfect.

However, the two issues noted for Silver version are actually specific to on-chain execution. The random number algorithm cannot interfere with these issues, and they must be circumvented by other security restrictions. In troubleshooting these issues, the developers found that the cost for hackers to open the blind box in this way is relatively high, with an initial cost of 10.1 GAS tokens and a cost of 1.05 GAS tokens per attempt to open the blind box. Trying twice without satisfaction would mean losing the chance to get a new blind box (at a cost of 2 GAS tokens per blind box).

Based on these undesirable economics, a hacker would have little motivation for an attack in this situation. Yet we wanted to remove even this unlikely vulnerability to a hacker attack. This meant that our search for the perfect contract for Neoverse was not yet done.

6. Crown Version

Culminating our search, Neo Community developer Liao Jinghui and NGD developers made a set of further improvements based on the already solid Diamond version. For this final version:

  1. We added a new contract call restriction: In this contract, only the Neoverse contract can be called in transactions to open the blind box.
  2. We implemented a new requirement to control script length calculation: Whether a user opens blind boxes one by one or in batches, the precise script length required must be calculated based on the real parameter length. Not even a single byte can be appended to the standard call script.

At this point, we had created a nearly perfect contract: The Crown version. This contract will ensure that the N3 Elements delivered in the Neoverse blind boxes are unique and firmly protected from hackers.

What’s Next?

To become eligible to receive Neoverse NFT airdrops, Neo community members can participate in various events host by NGD, Neo ecosystem projects and other partners. Purchase options will be available at Neoverse offical website which will go live in mid-to-late September.

As you get ready for Neoverse, you can find more information on the Neoverse NFT series here. And follow the Neo official twitter for the latest update.

Official Twitter Feed: @Neo_Blockchain