snipsco / rust-paillier

A pure-Rust implementation of the Paillier encryption scheme
Other
82 stars 12 forks source link

API for first release #6

Closed mortendahl closed 7 years ago

mortendahl commented 7 years ago

Current Use

let (ek, dk) = PlainPaillier::keypair(2048);

let m1 = PlainPaillier::encode(10);
let c1 = PlainPaillier::encrypt(&ek, &m1);
let m2 = PlainPaillier::encode(20);
let c2 = PlainPaillier::encrypt(&ek, &m2);

let c = PlainPaillier::add(&ek,
    &PlainPaillier::add(&ek, &c1, &c2),
    &PlainPaillier::add(&ek, &c3, &c4)
);

let m = PlainPaillier::decrypt(&dk, &c).0;

with the option of using Plaintext::from instead of PlainPaillier::encode:

let (ek, dk) = PlainPaillier::keypair(2048);

let m1 = Plaintext::from(10);
let c1 = PlainPaillier::encrypt(&ek, &m1);

of being specific about the underlying big integer type:

type MyScheme = plain::Scheme<RampBigInteger>;

let (ek, dk) = MyScheme::keypair(2048);

let m1 = MyScheme::encode(10);
let c1 = MyScheme::encrypt(&ek, &m1);

as well as abstract:

pub fn encryption<Scheme>()
where
    Scheme : plain::AbstractScheme,
    Scheme : plain::Encode<usize, I=<Scheme as plain::AbstractScheme>::BigInteger>,
    Scheme : KeyGeneration<<Scheme as plain::AbstractScheme>::BigInteger>
{
    let (ek, dk) = Scheme::keypair(2048);
    let m = Scheme::encode(10);
    let c = Scheme::encrypt(&ek, &m);
}

Finally, to use the packed variant, PlainPaillier is simply replaced by PackedPaillier.

Current Types

Future Features

Without over-engineering and with the option of adapting the interface later, these are some of the envisioned future features:

CRT decryption

Given knowledge of p and q we can speed up decryption by first converting to a CRT representation and then doing two smaller decryptions. This might be done by deriving a new decryption key with additional state from the standard decryption key.

Encryption precomputation

By computing encryptions of zero offline (e.g. in the background) we can cut the online encryption time roughly in half. This will expose additional methods for the precomputation as well as encryption taking these as input.

Zero-knowledge proofs

List of proofs to be defined; will likely need direct access to values used by the other operations, such as the randomness used by an encryption.

Rational encoding

We might want to encode (fixed-sized) rational numbers -- no direct application for SDA but would be useful in general purpose library.

Mixed encoding

Mix e.g. rational encoding with packed encoding, as opposed to having them mutually exclusive.

mortendahl commented 7 years ago

Decomposed Traits

use KeyGeneration;
let (ek, dk) = Paillier::keypair(2048);

let m1 = vec![1, 2, 3];
let m2 = vec![2, 4, 6];

use VectorEncoding;  // trait revealing functions for encoding vectors
let p1: Plaintext = Paillier::encode(m1, 10);  // 10 bits per component
let p2: Plaintext = Paillier::encode(m2, 10);

use Encryption;  // trait for standard encryption
let c1: Ciphertext = Paillier::encrypt(&ek, &p1);
let c2: Ciphertext = Paillier::encrypt(&ek, &p2);

use Addition;
let c: Ciphertext = Paillier::add(&ek, &c1, &c2);

use Decryption;  // trait for standard decryption (as opposed to CRT decryption)
let p: Plaintext = Paillier::decrypt(&dk, &c);

use VectorDecoding;
assert_eq!(Paillier::decode(p, 10), m1 + m2));

Alternatively the functions get added to types Plaintext, Scheme, etc. instead.

One benefits of splitting the API like this is that the different methods for e.g. decryptions are split (Decryption vs CRTDecryption).

mortendahl commented 7 years ago

CRT Decryption

use KeyGeneration;
let (ek, dk) = Paillier::keypair(2048);

let m1: usize = 5;
let m2: usize = 5;

use ScalarEncoding;
let p1 = m1.into();
let p2 = m1.into();

use Encryption;
let c1 = Paillier::encrypt(&ek, &p1);
let c2 = Paillier::encrypt(&ek, &p2);

use CRTDecryption;
let crtdk = dk.derive_crt_key();  // type is CRTDecryptionKey
let q1 = Paillier::decrypt(&crtdk, &c1);
let q2 = Paillier::decrypt(&crtdk, &c2);

use ScalarDecoding;
let n1: usize = q1.into();
let n2: usize = q2.into();
mortendahl commented 7 years ago

Rational encoding

let m1 = 1/2;
let m2 = 1/4;

use RationalEncoding;
let p1 = <Paillier as RationalEncoding>::from(m1, 6);  // type is RationalPlaintext(6)
let p2 = <Paillier as RationalEncoding>::from(m2, 12);    // type is RationalPlaintext(12)

use KeyGeneration;
let (ek, dk) = Paillier::keypair(2048);

use Encryption;
let c1 = <Paillier as RationalEncoding>::encrypt(&ek, &p1);  // type is RationalCiphertext(6)
let c2 = <Paillier as RationalEncoding>::encrypt(&ek, &p2);  // type is RationalCiphertext(12)

use Addition;
let c = <Paillier as RationalEncoding>::add(&c1, &c2);  // type is RationalCiphertext(12)

use Decryption;
let q = <Paillier as RationalEncoding>::decrypt(&dk, &c);  // type is RationalPlaintext(12)

use RationalDecoding;
let n = q.into();  // value is 3/4
mortendahl commented 7 years ago

keep interface simple, like sodium, yet allowing for research applications.

trait KeyGeneration {
  fn keypair() { Self::keypair(2048) }
  fn keypair(big_length: usize);
}