About - Crypto -
Paillier Cryptosystem
- API - Download

Fork me on GitHub


The following methods are provided in the Paillier module

 1Paillier.generateKeypair(keysize) # Returns privateKey, publicKey
 3Paillier.encrypt(publicKey, plaintext)
 4Paillier.eAdd(publicKey, cyphertext1, cyphertext2)
 5Paillier.eAddConst(publicKey, cyphertext, plaintext)
 6Paillier.eMulConst(publicKey, cyphertext, plaintext)
 8Paillier.decrypt(privateKey, publicKey, cyphertext)
10Paillier.sign(privateKey, publicKey, data)
11Paillier.validSignature?(publicKey, data, signature)
13Paillier::ZKP.new(publicKey, plaintext, validMessages)
14Paillier::ZKP.verifyZKP?(publicKey, ciphertext, validMessages, commitment)

Note that public keys, signatures, and ZKP commitments have to_s and from_s methods to make them easy to serialize and save to a file / database or send over a network.

The ZKP object has ciphertext and commitment methods to extract the information that must be sent to the server.

Examples of all of the above methods are provided below.


Encryption and decryption is trivial:

 1require 'paillier'
 3privkey, pubkey = Paillier.generateKeypair(2048)
 5x = 3
 6cx = Paillier.encrypt(pubkey, x)
 7dx = Paillier.decrypt(privkey, pubkey, cx)
 9# dx == 3

Adding two encrypted numbers together is also easy:

1x = 3
2y = 5
3cx = Paillier.encrypt(pubkey, x)
4cy = Paillier.encrypt(pubkey, y)
5cz = Paillier.eAdd(pubkey, cx, cy)
6z = Paillier.decrypt(privkey, pubkey, cz)
8# z == 8

You can also add plaintext constants to a message:

1x = 3
2cx = Paillier.encrypt(pubkey, x)
3cy = Paillier.eAddConst(pubkey, cx, 2)
4y = Paillier.decrypt(privkey, pubkey, cy)
6# y == 5

Multiplying by a constant is just as easy:

1x = 3
2cx = Paillier.encrypt(pubkey, x)
3cy = Paillier.eMulConst(pubkey, cx, 2)
4y = Paillier.decrypt(privkey, pubkey, cy)
6# y == 6


Paillier provides detached signatures, which can validate that a message has not been tampered with, and has been signed by the specified keypair.

1data = 1000 # Arbitrary example
2signature = Paillier.sign(privkey, pubkey, data)
3Paillier.validSignature?(pubkey, data, signature) # Will return true if signature okay

Zero-Knowledge Content Proofs

If there are a limited number of acceptable messages then we say a ciphertext is valid if its plaintext is in the set of acceptable messages. The ZKP allows a third party to prove a ciphertext is valid, without having the private key to read the message.

To prove a ciphertext is valid, the prover must create their ciphertext and a commitment, and send it to the validator. The validator can then call verifyZKP? to ensure the message is valid. The client and server must have agreed ahead of time on a set and order of valid messages.

Note: The ciphertext must be created with the ZKP object, as parts of the encryption process are re-used to create the commitment.

Client (prover) side:

 1msg = 7
 2valid_messages = [1, 3, 5, 7, 9]
 4# Create a ZKP object which will generate the commitment and ciphertext used for the proof
 5zkp = Paillier::ZKP.new(pubkey, msg, valid_messages)
 7ciphertext = zkp.ciphertext
 8commitment = zkp.commitment
 9# The client now sends the ciphertext and commitment to the server

Server (verifier) side:

1valid_messages = [1, 3, 5, 7, 9]
3message_okay = Paillier::ZKP.verifyZKP?(pubkey, ciphertext, valid_messages, commitment)
4if( message_okay )
5        # Plaintext is a valid message, but we don't know which one
7        # Plaintext is *not* a valid message


It is often necessary to convert data into text to make it easy to send over a network, save into a database, and so on. Our Paillier library provides several methods to make this process easier.

Public key serialization:

1privkey, pubkey = Paillier.generateKeypair(2048)
2stringKey = pubkey.to_s
4# stringKey can now be saved to a file, sent over network, etc
6newpubkey == Paillier::PublicKey.from_s(string)

Signature serialization:

1sig = Paillier.sign(privkey, pubkey, data)
2stringSig = sig.to_s
4# stringSig can now be saved to a file, sent over network, etc
6newsig = Paillier::Signature.from_s(stringSig)

ZKP Commitment serialization:

1zkp = Paillier::ZKP.new(pubkey, valid_messages, msg)
2commitment = zkp.commitment
3commitmentString = commitment.to_s
5# commitmentString can now be saved to a file, sent over network, etc
7newCommitment = Paillier::ZKP::ZKPCommit.from_s(commitment_string)

No such serialization methods are provided for the private key, to give developers pause before they try to send a private key in plaintext over the network.