Expand description

ZK-proof, called Пlog* or Rlog* in the CGGMP21 paper.

§Description

A party P has a number X = x G, with G being a generator of curve E. P has encrypted x as C. P shares X and C with V and wants to prove that the logarithm of X is the plaintext of C, and that the plaintext (i.e. x) is at most l bits.

Given:

  • key0, pkey0 - pair of public and private keys in paillier cryptosystem
  • Curve E
  • X = x G and C = key0.encrypt(x) - data to obtain proof about

Prove:

  • decrypt(C) = log X
  • bitsize(x) <= l

Disclosing only: key0, C, X

§Example

use rug::{Integer, Complete};
use generic_ec::{Point, curves::Secp256k1 as E};
use paillier_zk::{group_element_vs_paillier_encryption_in_range as p, IntegerExt};

// Prover and verifier have a shared protocol state
let shared_state_prover = sha2::Sha256::default();
let shared_state_verifier = sha2::Sha256::default();
let mut rng = rand_core::OsRng;

// 0. Setup: prover and verifier share common Ring-Pedersen parameters:

let aux: p::Aux = pregenerated::verifier_aux();
let security = p::SecurityParams {
    l: 1024,
    epsilon: 300,
    q: (Integer::ONE << 128_u32).complete(),
};

// 1. Setup: prover prepares the paillier keys

let private_key: fast_paillier::DecryptionKey =
    pregenerated::prover_decryption_key();
let key0 = private_key.encryption_key();

// 2. Setup: prover has some plaintext `x`, encrypts it and obtains `C`, and computes `X`

let x = Integer::from_rng_pm(&(Integer::ONE << security.l).complete(), &mut rng);
let (C, nonce) = key0.encrypt_with_random(&mut rng, &x)?;
let X = Point::<E>::generator() * x.to_scalar();

// 3. Prover computes a non-interactive proof that plaintext is at most `l` bits:

let data = p::Data {
    key0,
    c: &C,
    x: &X,
    b: &Point::<E>::generator().into(),
};
let (commitment, proof) =
    p::non_interactive::prove(
        shared_state_prover,
        &aux,
        data,
        p::PrivateData { x: &x, nonce: &nonce },
        &security,
        &mut rng,
    )?;

// 4. Prover sends this data to verifier

send(&data, &commitment, &proof);

// 5. Verifier receives the data and the proof and verifies it

let (data, commitment, proof) = recv();
p::non_interactive::verify(
    shared_state_verifier,
    &aux,
    data,
    &commitment,
    &security,
    &proof,
)?;

If the verification succeeded, verifier can continue communication with prover

Modules§

  • The interactive version of the ZK proof. Should be completed in 3 rounds: prover commits to data, verifier responds with a random challenge, and prover gives proof with commitment and challenge.
  • The non-interactive version of proof. Completed in one round, for example see the documentation of parent module.

Structs§

Type Aliases§