package paillier
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"math/big"
|
|
|
|
// prime "../prime"
|
|
"github.com/arnaucube/cryptofun/prime"
|
|
)
|
|
|
|
const (
|
|
bits = 16
|
|
)
|
|
|
|
// PublicKey stores the public key data
|
|
type PublicKey struct {
|
|
N *big.Int `json:"n"`
|
|
G *big.Int `json:"g"`
|
|
}
|
|
|
|
// PrivateKey stores the private key data
|
|
type PrivateKey struct {
|
|
Lambda *big.Int `json:"lambda"`
|
|
Mu *big.Int `json:"mu"`
|
|
}
|
|
|
|
// Key stores the public and private key data
|
|
type Key struct {
|
|
PubK PublicKey
|
|
PrivK PrivateKey
|
|
}
|
|
|
|
// GenerateKeyPair generates a random private and public key
|
|
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
|
|
}
|
|
|
|
// Encrypt encrypts a message m with given PublicKey
|
|
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
|
|
}
|
|
|
|
// Decrypt deencrypts a ciphertext c with given PublicKey and PrivateKey
|
|
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
|
|
}
|
|
|
|
// HomomorphicAddition calculates the addition of tow encrypted values given a PublicKey
|
|
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
|
|
}
|