The Doorway Into the Group: A Field Guide to Hashing a String Onto an Elliptic Curve (RFC 9380)
Turning a string into an elliptic-curve point is a two-decade problem behind a one-line API. Why H(m)*G and hunt-and-peck both fail, and how RFC 9380 fixes it.
Permalink1. They Timed the Handshake and Read the Wi-Fi Password
In April 2019, two researchers announced they could recover your Wi-Fi password without guessing it, phishing it, or breaking any cipher. They simply timed how long WPA3 took to turn the password into a point on an elliptic curve, and the clock spelled out the secret [2] [3]. The flaw was not in the encryption or the key exchange. It lived in a single, overlooked step that nearly every discrete-log protocol quietly leans on: the map that carries an arbitrary string into the group.
Get that one step wrong in the other obvious way, computing the point as , and you leak a different secret entirely. Now anyone can forge the signatures that map was supposed to protect [1] [4]. Two shortcuts, two spilled secrets, one primitive. This is the field guide to getting it right.
A function that maps an arbitrary byte string to a point on an elliptic curve, such that the point's discrete logarithm (its relationship to the group generator) is unknown even to the party computing it. RFC 9380 standardizes the interface as hash_to_curve and encode_to_curve [1].
The primitive looks trivial. Hash the input, get a point, move on. But "get a point" hides a genuine algorithm, because on an elliptic curve only about half of the field elements are valid -coordinates. The two things every engineer tries first are the two things you must never ship, and each betrays a different secret. So before you write a single line, ask three questions.
When you turn a string into a curve point, ask: (1) do you know the point's discrete log; (2) does your running time depend on the input; and (3) is the output distribution one your protocol's proof can treat as a random oracle? Every safe construction answers no, no, yes. Every named failure in this article is a wrong answer to exactly one of these.
WPA3-Personal answered the second question wrong. Its handshake, Simultaneous Authentication of Equals (SAE), derives a "password element" by hunt-and-peck: hash the password with a counter, test whether the result is a valid coordinate, and increment until it is [5]. The number of iterations depends on the password, so the time the handshake takes is a function of the secret. Mathy Vanhoef and Eyal Ronen showed that an attacker within range can measure that timing and mount an offline dictionary attack, recovering the password without ever seeing a valid login [2] [3].
Diagram source
sequenceDiagram
participant STA as Client (victim)
participant AP as Access point
participant Atk as Attacker (passive)
Note over STA,AP: WPA3-SAE, password shared by both sides
STA->>STA: Derive password element by hunt-and-peck
Note over STA: Iteration count depends on the password
STA->>AP: Send SAE Commit after the loop finishes
Atk-->>STA: Measure time from trigger to Commit
Note over Atk: Timing reveals the iteration count
Atk->>Atk: Offline dictionary attack narrows candidates RFC 9380, the standard that finally settled this primitive, is blunt about why try-and-increment is unsafe.
"The running time of this method, which is generally referred to as a probabilistic try-and-increment algorithm, depends on the input string. As such, it is not safe to use in protocols sensitive to timing side channels, as was exemplified by the Dragonblood attack." -- RFC 9380, Appendix A [1]
The story got worse before it got better. The Wi-Fi Alliance's first attempt at a fix switched SAE to Brainpool curves, which reintroduced a leak: the encoder now had to loop to find a hash smaller than the prime, and the number of iterations depended on the password and the client's MAC address [3]. This second act is the whole lesson in miniature: constant time cannot be patched in curve by curve. The disclosure site concludes that "implementing Dragonfly and WPA3 without side-channel leaks is surprisingly hard" [3]. Two rounds of the same class of bug, in the handshake now standard across WPA3 Wi-Fi.
Now hold that failure next to its mirror image. Suppose BLS signatures had mapped a message the naive way, for a public hash . A BLS signature is , so it would equal , where is the public key [1] [4]. Every term on the right is public. Anyone forges any signature with no secret key at all. One shortcut leaked a low-entropy password through the clock; the other would hand out the signing key's power to the entire world. The primitive that sits between them is where the security of BLS, every elliptic-curve OPRF, and every password PAKE is actually won or lost.
This is the sibling of a claim Part 15 made about the curve itself: the elliptic-curve discrete-log problem was hard; the danger was the soft gap around it. Here the gap has a name and a shape. It is the doorway, the map that carries untrusted strings into the group. Get the doorway wrong and you publish the discrete log, leak the password through the clock, or hand your proof a distribution it never agreed to. To see why "hash to a point" is an algorithm and not a one-liner, we have to go back to the moment it stopped being free.
2. When Hashing to a Group Stopped Being Free
For a generation of cryptographers, "hash into the group" was not a problem worth naming. In a prime field , the discrete-log setting Diffie and Hellman worked in, you hash your input to an integer and reduce it modulo , and you are already inside the group. Every nonzero residue is a group element, so the map is a single modular reduction with nothing to prove. This is the free lunch elliptic curves took away. In the group is the set of nonzero field elements, so any nonzero hash output is already a valid element. On a curve, the group is a sparse subset of the plane, and most field elements are not on it.
Elliptic curves broke the deal. When Victor Miller and Neal Koblitz independently proposed elliptic-curve cryptography in 1985 and 1987, they replaced with the points of a curve [6] [7]. That change bought smaller keys and harder discrete logs, but it quietly created a new problem: for a random field element , the quantity is a perfect square only about half the time, and only then is the coordinate of an actual point. "Hash to a group element" stopped being a reduction and became a search.
Nobody worried, because for a decade nobody needed to hash to a point. Ordinary ECDSA and ECDH hash to a scalar and multiply a fixed generator, which never leaves the safe world of exponents. Hashing to a scalar is trivial and always safe: any integer modulo the group order is a valid exponent. Hashing to a point is the hard problem, because most field elements are not on the curve.
Then, around the turn of the millennium, the demand arrived from two directions at once, and both directions needed a point.
A signature scheme by Boneh, Lynn, and Shacham built on a bilinear pairing. The signature on a message is , where is the message hashed to a curve point and is the secret key. Verification checks a pairing equation. Security requires that have unknown discrete log, or signatures become forgeable [4].
The first direction was pairing-based cryptography. In 2001 Boneh, Lynn, and Shacham introduced BLS short signatures, whose entire construction rests on hashing the message to a curve point of unknown discrete log, because the signature is that point scaled by the secret key [4]. The same year, Boneh and Franklin built identity-based encryption on the identical primitive, hashing an identity string to a point [8]. BLS shipped with the first answer anyone reaches for: MapToGroup, a try-and-increment loop [4]. Boneh and Franklin instead gave a deterministic map, but only for certain supersingular curves over fields of characteristic , too narrow a class to serve as general infrastructure [8].
The second direction was password-authenticated key exchange. In 2008 Dan Harkins proposed Simultaneous Authentication of Equals, a balanced PAKE that maps a password to a group element and then runs a zero-knowledge proof of it [9]. To do the mapping it introduced hunt-and-peck, the same try-and-increment idea aimed at a secret input. SAE was standardized as RFC 7664 in 2015, including its "Hunting and Pecking with ECC Groups" derivation, and then shipped to consumers in 2018 as the core of WPA3-Personal [5] [2].
A scoping note worth keeping honest: not every PAKE maps a password to a curve point. SPAKE2 uses fixed, independently generated group elements and rather than hashing the password onto the curve, and SRP works in an integer group, not on an elliptic curve at all. The "everything depends on hash-to-curve" claim is precise, not universal, and it applies to the named constructions in this article: SAE, CPace, OPAQUE's OPRF, the RFC 9497 OPRFs, and BLS. The lesson for a field guide: SPAKE2 and SRP are the counterexamples that keep "all PAKEs need hash-to-curve" from being true, and they stop you hunting for the primitive where it is not.
So by 2008 the problem was named and both naive answers were on the table, shipped in real systems: carried the finite-field intuition onto curves, and try-and-increment searched for a valid coordinate. Each was correct in the sense that it produced a usable point. Each was also a disaster, and for opposite reasons. To see exactly what each one leaks, we have to look at the two shortcuts side by side.
3. Two Shortcuts, Two Spilled Secrets
Both obvious maps are correct in the ordinary sense: they produce a point on the curve, quickly, with a few lines of code. That is exactly what makes them dangerous. Each satisfies most of the three properties and fails precisely one, and the property each fails is different, which is why they leak different secrets.
Shortcut A: compute the point as a known multiple of the generator
Hash the message to an integer and scalar-multiply the generator: . The output is uniform on the group, costs one scalar multiplication, and is trivially constant-time. It assumes nothing about the curve. It is the finite-field intuition carried straight onto the curve, and it violates Property 1: whoever computed knows its discrete log, because they chose it.
RFC 9380 does not hedge about the consequence.
"The resulting point has a known discrete log relationship to . Thus, except in cases where this method is specified by the protocol, it must not be used; doing so risks catastrophic security failures." -- RFC 9380, Appendix A [1]
"Catastrophic" is exact, not rhetorical. Take BLS. The public key is , and a signature is . If the map were for a public hash , then
Every quantity on the right -- from the public message, from the wire -- is public. Anyone computes the valid signature on any message directly, with no access to [1] [4]. This is not an edge case or a timing quirk. It is total, structural forgeability on every input. The same knife cuts elsewhere: for an OPRF, knowing the discrete log of the mapped input breaks obliviousness; for a PAKE, a password element with known discrete log no longer hides the password.
// ILLUSTRATION, NOT AN IMPLEMENTATION.
// We model the group as integers mod a small prime order n, with
// "scalar mult" [k]*P written as (k * P) mod n. Discrete log is trivial
// here on purpose -- the point is the STRUCTURE of the forgery, not hardness.
function scalarMul(k, P, n) { return ((k % n) * (P % n)) % n; }
const n = 97; // toy prime group order
const G = 1; // generator
const sk = 42; // signer's SECRET key
const PK = scalarMul(sk, G, n); // public key = [sk]*G
// The UNSAFE map: H(m) = [Hn(m)]*G, so its discrete log Hn(m) is public.
const Hn_m = 7; // public hash of the message
const Hm = scalarMul(Hn_m, G, n); // the mapped point (known DL!)
// Honest signer computes sigma = [sk]*H(m)
const legitSig = scalarMul(sk, Hm, n);
// Attacker never sees sk. Uses only Hn(m) and PK:
const forgedSig = scalarMul(Hn_m, PK, n); // [Hn(m)]*PK
console.log("legit signature :", legitSig);
console.log("forged signature:", forgedSig, "(computed with NO secret key)");
console.log("forgery succeeds:", legitSig === forgedSig); Press Run to execute.
Shortcut B: search for a valid coordinate
The other reflex fixes Property 1 and breaks Property 2. Hash the input together with a counter, test whether the candidate is a valid -coordinate, and loop until it is.
A map that hashes the input with a counter to a candidate , tests whether is a quadratic residue (a valid coordinate), and increments the counter until it is. A random works about half the time, so the expected number of tries is two [1]. The output has unknown discrete log, but the number of iterations depends on the input.
Because nobody chose the output as a multiple of , its discrete log is genuinely unknown, so Property 1 holds. That is exactly why BLS and SAE could ship with it and be functionally correct. The flaw is Property 2: the loop count is a function of the input, so the running time is too. When the input is a secret -- a password, a pre-shared key -- the clock becomes an oracle. That is Dragonblood [2] [1].
// ILLUSTRATION, NOT AN IMPLEMENTATION.
// Count hunt-and-peck iterations for several secret inputs over a toy field.
// A constant-time map would take the SAME work for every input; this does not.
const p = 103; // toy prime, p = 3 mod 4
const a = 2, b = 3; // toy curve y^2 = x^3 + a x + b
function modpow(base, exp, mod) {
let r = 1; base = base % mod;
while (exp > 0) {
if (exp & 1) r = (r * base) % mod;
base = (base * base) % mod;
exp = exp >> 1;
}
return r;
}
// Euler's criterion: x is a nonzero square mod p iff x^((p-1)/2) == 1
function isSquare(x, p) { return x === 0 ? true : modpow(x, (p - 1) / 2, p) === 1; }
// A stand-in for H(input || ctr): deterministic, input-dependent pseudo-x.
function candidateX(seed, ctr, p) { return ((seed * 131 + ctr * 419 + 17) % p + p) % p; }
function iterations(seed) {
for (let ctr = 1; ctr < 200; ctr++) {
const x = candidateX(seed, ctr, p);
const g = (((x * x % p) * x % p) + a * x + b) % p;
if (isSquare(g, p)) return ctr;
}
return -1;
}
for (const pw of [11, 23, 37, 58, 71, 90]) {
console.log("secret input " + pw + " -> " + iterations(pw) + " iterations");
}
console.log("Different inputs, different work: that difference is the leak."); Press Run to execute.
Here is the table that makes the whole article click. Two maps, three properties, and each map fails a different one.
| Map | Unknown discrete log (Prop 1) | Constant time (Prop 2) | Right distribution (Prop 3) | The secret it spills |
|---|---|---|---|---|
| Violated (DL is ) | Satisfied | Satisfied (uniform) | The signing key's power -- universal forgery [1] [4] | |
| Try-and-increment | Satisfied | Violated (loop depends on input) | Roughly satisfied | The secret input -- via handshake timing [1] [2] |
So the requirement is now sharp, and it looks almost contradictory. You need a map whose output has unknown discrete log, like try-and-increment, but whose running time is fixed, unlike try-and-increment. You need the safety of the search without the search. For a few years it was not obvious such a thing existed. The story of how the field built it, one property at a time, is the evolution of the primitive itself.
4. Moving Each Property Into the Curve
The next thirteen years read like a chain of defenses in which the defenders keep advancing. Each generation takes one property that used to depend on the implementer's care and locks it into the construction, where it holds by mathematics rather than by discipline. Three of those steps are true property wins. The rest are the engineering that made the winning map cheap enough and general enough to run on every curve real protocols use. Being honest about which is which is the difference between a clean story and a true one.
Diagram source
flowchart TD
Naive["Naive maps: known DL or variable time"] -->|"one leaks the DL, one leaks timing"| G1["SvdW 2006: constant time, unknown DL"]
G1 -->|"cheaper per-curve maps"| G2["Icart and Simplified SWU, 2007 to 2010"]
G1 -->|"a single map is not a random oracle"| G3["BCIMRT 2010: sum of two maps"]
G2 -->|"still a single map"| G3
G3 -->|"map per curve family"| G4["Elligator 2, 2013: Montgomery and Edwards"]
G3 -->|"pairing curves with A zero"| G5["Isogeny SSWU, 2019: BLS12-381"]
G4 --> RFC["RFC 9380, 2023: one interface"]
G5 --> RFC The first constant-time map: Shallue-van de Woestijne (2006)
The contradiction from the last section -- unknown discrete log without a search -- was resolved in 2006 by Andrew Shallue and Christiaan van de Woestijne. Their map is the "SW" in "SSWU." Given a field element , algebraic identities guarantee that among a small fixed set of candidate -values derived from , at least one is a valid coordinate [10]. So you compute the candidates, test them in a fixed order with a constant number of operations, and select a valid one. There is no rejection loop, which means no data-dependent branch, which means constant time by construction [10] [1]. The discrete log stays unknown. For the first time, a single map was simultaneously unknown-DL and constant-time on almost any curve with characteristic other than 2 or 3.
The idea had roots. Schinzel and Skalba had constructed curve points deterministically for a restricted class of curves in 2004, and Skalba generalized it in 2005; Shallue and van de Woestijne further generalized and simplified that line [11] [12] [1]. Boneh and Franklin's 2001 supersingular map was a deterministic co-origin, but too narrow to be general infrastructure [8]. SvdW survives today in RFC 9380 as the universal fallback for any curve the specialized maps do not cover [1].
But SvdW carried a flaw that every deterministic map after it would share, and it is the one no amount of cleverness in a single map can dodge.
The wall every single map hits
RFC 9380 states the obstacle plainly: the deterministic maps "map to some fraction of the points" on the curve, "not the entire curve," which "means that they cannot be used directly to construct a random oracle that outputs points on the curve" [1]. A single SvdW map hits only a constant fraction of the points and is statistically distinguishable from uniform. Any proof that models the map as a random oracle -- BLS's unforgeability, an OPRF's pseudorandomness, a password mapping -- does not go through. This is Property 3, and it is missing.
A formal criterion, defined by Maurer, Renner, and Holenstein in 2004, for when a constructed function can safely stand in for an ideal object such as a random oracle inside a security proof. A hash-to-curve construction is "indifferentiable from a random oracle" when no efficient distinguisher can separate it from a true random oracle, even given access to the underlying building blocks [13].
Before that wall was scaled, the field spent a few years making the map cheaper.
Cheaper maps: Ulas, Icart, Simplified SWU (2007-2010)
Ulas simplified SvdW in 2007 (the "U" in SWU) [14]. Icart gave an independent closed-form map in 2009 for fields with , built on a single cube root [15]. Brier and coauthors published the "Simplified SWU" map in 2010 for fields with [16]. Each is a fixed rational formula costing roughly one field exponentiation plus a few multiplications and one inversion -- cheaper and easier to implement in constant time than SvdW's heavier parameterization.
This was progress, but not on Property 3. Cheaper did not mean uniform: each remained a single map hitting a fraction of the curve, still unusable as a random oracle [1]. And the modular conditions left gaps. Icart needs ; Simplified SWU needs ; neither covers curves with such as secp256k1 and BLS12-381. The deeper question was sharper and universal: could you build something provably indifferentiable out of these non-uniform pieces? The answer arrived, remarkably, in the very same 2010 paper that gave Simplified SWU.
The breakthrough: add two maps (2010)
Here is the shift the whole standard turns on. A single deterministic map cannot be a random oracle. But the sum of two independent maps can be. Hash the message to two field elements, map each to a point, and add the points:
Brier, Coron, Icart, Madore, Randriam, and Tibouchi proved this construction indifferentiable from a random oracle, and it recovers Property 3 while keeping Properties 1 and 2 [16] [13]. All three properties, at last, guaranteed at once.
A single deterministic map can never be a random oracle: it reaches only a fraction of the curve and is distinguishable from uniform. The fix is structural, not a cleverer single map. Hash to two field elements, map each, and add the two points. The sum is indifferentiable from a random oracle. This is exactly why
hash_to_curve(the_RO_suites) costs twice whatencode_to_curve(the_NU_suites) costs: the second map is not waste, it is what buys the distribution [16] [17] [1].
Diagram source
flowchart TD
M["msg and DST"] --> HF["hash_to_field to two elements"]
HF --> Q0["map_to_curve of u0 gives Q0"]
HF --> Q1["map_to_curve of u1 gives Q1"]
Q0 --> ADD["add points: Q0 plus Q1"]
Q1 --> ADD
ADD --> RO["sum is indifferentiable from a random oracle"]
RO --> CC["clear_cofactor"]
CC --> P["point in the prime-order subgroup"] Precision matters here, because it is easy to over-credit. Brier et al. proved the sum-of-two construction indifferentiable specifically for Icart's map. The general result -- that summing two copies of essentially any deterministic map yields a random oracle -- is due to Farashahi, Fouque, Shparlinski, Tibouchi, and Voloch in 2013. Attribute the general theorem to FFSTV13, not to BCIMRT. RFC 9380's Appendix A is careful about this: BCIMRT proved it for Icart's method; FFSTV13 "improve the analysis, showing that it applies to essentially all deterministic mappings" [1] [17]. After 2010, nothing about Property 3 was left to invent. What remained was coverage: the sum-of-two construction needs a concrete constant-time inner map for your curve family, and two families were still uncovered.
Covering the remaining curves: Elligator 2 (2013) and isogeny SSWU (2019)
The Montgomery and twisted-Edwards curves -- Curve25519, Curve448, and the Edwards forms behind modern signature and OPRF suites -- needed their own map, because SSWU targets short-Weierstrass curves. Elligator 2 supplied it.
An efficient, invertible map from a field element to a point on any curve that has a point of order 2 (Montgomery or twisted-Edwards form), introduced by Bernstein, Hamburg, Krasnova, and Lange in 2013. RFC 9380 uses it for the Curve25519/448 and edwards25519/448 families and the ristretto255/decaf448 groups [18] [1].
Elligator's origin is a small marvel. It was built for censorship resistance, a way to make a public key look like uniform random bytes so a network censor cannot even tell a key exchange is happening. The elligator.org site records the pivot in its own words: a number of protocols "need a way to map an arbitrary input to an elliptic curve point whose factorisation is unknown ('hashing to an elliptic curve'), such as verifiable random functions (VRFs) and oblivious pseudorandom functions (OPRFs)." A steganography tool became hash-to-curve infrastructure [19]. The tool built to hide a key exchange became the constant-time inner map for an entire curve family's hashing.
The last gap was the pairing-friendly curve BLS needs. BLS12-381 has , exactly where Simplified SWU does not apply. In 2019 Riad Wahby and Dan Boneh closed it: map with SSWU onto an isogenous curve where the parameters are admissible, then push the point back to the target curve through a fixed isogeny of small degree [20] [1]. The result is constant-time and works in any characteristic, and it is what made constant-time hashing to BLS12-381 practical at blockchain scale. Their headline measurement is the number that ends an old excuse: the constant-time functions run "within 9% of the fastest, non-constant-time alternatives" [20].
| Generation | Year | Key idea | Time | What it secured | Status |
|---|---|---|---|---|---|
| ~2001 | scalar-mult the generator | constant | nothing (DL is known) | never safe as a map [1] | |
| Try-and-increment | 2001-2008 | search for a valid coordinate | variable | unknown discrete log | deprecated for secret inputs [4] [1] |
| SvdW | 2006 | rational parameterization, no loop | constant | constant time by construction | general fallback [10] |
| Ulas / Icart / Simplified SWU | 2007-2010 | cheaper closed-form maps | constant | efficiency, per-curve forms | inner maps [14] [15] [16] |
| BCIMRT sum-of-two | 2010 | add two mapped points | constant | random-oracle distribution | the _RO_ core [16] [17] |
| Elligator 2 | 2013 | invertible map for order-2 curves | constant | Montgomery/Edwards coverage | active [18] |
| Isogeny SSWU | 2019 | map via an isogenous curve | constant | pairing-curve coverage | active [20] |
Every curve family that deployed protocols use now has a constant-time, unknown-DL inner map, and the sum-of-two construction wraps any of them into a random oracle. All three properties are achievable everywhere. But an implementer still has to assemble the hashing, the map, the cofactor clearing, the domain separation, and the choice of variant, by hand, and any one of those is a place to slip. What packages the whole lineage so you cannot get it wrong?
5. RFC 9380: All Three Properties at Once
In August 2023 the CFRG published RFC 9380, "Hashing to Elliptic Curves," by Armando Faz-Hernandez, Sam Scott, Nick Sullivan, Riad Wahby, and Christopher Wood [1]. It invents no new map. It does something more useful: it folds two decades of maps into a single interface an ordinary engineer cannot easily misuse, and it makes every security-relevant choice legible in the name.
The pipeline has three stages [1]:
hash_to_fieldturns the input and a domain tag into one or more field elements, usingexpand_message_xmdfor fixed-output hashes like SHA-256 andexpand_message_xoffor extendable-output functions like SHAKE.map_to_curvesends each field element to a curve point using the map that fits the curve: Simplified SWU for short-Weierstrass curves, isogeny-SSWU for the pairing curves, Elligator 2 for Montgomery and Edwards curves, and SvdW as the general fallback.clear_cofactorforces the result into the prime-order subgroup.
Diagram source
flowchart TD
IN["input msg and DST"] --> HF["hash_to_field"]
HF --> BR{"which variant"}
BR -->|"<em>RO</em> hash_to_curve"| TWO["two field elements, two maps, add"]
BR -->|"<em>NU</em> encode_to_curve"| ONE["one field element, one map"]
TWO --> CC["clear_cofactor"]
ONE --> CC
CC --> OUT["point in the prime-order subgroup"] The two-element margin is a proven bound
The first stage hides a subtlety worth pausing on. Reducing a uniformly random integer modulo is not exactly uniform, because the top of the range wraps around. RFC 9380 fixes this by oversampling.
The first pipeline stage: expand the input and the domain tag into field elements. It draws bytes per element and reduces modulo , so each element is within statistical distance of uniform. The standard suites set , giving a margin [1].
That is a proven statistical bound, not a hopeful heuristic, and it is exactly why the byte-length formula is what it is [1].
The variant is in the name
The choice between a uniform, proof-usable point and a cheaper nonuniform one is encoded directly in the suite name. hash_to_curve, the _RO_ family, runs the two-element sum-of-two construction and is indifferentiable from a random oracle. encode_to_curve, the _NU_ family, runs a single map at about half the cost and produces a nonuniform distribution [1]. The trailing tag is not decoration; it tells you whether the output is safe to feed a proof that assumes a random oracle.
RFC 9380 suite identifiers follow the pattern CURVE_XMD:HASH_MAP_VARIANT_. Once you can read one, you can read them all.
| Field | In BLS12381G2_XMD:SHA-256_SSWU_RO_ | What it fixes |
|---|---|---|
| Curve / group | BLS12381G2 | the target group: BLS12-381, subgroup G2 |
| Expander | XMD | expand_message_xmd (a fixed-output hash) |
| Hash | SHA-256 | the underlying hash function |
| Inner map | SSWU | Simplified SWU (isogeny variant here, since ) |
| Variant | RO | _RO_: uniform, indifferentiable from a random oracle |
Read edwards25519_XMD:SHA-512_ELL2_RO_ the same way and it decodes itself: the edwards25519 group, XMD expansion over SHA-512, the Elligator 2 map, uniform variant [1]. The name is the spec.
// Decompose an RFC 9380 suite ID: CURVE_EXPANDER:HASH_MAP_VARIANT_
function parseSuite(id) {
const [left, right] = id.split(":");
const leftParts = left.split("_");
const expander = leftParts.pop(); // XMD or XOF
const curve = leftParts.join("_"); // e.g. BLS12381G2, edwards25519
const rp = right.split("_").filter(function (s) { return s.length > 0; });
const hash = rp[0]; // SHA-256, SHA-512, SHAKE256
const variant = rp[rp.length - 1]; // RO or NU
const map = rp.slice(1, rp.length - 1).join("_"); // SSWU, ELL2, SVDW
return { curve: curve, expander: expander, hash: hash, map: map,
variant: variant,
uniform: variant === "RO" ? "uniform (random oracle)" : "nonuniform" };
}
["BLS12381G2_XMD:SHA-256_SSWU_RO_",
"edwards25519_XMD:SHA-512_ELL2_RO_",
"P256_XMD:SHA-256_SSWU_NU_"].forEach(function (id) {
console.log(id);
console.log(" ", JSON.stringify(parseSuite(id)));
}); Press Run to execute.
The two steps you must not skip
Two pipeline stages are easy to forget and dangerous to omit. The first is the domain tag.
A byte string, unique to a protocol and its version, mixed into hash_to_field so the same input maps to different points in different protocols. RFC 9380 makes it mandatory; DSTs longer than 255 bytes are themselves hashed before use. Without a unique DST, two protocols that share a curve can be driven to collide [1].
The second is cofactor clearing, the final stage that lands the point where the group arithmetic is safe.
The final pipeline stage: multiply the mapped point (or apply a faster endomorphism-based equivalent) by the curve's cofactor to force it into the prime-order subgroup, closing off small-subgroup attacks. edwards25519 has cofactor 8; BLS12-381's G1 and G2 have large cofactors with fast clearing methods [1].
Step back and the three properties resolve into one sentence. The mapped point had to be a stranger -- its discrete log unknown, or forgery follows. It had to arrive on time -- in work independent of the input, or the clock leaks the secret. And it had to look the part -- drawn from a distribution the proof can treat as a random oracle, or the proof does not hold.
The point had to be a stranger, arrive on time, and look the part. RFC 9380 is the standard that guarantees all three, and encodes which ones you asked for in a single suite name.
That framing also closes the loop this article opened. WPA3's answer to Dragonblood is Hash-to-Element, or H2E.
The doorway is finally built to spec. The natural next question is who is actually walking through it, because the answer is: far more of your daily software than you would guess.
6. Who Quietly Depends on This Today
You have almost certainly relied on hash-to-curve this week without noticing. It sits under signatures that finalize blockchains, under the private authentication that hides your browsing from a token issuer, under the password login protocol that never sees your password, and under WPA3. None of these advertise the primitive. All of them break if it is wrong.
Diagram source
flowchart TD
BLS["BLS signatures on Ethereum"] --> H2C["RFC 9380 hash-to-curve"]
OPRF["OPRF and VOPRF (RFC 9497)"] -->|"one HashToGroup call"| H2C
OPAQUE["OPAQUE aPAKE (RFC 9807)"] -->|"indirect"| OPRF
PP["Privacy Pass (RFC 9578)"] --> OPRF
CPace["CPace PAKE (draft)"] --> H2C
SAE["WPA3-Personal SAE"] -->|"H2E"| H2C BLS signatures and Ethereum consensus
The highest-volume deployment, by signature-verification throughput, is BLS. Every BLS signature hashes its message to a point in G2 and scales it by the secret key, so hash_to_point is not an accessory but the heart of the scheme [22]. Ethereum's consensus specification fixes this for validator signatures: it adopts the suite BLS12381G2_XMD:SHA-256_SSWU_RO_ -- the isogeny-SSWU map wrapped in the _RO_ construction -- so every consensus client hashes exactly this way [23] [22] [1]. The _RO_ variant is not optional here: the unforgeability proof models the map as a random oracle, so a nonuniform _NU_ map would void the guarantee. Notably, the scheme the entire Ethereum validator set relies on is still specified only by an Internet-Draft, which the consensus spec references directly [23] [22]. Unlike ECDSA, BLS is deterministic and uses no per-signature nonce, so it sidesteps the nonce-reuse failures that have repeatedly broken ECDSA deployments (Part 8). Its one hash-to-curve call becomes the security-critical primitive in place of the nonce [22].
OPRFs, and everything built on them
The second large consumer is the oblivious pseudorandom function and its verifiable and partially-oblivious variants, standardized in RFC 9497 [24].
A two-party protocol in which a client learns for its input and the server's key , while the server learns neither nor the result. The client's first step hashes to a curve point and blinds it; that single HashToGroup call is the protocol's entire hash-to-curve surface [24].
The dependency is remarkably concentrated. The client's Blind(input) computes HashToGroup(input) and then blinds the point; every other message is scalar arithmetic and proofs. So the whole hash-to-curve exposure of an OPRF is one call, instantiated with Elligator 2 for ristretto255 and SSWU for the P-256, P-384, and P-521 suites [24].
Because OPRFs are a building block, their hash-to-curve dependency propagates. OPAQUE, the augmented PAKE standardized as RFC 9807 in July 2025, lets a server authenticate a user by password without ever learning the password, and it does so by running an OPRF; its hash-to-curve dependency is indirect but real, flowing through RFC 9497 [25] [24]. Privacy Pass, standardized across RFC 9576, RFC 9577, and RFC 9578 in June 2024, issues anonymous authentication tokens; its privately verifiable issuance is "based on the Oblivious Pseudorandom Function," with token type 0x0001 being a VOPRF over P-384, which is the SSWU path [26] [27] [28].
PAKEs and Wi-Fi
Two more consumers map a secret rather than a public message. CPace, a balanced PAKE still in CFRG draft with datatracker status "Waiting for IRTF Chair," maps the password to a session generator using SSWU or Elligator 2 depending on the group [29]. And WPA3-Personal's SAE now derives its password element with the constant-time H2E map, the fix that closed Dragonblood [3].
The whole deployed picture fits in one adoption map.
| Consumer | Where hash-to-curve is called | Suite / map | Standard status |
|---|---|---|---|
| BLS / Ethereum consensus | hash_to_point(msg) into G2 | BLS12381G2_XMD:SHA-256_SSWU_RO_ [22] | Internet-Draft [22] |
| OPRF / VOPRF / POPRF | Blind calls HashToGroup | ristretto255 to Elligator 2; P-curves to SSWU [24] | RFC 9497 (2023) [24] |
| OPAQUE (aPAKE) | indirect, via its OPRF | inherits the OPRF suite [25] | RFC 9807 (2025) [25] |
| Privacy Pass | VOPRF token issuance | P-384 VOPRF to SSWU [26] | RFC 9576/9577/9578 (2024) [26] |
| CPace (balanced PAKE) | password to session generator | SSWU or Elligator 2 by group [29] | draft, "Waiting for IRTF Chair" [29] |
| WPA3-Personal (SAE) | password element (PWE) | H2E, constant-time SSWU [3] | IEEE 802.11 |
What actually ships
Under all of this sit a few load-bearing libraries. The blst library implements BLS12-381 hash-to-curve in C and assembly, is compliant with RFC 9380, was audited by NCC Group in January 2021, and is the subject of an ongoing Galois formal-verification effort [30] [31]. Cloudflare's CIRCL provides RFC 9380 hash-to-curve and RFC 9497 OPRFs in Go, though it labels itself experimental and cautions against production use of parts of it [32]. In Rust, curve25519-dalek exposes an Elligator-based one-way map through RistrettoPoint::from_uniform_bytes [33].
The headline is quiet by design: the primitive is standardized and load-bearing under a stack of shipping protocols, and almost nobody who depends on it has to think about it. That is what a well-built doorway looks like. Which raises a fair question: if every consumer just names a suite, is there ever a real choice to make, or has the standard decided everything for you?
7. The Decision Matrix
There is no "best" hash-to-curve, and that is a feature. Almost every knob is set for you by something structural: the curve you already committed to, or the distribution your proof already assumes. The value of a field guide is naming which axis governs which choice, and where a wrong turn is a vulnerability rather than a mere preference.
Distribution need decides the variant
The _RO_ versus _NU_ choice is governed by one question: does your proof need a random oracle? For BLS, OPRFs, and password mapping, it does, so _RO_ is the default. The _NU_ variant is an optimization you reach for only with a specific proof that non-uniformity is acceptable, because its output is measurably not uniform.
| Dimension | hash_to_curve (_RO_) | encode_to_curve (_NU_) |
|---|---|---|
| Field elements and maps | 2 elements, 2 maps, 1 addition | 1 element, 1 map |
| Relative cost | about twice _NU_ | baseline, about half of _RO_ |
| Output distribution | indifferentiable from a random oracle [1] | nonuniform: at least one eighth of G, weights vary by up to a factor of four [1] |
| Proof compatibility | usable where a proof assumes a random oracle | only where non-uniformity is provably sufficient |
| Decision rule | default for BLS, OPRF, PAKE mapping | optimization only, with a proof |
Getting this backward is a shippable misuse: a _NU_ map where the proof assumed _RO_ produces a point from a distribution the proof never agreed to, which is the third of our three failures made concrete [1].
Curve family decides the map
The choice among the inner maps is not a matter of taste at all. It is fixed by the shape of your curve.
Diagram source
flowchart TD
Q{"what curve do you have"}
Q -->|"short Weierstrass, p is 3 mod 4"| SSWU["Simplified SWU"]
Q -->|"A is zero: secp256k1, BLS12-381"| ISO["Isogeny SSWU"]
Q -->|"Montgomery or Edwards"| ELL["Elligator 2"]
Q -->|"none of the above"| SVDW["SvdW fallback"] | Map | Curve condition | Curves in RFC 9380 | Dominant cost |
|---|---|---|---|
| Simplified SWU | short-Weierstrass, , | P-256, P-384, P-521 | about one square root plus selects |
| Isogeny SSWU | Weierstrass | secp256k1, BLS12-381 G1/G2 | SSWU on plus one isogeny evaluation |
| Elligator 2 | curve with a point of order 2 | curve25519/448, edwards25519/448, ristretto255/decaf448 | about one exponentiation |
| SvdW | any curve, characteristic other than 2 or 3 | fallback when none of the above fit | a few exponentiations and inversions |
The two knobs that are real, but small
Two remaining choices are genuine but low-stakes. The expander, expand_message_xmd versus expand_message_xof, follows your hash family: XMD for SHA-2, XOF for SHAKE, and neither dominates on security, so you pick the hash you already have [1]. And within BLS, you can hash to either pairing group.
The number that ends an old argument
For years, the excuse for variable-time hunt-and-peck was that constant-time maps were too slow. Wahby and Boneh's nine-percent measurement retired it: constant time is essentially free here, and simpler to implement correctly, which is why RFC 9380 can require it without asking anyone to pay for the safety [20].
It is worth remembering how strange this matrix would look to a cryptographer of 1995. In a finite field, hashing into the group is a single modular reduction with no decision matrix at all [6]. Elliptic curves bought hard discrete logs and small keys, and the bill came due as this exact table: a real algorithm, with real parameters, that you must get right. Two maps, an oversampling margin, a distribution that is deliberately "almost uniform": none of it is arbitrary. The next section proves they are the right choices, not just good ones.
8. Why Two Maps, and How Uniform Is "Uniform"
The two-map construction can feel like a clever hack. It is not. It is the provable optimum, and the theory that says so also explains the oversampling margin and the one caveat you must respect.
The lower bound that forces two maps
Start with what a single map cannot do. No efficient deterministic map to a general elliptic curve is both surjective and uniform. Its image is only a constant fraction of the curve, with some points weighted more heavily than others. RFC 9380 quantifies the residual for the single-map case exactly: the output distribution "includes at least one eighth of the points in G," and the probability of points "varies by at most a factor of four" [1]. Those bounds descend from the analyses of the individual maps [10] [18] [35]. A distribution that misses seven-eighths of the group in the worst case and re-weights the rest simply cannot be indifferentiable from a uniform random oracle. One map is not enough, and this is why.
The matching upper bound
Now the other side. Hashing to two field elements, mapping each, and adding the points is indifferentiable from a random oracle, proven for Icart's map by Brier et al. and generalized to essentially all maps by Farashahi et al. [16] [17] [13]. The lower bound says one map cannot suffice; the upper bound says two do. The gap is closed. The _RO_ construction is the tight, achievable answer to "produce a uniform, proof-usable point," and RFC 9380 standardizes precisely that optimum, no more and no less [1].
Why the oversampling margin is what it is
The same "prove it, do not hope it" discipline governs hash_to_field. Reducing a uniform -byte integer modulo leaves a small bias from the wrap-around at the top of the range. Oversampling by bits, with
drives the statistical distance from uniform below . RFC 9380 fixes , so every field element is within of uniform [1]. That is a proven bound, which is why truncating the byte length is not a harmless optimization but a real weakening of the margin.
The one caveat that survives all of this
Here the humility arrives. "Indifferentiable from a random oracle" does not mean "safe to drop into any random-oracle proof."
There is a smaller but instructive caveat in the same spirit. Either encoding can, with probability roughly for a random input, output the identity element. That probability is negligible and it is infeasible to find such an input deliberately, so RFC 9380 says protocols "SHOULD NOT add a special case to detect and 'fix' the identity element." The special case is itself a bug surface, more likely to introduce a flaw than to prevent one [1]. The right move is to do nothing special, which is counterintuitive enough that people get it wrong by trying too hard.
One boundary is worth stating precisely, because it sets up everything still open. The "unknown discrete log" property adds no new hardness assumption: it inherits the elliptic-curve discrete-log hardness of the target group, the same assumption Part 15 examined [1]. And so, like all elliptic-curve cryptography, it falls to Shor's algorithm on a fault-tolerant quantum computer. Post-quantum signatures sidestep the primitive entirely, because they use no curve. But the consumers that specifically need a point of unknown discrete log -- OPRFs and VRFs -- have no such escape. That is where the frontier actually is.
9. Where It Is Still Moving
A solved primitive with live frontiers sounds like a contradiction, but hash-to-curve is exactly that. The classical mathematics is settled; the engineering, the assurance, and the post-quantum future are not.
Constant time, all the way down
RFC 9380 guarantees constant time at the interface: no data-dependent loop. The guarantee has to hold much further down, though, through the field primitives the map calls -- the square root, the sign function sgn0, the zero-guarded inversion inv0, general inversion, and the conditional selects -- each of which can leak through timing, cache, or micro-architecture if written naively [1]. And the map runs on secrets: passwords in SAE and CPace, blinded inputs in OPRFs. A leak in one field routine re-opens the exact class of attack Dragonblood exploited.
The expensive curves
Hashing to G2 of BLS12-381, over the field and with a large cofactor, is markedly costlier than hashing to G1. Faster maps and faster cofactor clearing are open engineering targets, and they matter because Ethereum verifies huge volumes of signatures, so every millisecond of G2 hashing multiplies across the network. Wahby and Boneh brought constant-time hashing within nine percent of variable-time, and the fast-G2 cofactor-clearing line descends from work like Scott and coauthors' "Fast Hashing to G2," but G2 remains the expensive path, and each new pairing-friendly curve keeps the problem alive [20] [34].
Machine-checked implementations
Because constant time is hard to get right, the field increasingly wants implementations proven correct by machine, not just audited by eye. The leading edge is visible in blst, the highest-volume hash-to-G2 implementation: it was audited by NCC Group in January 2021, and its formal verification by Galois is, in the project's own words, ongoing [30] [31]. That is the honest status: verification of a deployed hash-to-curve path is in progress, not finished. Full end-to-end machine-checked hash-to-curve -- map, cofactor clearing, and constant time, across curve families -- remains open.
The genuinely open frontier: post-quantum
The deepest gap is post-quantum. Signatures have a post-quantum future without curves, so they abandon hash-to-curve. The unknown-DL consumers do not have that luxury. OPRFs and VRFs -- and therefore OPAQUE, Privacy Pass, and anonymous-credential systems built on them -- rest on the hardness of the elliptic-curve discrete log, and a quantum adversary breaks that foundation. Lattice- and isogeny-based OPRF and VRF constructions exist in the research literature, but none is competitive with the elliptic-curve versions in bandwidth or round complexity, and none is standardized. This guide states the frontier without pinning a specific paper, holding to the same citation standard as the rest of the series. There is no drop-in "post-quantum hash-to-curve," because the whole unknown-DL abstraction has to be rebuilt on different assumptions, and the competitive replacement does not yet exist.
Steady-state engineering
Finally, the everyday work: as deployments adopt new pairing-friendly curves (BLS12-377 and BW6 are recent examples) and new prime-order abstractions, each needs its admissible map and cofactor-clearing constants worked out and folded into the suite registry [1]. This keeps the "which map for which curve" table a living document rather than a finished one. Given all of it, the practical question remains: what should you actually do on Monday?
10. The Decision Rules, Made Operational
Here is the spine turned into something you can apply to a code review this afternoon. The rules are short because the standard did the hard part; your job is to name the right suite and not undo its work.
Use a vetted suite, never a hand-rolled map. Always call a RFC 9380 suite from a constant-time library for your curve. Never compute , and never write your own map. The two most catastrophic errors in this whole area are the two shortcuts from Section 3 [1].
Default to _RO_. Use hash_to_curve (_RO_) unless you hold a specific proof that non-uniformity is acceptable, in which case encode_to_curve (_NU_) halves the cost [1].
Always set a unique DST. Make the domain-separation tag specific to your protocol and version, hash it if it exceeds 255 bytes, and never share one across protocols. This is domain separation, the same discipline Part 13 develops for keys [1].
Map by curve, not by taste. Short-Weierstrass with uses SSWU; uses isogeny-SSWU; Montgomery and Edwards use Elligator 2; anything else uses SvdW [1].
Then the per-protocol specifics:
- BLS: use
BLS12381G2_XMD:SHA-256_SSWU_RO_for minimal-pubkey-size, or the G1 suite for minimal-signature-size;_RO_is required for the unforgeability proof; clear the cofactor [22]. - OPRF, VOPRF, OPAQUE: call RFC 9497's
HashToGroupandHashToScalarat the ciphersuite's suite; do not substitute your own map; reject the identity element on the wire [24]. - PAKE mapping a password (SAE, CPace): use a constant-time map only, never hunt-and-peck a secret, and pre-hash the password with a slow KDF such as PBKDF2, scrypt, or Argon2 before mapping, so an adversary who sees an intermediate value still faces a slow dictionary attack [1]. Part 12's password-entropy argument is exactly why this matters.
Pick the suite for your curve, default to
_RO_, set a unique DST, and clear the cofactor. Four decisions, each with a safe default, and RFC 9380 has already made three of them for you the moment you name the suite [1].
The mirror image of the rules is the list of things that never belong in a diff. Each is a real, shippable bug that maps to exactly one of the three properties, or to the two guardrails around them.
| Misuse | What it violates | The fix |
|---|---|---|
| instead of a map | Unknown discrete log | use a real RFC 9380 map [1] |
| Hunt-and-peck over a secret | Constant time | constant-time suite; H2E for SAE [1] [3] |
_NU_ where the proof needs _RO_ | Random-oracle distribution | default to _RO_ [1] |
| Missing or shared DST | Domain separation | unique per-protocol, per-version DST [1] |
| Skipped cofactor clearing | Subgroup safety | clear the cofactor; check the subgroup [1] |
Truncated hash_to_field output | Uniformity margin | use the full bytes [1] |
| Raw password without a slow KDF | Offline-guessing resistance | PBKDF2, scrypt, or Argon2 first [1] |
A quick way to sanity-check any hash-to-curve library
RFC 9380 ships official test vectors for every suite. Before you trust an implementation, feed it the standard's sample inputs and DSTs and confirm the output points match byte for byte. A library that reproduces the vectors implements the pipeline correctly; one that does not should never touch a secret [1].
A checklist answers "what to do." The last thing to handle is the set of "but why can't I just..." questions that every reviewer and implementer keeps asking, because the answers are where the understanding finally sets.
11. FAQ and Common Misuse
Frequently asked questions
Why can't I just compute H(m) times G?
Because its discrete log is , which is public, so the point is not a stranger to anyone. In BLS this is fatal: a signature becomes , which anyone computes from the public message and public key with no secret key. The same known-discrete-log flaw breaks OPRF obliviousness and a PAKE's password element [1] [4].
Isn't try-and-increment fine?
Only when the input is public and you need neither constant time nor a random-oracle distribution. Over a secret input the loop count is a function of the secret, so the running time leaks it. That is precisely the Dragonblood attack that recovered WPA3 passwords, and it is why RFC 9380 declines to specify the method [1] [2].
RO or NU, does it actually matter?
Yes. The _NU_ output is provably not a random oracle: it covers at least one eighth of the group with weights varying by up to a factor of four [1]. If your proof assumes a random oracle -- as the BLS, OPRF, and PAKE proofs do -- you need _RO_. Use _NU_ only with a specific proof that non-uniformity is acceptable [1].
Do I really need a domain-separation tag?
Always. The DST is domain separation, not decoration: without a unique, protocol-and-version-specific tag, two protocols sharing a curve can be driven to collide. RFC 9380 makes it mandatory and hashes tags longer than 255 bytes [1].
Which map do I pick for Curve25519 or for BLS12-381?
You don't; the curve decides. Curve25519 and edwards25519 use Elligator 2, because they have a point of order 2. BLS12-381 uses isogeny-SSWU, because . The map is a structural consequence of the curve, not a preference [1].
Is hash-to-curve quantum-safe?
No. It is bound to elliptic-curve cryptography and falls to Shor's algorithm. Post-quantum signatures avoid the primitive entirely because they use no curve, but the consumers that need a point of unknown discrete log -- OPRFs and VRFs, and the systems built on them -- have no settled, efficient post-quantum replacement yet [1].
Are encode_to_curve and hash_to_curve the same thing?
No. encode_to_curve (_NU_) runs one map and produces a nonuniform point at about half the cost. hash_to_curve (_RO_) hashes to two field elements, maps each, and adds the points, which is indifferentiable from a random oracle. The extra map is what buys the distribution [1].
The Point Had to Be a Stranger, Arrive on Time, and Look the Part
Look back at the failures with the whole picture in hand, and they line up with eerie precision. Each was a wrong answer to exactly one of the three questions. Computing published the discrete log: the point was not a stranger, and universal forgery followed [1] [4]. Hunt-and-peck leaked the password through the clock: the point did not arrive on time, and Dragonblood read it off the handshake [2]. Reaching for _NU_ where a proof needs _RO_ handed the proof a distribution it never agreed to: the point did not look the part [1]. Three questions, three ways to fail, three real systems that failed them.
That is the sibling claim to the one Part 15 made about the curve itself. The elliptic-curve arithmetic was sound; the danger was the soft gap around it. Here the gap has a name and a shape. It is the doorway, the single step that carries an untrusted string into the group, and getting it right means answering all three questions at once: unknown discrete log, constant time, and a proof-usable distribution. RFC 9380 is the standard that guarantees all three and encodes which ones you asked for in a suite name you can read at a glance.
For classical curves, the doorway is finally built to spec. The two-map construction is the provable optimum, the oversampling margin is a proven bound, and a handful of audited libraries carry the whole load quietly under BLS, OPRFs, OPAQUE, Privacy Pass, and WPA3. The open frontier has moved elsewhere: to machine-checked implementations of what already ships, to the stubbornly expensive pairing curves, and above all to a post-quantum world where the unknown-DL consumers have no settled replacement.
So the next time you call a one-line hash-to-curve API, you will know to ask the three questions it answers for you. Do you know the point's discrete log? Does your running time depend on the input? Can your proof model the output as a random oracle? For any construction worth shipping, the answers are the same three words this whole field spent two decades earning: no, no, yes.
Study guide
Key terms
- Hash-to-curve
- A map from an arbitrary byte string to a curve point of unknown discrete log; standardized by RFC 9380.
- BLS signature
- A pairing-based signature where the signature is the hashed message point scaled by the secret key.
- Try-and-increment
- Hash with a counter until the result is a valid coordinate; unknown DL but variable time.
- Indifferentiability
- A formal criterion for when a construction can safely replace an ideal object such as a random oracle.
- Simplified SWU
- A closed-form map to short-Weierstrass curves with p equal to 3 mod 4 and nonzero A and B.
- Elligator 2
- An invertible map for curves with a point of order 2, used for Montgomery and Edwards curves.
- hash_to_field
- The first pipeline stage: expand input and DST into field elements within 2^-128 of uniform.
- Domain Separation Tag
- A mandatory, protocol-and-version-specific tag mixed into hashing to prevent cross-protocol collisions.
- Cofactor clearing
- The final stage that forces the mapped point into the prime-order subgroup.
- Oblivious PRF
- A protocol where the client learns a keyed function of its input while the server learns neither input nor output.
Flashcards
Flashcards
1 / 5Comprehension questions
State the three properties a safe hash-to-curve map must satisfy.
Unknown discrete log, constant running time, and a distribution indifferentiable from a random oracle.
Which property does each naive map violate, and what does each leak?
H(m) times G violates unknown discrete log and leaks universal forgery; try-and-increment violates constant time and leaks a secret input by timing.
Why is the RO variant the provable optimum?
A single map cannot be uniform and surjective; the sum of two maps is indifferentiable; RFC 9380 standardizes exactly that.
What is a DST for, and when must it be hashed?
Domain separation between protocols; it must be hashed when longer than 255 bytes and unique per protocol and version.
Where is the open frontier?
Post-quantum OPRFs and VRFs, formal verification of deployed implementations, and efficient hashing to G2.
References
- (2023). RFC 9380: Hashing to Elliptic Curves. https://www.rfc-editor.org/rfc/rfc9380.html ↩
- (2020). Dragonblood: Analyzing the Dragonfly Handshake of WPA3 and EAP-pwd. https://doi.org/10.1109/sp40000.2020.00031 ↩
- (2019). Dragonblood: Analysing WPA3 and EAP-pwd. https://wpa3.mathyvanhoef.com/ ↩
- (2001). Short Signatures from the Weil Pairing. https://doi.org/10.1007/3-540-45682-1_30 ↩
- (2015). RFC 7664: Dragonfly Key Exchange. https://www.rfc-editor.org/rfc/rfc7664.html ↩
- (1985). Use of Elliptic Curves in Cryptography. https://doi.org/10.1007/3-540-39799-X_31 ↩
- (1987). Elliptic Curve Cryptosystems. https://doi.org/10.1090/S0025-5718-1987-0866109-5 ↩
- (2001). Identity-Based Encryption from the Weil Pairing. https://doi.org/10.1007/3-540-44647-8_13 ↩
- (2008). Simultaneous Authentication of Equals: A Secure, Password-Based Key Exchange for Mesh Networks. https://doi.org/10.1109/SENSORCOMM.2008.131 ↩
- (2006). Construction of Rational Points on Elliptic Curves over Finite Fields. https://doi.org/10.1007/11792086_36 ↩
- (2004). On Equations y^2 = x^n + k in a Finite Field. https://doi.org/10.4064/ba52-3-1 ↩
- (2005). Points on Elliptic Curves over Finite Fields. https://doi.org/10.4064/aa117-3-7 ↩
- (2004). Indifferentiability, Impossibility Results on Reductions, and Applications to the Random Oracle Methodology. https://doi.org/10.1007/978-3-540-24638-1_2 ↩
- (2007). Rational Points on Certain Hyperelliptic Curves over Finite Fields. https://doi.org/10.4064/ba55-2-1 ↩
- (2009). How to Hash into Elliptic Curves. https://doi.org/10.1007/978-3-642-03356-8_18 ↩
- (2010). Efficient Indifferentiable Hashing into Ordinary Elliptic Curves. https://doi.org/10.1007/978-3-642-14623-7_13 ↩
- (2013). Indifferentiable Deterministic Hashing to Elliptic and Hyperelliptic Curves. https://doi.org/10.1090/S0025-5718-2012-02606-8 ↩
- (2013). Elligator: Elliptic-Curve Points Indistinguishable from Uniform Random Strings. https://doi.org/10.1145/2508859.2516734 ↩
- Elligator. https://elligator.org/ ↩
- (2019). Fast and Simple Constant-Time Hashing to the BLS12-381 Elliptic Curve. https://doi.org/10.46586/tches.v2019.i4.154-179 ↩
- hostap / w1.fi security advisories. https://w1.fi/security/ ↩
- (2026). BLS Signatures (draft-irtf-cfrg-bls-signature-07). https://datatracker.ietf.org/doc/draft-irtf-cfrg-bls-signature/ ↩
- (2026). Ethereum Consensus Specifications: The Beacon Chain (BLS Signatures). https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/beacon-chain.md - Deployment-class source: the Ethereum consensus spec fixes the BLS12-381 G2 SSWU_RO hash-to-curve ciphersuite that every consensus client implements. ↩
- (2023). RFC 9497: Oblivious Pseudorandom Functions (OPRFs) Using Prime-Order Groups. https://www.rfc-editor.org/rfc/rfc9497.html ↩
- (2025). RFC 9807: The OPAQUE Augmented Password-Authenticated Key Exchange (aPAKE) Protocol. https://www.rfc-editor.org/rfc/rfc9807.html ↩
- (2024). RFC 9578: Privacy Pass Issuance Protocols. https://www.rfc-editor.org/rfc/rfc9578.html ↩
- (2024). RFC 9576: The Privacy Pass Architecture. https://www.rfc-editor.org/rfc/rfc9576.html ↩
- (2024). RFC 9577: The Privacy Pass HTTP Authentication Scheme. https://www.rfc-editor.org/rfc/rfc9577.html ↩
- CPace, a balanced composable PAKE (draft-irtf-cfrg-cpace). https://datatracker.ietf.org/doc/draft-irtf-cfrg-cpace/ ↩
- blst: a BLS12-381 signature library. https://github.com/supranational/blst ↩
- BLST-Verification: Formal verification of the blst library. https://github.com/GaloisInc/BLST-Verification ↩
- CIRCL: Cloudflare Interoperable, Reusable Cryptographic Library. https://github.com/cloudflare/circl ↩
- curve25519-dalek: RistrettoPoint::from_uniform_bytes. https://docs.rs/curve25519-dalek/latest/curve25519_dalek/ ↩
- (2009). Fast Hashing to G2 on Pairing-Friendly Curves. https://doi.org/10.1007/978-3-642-03298-1_8 ↩
- (2012). Indifferentiable Hashing to Barreto-Naehrig Curves. https://doi.org/10.1007/978-3-642-33481-8_1 ↩