# RFC 9381 - EC VRF Notes https://datatracker.ietf.org/doc/rfc9381/ ## 5. ECVRF General math objects and domains: - `F`: finite field - `E`: elliptic curve defined over `F` - `G`: subgroup of `E` with large prime order - `q`: prime order of `G` - `B`: generator of group `G` - `co`: cofactor, i.e. number of points in `E` divided by `q` Encoded lengths (as octet-strings): - `hLen`: output length of `hash` - `fLen`: encoded length of an element in `F` - `ptLen`: encoded length of a point on `E` - `qLen`: encoded length of `q` - `cLen`: encoded length of the challenge value used by the VRF Parameters: - `x`: Secret scalar (sk). - `Y = x·B`: Public point (pk) - `𝛼`: VRF input (string) - `𝛾`: VRF pre-output - `𝜋`: VRF proof - `𝛽`: VRF output (string) - `suite`: specifies ECVRF cipher-suite (string) Functions: - `hash`: cryptographic hash function - `encode_to_curve`: function to map octet-strings to points in `E` - `nonce`: pseudo-random nonce from `sk` and input as part of VRF proving - `challenge`: basically a Fiat-Shamir transform - `point_to_string`: maps a point into an octet-string - `prove`: proof generation - `proof_to_output`: from proof to actual vrf output - `verify`: proof verification Notes: - RFC defines an optional salt for hash to curve. We just ignore it here. - RFC differentiates from octet-string encoded and not-encoded forms for mathematical objects. We don't do this here as the mapping from encoded/non-ecoded form is not ambiguous. - Standard different ### 5.1 Proving Basically a *Schnorr* signature, with `𝛾` embedded in the challenge. prove(x, 𝛼) -> 𝜋 Steps: ``` - H = encode_to_curve(𝛼) - hₛ = point_to_string(H) - 𝛾 = x·H - k = nonce(x, hₛ) (ref 5.4.2) - c = challenge(Y, H, 𝛾, k·B, k·H) (ref 5.4.3) - s = (k + c·x) mod q (Schnorr signature) - 𝜋 = (𝛾, c, s) ``` Note: proof is different from Schnorr, we encode the challenge `c` instead of `k·B`. ### 5.2 Proof to Output proof_to_output(𝜋) -> 𝛽 From proof to the actual VRF output. - dom_sep_front = `0x03` - dom_sep_back = `0x00` Steps: ``` - 𝛽 = hash(suite, dom_sep_front, point_to_string(co · 𝜋.𝛾), dom_sep_back) ``` ### 5.3 Verifying verify(Y, 𝛼, 𝜋) -> (bool, 𝛽) Steps: ``` - (𝛾, c, s) = 𝜋 - H = encode_to_curve(𝛼) - U = s·B - c·Y ≡ k·B + c·x·B - c·x·B = k·B - V = s·H - c·𝛾 ≡ k·H + c·x·H - c·x·H = k·H - c' = challenge(Y, H, 𝛾, U, V) - assert c = c' ```