Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Modified ElGamal


Modified ElGamal [JCJ02] is a public key encryption scheme over a cyclic group of prime order that introduces a two-dimensional secret key and a three-component ciphertext. The change preserves the core guarantees of classical ElGamal (IND-CPA under DDH, rerandomizability, and homomorphism) while making the ciphertext structure more convenient for zero-knowledge proofs, shuffles, and threshold-style workflows.

Mathematical setting

Let be a cyclic group of prime order with independent generators .

  • Secret key: sampled uniformly at random.
  • Public key: .

Encryption of :

  1. Sample uniformly at random.
  2. Output ciphertext where

Decryption with secret key :

Correctness follows since:

Homomorphism

For any two ciphertexts and , Thus Modified ElGamal is multiplicatively homomorphic.

When messages are represented in the exponent, i.e., for a third fixed generator , then which induces additive homomorphism on exponents. Recovering from requires solving a discrete logarithm and is feasible only for small message domains.

Rerandomization

Given , any party can produce a distribution-identical ciphertext on the same plaintext by sampling in and outputting Rerandomization preserves correctness and hides .

Applications

  • Verifiable shuffles and mix-nets: ciphertexts can be permuted and rerandomized while preserving plaintexts.
  • Threshold workflows: the split structure of the secret key and the explicit randomness terms simplify share verifications.
  • Privacy-preserving systems: voting, sealed-bid auctions, credential systems, and any setting that benefits from efficient NIZKs over ElGamal relations.

Example

The crate is generic over a group backend. For documentation builds, select exactly one backend feature for the library (for example, p256 or ristretto). The alias Curve refers to the selected backend in this build.

// In Cargo.toml of this doc build:
// dlog-sigma-primitives = { version = "x.y.z", features = ["p256"] }

use rand_core::OsRng;
use dlog_sigma_primitives::prelude::*;

// The library exposes a concrete backend alias selected by features:
// type Curve = dlog_group::<backend>::Group;
// All APIs remain generic; Curve is provided for convenience.

fn main() {
let mut rng = OsRng;
// (sk, pk) sampled in the selected Curve
let params = ElGamalParams::<Curve>::new(&mut rng);
let (sk, pk) = KeyPair::<Curve>::new_from_params(&params, &mut rng).into_tuple();

// Sample a random message
let m = Curve::generator() * Curve::scalar_random(&mut rng);

// Encrypt and decrypt
let (ct, _r) = pk.encrypt(m, &params, &mut rng).into_tuple();

let m_dec = sk.decrypt(&ct);

assert_eq!(m, m_dec);
}