Tenzro Testnet is live. Get testnet TNZO

Verifiable Random Function (VRF)

Tenzro implements ECVRF-EDWARDS25519-SHA512-TAI per RFC 9381 §5.4.1.1 (suite string 0x04). A VRF lets a secret-key holder produce a deterministic, pseudo-random output together with a proof that any third party can verify using only the matching public key — without revealing the secret key and without re-running the randomness source.

Why VRF on Tenzro

  • Provably-fair NFT reveals — mint a token ID that nobody (not even the contract deployer) could predict
  • Randomized trait assignment — assign rarity, attributes, or outcomes with on-chain auditable randomness
  • Lotteries and raffles — pick winners verifiably, post-hoc inspectable
  • Leader selection — augment TEE-weighted HotStuff-2 rotation with additional randomization
  • Agentic workloads — let an autonomous agent commit to a random action without trusting a centralized oracle

Properties

PropertyValue
Cipher suiteECVRF-EDWARDS25519-SHA512-TAI (RFC 9381 suite 0x04)
CurveEdwards25519 (reuses Ed25519 validator keys)
Secret key32 bytes
Public key32 bytes (compressed Edwards point)
Proof (π)80 bytes — gamma(32) ‖ c(16) ‖ s(32)
Output (β)64 bytes — SHA-512 of proof-to-hash input
SecurityUnforgeability, full uniqueness, pseudorandomness — low-order and non-canonical-scalar points rejected

API — tenzro-crypto

use tenzro_crypto::vrf::{VrfKeyPair, prove, verify, proof_to_hash};

// Generate a fresh VRF key pair (or reuse an existing Ed25519 validator key)
let keypair = VrfKeyPair::generate()?;

// Produce a VRF proof over an input ("alpha")
let alpha: &[u8] = b"block-hash-42";
let proof = prove(&keypair.secret_key(), alpha)?;   // 80-byte π

// Any verifier with the public key can verify and recover the deterministic output
let beta = verify(&keypair.public_key(), alpha, &proof)?; // 64-byte β

// Without a secret key, proof-to-hash recovers the output from the proof alone
let beta_hash = proof_to_hash(&proof)?;
assert_eq!(beta, beta_hash);

EVM Precompile 0x1007

The VRF verifier is exposed to EVM smart contracts at precompile address 0x0000000000000000000000000000000000001007. It is stateless and costs 50,000 base gas + 3 gas per byte of alpha (matching the pattern of ecrecover).

// Precompile input layout:
//   offset 0..32    : pubkey (left-padded 32-byte Edwards25519 public key)
//   offset 32..112  : proof  (80-byte ECVRF proof π = gamma ‖ c ‖ s)
//   offset 112..    : alpha  (arbitrary-length VRF input)
//
// Precompile output:
//   64 bytes (β) on success — the deterministic VRF output
//   revert on verification failure

// Solidity helper
address constant VRF = 0x0000000000000000000000000000000000001007;

function vrfVerify(bytes32 pubkey, bytes calldata proof, bytes calldata alpha)
    internal view returns (bytes32 high, bytes32 low)
{
    require(proof.length == 80, "bad proof len");
    bytes memory input = abi.encodePacked(pubkey, proof, alpha);
    (bool ok, bytes memory out) = VRF.staticcall(input);
    require(ok && out.length == 64, "vrf verify failed");
    assembly {
        high := mload(add(out, 32))
        low  := mload(add(out, 64))
    }
}

NFT mintRandom

The built-in NFT factory exposes a mintRandom(bytes32 pubkey, bytes proof, bytes alpha) entry point — selector 0x52517e21, gas budget 130,000. It verifies the VRF proof through precompile 0x1007, then derives a candidate token ID from the 64-byte output with a 4-round collision retry before minting.

# CLI  generate proof + mint a provably-random NFT

# 1. Generate a VRF keypair
tenzro vrf keygen
#   secret: 0xabc...
#   public: 0xdef...

# 2. Produce a proof over an input
tenzro vrf prove --secret-key 0xabc... --alpha 0xdeadbeef
#   proof: 0x...

# 3. Verify locally (optional)
tenzro vrf verify --pubkey 0xdef... --proof 0x... --alpha 0xdeadbeef
#   output (β): 0x...

# 4. Mint an NFT whose token ID is derived from the VRF output
tenzro nft mint-random \
  --collection 0xCOLLECTION... \
  --pubkey 0xdef... \
  --proof 0x... \
  --alpha 0xdeadbeef

JSON-RPC

MethodParamsReturns
tenzro_generateVrfProofsecretKey (32B hex), alpha (hex){ proof, output, publicKey }
tenzro_verifyVrfProofpublicKey (32B hex), proof (80B hex), alpha (hex){ valid: bool, output?: hex }

MCP & A2A

The same operations are available to AI agents over the Model Context Protocol and Agent-to-Agent protocol as verify_vrf_proof and generate_vrf_proof. The A2A verification skill advertises tags vrf and randomness so capability-matching routers can discover VRF-capable agents.

Security Notes

  • Low-order point rejection — the verifier rejects gamma and public key points in the 8-torsion subgroup, which would otherwise allow trivial proofs.
  • Canonical scalar enforcement — the s component is checked to be a canonical scalar mod ; non-canonical encodings are rejected.
  • Suite-string domain separation — all hash-to-curve calls include the fixed prefix 0x04 and the full suite string, preventing cross-suite replay.
  • Deterministic outputs — for a given (sk, alpha) pair the proof nonce is derived deterministically per RFC 9381 §5.4.2.2, ensuring identical outputs on every call without needing secure randomness at proof time.

Related Documentation

Cryptography — Ed25519, Secp256k1, BLS12-381, MPC
ZK Proofs — Groth16 on BN254 for verifiable computation
NFT Infrastructure — collections, minting, and mintRandom
Consensus — HotStuff-2 leader selection