Crypto Lab

Worksheet · Public-key & signatures

Worksheet: ECDSA Forge

Exhibit
ECDSA Forge
Time
About 29 minutes of class time; Predict is pre-class reading and Explain is a spoken debrief
Checked against
Lab commit 1de890f5e9f9 on 2026-09-22

Outcomes this worksheet serves

Raw Markdown to edit View source on GitHub Hand-out for the whole module

Predict

Answer these before you open the exhibit. There are no penalties for wrong predictions; the point is to compare them with what you see.

  1. An ECDSA signer holds a secret scalar d and publishes Q = d·G. To sign a message hash e the signer picks a nonce k, computes r as the x-coordinate of k·G reduced mod n, and s = k⁻¹(e + r·d) mod n. The signer now signs two different messages with the same d and the same k. Predict which of r, s and e come out the same across the two signatures and which come out different. Give your reason for each.
  2. Write the two signing equations from question 1 side by side, one per message. Treating d and k as the unknowns and r, s₁, s₂, e₁, e₂ as known, count the equations and count the unknowns. Predict whether someone who never sees the private key can solve for d, and say what the first step of that solution would be.
  3. An attacker instead has only the public key Q and the generator G, and no signatures at all. Predict whether d can be recovered from those two points, and say what makes this case different from question 2.
  4. RFC 6979 computes the nonce from the private key and the message with HMAC-SHA-256 instead of drawing it from a random number generator. Predict what happens to the signature when the same message is signed twice this way, and what happens to the nonce when two different messages are signed. Then say what each answer does to the attack you described in question 2.

Do

  1. Open the exhibit and stay in What Is ECDSA?. Leave Curve on its starting option and press Generate Keypair. Record what Public key Q (compressed) now shows, what the line beginning Private key shows, and the status line at the bottom of the message panel.
  2. In the same section's right-hand panel, leave the text in Message as you found it. Press Sign Random and record Signature (r, s). Press Verify and record the status line. Press Sign Random a second time and record the new Signature (r, s), then press Verify again.
  3. Scroll to The Nonce-Reuse Attack and read Why it works: two equations, two unknowns. Then move to Try it yourself on the toy curve, leave all four sliders at the values they load with, and read the four cards the panel prints below them. Record r from Signature 1, r from Signature 2, both s values, the recovered k, the recovered d, and what the last card reports about the freshly forged signature.
  4. Still in the toy panel, make these changes one at a time and record what the panel says after each. Move Private key d to any other value. Move Reused nonce k to 7, then to 12, then back to the value it loaded with. Finally drag Message hash e₁ until it equals Message hash e₂, then put it back.
  5. Scroll to Now on real 256-bit keys. Before pressing anything, note what the VICTIM box shows in place of Alice's private key. Press Run Full Compromise. Read the five timeline steps, then expand Show the full 256-bit values and record the values listed in the Record table. Note what the VICTIM box shows now.
  6. Press Run Full Compromise a second time and record the same values from the second run.
  7. Scroll to RFC 6979 Deterministic Nonces and press Reset Samples first, so both lists start empty. Leaving Message for comparison as you found it, press Sign Random in this panel twice, then press Sign RFC 6979 twice. Record the rows that appear under Random nonce output and under RFC 6979 output.
  8. Change Message for comparison — add a word — and press Sign RFC 6979 once more. Record the new row. Then press Try the nonce-reuse attack against RFC 6979 and record the status line beneath it.

Record

Every value below comes from your own run. The 256-bit numbers are far too long to copy out: for those, write the first six and the last six digits, which is enough to tell two runs apart.

From the first panelWhat it showed
Public key Q (compressed)blank for your answer
The line beginning Private keyblank for your answer
PressSignature (r, s) shownStatus line
Sign Random, first pressblank for your answerblank for your answer
Verify, after the first Sign Randomblank for your answerblank for your answer
Sign Random, second pressblank for your answerblank for your answer
Verify, after the second Sign Randomblank for your answerblank for your answer
Toy panel, sliders as loadedValue
r in Signature 1blank for your answer
r in Signature 2blank for your answer
s₁blank for your answer
s₂blank for your answer
Recovered kblank for your answer
Recovered dblank for your answer
What the forgery card reportsblank for your answer
Change I made in the toy panelWhat the panel reported
Private key d moved toblank for your answer
Reused nonce k = 7blank for your answer
Reused nonce k = 12blank for your answer
e₁ set equal to e₂blank for your answer
From Show the full 256-bit valuesRun 1Run 2
n (order)blank for your answerblank for your answer
e1 = H("Transfer $10 to Bob")blank for your answerblank for your answer
e2 = H("Transfer $20 to Charlie")blank for your answerblank for your answer
r (shared)blank for your answerblank for your answer
s1blank for your answerblank for your answer
s2blank for your answerblank for your answer
recovered kblank for your answerblank for your answer
recovered dblank for your answerblank for your answer
victim's real dblank for your answerblank for your answer
the match line, in my own wordsblank for your answerblank for your answer
Alice's private key, as the VICTIM box shows it after the runblank for your answerblank for your answer
Timeline stepWhat it reported, in my own words
Step 2 · Spot the reused nonceblank for your answer
Step 5 · Forge a new signatureblank for your answer
RFC 6979 panel, row by rowk, where the row shows oner
Random nonce output, first pressblank for your answerblank for your answer
Random nonce output, second pressblank for your answerblank for your answer
RFC 6979 output, first pressblank for your answerblank for your answer
RFC 6979 output, second pressblank for your answerblank for your answer
RFC 6979 output, after changing the messageblank for your answerblank for your answer
Status line under Try the nonce-reuse attack against RFC 6979
blank for your answer

