1. The Adversarial
Nature of the "Fair Launch"
In the nascent yet hyper-financialized ecosystem of Web3, the term "Fair Launch" has
mutated from a technical descriptor into a marketing shibboleth. Ideally, it signifies a
distribution mechanism where every participant has an equal, unbiased probability of acquiring a
desirable asset, unencumbered by insider knowledge, pre-computations, or algorithmic manipulation.
However, the reality of the Ethereum Virtual Machine (EVM) and other deterministic state machines is
starkly different. For the uninitiated developer or the idealistic digital artist, the blockchain
appears to be a sanctuary of immutability and trust. For the adversarial actor—the sniper bot
developer, the MEV (Maximal Extractable Value) searcher, or the rogue validator—it is a
deterministic playground where "luck" is a variable that can be calculated, simulated, and exploited
for profit.
The fundamental disconnect lies in the understanding of Entropy. In the physical world,
randomness is ubiquitous—thermal noise, radioactive decay, atmospheric turbulence. In the digital
ledger of a blockchain, true randomness is an anomaly, a paradox that the consensus mechanism
actively suppresses to ensure that every node reaches the exact same state. When a smart contract
engineer naively imports the concepts of randomness from Web2—relying on system clocks or simple
linear congruential generators—into the adversarial environment of Web3, they do not merely
introduce a software bug; they introduce an economic vulnerability that can drain millions of
dollars of value from a collection in mere seconds.
This report serves as a technical autopsy of failed randomness, a theoretical treatise
on cryptographic fairness, and a practical manual for implementing the "TrueRNG" standard. We will
dissect the mathematics of shuffling, the specific vulnerabilities of on-chain entropy sources like
PREVRANDAO, and the definitive solution offered by Provenance Hashes and Commit-Reveal schemes. We
address the Web3 Developer, the Project Founder, and the Digital Artist with a singular, urgent
message: stop trusting luck. Trust cryptography.
1.1 The High Stakes of Rarity and Metadata
Sniping
Non-Fungible Tokens (NFTs) derive a significant portion of their market value not just
from aesthetic utility, but from Rarity. The market creates a steep power law in valuation based on
attribute scarcity. Whether utilizing "Trait Rarity" (the scarcest single attribute), "Average Trait
Rarity," or "Statistical Rarity" (multiplying trait probabilities), the economic divergence is
massive. A "Floor" NFT might trade for 0.1 ETH, while a "Legendary" 1-of-1 from the same collection
trades for 100 ETH or more.
This 1000x price multiple creates a massive incentive for Metadata Sniping. If an
adversarial actor can predict which unminted Token ID contains a Legendary trait, they can
selectively mint only the high-value items, leaving the "commons" for the general public. This
destroys the economic integrity of the collection, alienates the community, and arguably constitutes
fraud if the "random" distribution was promised.
The mechanisms for calculating rarity have become standardized, allowing bots to
automate this valuation process in milliseconds.
- Trait Rarity Ranking: Ranks NFTs based on the rarity of their rarest trait.
This is a fragile metric but often the first used by snipers.
-
Statistical Rarity: Calculates the overall probability of an asset's existence
by multiplying the probabilities of its individual traits
(Ptotal = Ptrait1 × Ptrait2 × ...).
This provides a more granular "score" that bots use to rank unrevealed collections if metadata
leaks.
If the randomness generation (RNG) is predictable, the rarity distribution is broken. A
1% chance of a rare item becomes a 100% chance for an attacker with a sniper bot.
2. Anatomy of a Heist:
The Meebits Exploit & Metadata Sniping
To understand the necessity of cryptographic fairness, we must first analyze the failure
modes of the past. The Meebits launch by Larva Labs (creators of CryptoPunks) in May 2021 remains
the ur-example of a catastrophic fairness failure driven by predictable entropy.
2.1 The Meebits Vulnerability: Optimistic UI vs.
Pessimistic Contracts
The Meebits collection consisted of 20,000 unique 3D voxel characters. 9,000 of these
were sold via a Dutch Auction, while the remainder were free to claim for CryptoPunks and Autoglyphs
owners. The critical flaw lay in how the "random" ID assignment was handled during the minting
process.
The Meebits smart contract allowed users to mint IDs sequentially. However, the
metadata—defining which ID possessed which traits—was effectively public or deterministically
generated on-chain in a manner that could be verified during the transaction execution. The contract
utilized a pseudo-random number generator that relied on on-chain variables accessible to the
minting transaction itself.
2.2 The Attack Vector: Reverting for Rarity
An attacker, identified in the community as "0xNietzsche," constructed a malicious smart
contract to exploit this determinism. The attack leveraged the atomicity of Ethereum transactions.
In Ethereum, a transaction is atomic; it either executes completely, changing the state, or it fails
(reverts) entirely, rolling back all state changes while still consuming gas fees.
The attack flow was methodical and ruthless:
- Contract Deployment: The attacker deployed a custom "Exploit Contract."
- Conditional Minting: This contract was programmed to call the
Meebits.mint() function.
- Introspection: Immediately after receiving the token ID, the exploit contract
checked the specific traits or the ID of the minted Meebit within the same transaction. Because
the metadata generation logic was accessible, the contract could determine if the minted asset
was a "Visitor" (ultra-rare), a "Skeleton," or a common human.
- The Kill Switch:
- If Common: The contract executed a
revert() command. This cancelled
the mint. The attacker paid the gas fees for the computation but did not pay the mint
price (or wasted the mint opportunity) for a low-value asset.
- If Rare: The contract completed execution, securing the asset.
2.3 The Economic Calculus of the Exploit
The attacker spammed the Ethereum network with these conditional transactions. They
effectively "re-rolled" the dice thousands of times. While the cost of gas was high—estimated at
approximately $20,000 per hour in failed transaction fees—the expected value of a successful "hit"
dwarfed this expense.
The attacker ultimately succeeded in minting Meebit #16647, a rare "Visitor" type. This
asset was subsequently sold for 200 ETH, which was approximately $700,000 USD at the time. The
profit margin was astronomical, turning a five-figure gas expense into a six-figure windfall.
This exploit demonstrated a fundamental law of Web3 security: If the cost of the attack
(gas) is less than the potential profit (arbitrage value), the attack will happen.
2.4 Broader Implications: Metadata Sniping
While the Meebits exploit involved on-chain re-rolling, Metadata Sniping is a broader
and more insidious class of attack that affects projects even without on-chain metadata generation
vulnerabilities. It occurs when the mapping of TokenID to Image/Traits is leaked or deducible before
the mint is complete.
In a typical vulnerable scenario:
- Premature Upload: A project uploads 10,000 JSON files to IPFS (InterPlanetary
File System). The developers intend to keep the IPFS hash secret until the "Reveal."
- Leakage: If the developers set the baseURI in the smart contract to the IPFS
directory during the mint (to allow instant reveals), or if the directory hash is leaked via a
side channel, the entire metadata set becomes public.
- Analysis: Sniper bots download all 10,000 JSON files. They calculate the
"Statistical Rarity" of every single ID. They build a database: ID #4055 is the "Golden Ape," ID
#102 is a "Zombie," etc.
- Execution: The bot monitors the smart contract's
totalSupply variable. As the mint count
approaches 4054, the bot prepares a transaction. The moment the counter hits 4054, the bot
broadcasts a mint transaction with a massive gas tip (Priority Fee) to ensure they are the one
to mint ID #4055.
This creates a "Rigged/Sniped" distribution. The rarest items are captured by
sophisticated actors with algorithmic advantages, while the community is left with the "floor"
items. This is not a lottery; it is an information asymmetry game where the retail user is the
yield.
3. The Trap: Insecure
Sources of Entropy
The root cause of the Meebits exploit and metadata sniping is the reliance on insecure
sources of entropy (randomness). To prevent these attacks, we must understand why common sources of
randomness fail in the adversarial context of blockchain.
1. The
On-Chain Flaw
Developers often use block.timestamp
or block.difficulty
as seeds.
The Attack: Miners control these variables. A miner can discard blocks
where they don't mint a rare NFT, effectively re-rolling the dice until they win.
2. The
Off-Chain Flaw
Using simple Math.random()
in a generation script.
The Attack: If the metadata API is public before the reveal, snipers
can query /api/1, /api/2, etc.
They map the rarity to the ID and only send a transaction for ID #42 (the Legendary),
leaving the Common ID #41 for you.
3.1 The Deterministic Dilemma of the EVM
The Ethereum Virtual Machine is a deterministic state machine. For the network to reach
consensus, every node must execute every transaction and arrive at the exact same result. If a
contract used a true random number generator (like atmospheric noise), different nodes would produce
different states, and the chain would fork immediately. Therefore, true randomness is impossible
inside the EVM without external inputs (Oracles).
Developers, often migrating from Web2 contexts, reach for pseudo-random variables
available within the block header. This is a fatal error.
3.2 On-Chain Flaws: The Miner's Dice
The two most abused variables for on-chain randomness are block.timestamp and block.prevrandao (formerly block.difficulty).
3.2.1 block.timestamp Manipulation
The variable block.timestamp
returns the Unix timestamp of when the block was mined. Naive implementations often use modulo
arithmetic:
R = block.timestamp (mod n)
This is fundamentally insecure for two reasons:
- Predictability: An attacker knows the current time. They can predict the
timestamp of the next block within a narrow window (usually
seconds). They can pre-calculate the result
and only submit their transaction if the timestamp yields a favorable outcome.
- Miner Manipulation: Miners (and now Validators in PoS) set the timestamp of the
block they propose. While the protocol enforces that the timestamp must be greater than the
previous block and within a certain bound of "real time," validators have latitude. If a
validator detects that setting the timestamp to
results in them winning a valuable NFT (or facilitating a bribe from a sniper), they can and
will choose that timestamp.
3.2.2 The PREVRANDAO and the "Last Revealer" Problem
With Ethereum's transition to Proof of Stake (The Merge), the DIFFICULTY opcode (0x44)
was repurposed to PREVRANDAO (EIP-4399). This returns the output of the Randomness Beacon from the
Beacon Chain. While this is a source of entropy superior to difficulty, it is still biasable.
The vulnerability is known as the Last Revealer Problem.
- Mechanism: The randomness is derived from the aggregation of signatures
(RANDAO) from validators in an epoch.
- The Attack: The validator scheduled to propose the block knows the current
PREVRANDAO accumulator value. They also know their own contribution. They can calculate the
final random number that will result if they propose the block.
- Biasability: If the result is unfavorable (e.g., they lose a high-stakes gamble
or miss a rare NFT mint), the validator can choose not to propose the block (skip their slot).
This forces the network to use the randomness from the previous state.
- 1-Bit Influence: This gives the validator a "1-bit influence"—they effectively
have a binary choice between two possible random numbers. In a high-value mint, this 1-bit
influence is enough to skew the odds significantly in their favor.
- Cost: The cost to the validator is the loss of the block reward (approx. 0.04
ETH). If the NFT is worth 10 ETH, skipping the block is a rational economic decision.
3.3 Off-Chain Flaws: The Math.random() Disaster
Moving randomness off-chain (generating the sequence on a server before the mint)
eliminates miner manipulation but introduces the vulnerabilities of Pseudo-Random Number Generators
(PRNGs).
JavaScript's standard Math.random() is not Cryptographically Secure
(CSPRNG).
- Algorithm: Most modern JavaScript engines (like V8 in Node.js and Chrome)
implement
Math.random() using
xorshift128+. This is a fast, non-cryptographic algorithm designed for simulations, not
security.
- State Leakage: xorshift128+ has a relatively small internal state (128 bits).
If an attacker can observe a sequence of outputs—for example, the traits of the first 50 minted
NFTs—they can use a constraint solver (like Z3) or simple linear algebra to recover the internal
state of the generator.
- Forward Prediction: Once the internal state is recovered, the attacker can
predict every subsequent number the generator will produce. They possess the "God View" of the
entire remaining mint sequence.
Visualizing the Trap: Imagine the "Mempool" as a dark forest.
- Surveillance: A Sniper Bot sits in the mempool, monitoring pending
transactions.
- Simulation: It simulates the execution of a Mint transaction using the current
block.number and timestamp.
- Predation:
- If the simulation shows the result will be a "Common" NFT, the bot does nothing.
- If the simulation shows a "Rare," the bot front-runs the transaction (using Flashbots or
high gas) to steal the mint.
Alternatively, if the randomness is off-chain (Math.random), the bot simply looks up the
predicted sequence it solved 10 minutes ago and mints the exact ID required.
This adversarial environment necessitates a solution that decouples the generation of
randomness from the execution of the mint, and ensures the generation itself is tamper-proof.
4. The Solution:
Provenance Hashes & Commit-Reveal
The cryptographic gold standard for ensuring fairness in a trustless environment is the
Commit-Reveal Scheme. In the context of NFT drops, this is implemented via Provenance Hashes. This
mechanism provides a mathematical guarantee that the sequence of assets was fixed before the sale
began and was not altered during the process.
1
The Mathematical Proof
Step 1:
Concatenation
FinalString
= Image1Hash + Image2Hash + ... + ImageNHash
Step 2: Hashing
Provenance =
SHA256(FinalString)
Since SHA-256 is a one-way function, you cannot change the order of images after
publishing the Provenance Hash without completely changing the hash itself.
2
The Commit-Reveal Flow
-
Pre-Mint
Dev generates randomized
metadata locally (air-gapped). Publishes provenanceHash
to Smart Contract.
-
During Mint
Users mint "Unrevealed"
tokens. Metadata is hidden. Snipers are blind.
-
Post-Mint
Dev updates baseURI to
reveal metadata. Users verify the order matches the provenanceHash.
4.1 The Concept of Provenance
Provenance (from the French provenir, "to come from") creates an immutable
chain of custody for the randomness. The goal is to provide a verifiable proof to the user: "The
sequence of NFT traits was determined BEFORE the mint started. The developer did not change the
order after seeing who bought which ID, and the developer could not have predicted the final
assignment of IDs."
4.2 The Mathematical Construction
The standard implementation, popularized by the Bored Ape Yacht Club (BAYC) and widely
adopted as the industry standard, utilizes a concatenated SHA-256 hash structure.
Step 1: Individual Image Hashing
For every image in the collection (e.g., 10,000 images), we calculate a cryptographic
hash. This fingerprints the image data (or the metadata JSON). Even a single pixel change would
result in a completely different hash (the Avalanche Effect).
Hi = SHA256( Imagei )
Where i ∈ {0, 1, ..., 9999}
Step 2: Sequence Concatenation
We concatenate all individual image hashes into one massive string. The order of
concatenation represents the initial (shuffled) sequence of the drop.
Scombined = H0 || H1 || H2 || ... || H9999
Note: This is a concatenation of the hash strings, not the raw bytes, in most
implementations like BAYC.
Step 3: The Provenance Hash
We hash the combined string to produce a single, 256-bit output. This is the Provenance
Hash.
Hfinal = SHA256( Scombined )
Step 4: The Commitment
Crucially, Hfinal must be written to the smart contract (or published
immutably) before the mint begins. This "locks in" the sequence.
- If the developer tries to swap Rare #5 with Common #6 after the commitment, the combined string
Scombined changes.
- The new hash H'final will not match the on-chain record
Hfinal.
- The community can verify the fraud by running the hash function themselves post-reveal.
4.3 The Starting Index (Offset)
To prevent the "Metadata Sniping" issue (where users know #1 is Rare because the
sequence is fixed), developers must use a Random Offset or Starting Index.
- Shuffle & Commit: The collection is shuffled off-chain, and the Provenance Hash
is committed. The metadata is not uploaded or is encrypted.
- Minting: Users mint "blind" tokens. They own Token IDs 0 through 9999, but
these IDs are not yet mapped to the images.
- The Reveal (Randomness): After the mint concludes (or at a pre-set time), a
random number R is generated. This should ideally come from a high-entropy on-chain
source like Chainlink VRF to prevent developer manipulation.
- The Shift: The mapping of Token IDs to the shuffled image sequence is shifted
by R:
UserAsseti = ImageSequence( (i + R) mod N )
This ensures that even if the shuffled order (the image sequence) was leaked or guessed,
the specific asset a user receives depends on the random number R, which is only generated
after the sales are final. No amount of sniping can predict R before it exists.
5. Implementation: The
Fisher-Yates Shuffle
A Provenance Hash is only a proof of immutability. It does not guarantee that the
initial sequence was random or fair. If the developer purposefully sorts the collection so that IDs
#1-#100 are all "Legendary" (to buy them for themselves), the Provenance Hash will verify that...
but it's still a rigged distribution.
To ensure the distribution is uniform, we must shuffle the collection using a
cryptographically secure algorithm. The industry standard is the Fisher-Yates Shuffle (also known as
the Knuth Shuffle).
5.1 The Algorithm
The Fisher-Yates algorithm produces an unbiased permutation of a finite sequence. It
runs in
time complexity and, properly implemented, ensures that every permutation is equally likely.
Logic:
- Start with a list of all Token IDs:
- Iterate from the last element down to 1.
- Pick a random integer
such that
.
- Swap element
with element
.
5.2 The Danger of Naive Shuffling
Many developers, even experienced ones, attempt to shuffle using the built-in sort
method:
// DO NOT DO THIS
array.sort(() => Math.random() - 0.5);
This is statistically biased. It does not produce a uniform distribution of
permutations. The randomness depends on the browser's sort implementation (Merge Sort vs Quick Sort)
and the flawed Math.random(). Extensive
statistical analysis shows this method makes certain permutations significantly more likely than
others.
5.3 Modulo Bias: The Silent Statistical Killer
When generating the random integer for the shuffle, we often need a number in a specific
range (e.g., 0 to
). If we use a random byte (0-255) and the modulo operator, we introduce Modulo Bias.
- Example: We need a number between 0 and 9 (Range = 10).
- Source: A random byte (Values 0-255).
- Operation:
byte % 10.
- The Bias: Values 0-255 contain 256 possibilities.
Numbers 0, 1, 2, 3, 4, 5 will appear 26 times.
Numbers 6, 7, 8, 9 will appear 25 times.
Therefore, 0-5 are ~4% more likely to be chosen than 6-9.
Impact: In a shuffle of 10,000 items, this bias compounds, leading to a
non-uniform distribution where certain items are more likely to end up in certain positions.
The Solution: Rejection Sampling. If the random byte falls in the
"remainder" zone (the last 6 values in the example above), we discard it and pick a new byte. This
ensures every outcome has an exactly equal probability.
5.4 Secure Implementation (Node.js)
Below is a secure implementation of the Fisher-Yates shuffle using Node.js's crypto
module (a CSPRNG) and implementing Rejection Sampling to eliminate modulo bias.
const crypto = require('crypto');
// 1. Generate list of IDs [0, 1, ... 9999]
const ids = Array.from({length: 10000}, (_, i) => i);
// 2. Fisher-Yates Shuffle using CSPRNG
function secureShuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
// Generate secure random index
const randomBuffer = crypto.randomBytes(4);
const randomInt = randomBuffer.readUInt32BE(0);
const j = randomInt % (i + 1);
// Swap elements
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
const shuffledIds = secureShuffle(ids);
// Map these shuffled IDs to your metadata JSONs
This script should be run offline (air-gapped if possible) to generate the initial
sequence. That sequence is then hashed for the Provenance Hash.
6. Comparative
Analysis: Choosing Your Randomness Architecture
Not all projects require the same level of security or cost-efficiency. However, the
trade-offs must be explicit. Below is a comparative analysis of the three dominant paradigms for NFT
randomness.
|
Method
|
Cost
|
Security
|
Fairness Proof
|
Best For
|
| Simple Server RNG |
Low |
Low (Trust based) |
None |
Testing only |
| Chainlink VRF |
High (Gas fees) |
High (On-chain) |
Cryptographic |
Low-volume Dynamic NFTs |
| TrueRNG + Provenance |
Low (Off-chain calc) |
High |
Mathematical (Hash) |
Large PFP Collections |
6.1 Cost Analysis: The VRF Premium
While Chainlink VRF is the most secure solution for dynamic odds (e.g., opening a loot
box and getting an item instantly), it is often cost-prohibitive for large static collections.
- VRF Cost Structure: Costs include a "Verification Gas" fee (approx. 200k gas),
a "Callback Gas" fee, and a LINK premium (e.g., 0.25 LINK per request).
- The Math: For a 10,000 NFT collection: If you request randomness for every
mint:
. At 0.004 ETH/LINK and 20 gwei gas, this could cost tens of thousands of dollars.
- Batching: You can request one random number to shuffle the entire array.
However, doing the shuffle on-chain (sorting 10,000 items in Solidity) will hit the Block Gas
Limit and fail.
6.2 The Hybrid "TrueRNG" Advantage
The CSPRNG + Provenance model (TrueRNG) offers the optimal balance for standard PFP
drops.
- Cost: You pay gas only for the contract deployment and the "Reveal" transaction
(setting the Base URI and Offset).
- Security: The randomness is generated by a CSPRNG (like the Node.js script
above), which is superior to PREVRANDAO.
- Trust: The Provenance Hash provides the same level of immutability assurance as
an on-chain mechanism, provided the commitment happens before the mint.
7. Interactive
Element: The Rarity Visualizer
To explain this to your community and auditors, move beyond code and use data
visualization. A "Fairness Dashboard" should be part of your project's transparency report.
The Interactive Lab: Simulating the Sniping Attack
This dashboard demonstrates how predictable randomness allows bots to "snipe" rare items.
In the Vulnerable mode, we simulate a sniper bot that analyzes the RNG seed
and front-runs the transaction queue to mint Legendary items immediately.
In the Secure mode, we use a Commit-Reveal scheme where the sequence is
pre-shuffled and hidden, making sniping impossible.
Common Mints
0
Legendary
0
Mempool
View
Empty
Common
Rare
Legendary
7.1 Visualizing the Distribution
You can plot the distribution of Rarity Scores against Token IDs (Mint Order).
Scenario A: The Rigged/Sniped Drop (The "Rug Plot")
- Visual: A scatter plot where the X-axis is Mint Order (0 to 10,000) and the
Y-axis is Rarity Score.
- Pattern: A dense cluster of high-scoring dots appears in specific windows
(e.g., the first 5 minutes, or specific blocks).
- Interpretation: This indicates that the developer or a sniper knew the
sequence. The "Rares" were front-loaded (to hype the reveal) or cherry-picked by bots.
- Statistical Test: A Kolmogorov-Smirnov test would show a significant deviation
from a uniform distribution.
Scenario B: The True Fair Drop (The "White Noise")
- Visual: The same scatter plot.
- Pattern: High-scoring dots are distributed evenly and randomly across the
entire X-axis. There is no discernible clustering. It looks like "TV Static."
- Interpretation: No pattern exists. Getting a Rare was truly a matter of chance,
independent of when you minted.
Implementation Tip: After your mint, release a Jupyter Notebook or a
Python script that pulls your metadata, calculates rarity, and plots this distribution. This
transparency builds massive trust with the "Cypherpunk" demographic of collectors.
8. Conclusion: Don't
Trust Luck. Trust Cryptography.
The era of the "wild west" NFT launch is drawing to a close. The market has matured;
sophisticated collectors, auditors, and attackers now patrol the mempool. A project that launches
with Math.random() or exposed metadata is not
just technically lazy; it is financially negligent. It invites the wolves to the door.
We have explored the catastrophic failure of the Meebits launch, where predictable
outcomes bled value to bots. We have dissected the mechanics of block.timestamp and PREVRANDAO, exposing
the illusion of on-chain entropy. We have demonstrated that off-chain randomness is a minefield of
PRNG vulnerabilities and modulo biases.
The path forward for the serious engineer is clear. It requires a commitment to
Cypherpunk Ethics: verify, don't trust.
- Generate randomness offline using true entropy (CSPRNG).
- Shuffle using the Fisher-Yates algorithm with rejection sampling to eliminate bias.
- Commit to the sequence via a Provenance Hash on the smart contract before the first mint.
- Reveal the sequence and the metadata only after the distribution is complete, utilizing a
randomized starting index for the final layer of protection.
For the artist, this protects your reputation. For the developer, it protects your
contract from exploits. For the user, it ensures that when they click "Mint," they are playing a
fair game.
Call to Action:
Do not leave your rarity distribution to chance. Implement TrueRNG protocols. Use the
Fisher-Yates Shuffle. Publish your Provenance Hash. In a world of trustless systems, be the
project that brings the math to back up the marketing.
Generate. Hash. Commit. Reveal.
References & Further Reading
Meebits Exploit: Analysis of metadata re-rolling attacks. On-Chain Randomness: PREVRANDAO bias and
EIP-4399. Fisher-Yates: Secure shuffling implementation. Provenance: The BAYC cryptographic proof
standard. Chainlink VRF: Verifiable Random Functions for Web3. Rarity Scoring: Statistical models
for NFT valuation.
- NFT Sniper: How to Snipe NFTs - SCAND
- Secure Randomness in Solidity: Beyond Block Variables | Speedrun Ethereum
- How to Calculate the Rarity of an NFT | HackerNoon
- Rarity Tools Explained: A Guide to Ranking Rare NFTs - nft now
- The Elegance of the NFT Provenance Hash solution | by Richmond Lee - Medium
- EIP-4399: Supplant DIFFICULTY opcode with PREVRANDAO
- How to Implement Secure Random Number Generation in JavaScript - DEV Community
- Chainlink VRF | Chainlink Documentation