About - Crypto -
Paillier Cryptosystem
- API - Download

Fork me on GitHub

Overview

The following methods are provided in the Paillier module

Paillier.generateKeypair(keysize) # Returns privateKey, publicKey

Paillier.encrypt(publicKey, plaintext)
Paillier.eAdd(publicKey, cyphertext1, cyphertext2)
Paillier.eAddConst(publicKey, cyphertext, plaintext)
Paillier.eMulConst(publicKey, cyphertext, plaintext)

Paillier.decrypt(privateKey, publicKey, cyphertext)

Paillier.sign(privateKey, publicKey, data)
Paillier.validSignature?(publicKey, data, signature)

Paillier::ZKP.new(publicKey, plaintext, validMessages)
Paillier::ZKP.verifyZKP?(publicKey, ciphertext, validMessages, commitment)

Note that public and private 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

Encryption and decryption is trivial:

require 'paillier'

privkey, pubkey = Paillier.generateKeypair(2048)

x = 3
cx = Paillier.encrypt(pubkey, x)
dx = Paillier.decrypt(privkey, pubkey, cx)

# dx == 3

Adding two encrypted numbers together is also easy:

x = 3
y = 5
cx = Paillier.encrypt(pubkey, x)
cy = Paillier.encrypt(pubkey, y)
cz = Paillier.eAdd(pubkey, cx, cy)
z = Paillier.decrypt(privkey, pubkey, cz)

# z == 8

You can also add plaintext constants to a message:

x = 3
cx = Paillier.encrypt(pubkey, x)
cy = Paillier.eAddConst(pubkey, cx, 2)
y = Paillier.decrypt(privkey, pubkey, cy)

# y == 5

Multiplying by a constant is just as easy:

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

# y == 6

Signatures

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

data = 1000 # Arbitrary example
signature = Paillier.sign(privkey, pubkey, data)
Paillier.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:

msg = 7
valid_messages = [1, 3, 5, 7, 9]

# Create a ZKP object which will generate the commitment and ciphertext used for the proof
zkp = Paillier::ZKP.new(pubkey, msg, valid_messages)

ciphertext = zkp.ciphertext
commitment = zkp.commitment
# The client now sends the ciphertext and commitment to the server

Server (verifier) side:

valid_messages = [1, 3, 5, 7, 9]

message_okay = Paillier::ZKP.verifyZKP?(pubkey, ciphertext, valid_messages, commitment)
if( message_okay )
        # Plaintext is a valid message, but we don't know which one
else
        # Plaintext is *not* a valid message
end

Serialization

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:

privkey, pubkey = Paillier.generateKeypair(2048)
stringKey = pubkey.to_s

# stringKey can now be saved to a file, sent over network, etc

newpubkey == Paillier::PublicKey.from_s(string)

Private key serialization:

privkey, pubkey = Paillier.generateKeypair(2048)
stringKey = privkey.to_s

# stringKey can now be saved to a file, sent to another program, etc

newprivkey == Paillier::PrivateKey.from_s(string)

WARNING: Serialized private keys are in plaintext! This functionality is provided so keys can be exported to another program and saved securely. Do not send your serialized private key across a network or save it in an insecure environment.

Signature serialization:

sig = Paillier.sign(privkey, pubkey, data)
stringSig = sig.to_s

# stringSig can now be saved to a file, sent over network, etc

newsig = Paillier::Signature.from_s(stringSig)

ZKP Commitment serialization:

zkp = Paillier::ZKP.new(pubkey, valid_messages, msg)
commitment = zkp.commitment
commitmentString = commitment.to_s

# commitmentString can now be saved to a file, sent over network, etc

newCommitment = Paillier::ZKP::ZKPCommit.from_s(commitment_string)