# 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'
```