From cfa2d72befe8e2f1e80f86682ee44017c33bcd43 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Mon, 9 Jul 2018 09:34:09 +0200 Subject: [PATCH] Added EncryptWithR allowing to specify the randomness Function `EncryptWithR` lets to specify randomness `r` explicitely. For some ZKPs based on the Paillier scheme, it's required to use the same `r` for encryption and constructing ZKP. It wasn't possible previously, because `r` was generated internally and never returned. I did not want to modify `Encrypt` to return `r` because it would break existing code using this API, as well as, I want to make sure person using the specific `r` and using it somewhere else really knows what he's doing. --- paillier.go | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/paillier.go b/paillier.go index 9eca2ab..557ceab 100644 --- a/paillier.go +++ b/paillier.go @@ -14,6 +14,31 @@ func (pk *PublicKey) GetNSquare() *big.Int { return new(big.Int).Mul(pk.N, pk.N) } +// EncryptWithR encrypts a plaintext into a cypher one with random `r` specified +// in the argument. The plain text must be smaller that N and bigger or equal +// than zero. `r` is the randomness used to encrypt the plaintext. `r` must be +// a random element from a multiplicative group of integers modulo N. +// +// If you don't need to use the specific `r`, you should use the `Encrypt` +// function instead. +// +// m - plaintext to encrypt +// r - randomness used for encryption +// E(m, r) = [(1 + N) r^N] mod N^2 +// +// See [KL 08] construction 11.32, page 414. +func (pk *PublicKey) EncryptWithR(m *big.Int, r *big.Int) (*Cypher, error) { + nSquare := pk.GetNSquare() + + // g is _always_ equal n+1 + // Threshold encryption is safe only for g=n+1 choice. + // See [DJN 10], section 5.1 + g := new(big.Int).Add(pk.N, big.NewInt(1)) + gm := new(big.Int).Exp(g, m, nSquare) + rn := new(big.Int).Exp(r, pk.N, nSquare) + return &Cypher{new(big.Int).Mod(new(big.Int).Mul(rn, gm), nSquare)}, nil +} + // Encrypt a plaintext into a cypher one. The plain text must be smaller that // N and bigger or equal than zero. random is usually rand.Reader from the // package crypto/rand. @@ -29,15 +54,8 @@ func (pk *PublicKey) Encrypt(m *big.Int, random io.Reader) (*Cypher, error) { if err != nil { return nil, err } - nSquare := pk.GetNSquare() - // g is _always_ equal n+1 - // Threshold encryption is safe only for g=n+1 choice. - // See [DJN 10], section 5.1 - g := new(big.Int).Add(pk.N, big.NewInt(1)) - gm := new(big.Int).Exp(g, m, nSquare) - rn := new(big.Int).Exp(r, pk.N, nSquare) - return &Cypher{new(big.Int).Mod(new(big.Int).Mul(rn, gm), nSquare)}, nil + return pk.EncryptWithR(m, r) } // Add takes an arbitrary number of cyphertexts and returns one that encodes -- 2.55.0