Skip to content

Latest commit

 

History

History
113 lines (76 loc) · 4.62 KB

File metadata and controls

113 lines (76 loc) · 4.62 KB

VRF (Verifiable Random Function)

Overview

The TEE node supports VRF as a wallet signing algorithm, enabling generation of provably random values. The scheme is based on "Making NSEC5 Practical for DNSSEC" (Cryptology ePrint Archive, Report 2017/099, Section 2.3).

  • Signing algorithm: keccak256-secp256k1-vrf (wallets.VRFAlgo)
  • Curve: secp256k1
  • Signature size: approximately 939 bytes (JSON-encoded proof)
  • Core implementation: pkg/wallets/vrf/vrf.go

Route

F_WALLET / VRF (instruction, available in base mode only)

Request

The instruction contains:

  • walletId (bytes32) — target wallet
  • keyId (uint64) — key within the wallet
  • nonce (bytes) — input to the VRF, must be non-empty

ABI encoding uses vrfstruct.ITeeVrfVrfInstructionMessage from go-flare-common.

Processing Flow

Threshold Phase

  1. Decode and validate the instruction payload via types.ParseVRFInstruction
  2. Load the wallet from storage and verify SigningAlgo == VRFAlgo
  3. Validate that the cosigners declared in the instruction match the stored wallet's configured cosigner set and threshold (processorutils.CheckMatchingCosigners), mirroring the XRP signing path
  4. Convert the wallet private key to an ECDSA key
  5. Call vrf.VerifiableRandomness(key, nonce) to generate the proof with pre-computed witness points
  6. Return ProveRandomnessResponse (JSON) containing wallet metadata, nonce, and the VRF proof

End Phase

No operation is performed. Rewarding data is generated by the instruction framework.

Response

ProveRandomnessResponse (defined in pkg/types/vrf.go):

Field Description
walletId Wallet identifier
keyId Key identifier
nonce Input nonce
proof VRF proof (see below)

Proof Structure

Field Type Description
gamma Point (x, y) gamma = sk * HashToCurve(nonce)
c Scalar Challenge: HashToZn(Pack(G, H, pk, gamma, u, v))
s Scalar Response: s = k - sk * c (mod N)
u Point (x, y) Witness: u = k * G (equals c * pk + s * G)
cGamma Point (x, y) Witness: c * gamma
v Point (x, y) Witness: v = k * H (equals c * gamma + s * H)
zInv Field element modInv(cGamma.X - v.X, P)

The witness points (u, cGamma, v, zInv) are pre-computed off-chain and required by the on-chain TeeVRFVerifier contract to avoid expensive secp256k1 scalar multiplications in the EVM.

Cryptographic Details

Proof Generation (VerifiableRandomness)

Given private key x, public key Y = x * G, and nonce m:

  1. H = HashToCurve(m) — iterative Keccak256 hashing until a valid curve point is found
  2. gamma = x * H
  3. Sample random k
  4. u = k * G, v = k * H
  5. c = HashToZn(abi.encode(G, H, Y, gamma, u, v)) — Keccak256 reduced mod N
  6. s = (k - c * x) mod N
  7. Pre-compute: cGamma = c * gamma, zInv = modInv(cGamma.X - v.X, P)

If the zInv denominator is zero (negligible probability), proof generation returns an error.

Proof Verification (VerifyRandomness)

Off-chain verification performs five checks:

  1. zInv * (cGamma.X - v.X) == 1 (mod P) — ZInv is valid
  2. c * pk + s * G == u — prover knows sk such that pk = sk * G
  3. c * gamma == cGamma — cGamma is correctly derived
  4. cGamma + s * H == v — v is correctly derived
  5. HashToZn(abi.encode(G, H, pk, gamma, u, v)) == c — challenge is consistent

Checks 1-4 verify the witness points independently. Check 5 binds c to all committed values. Together they prove gamma == sk * H.

On-Chain Verification

The TeeVRFVerifier Solidity contract (from go-flare-common) implements the same verification logic using ecrecover to avoid expensive elliptic curve operations in the EVM.

Randomness Extraction

Proof.RandomnessFromProof() derives the final randomness output:

keccak256(gamma.X || gamma.Y)

where gamma.X and gamma.Y are 32-byte big-endian encoded coordinates.

Tests

  • Core VRF: pkg/wallets/vrf/vrf_test.go
  • Contract compatibility: pkg/wallets/vrf/vrf_contract_test.go
  • Instruction processor: internal/processors/instructions/vrfutils/vrfutils_test.go
  • End-to-end: internal/processors/processor_test.go