diff --git a/README.md b/README.md index e693476..3c56947 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange https://en.wikipedia.org/wiki/Elliptic-curve_cryptography - [x] define elliptic curve - [x] get point at X +- [x] get order of a Point on the elliptic curve - [x] Add two points on the elliptic curve - [x] Multiply a point n times on the elliptic curve @@ -43,6 +44,14 @@ https://en.wikipedia.org/wiki/ElGamal_encryption - [x] ECC ElGamal Encrypton - [x] ECC ElGamal Decryption +## ECC ECDSA +https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +- [x] define ECDSA data structure +- [x] ECDSA Sign +- [x] ECDSA Verify signature + + + --- To run all tests: diff --git a/ecc/ecc_test.go b/ecc/ecc_test.go index ae91541..96a8ae5 100644 --- a/ecc/ecc_test.go +++ b/ecc/ecc_test.go @@ -44,11 +44,11 @@ func TestAdd(t *testing.T) { } // check that q exists on the elliptic curve - pt, pt_, err := ec.At(q.X) + pt, pti, err := ec.At(q.X) if err != nil { t.Errorf(err.Error()) } - if !q.Equal(pt) && !q.Equal(pt_) { + if !q.Equal(pt) && !q.Equal(pti) { t.Errorf("q not exist on the elliptic curve") } diff --git a/ecdsa/ecdsa.go b/ecdsa/ecdsa.go new file mode 100644 index 0000000..7ac4d8a --- /dev/null +++ b/ecdsa/ecdsa.go @@ -0,0 +1,71 @@ +package ecdsa + +import ( + "bytes" + "math/big" + + ecc "../ecc" +) + +// DSA is the ECDSA data structure +type DSA struct { + EC ecc.EC + G ecc.Point + N int +} + +// NewDSA defines a new DSA data structure +func NewDSA(ec ecc.EC, g ecc.Point) (DSA, error) { + var dsa DSA + var err error + dsa.EC = ec + dsa.G = g + dsa.N, err = ec.Order(g) + return dsa, err +} + +// PubK returns the public key Point calculated from the private key over the elliptic curve +func (dsa DSA) PubK(privK int) (ecc.Point, error) { + // privK: rand < ec.Q + pubK, err := dsa.EC.Mul(dsa.G, privK) + return pubK, err +} +func (dsa DSA) Sign(hashval *big.Int, privK int, r *big.Int) ([2]*big.Int, error) { + m, err := dsa.EC.Mul(dsa.G, int(r.Int64())) + if err != nil { + return [2]*big.Int{}, err + } + // inv(r) mod dsa.N + inv := new(big.Int).ModInverse(r, big.NewInt(int64(dsa.N))) + // m.X * privK + xPrivK := new(big.Int).Mul(m.X, big.NewInt(int64(privK))) + // (hashval + m.X * privK) + hashvalXPrivK := new(big.Int).Add(hashval, xPrivK) + // inv * (hashval + m.X * privK) mod dsa.N + a := new(big.Int).Mul(inv, hashvalXPrivK) + r2 := new(big.Int).Mod(a, big.NewInt(int64(dsa.N))) + return [2]*big.Int{m.X, r2}, err +} + +func (dsa DSA) Verify(hashval *big.Int, sig [2]*big.Int, pubK ecc.Point) (bool, error) { + w := new(big.Int).ModInverse(sig[1], big.NewInt(int64(dsa.N))) + u1raw := new(big.Int).Mul(hashval, w) + u1 := new(big.Int).Mod(u1raw, big.NewInt(int64(dsa.N))) + u2raw := new(big.Int).Mul(sig[0], w) + u2 := new(big.Int).Mod(u2raw, big.NewInt(int64(dsa.N))) + + gU1, err := dsa.EC.Mul(dsa.G, int(u1.Int64())) + if err != nil { + return false, err + } + pubKU2, err := dsa.EC.Mul(pubK, int(u2.Int64())) + if err != nil { + return false, err + } + p, err := dsa.EC.Add(gU1, pubKU2) + if err != nil { + return false, err + } + pXmodN := new(big.Int).Mod(p.X, big.NewInt(int64(dsa.N))) + return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()), nil +} diff --git a/ecdsa/ecdsa_test.go b/ecdsa/ecdsa_test.go new file mode 100644 index 0000000..0655ea4 --- /dev/null +++ b/ecdsa/ecdsa_test.go @@ -0,0 +1,51 @@ +package ecdsa + +import ( + "math/big" + "testing" + + ecc "../ecc" +) + +func TestNewECDSA(t *testing.T) { + ec := ecc.NewEC(1, 18, 19) + g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} + dsa, err := NewDSA(ec, g) + if err != nil { + t.Errorf(err.Error()) + } + privK := 5 + pubK, err := dsa.PubK(privK) + if err != nil { + t.Errorf(err.Error()) + } + if !pubK.Equal(ecc.Point{big.NewInt(int64(13)), big.NewInt(int64(9))}) { + t.Errorf("pubK!=(13, 9)") + } +} + +func TestECDSASignAndVerify(t *testing.T) { + ec := ecc.NewEC(1, 18, 19) + g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} + dsa, err := NewDSA(ec, g) + if err != nil { + t.Errorf(err.Error()) + } + privK := 5 + pubK, err := dsa.PubK(privK) + if err != nil { + t.Errorf(err.Error()) + } + hashval := big.NewInt(int64(40)) + r := big.NewInt(int64(11)) + + sig, err := dsa.Sign(hashval, privK, r) + if err != nil { + t.Errorf(err.Error()) + } + + verified, err := dsa.Verify(hashval, sig, pubK) + if !verified { + t.Errorf("verified == false") + } +}