diff --git a/paillier.go b/paillier.go index 9eca2ab..0e32b23 100644 --- a/paillier.go +++ b/paillier.go @@ -63,6 +63,19 @@ func (pk *PublicKey) Add(cypher ...*Cypher) *Cypher { } } +// Mul returns a product of `cypher` and `scalar` without decrypting `cypher`. +// +// It's possible because Paillier is a homomorphic encryption scheme, where +// an encrypted plaintext `m` raised to an integer `k` will decrypt to the +// product of the plaintext `m` and `k`: +// +// D( E(m)^k mod N^2 ) = km mod N +func (pk *PublicKey) Mul(cypher *Cypher, scalar *big.Int) *Cypher { + return &Cypher{ + C: new(big.Int).Exp(cypher.C, scalar, pk.GetNSquare()), + } +} + type PrivateKey struct { PublicKey Lambda *big.Int diff --git a/paillier_test.go b/paillier_test.go index e157ec2..75a759d 100644 --- a/paillier_test.go +++ b/paillier_test.go @@ -92,3 +92,36 @@ func TestAddCypherWithSmallKeyModulus(t *testing.T) { t.Errorf("Unexpected decrypted value [%v]", m) } } + +func TestMulCypher(t *testing.T) { + privateKey := CreatePrivateKey(big.NewInt(17), big.NewInt(13)) + + cypher, err := privateKey.Encrypt(big.NewInt(3), rand.Reader) + if err != nil { + t.Fatal(err) + } + + cypherMultiple := privateKey.Mul(cypher, big.NewInt(7)) + multiple := privateKey.Decrypt(cypherMultiple) + + if !reflect.DeepEqual(multiple, big.NewInt(21)) { + t.Errorf("Unexpected decrypted value [%v]", multiple) + } +} + +func TestMulCypherWithSmallKeyModulus(t *testing.T) { + privateKey := CreatePrivateKey(big.NewInt(7), big.NewInt(5)) + + cypher, err := privateKey.Encrypt(big.NewInt(30), rand.Reader) + if err != nil { + t.Fatal(err) + } + + cypherMultiple := privateKey.Mul(cypher, big.NewInt(93)) + multiple := privateKey.Decrypt(cypherMultiple) + + // (30*93) mod (7*5) = 25 + if !reflect.DeepEqual(multiple, big.NewInt(25)) { + t.Errorf("Unexpected decrypted value [%v]", multiple) + } +}