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 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

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

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

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)