From 6ce09111f96cd03286e0397b6bd8df2816922f9f Mon Sep 17 00:00:00 2001 From: arnaucode Date: Sun, 22 Jul 2018 13:33:11 +0200 Subject: [PATCH] paillier encrypt & decrypt, homomorphic addition --- README.md | 5 ++ paillier/paillier.go | 111 ++++++++++++++++++++++++++++++++++++++ paillier/paillier_test.go | 41 ++++++++++++++ prime/prime.go | 5 ++ rsa/rsa.go | 43 ++++++++------- rsa/rsa_test.go | 20 +++++-- 6 files changed, 200 insertions(+), 25 deletions(-) create mode 100644 paillier/paillier.go create mode 100644 paillier/paillier_test.go diff --git a/README.md b/README.md index 71c2f46..35a4fd5 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,10 @@ Crypto algorithms from scratch. Academic purposes only. - [x] Homomorphic Multiplication ## Paillier +- [x] GenerateKeyPair +- [x] Encrypt +- [x] Decrypt +- [x] Homomorphic Addition + ## ECC ## Shamir Secret Sharing diff --git a/paillier/paillier.go b/paillier/paillier.go new file mode 100644 index 0000000..cbbb78e --- /dev/null +++ b/paillier/paillier.go @@ -0,0 +1,111 @@ +package paillier + +import ( + "crypto/rand" + "errors" + "math/big" + + prime "../prime" +) + +const ( + bits = 16 +) + +type PublicKey struct { + N *big.Int `json:"n"` + G *big.Int `json:"g"` +} +type PrivateKey struct { + Lambda *big.Int `json:"lambda"` + Mu *big.Int `json:"mu"` +} + +type Key struct { + PubK PublicKey + PrivK PrivateKey +} + +func GenerateKeyPair() (key Key, err error) { + p, err := rand.Prime(rand.Reader, bits/2) + if err != nil { + return key, err + } + q, err := rand.Prime(rand.Reader, bits/2) + if err != nil { + return key, err + } + + pq := new(big.Int).Mul(p, q) + p1q1 := big.NewInt((p.Int64() - 1) * (q.Int64() - 1)) + gcd := new(big.Int).GCD(nil, nil, pq, p1q1) + if gcd.Int64() != int64(1) { + return key, errors.New("gcd comprovation failed") + } + + n := new(big.Int).Mul(p, q) + lambda := big.NewInt(int64(Lcm(float64(p.Int64())-1, float64(q.Int64())-1))) + + //g generation + alpha := big.NewInt(int64(prime.RandInt(0, int(n.Int64())))) + beta := big.NewInt(int64(prime.RandInt(0, int(n.Int64())))) + alphan := new(big.Int).Mul(alpha, n) + alphan1 := new(big.Int).Add(alphan, big.NewInt(1)) + betaN := new(big.Int).Exp(beta, n, nil) + ab := new(big.Int).Mul(alphan1, betaN) + n2 := new(big.Int).Mul(n, n) + g := new(big.Int).Mod(ab, n2) + //in some Paillier implementations use this: + // g = new(big.Int).Add(n, big.NewInt(1)) + + key.PubK.N = n + key.PubK.G = g + + //mu generation + Glambda := new(big.Int).Exp(g, lambda, nil) + u := new(big.Int).Mod(Glambda, n2) + L := L(u, n) + mu := new(big.Int).ModInverse(L, n) + + key.PrivK.Lambda = lambda + key.PrivK.Mu = mu + + return key, nil +} + +func Lcm(a, b float64) float64 { + r := (a * b) / float64(prime.Gcd(int(a), int(b))) + return r + +} +func L(u *big.Int, n *big.Int) *big.Int { + u1 := new(big.Int).Sub(u, big.NewInt(1)) + L := new(big.Int).Div(u1, n) + return L +} + +func Encrypt(m *big.Int, pubK PublicKey) *big.Int { + gM := new(big.Int).Exp(pubK.G, m, nil) + r := big.NewInt(int64(prime.RandInt(0, int(pubK.N.Int64())))) + rN := new(big.Int).Exp(r, pubK.N, nil) + gMrN := new(big.Int).Mul(gM, rN) + n2 := new(big.Int).Mul(pubK.N, pubK.N) + c := new(big.Int).Mod(gMrN, n2) + return c +} +func Decrypt(c *big.Int, pubK PublicKey, privK PrivateKey) *big.Int { + cLambda := new(big.Int).Exp(c, privK.Lambda, nil) + n2 := new(big.Int).Mul(pubK.N, pubK.N) + u := new(big.Int).Mod(cLambda, n2) + L := L(u, pubK.N) + LMu := new(big.Int).Mul(L, privK.Mu) + m := new(big.Int).Mod(LMu, pubK.N) + return m +} + +func HomomorphicAddition(c1 *big.Int, c2 *big.Int, pubK PublicKey) *big.Int { + c1c2 := new(big.Int).Mul(c1, c2) + n2 := new(big.Int).Mul(pubK.N, pubK.N) + d := new(big.Int).Mod(c1c2, n2) + return d +} diff --git a/paillier/paillier_test.go b/paillier/paillier_test.go new file mode 100644 index 0000000..e5a7959 --- /dev/null +++ b/paillier/paillier_test.go @@ -0,0 +1,41 @@ +package paillier + +import ( + "bytes" + "fmt" + "math/big" + "testing" +) + +func TestEncryptDecrypt(t *testing.T) { + key, err := GenerateKeyPair() + if err != nil { + t.Errorf(err.Error()) + } + fmt.Println(key) + mBytes := []byte("Hi") + m := new(big.Int).SetBytes(mBytes) + c := Encrypt(m, key.PubK) + d := Decrypt(c, key.PubK, key.PrivK) + if m == d { + fmt.Println(key) + t.Errorf("m not equal to decrypted") + } +} + +func TestHomomorphicAddition(t *testing.T) { + key, err := GenerateKeyPair() + if err != nil { + t.Errorf(err.Error()) + } + n1 := big.NewInt(int64(110)) + n2 := big.NewInt(int64(150)) + c1 := Encrypt(n1, key.PubK) + c2 := Encrypt(n2, key.PubK) + c3c4 := HomomorphicAddition(c1, c2, key.PubK) + d := Decrypt(c3c4, key.PubK, key.PrivK) + if !bytes.Equal(new(big.Int).Add(n1, n2).Bytes(), d.Bytes()) { + fmt.Println(key) + t.Errorf("decrypted result not equal to original result") + } +} diff --git a/prime/prime.go b/prime/prime.go index a412287..ebd0e3f 100644 --- a/prime/prime.go +++ b/prime/prime.go @@ -2,6 +2,11 @@ package prime import "math/rand" +const ( + MaxPrime = 2000 + MinPrime = 500 +) + func RandInt(min int, max int) int { r := rand.Intn(max-min) + min return r diff --git a/rsa/rsa.go b/rsa/rsa.go index 7d02224..3ed54e5 100644 --- a/rsa/rsa.go +++ b/rsa/rsa.go @@ -2,18 +2,16 @@ package rsa import ( "bytes" + "crypto/rand" "math/big" - "math/rand" - "time" - - prime "../prime" ) const ( - MaxPrime = 2000 - MinPrime = 500 + bits = 512 // 2048 ) +var bigOne = big.NewInt(int64(1)) + type PublicKey struct { E *big.Int `json:"e"` N *big.Int `json:"n"` @@ -32,37 +30,42 @@ type Key struct { PrivK PrivateKey } -func GenerateKeyPair() (key Key) { - rand.Seed(time.Now().Unix()) - p := prime.RandPrime(MinPrime, MaxPrime) - q := prime.RandPrime(MinPrime, MaxPrime) +func GenerateKeyPair() (key Key, err error) { + p, err := rand.Prime(rand.Reader, bits/2) + if err != nil { + return key, err + } + q, err := rand.Prime(rand.Reader, bits/2) + if err != nil { + return key, err + } - n := p * q - phi := (p - 1) * (q - 1) + n := new(big.Int).Mul(p, q) + p_1 := new(big.Int).Sub(p, bigOne) + q_1 := new(big.Int).Sub(q, bigOne) + phi := new(big.Int).Mul(p_1, q_1) e := 65537 var pubK PublicKey pubK.E = big.NewInt(int64(e)) - pubK.N = big.NewInt(int64(n)) + pubK.N = n - d := new(big.Int).ModInverse(big.NewInt(int64(e)), big.NewInt(int64(phi))) + d := new(big.Int).ModInverse(big.NewInt(int64(e)), phi) var privK PrivateKey privK.D = d - privK.N = big.NewInt(int64(n)) + privK.N = n key.PubK = pubK key.PrivK = privK - return key + return key, nil } func Encrypt(m *big.Int, pubK PublicKey) *big.Int { - Me := new(big.Int).Exp(m, pubK.E, nil) - c := new(big.Int).Mod(Me, pubK.N) + c := new(big.Int).Exp(m, pubK.E, pubK.N) return c } func Decrypt(c *big.Int, privK PrivateKey) *big.Int { - Cd := new(big.Int).Exp(c, privK.D, nil) - m := new(big.Int).Mod(Cd, privK.N) + m := new(big.Int).Exp(c, privK.D, privK.N) return m } diff --git a/rsa/rsa_test.go b/rsa/rsa_test.go index 30a234f..d2ebfc1 100644 --- a/rsa/rsa_test.go +++ b/rsa/rsa_test.go @@ -2,13 +2,17 @@ package rsa import ( "bytes" + "fmt" "math/big" "testing" ) func TestEncryptDecrypt(t *testing.T) { - key := GenerateKeyPair() - + key, err := GenerateKeyPair() + if err != nil { + t.Errorf(err.Error()) + } + fmt.Println(key) mBytes := []byte("Hi") m := new(big.Int).SetBytes(mBytes) c := Encrypt(m, key.PubK) @@ -19,7 +23,10 @@ func TestEncryptDecrypt(t *testing.T) { } } func TestBlindSignature(t *testing.T) { - key := GenerateKeyPair() + key, err := GenerateKeyPair() + if err != nil { + t.Errorf(err.Error()) + } mBytes := []byte("Hi") m := new(big.Int).SetBytes(mBytes) @@ -39,8 +46,11 @@ func TestBlindSignature(t *testing.T) { } } -func TestHomomorphiMultiplication(t *testing.T) { - key := GenerateKeyPair() +func TestHomomorphicMultiplication(t *testing.T) { + key, err := GenerateKeyPair() + if err != nil { + t.Errorf(err.Error()) + } n1 := big.NewInt(int64(11)) n2 := big.NewInt(int64(15))