Explain

  1. Your two toy signatures printed the same r, and the panel marks that as the tell. Using the signing rule the page prints — r is the x-coordinate of k·G reduced mod n — explain why reusing k forces r to repeat. Then explain why the two s values still came out different.
  2. Take the five numbers the toy panel's recovery works from — r, s₁, s₂ and the two message hashes on the sliders — and list which of them a signer publishes and which the signer is supposed to keep.
  3. Compare your two Run Full Compromise runs. Say which recorded values changed between the runs and which did not. For each value that did not change, point to the line the page prints that explains why it could not.
  4. The note under the finite-field plot, in The Math You Can See, says that multiplying G is easy and that finding k from the highlighted point is the hard problem ECDSA relies on. Alice's public key was on the page from the start, and it did not give up her private key. The compromise recovered that same private key in one press. Say precisely what the attacker had in the second case that she did not have in the first.
  5. Your two Sign RFC 6979 presses on one message, and the third press after you changed the message, gave three rows. Say what each comparison shows about the nonce. Then read the paragraph at the top of RFC 6979 Deterministic Nonces and the status line you recorded, and state both what the page says blocks the attack and what the page says that block rests on.

Fix / Extend

  1. Fix. A hardware wallet signs with a nonce from a random number generator that occasionally restarts from the same seed. Say what an attacker watching that wallet's published signatures would look for, name which of the two signing buttons on this page corresponds to the fix, and state — from the page's own wording — what that fix still depends on.
  2. Fix. You are reviewing a signing service that avoids repeats by taking its nonce from a counter: k = 1 for the first signature, k = 2 for the second, and so on. No nonce is ever reused. Look at the second line of the recovery the toy panel prints, d = (s₁·k − e₁)·r⁻¹, and say what an attacker who can guess k needs in order to run that line, and how many signatures it would take. Say whether the tell you identified in Explain 1 would appear here.
  3. Extend. Open What Is ECDSA?, press Generate Keypair, and press Sign Random once so that a signature exists. Now edit Message — add a word to it — and press Verify without signing again. Write down the status line. Restore the original wording, press Verify once more, and write down the status line again. Say whether the signature had to be made a second time for the restored message to pass.
  4. Extend. Still in What Is ECDSA?, with a keypair generated and Message as you found it, press Sign Deterministic (RFC 6979) twice in a row and write down Signature (r, s) after each press. Say whether the two presses agree, and compare them with the two Sign Random signatures in your Record table.
  5. Extend. Work the toy panel's recovery by hand. In Try it yourself on the toy curve, leave the four sliders at the values they load with and take r, s₁, s₂ and the two message hashes from the cards and the slider labels. Then, mod 19, compute k = (e₁ − e₂)·(s₁ − s₂)⁻¹ and d = (s₁·k − e₁)·r⁻¹, working both modular inverses out by hand. Check your k and d against the recovered values the panel prints, and your d against the Private key d slider.
  6. Extend. Scroll to The Math You Can See and work in the right-hand panel, The real thing: a finite field. Move the Walk k·G slider and read the line under the plot. Write down the point the page reports for k = 5, for k = 7, and for one more value of your choosing, then read the note printed below that line.
  7. Extend. Move the Walk k·G slider through each value from 1 to 18 and write down the point for each. Count how many distinct x-coordinates appear. The panel builds r from that x-coordinate, so say how many different r values this toy curve can produce, and what that means for two signatures that happen to share an r.
  8. Extend. Setting Reused nonce k to 7 in the toy panel stops the attack, and the panel names the reason; set it there again if you need the wording in front of you. Now move the Walk k·G slider to 7, read the point the page reports, and work out what r would be for that nonce. Then substitute that r into s = k⁻¹(e + r·d) mod n and say what s reduces to. Does refusing that nonce protect the private key, or does it prevent a different problem?
  9. Extend. Change Curve to the other option and press Run Full Compromise again. Compare n (order), e1 and e2 with the runs you already recorded, and say which of the three the curve choice changed. Note what the status line in the first panel now asks you to do, and why.
  10. Extend. Open ECDSA vs Ed25519 and read the rows Deterministic by default, Nonce reuse catastrophic and Malleable signatures. Say which row the RFC 6979 panel is demonstrating, and name a property the table still records differently for the two schemes once RFC 6979 is in use.

Crypto Lab exhibits are teaching demonstrations, not production libraries. Do not use exhibit code to protect real data.