Initially, we did not wait for all goroutines to finish which was fine
as long as we did not run all tests with `go test` and observe deadlock
in 50% of cases. This is interesting, since deadlock never occurred when
running safe_prime_generator_test.go. Anyway, waiting for all go
routines to finish shouldn't harm the performance a lot and it gives a
guarantee we did not miss anything.
How fast we generate a prime number is mostly a matter of luck. It
varies from miliseconds to seconds and depends how lucky we are with
drawing bytes.
With today's multicore processors, we can execute the process on
multiple cores concurrently, accept the first valid result and cancel
the rest of work. This way, with the same algorithm, we get the result
faster.
I've adapted a Go code for generating random numbers by inserting some
optimisations that will allow us to generate safe primes faster than
with the previous, naive approach.
First of all, having q which can be prime, we first check whether q%3=1.
If that's true, there is no chance p=2q+1 is prime. It lets us to reject
candidate numbers quicker without running an expensive primality tests.
Also, before we run a primality test for q, we may check p=2q+1 against
the primes between 3-53 (We are limited by Go's uint64 range).
If all those conditions are met and we know p is prime, it's enough to
check Pocklington criterion for q instead of running an expensive
primality test for it.
It's now possible to multiply Cypher by an integer.
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`.
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.
`PublicKey.Add` accepts now an arbitrary number of `*Cypher`s.
Previously, it was possible to add only two `*Cypher*` instances and it
was quite unwieldy for a lot of use cases.
The current implementation is backward compatible. It's still possible
to pass just two `*Cypher` arguments, so every project referencing the
library will observe no compilation issues.
First of all, we should check both `p,p1` and `q,q1` in the `TestInitPsAndQs`. Moreover, it's better to operate on primes in `TestArePsAndQsGood` and in `TestInitShortcuts` because non-prime numbers are not allowed there in a real world and tests were a bit misleading because of it.
It's better to have no code encouraging to turn key into a string and printing it somewhere, especially that string contains private key Lambda parameter.
We don't need G for our PublicKey since it's now always equal N+1. It's required by the `ThresholdKey` to compile, so I moved it there. I will investigate if for a threshold Paillier scheme G is really needed in the pkey.
Let's keep this structure clean. Computing N^2 is just a really small piece of encryption/decryption work and if we decide we need to tweak performance, we will need a different approach anyway.
The code for generating private key is based on approach described in [KL 08], construction 11.32 which is compatible with the one described in [DJN 10], section 3.2 except that instead of generating Lamda private key compontent from LCM of `p` and `q` we use Euler's totient function as suggested in [KL 08]. I cleared up naming as well as removed G and Mu parameters from Paillier key. For the modification of Paillier scheme we use, where g = n + 1, N is the only one parameter needed for a public key. Also, Mu is needed only for Decrypting and can be computed there from Lambda and N so there is no need to keep it in the private key.
I added documentation to <Key, Enc, Dec> functions with an important note that `p` and `q` supplied to `CreatePrivateKey` must be either of equal length or `gcd(pq, (p-1)(q-1)) = 1` which is assured if both primes are of equal length. This requirement is mentioned both in [KL 08] and [DJN 10].
[KL 08]: Jonathan Katz, Yehuda Lindell, (2008)
Introduction to Modern Cryptography: Principles and Protocols,
Chapman & Hall/CRC
[DJN 10]: Ivan Damgard, Mads Jurik, Jesper Buus Nielsen, (2010)
A Generalization of Paillier’s Public-Key System
with Applications to Electronic Voting
Aarhus University, Dept. of Computer Science, BRICS