Elliptic Curve Digital Signature Algorithm (ECDSA) is used within Bitcoin and Ethereum. In this case we will generate a private key and a public key point \((x,y)\). This create a signature value of the \((r,s)\). You should be able to enter base 10 or base 16 (hex) integer values for the public key point \((x,y)\) and the signature \((r,s)\).
ECDSA Creation and Verification |
Method
The following is an outline of ECDSA. With this, Bob signs a hash of a message with his private key, and then then Alice proves with his public key. Bob also uses a random nonce value for the signature (\(k\)):
With ECDSA, Alice will sign a message with her private key, and then Bob will use her public key to verify that she signed the message (and that the message has now changed):
Alice signs the message with the following:
- Create a hash of the message \(e=\textrm{HASH}(m)\).
- Let \(h\) be the \(L_{n}\) be the leftmost bits of \(e\), \(L_{n}\) has a bit length of the group order \(N\).
- Create a random number \(k\) which is between 1 and \(N-1\).
- Calculate a point on the curve as \((x_{1},y_{1})=k\times G\).
- Calculate \( r=x_{1} \pmod N \). If \(r=0\), go back to Step 3.
- Calculate \(s=k^{-1}(h+rd_{A}) \pmod N\). If \(s=0\), go back to Step 3.
- The signature is the pair \((r,s)\).
Bob will check with:
- Create a hash of the message \(e=\textrm{HASH}(m)\).
- Let \(h\) be the \(L_{n}\) leftmost bits of \(e\).
- Calculate \(c=s^{-1} \pmod N\)
- Calculate \(u_{1}=h \cdot c \pmod N\) and \(u_{2}=r \cdot c \pmod N\).
- Calculate the curve point (\(x_{1},y_{1})=u_{1}\times G+u_{2}\times Q_{A}\). If \((x_{1},y_{1})=O\) then the signature is invalid.
- The signature is valid if \(r\equiv x_{1}{\pmod {n}}\), invalid otherwise.
(\(x_{1},y_{1})=u_{1}\times G+u_{2}\times Q_{A} = h \cdot c \cdot G + r \cdot c \cdot Q_A = c (hG + rQ_A) = \frac{hG + rQ_A} {k^{-1}(h+rd_A) } = \frac{hG + rd_A G} {k^{-1}(h+rd_A) } = \frac{(h + rd_A) G} {k^{-1}(h+rd_A) } = kG \).
Outline
The code is:
package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "fmt" "os" "strings" "github.com/dustinxie/ecc" ) func getCurve(s string) elliptic.Curve { if strings.Contains(s, "224") { return (elliptic.P224()) } else if strings.Contains(s, "384") { return (elliptic.P384()) } else if strings.Contains(s, "521") { return (elliptic.P521()) } return (ecc.P256k1()) } func main() { msg := "Hello 123" curveType := "" argCount := len(os.Args[1:]) if argCount > 0 { msg = os.Args[1] } if argCount > 1 { curveType = os.Args[2] } pubkeyCurve := getCurve(curveType) m := []byte(msg) digest := sha256.Sum256(m) privatekey, _ := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) pubkey := privatekey.PublicKey r, s, _ := ecdsa.Sign(rand.Reader, privatekey, digest[:]) fmt.Printf("=== Message ===\n") fmt.Printf("Msg=%s\nHash=%x\n", msg, digest) fmt.Printf("\n=== Private key ===\n") fmt.Printf("Private key=%x\n", privatekey.D) fmt.Printf("Curve=%s\n", privatekey.Curve.Params().Name) fmt.Printf("Bit size=%d\n", privatekey.Curve.Params().BitSize) fmt.Printf("Base point (G) =(%d, %d)\n", privatekey.Curve.Params().Gx, privatekey.Curve.Params().Gy) fmt.Printf("Prime=%d, Order=%d", privatekey.Curve.Params().P, privatekey.Curve.Params().N) fmt.Printf("\n=== Public key (X,Y) ===\n") fmt.Printf("X=%s Y=%s\n", pubkey.X, pubkey.Y) fmt.Printf(" Hex: X=%x Y=%x\n", pubkey.X.Bytes(), pubkey.Y.Bytes()) fmt.Printf("\n=== Signature (R,S) ===\n") fmt.Printf("R=%s S=%s\n", r, s) fmt.Printf(" Hex: R=%x S=%x\n", r, s) rtn := ecdsa.Verify(&pubkey, digest[:], r, s) if rtn { fmt.Printf(\n"Signature verifies") } else { fmt.Printf("\nSignature does not verify") } }
A sample run:
=== Message === Msg=Hello 123 Hash=859e38d581e214dc7c8c871c425642913363a829065cf4acddd120ed5391b04b === Private key === Private key=b3645f2efea9a96d28cbeb5bf8a5304a3dc96b2a42bee21c0b3aaa88f595df2d Curve=P-256k1 Bit size=256 Base point (G) =(55066263022277343669578718895168534326250603453777594175500187360389116729240, 32670510020758816978083085130507043184471273380659243275938904335757337482424) Prime=115792089237316195423570985008687907853269984665640564039457584007908834671663, Order=115792089237316195423570985008687907852837564279074904382605163141518161494337 === Public key (X,Y) === X=77007236596272499552697218405908714888874625059778411542685725622785792316534 Y=20745252821220973789342590850065442758134973002375340605949893038975196614597 Hex: X=aa408d244da8a2ea673213ef63536ea96486ce0412a5294c9cdf0959cc689476 Y=2ddd65a19ed17f361b0381a72713f740b63d4fdca059427c389239da39004fc5 === Signature (R,S) === R=33027995512220841690000083421269061534408622570666620793995266029032826750381 S=44867240085578618664628913670877492263668786345184239470907981535519639811276 Hex: R=49052ed8fcf1903f530bda10ea9b578b6bb77487ea6b22b5558fc68524e045ad S=6331f53ce5e1a64e4043712631aeeb3f5c0ed753140a0fd76a8c5367e69b34cc Signature verifies