|
| 1 | + |
| 2 | +using TinyCrypto |
| 3 | + |
| 4 | +# 1. Define a toy Weierstrass curve over 𝔽₃₁ with G of order 37 |
| 5 | +curve = Weierstrass(31, 6, 9, 37, 1, (0, 3)) |
| 6 | +# Weierstrass{𝔽₃₁}: y² = x³ + 6x + 9 | G = (0,3), order = 37, cofactor = 1 |
| 7 | + |
| 8 | +# 2. Create a mock blockchain transaction |
| 9 | +tx = "hello ethereum" |
| 10 | + |
| 11 | +# 3. Hash it (you fake Keccak256 with H₈ → SHA256 first 8 bytes) |
| 12 | +z = Int(H₈(tx)) % curve.order # H₈ returns UInt8; convert to Int for modular arithmetic |
| 13 | + |
| 14 | +# 4. Generate keypair |
| 15 | +priv = rand(1:curve.order - 1) # private key is a uniformly random integer in [1, curve order − 1] |
| 16 | +pub = priv * curve.G # public key is the scalar multiple of the generator: pub = priv · G |
| 17 | + |
| 18 | +# 5. Sign: create ephemeral scalar `k` and calculate signature (r, s) |
| 19 | +k = rand(1:curve.order - 1) # draw a random ephemeral scalar used once per signature |
| 20 | +R = k * curve.G # then construct an ephemeral public point R = k·G on the curve |
| 21 | +v = isodd(R.point.y.val) ? 1 : 0 # and compute the parity (Ethereum) bit from LSB of y which is used for ECrecover |
| 22 | + |
| 23 | +r = mod(R.point.x, curve.order) # use x-coordinate of R as first signature component |
| 24 | +k_inv = invmod(k, curve.order) # compute modular inverse of ephemeral scalar |
| 25 | +s = mod(k_inv * (z + r * priv), curve.order) # second signature component s = k⁻¹(z + r·priv) mod n |
| 26 | + |
| 27 | +# 6. The signature is (r, s, v + 27) `27` roots back to early Bitcoin compact signatures, parity bit is used on Ethereum |
| 28 | +# whereas Bitcoin uses recovery ID : = {0,1,2,3} |
| 29 | +println("Signature: (r = $r, s = $s, v = $(v + 27))") |
| 30 | + |
| 31 | +# 7. Verification |
| 32 | +s_inv = invmod(s, curve.order) # compute inverse of signature scalar s⁻¹ mod n |
| 33 | +u₁ = z * s_inv % curve.order # u₁ = z · s⁻¹ mod n |
| 34 | +u₂ = r * s_inv % curve.order # u₂ = r · s⁻¹ mod n |
| 35 | +P = u₁ * curve.G + u₂ * pub # recover point P = u₁·G + u₂·Q (should equal R) |
| 36 | + |
| 37 | +is_valid = mod(P.point.x, curve.order) == r # check if recovered R.x matches r component |
| 38 | +println("Signature valid? ", is_valid) |
| 39 | + |
| 40 | + |
| 41 | +# 8. Recover public key from (r, s, v) and message hash z |
| 42 | +# TODO: ECRecover implementation — left as an exercise |
| 43 | + |
0 commit comments