RFC 6979. Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)
https://www.rfc-editor.org/rfc/rfc6979
k- a fresh random value for signature generation.
E- an elliptic curve.q- a sufficiently large prime number that is divisor of the curve.G- a point ofE, of orderq.Gis such thatqG = 0.
Compute jG, where j ranges from 0 to q-1.
xis a private key taken moduleq.xshall not be0; hencexis an integer in the range[1, q-1].Uis a public key.U = xG.
qlenis the binary length ofq.rlenis equal toqlen, rounded up to the next multiple of8. SeeroundUp8function. Unrelated tor.blenis the length (in bits) of an input sequence.
MSB first.
The bits2int transform takes as input a sequence of blen bits and outputs a non-negative integer that is less than 2^qlen. An alternative name is vec2Uint.
const bits2int: (qlen: bigint) => (b: Vec) => bigint
const int2octets: (qlen: bigint) => (x: bigint) => Vec
const bits2octets: (q: bigint) => (b: Vec) => Vec
His a cryptographic hash function, which returns a bit vector of lengthhlen.mis an input message.H(m).
h = bits2int(H(m)) mod q.kis a random value moduleq. It shall not be0.r = (kG).x mod q: theXcoordinate ofkG(a member of the field over whichEis defined), reduced moduloq. Ifris0, select newk.s = (h+x*r)/k mod q
The pair (r, s) is the signature.
HMAC_K(V) is HMAC with the key K over data V, which returns a sequence of bits of length hlen.
- a.
h1 = H(m) - b.
V = 0x01 0x01 ... 0x01such that the length ofVis equal to8*ceil(hlen/8). - c.
K = 0x00 0x00 ... 0x00such that the length of K, in bits, is equal to8*ceil(hlen/8). - d.
K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)). - e.
V = HMAC_K(V). - h. Apply the following algorithm until a proper value is found for
k:
1. Set T to the empty sequence, so tlen = 0.
2. while tlen < qlen do:
- V = HMAC_K(V)
- T = T || V
3. Compute k = bits2int(T). If k is not in [1, q-1] or kG = 0 then
- K = HMAC_K(V || 0x00)
- V = HMAC_K(V)
and loop (try to generate a new T, and so on). Return to step 1.
We use elliptic curves for digital signatures.
z is a hash of a message.
k is a unique for each z and secret.
R = G * k.
r = R.x mod q.
s = ((z + r * d) / k) mod q.
If r or s is 0, the signature is invalid and k must be selected again; sign does not select again yet, and refuses instead.
The signature is (r, s).
verify checks (r, s) against the public key Q = G * d. All arithmetic on scalars is modulo q.
- If
Qis not a valid public key, orrorsis not in[1, q-1], the signature is invalid. A valid public key is not the point at infinity, has coordinates in[0, p-1], lies on the curve, and satisfiesQ * q = 0(SEC 1 §3.2.2.1,isPublicKeyin../secp, which also requiresq^2 > p + 1 + 2√p, so that, for the primeqECDSA requires,Q * q = 0putsQin the subgroup ofG). w = 1/su1 = z * wandu2 = r * wX = G * u1 + Q * u2- If
Xis the point at infinity, the signature is invalid: it has nox. v = X.x mod q
The signature is valid if v = r.
demo.f.mjs starts from RFC 6979 A.2.5 and shows Alice signing, Eve intercepting and Bob verifying. The diagram separates the packet route through Eve from Bob’s trust in Alice’s public key. One explanation beneath Bob shows why a substituted key cannot authenticate Alice. It reflows vertically on narrow screens. Typing updates Alice's local signing output; Send message transmits a public snapshot to Eve. Forward to Bob commits Eve's outgoing packet and verifies it on delivery. Neither action transmits a private key or the deterministic nonce.
Alice's draft, Eve's original packet and edits, and Bob's last delivery are independent immutable values. Switching attacks starts from the intercepted packet; Reset Eve restores it in Modify message mode, ready to forward unchanged. Another Send replaces Eve's packet without changing Bob's last delivery. Bob retains Alice's trusted public key from that exchange, separately from the received packet's key.
Eve can modify the message, modify the signature, or replace the public key and sign with her own demo-only key. Bob always verifies with Alice's trusted key. In the replacement scenario he also verifies with the received key: a signature valid under Eve's key proves that key signed the message, not that Alice sent it. The demo models trust as Alice's public key established at Send; it does not implement a real identity or key-distribution protocol.
Malformed hexadecimal and oversized messages are refused before forwarding. Parsed signature scalars, including zero and out-of-range values, reach the actual verifier so Bob can show rejection. A changed signature is not assumed invalid: ECDSA also admits (r, q-s) for the same key and message.
After Forward to Bob, a copyable Bash/OpenSSL command checks Bob's last received message and DER signature with Alice's saved trusted public key, encoded as a PEM SubjectPublicKeyInfo. The selected curve is carried by the key's named-curve OID. Later Alice or Eve edits do not change this command; forwarding another packet does. Eve's replacement key never replaces the trusted key in the command. Shell arguments are quoted literally; a message containing NUL cannot be represented as a shell argument, so its command is refused.
A separate Why nonce reuse reveals the private key section lets readers edit two messages, a demo private key, and one shared nonce. P-256/SHA-256 stays fixed. It starts with sample, test, and k = 7; editing any input recalculates both hashes, signatures, and the recovered demo private key:
x = (s1·h2 − s2·h1) / (r·(s2 − s1)) mod q.
This needs distinct hashes modulo q and a nonzero denominator. Repeating the same deterministic signature for the same message alone supplies no independent second equation. Equal hashes leave both signatures visible with an explanation of the zero recovery denominator; malformed hex, oversized messages, invalid scalar ranges, and zero signature scalars are refused. The section reports whether the recovered key matches the entered demo key. Its state is independent of Alice, Eve, and Bob. The deliberately broken signer is separate from Alice's RFC 6979 exchange; its demo inputs are never used by that exchange.
Scalar equalities below are modulo q, the order of G.
X = G * (z * 1/s) + Q * (r * 1/s)X = G * z * 1/s + G * d * r * 1/sG * (z * 1/s + d * r * 1/s) = G * kz * 1/s + d * r * 1/s = kz + d * r = k * sz + d * r = k * (z + r * d) / kz + d * r = z + r * d