From d4e05e49c376615202888af95636b6dd346383e6 Mon Sep 17 00:00:00 2001 From: arnaucode Date: Sat, 28 Jul 2018 21:57:03 +0200 Subject: [PATCH] added ECC ElGamal Encryption and Decryption --- ElGamal/elGamal.go | 60 +++++++++++++++++++++++++++++ ElGamal/elGamal_test.go | 77 ++++++++++++++++++++++++++++++++++++++ README.md | 7 ++++ ecc/ecc.go | 44 ++++++++++++++++++---- ecc/ecc_test.go | 68 ++++++++++++++++----------------- ecc/{coord.go => point.go} | 2 + 6 files changed, 215 insertions(+), 43 deletions(-) create mode 100644 ElGamal/elGamal.go create mode 100644 ElGamal/elGamal_test.go rename ecc/{coord.go => point.go} (69%) diff --git a/ElGamal/elGamal.go b/ElGamal/elGamal.go new file mode 100644 index 0000000..55259e0 --- /dev/null +++ b/ElGamal/elGamal.go @@ -0,0 +1,60 @@ +package elgamal + +import ( + ecc "../ecc" +) + +// EG is the ElGamal data structure +type EG struct { + EC ecc.EC + G ecc.Point + N int +} + +// NewEG defines a new EG data structure +func NewEG(ec ecc.EC, g ecc.Point) (EG, error) { + var eg EG + var err error + eg.EC = ec + eg.G = g + eg.N, err = ec.Order(g) + return eg, err +} + +// PubK returns the public key Point calculated from the private key over the elliptic curve +func (eg EG) PubK(privK int) (ecc.Point, error) { + // privK: rand < ec.Q + pubK, err := eg.EC.Mul(eg.G, privK) + return pubK, err +} + +// Encrypt encrypts a point m with the public key point, returns two points +func (eg EG) Encrypt(m ecc.Point, pubK ecc.Point, r int) ([2]ecc.Point, error) { + p1, err := eg.EC.Mul(eg.G, r) + if err != nil { + return [2]ecc.Point{}, err + } + p2, err := eg.EC.Mul(pubK, r) + if err != nil { + return [2]ecc.Point{}, err + } + p3, err := eg.EC.Add(m, p2) + if err != nil { + return [2]ecc.Point{}, err + } + c := [2]ecc.Point{p1, p3} + return c, err +} + +// Decrypt decrypts c (two points) with the private key, returns the point decrypted +func (eg EG) Decrypt(c [2]ecc.Point, privK int) (ecc.Point, error) { + c1 := c[0] + c2 := c[1] + c1PrivK, err := eg.EC.Mul(c1, privK) + if err != nil { + return ecc.Point{}, err + } + c1PrivKNeg := eg.EC.Neg(c1PrivK) + d, err := eg.EC.Add(c2, c1PrivKNeg) + return d, err +} diff --git a/ElGamal/elGamal_test.go b/ElGamal/elGamal_test.go new file mode 100644 index 0000000..9634dd6 --- /dev/null +++ b/ElGamal/elGamal_test.go @@ -0,0 +1,77 @@ +package elgamal + +import ( + "math/big" + "testing" + + ecc "../ecc" +) + +func TestNewEG(t *testing.T) { + ec := ecc.NewEC(1, 18, 19) + g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} + eg, err := NewEG(ec, g) + if err != nil { + t.Errorf(err.Error()) + } + privK := 5 + pubK, err := eg.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 TestEGEncrypt(t *testing.T) { + ec := ecc.NewEC(1, 18, 19) + g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} + eg, err := NewEG(ec, g) + if err != nil { + t.Errorf(err.Error()) + } + privK := 5 + pubK, err := eg.PubK(privK) + if err != nil { + t.Errorf(err.Error()) + } + // m: point to encrypt + m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))} + c, err := eg.Encrypt(m, pubK, 15) + if err != nil { + t.Errorf(err.Error()) + } + if !c[0].Equal(ecc.Point{big.NewInt(int64(8)), big.NewInt(int64(5))}) { + t.Errorf("c[0] != (8, 5), encryption failed") + } + if !c[1].Equal(ecc.Point{big.NewInt(int64(2)), big.NewInt(int64(16))}) { + t.Errorf("c[1] != (2, 16), encryption failed") + } +} + +func TestEGDecrypt(t *testing.T) { + ec := ecc.NewEC(1, 18, 19) + g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} + eg, err := NewEG(ec, g) + if err != nil { + t.Errorf(err.Error()) + } + privK := 5 + pubK, err := eg.PubK(privK) + if err != nil { + t.Errorf(err.Error()) + } + // m: point to encrypt + m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))} + c, err := eg.Encrypt(m, pubK, 15) + if err != nil { + t.Errorf(err.Error()) + } + d, err := eg.Decrypt(c, privK) + if err != nil { + t.Errorf(err.Error()) + } + if !m.Equal(d) { + t.Errorf("m != d, decrypting failed") + } +} diff --git a/README.md b/README.md index 69923ee..e693476 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ https://en.wikipedia.org/wiki/Elliptic-curve_cryptography - [x] Add two points on the elliptic curve - [x] Multiply a point n times on the elliptic curve +## ECC ElGamal +https://en.wikipedia.org/wiki/ElGamal_encryption +- [x] ECC ElGamal key generation +- [x] ECC ElGamal Encrypton +- [x] ECC ElGamal Decryption + +--- To run all tests: ``` diff --git a/ecc/ecc.go b/ecc/ecc.go index 4e62e75..06dbfc4 100644 --- a/ecc/ecc.go +++ b/ecc/ecc.go @@ -6,6 +6,7 @@ import ( "math/big" ) +// EC is the data structure for the elliptic curve parameters type EC struct { A *big.Int B *big.Int @@ -40,14 +41,29 @@ func (ec *EC) At(x *big.Int) (Point, Point, error) { return Point{x, y}, Point{x, new(big.Int).Sub(ec.Q, y)}, nil } -// TODO add valid checker point function +// TODO add valid checker point function Valid() +// Neg returns the inverse of the P point on the elliptic curve func (ec *EC) Neg(p Point) Point { // TODO get error when point not found on the ec return Point{p.X, new(big.Int).Sub(ec.Q, p.Y)} } -// Add adds two points p1 and p2 and gets q +// Order returns smallest n where nG = O (point at zero) +func (ec *EC) Order(g Point) (int, error) { + for i := 1; i < int(ec.Q.Int64())+1; i++ { + mPoint, err := ec.Mul(g, i) + if err != nil { + return i, err + } + if mPoint.Equal(zeroPoint) { + return i, nil + } + } + return -1, errors.New("invalid order") +} + +// Add adds two points p1 and p2 and gets q, returns the negate of q func (ec *EC) Add(p1, p2 Point) (Point, error) { if p1.Equal(zeroPoint) { return p2, nil @@ -69,7 +85,7 @@ func (ec *EC) Add(p1, p2 Point) (Point, error) { numerator = new(big.Int).Add(x23, ec.A) // 2 * y denominator = new(big.Int).Mul(big.NewInt(int64(2)), p1.Y) - // (3 * x^2 + a) / (2 * y) mod ec.Q + // s = (3 * x^2 + a) / (2 * y) mod ec.Q denInv := new(big.Int).ModInverse(denominator, ec.Q) sRaw = new(big.Int).Mul(numerator, denInv) s = new(big.Int).Mod(sRaw, ec.Q) @@ -79,7 +95,7 @@ func (ec *EC) Add(p1, p2 Point) (Point, error) { numerator = new(big.Int).Sub(p1.Y, p2.Y) // x0-x1 denominator = new(big.Int).Sub(p1.X, p2.X) - // (y0-y1) / (x0-x1) mod ec.Q + // s = (y0-y1) / (x0-x1) mod ec.Q denInv := new(big.Int).ModInverse(denominator, ec.Q) sRaw = new(big.Int).Mul(numerator, denInv) s = new(big.Int).Mod(sRaw, ec.Q) @@ -104,17 +120,29 @@ func (ec *EC) Add(p1, p2 Point) (Point, error) { // q.Y = (s(p1.X - q.X) - p1.Y) mod ec.Q q.Y = new(big.Int).Mod(sXoX2Y, ec.Q) + // negate q + // q = ec.Neg(q) return q, nil } // Mul multiplies a point n times on the elliptic curve func (ec *EC) Mul(p Point, n int) (Point, error) { var err error - for i := 0; i < n; i++ { - p, err = ec.Add(p, p) + p2 := p + r := zeroPoint + for 0 < n { + if n&1 == 1 { + r, err = ec.Add(r, p2) + if err != nil { + return p, err + } + } + n = n >> 1 + p2, err = ec.Add(p2, p2) if err != nil { - return zeroPoint, err + return p, err } + } - return p, nil + return r, nil } diff --git a/ecc/ecc_test.go b/ecc/ecc_test.go index ced18cf..ae91541 100644 --- a/ecc/ecc_test.go +++ b/ecc/ecc_test.go @@ -1,51 +1,46 @@ package ecc import ( + "fmt" "math/big" "testing" ) func TestECC(t *testing.T) { ec := NewEC(0, 7, 11) - p1, p1_, err := ec.At(big.NewInt(int64(7))) + p1, p1i, err := ec.At(big.NewInt(int64(7))) if err != nil { t.Errorf(err.Error()) } if !p1.Equal(Point{big.NewInt(int64(7)), big.NewInt(int64(3))}) { t.Errorf("p1!=(7, 11)") } - if !p1_.Equal(Point{big.NewInt(int64(7)), big.NewInt(int64(8))}) { - t.Errorf("p1_!=(7, 8)") + if !p1i.Equal(Point{big.NewInt(int64(7)), big.NewInt(int64(8))}) { + t.Errorf("p1i!=(7, 8)") } } func TestNeg(t *testing.T) { ec := NewEC(0, 7, 11) - p1, p1_, err := ec.At(big.NewInt(int64(7))) + p1, p1i, err := ec.At(big.NewInt(int64(7))) if err != nil { t.Errorf(err.Error()) } p1Neg := ec.Neg(p1) - if !p1Neg.Equal(p1_) { - t.Errorf("p1Neg!=p1_") + if !p1Neg.Equal(p1i) { + t.Errorf("p1Neg!=p1i") } } func TestAdd(t *testing.T) { ec := NewEC(0, 7, 11) - p1, _, err := ec.At(big.NewInt(int64(7))) - if err != nil { - t.Errorf(err.Error()) - } - p2, _, err := ec.At(big.NewInt(int64(6))) - if err != nil { - t.Errorf(err.Error()) - } + p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(7))} + p2 := Point{big.NewInt(int64(2)), big.NewInt(int64(2))} q, err := ec.Add(p1, p2) if err != nil { t.Errorf(err.Error()) } - if !q.Equal(Point{big.NewInt(int64(2)), big.NewInt(int64(9))}) { - t.Errorf("q!=(2, 9)") + if !q.Equal(Point{big.NewInt(int64(3)), big.NewInt(int64(1))}) { + t.Errorf("q!=(3, 1)") } // check that q exists on the elliptic curve @@ -61,47 +56,50 @@ func TestAdd(t *testing.T) { func TestAddSamePoint(t *testing.T) { ec := NewEC(0, 7, 11) - p1, p1_, err := ec.At(big.NewInt(int64(4))) - if err != nil { - t.Errorf(err.Error()) - } + p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(7))} + p1i := Point{big.NewInt(int64(4)), big.NewInt(int64(4))} q, err := ec.Add(p1, p1) if err != nil { t.Errorf(err.Error()) } - if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(6))}) { - t.Errorf("q!=(6, 6)") + if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(5))}) { + t.Errorf("q!=(6, 5)") } - q_, err := ec.Add(p1_, p1_) + q_, err := ec.Add(p1i, p1i) if err != nil { t.Errorf(err.Error()) } - if !q_.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(5))}) { - t.Errorf("q_!=(6, 5)") + if !q_.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(6))}) { + t.Errorf("q_!=(6, 6)") } } func TestMulEqualSelfAdd(t *testing.T) { - ec := NewEC(0, 7, 11) - p1, _, err := ec.At(big.NewInt(int64(4))) + ec := NewEC(0, 7, 29) + p1 := Point{big.NewInt(int64(11)), big.NewInt(int64(27))} + + p1p1, err := ec.Add(p1, p1) if err != nil { t.Errorf(err.Error()) } - p1p1, err := ec.Add(p1, p1) + p1p1, err = ec.Add(p1p1, p1) if err != nil { t.Errorf(err.Error()) } - q, err := ec.Mul(p1, 1) + q, err := ec.Mul(p1, 3) if err != nil { t.Errorf(err.Error()) } if !q.Equal(p1p1) { + fmt.Println(q) + fmt.Println(p1p1) t.Errorf("q!=p1*p1") } } + func TestMul(t *testing.T) { ec := NewEC(0, 7, 29) p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(19))} @@ -109,22 +107,22 @@ func TestMul(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - if !q3.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(15))}) { - t.Errorf("q3!=(19, 15)") + if !q3.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(7))}) { + t.Errorf("q3!=(6, 7)") } q7, err := ec.Mul(p1, 7) if err != nil { t.Errorf(err.Error()) } - if !q7.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(15))}) { - t.Errorf("q7!=(19, 15)") + if !q7.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(14))}) { + t.Errorf("q7!=(19, 14)") } q8, err := ec.Mul(p1, 8) if err != nil { t.Errorf(err.Error()) } - if !q8.Equal(Point{big.NewInt(int64(4)), big.NewInt(int64(19))}) { - t.Errorf("q8!=(4, 19)") + if !q8.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(15))}) { + t.Errorf("q8!=(19, 15)") } } diff --git a/ecc/coord.go b/ecc/point.go similarity index 69% rename from ecc/coord.go rename to ecc/point.go index c963171..1a4747d 100644 --- a/ecc/coord.go +++ b/ecc/point.go @@ -10,11 +10,13 @@ var ( zeroPoint = Point{bigZero, bigZero} ) +// Point is the data structure for a point, containing the X and Y coordinates type Point struct { X *big.Int Y *big.Int } +// Equal compares the X and Y coord of a Point and returns true if are the same func (c1 *Point) Equal(c2 Point) bool { if !bytes.Equal(c1.X.Bytes(), c2.X.Bytes()) { return false