Skip to main content

Overview

The encryption module provides implementations of:
  • Pedersen commitments using Ristretto/Curve25519
  • Twisted ElGamal public-key encryption
  • AES-GCM-SIV authenticated encryption

Constants

AE_KEY_LEN
usize
default:"16"
Byte length of an authenticated encryption secret key
AE_CIPHERTEXT_LEN
usize
default:"36"
Byte length of a complete authenticated encryption ciphertext (includes ciphertext and nonce)
DECRYPT_HANDLE_LEN
usize
default:"32"
Byte length of a decrypt handle
ELGAMAL_CIPHERTEXT_LEN
usize
default:"64"
Byte length of an ElGamal ciphertext (commitment + decrypt handle)
ELGAMAL_PUBKEY_LEN
usize
default:"32"
Byte length of an ElGamal public key
ELGAMAL_SECRET_KEY_LEN
usize
default:"32"
Byte length of an ElGamal secret key
ELGAMAL_KEYPAIR_LEN
usize
default:"64"
Byte length of an ElGamal keypair (public key + secret key)
PEDERSEN_OPENING_LEN
usize
default:"32"
Byte length of a Pedersen opening
PEDERSEN_COMMITMENT_LEN
usize
default:"32"
Byte length of a Pedersen commitment

ElGamal Encryption

ElGamalKeypair

An ElGamal encryption keypair containing public and secret keys.

Methods

new_rand
() -> Self
Generates a random ElGamal keypair using OsRng.
use solana_zk_sdk::encryption::elgamal::ElGamalKeypair;

let keypair = ElGamalKeypair::new_rand();
new
(secret: ElGamalSecretKey) -> Self
Creates a keypair from an existing secret key.
let secret = ElGamalSecretKey::new_rand();
let keypair = ElGamalKeypair::new(secret);
new_from_signer
(signer: &dyn Signer, public_seed: &[u8]) -> Result<Self>
Deterministically derives a keypair from a Solana signer and public seed.
use solana_signer::Signer;

let keypair = ElGamalKeypair::new_from_signer(&signer, b"seed")?;
pubkey
(&self) -> &ElGamalPubkey
Returns a reference to the public key.
let pubkey = keypair.pubkey();
secret
(&self) -> &ElGamalSecretKey
Returns a reference to the secret key.
let secret = keypair.secret();
read_json_file
<F: AsRef<Path>>(path: F) -> Result<Self>
Reads a keypair from a JSON file.
let keypair = ElGamalKeypair::read_json_file("keypair.json")?;
write_json_file
<F: AsRef<Path>>(&self, path: F) -> Result<String>
Writes the keypair to a JSON file.
keypair.write_json_file("keypair.json")?;

ElGamalPubkey

ElGamal public key for encryption.

Methods

encrypt
<T: Into<Scalar>>(&self, amount: T) -> ElGamalCiphertext
Encrypts a value using randomized encryption.
let ciphertext = pubkey.encrypt(100_u64);
encrypt_with
<T: Into<Scalar>>(&self, amount: T, opening: &PedersenOpening) -> ElGamalCiphertext
Encrypts a value using a specific Pedersen opening.
let opening = PedersenOpening::new_rand();
let ciphertext = pubkey.encrypt_with(100_u64, &opening);
decrypt_handle
(&self, opening: &PedersenOpening) -> DecryptHandle
Generates a decrypt handle for a Pedersen opening.
let opening = PedersenOpening::new_rand();
let handle = pubkey.decrypt_handle(&opening);
to_bytes
(&self) -> [u8; 32]
Serializes the public key to bytes.
let bytes = pubkey.to_bytes();
from_bytes
(bytes: &[u8]) -> Option<Self>
Deserializes a public key from bytes.
let pubkey = ElGamalPubkey::from_bytes(&bytes)?;

ElGamalSecretKey

ElGamal secret key for decryption. Instances are zeroized on drop.

Methods

new_rand
() -> Self
Randomly samples a secret key.
let secret = ElGamalSecretKey::new_rand();
from_seed
(seed: &[u8]) -> Result<Self>
Derives a secret key from an entropy seed (minimum 32 bytes).
let secret = ElGamalSecretKey::from_seed(&seed)?;
decrypt
(&self, ciphertext: &ElGamalCiphertext) -> DiscreteLog
Decrypts a ciphertext, returning a discrete log instance.
let discrete_log = secret.decrypt(&ciphertext);
decrypt_u32
(&self, ciphertext: &ElGamalCiphertext) -> Option<u64>
Decrypts a ciphertext as a 32-bit number.
This function is not constant time and should only be used for small values.
if let Some(amount) = secret.decrypt_u32(&ciphertext) {
    println!("Amount: {}", amount);
}

ElGamalCiphertext

A twisted ElGamal ciphertext consisting of a Pedersen commitment and decrypt handle.

Structure

commitment
PedersenCommitment
The Pedersen commitment encoding the encrypted message
handle
DecryptHandle
The decrypt handle binding the commitment to a public key

Methods

decrypt
(&self, secret: &ElGamalSecretKey) -> DiscreteLog
Decrypts the ciphertext using a secret key.
let discrete_log = ciphertext.decrypt(secret);
to_bytes
(&self) -> [u8; 64]
Serializes the ciphertext to bytes.
let bytes = ciphertext.to_bytes();
from_bytes
(bytes: &[u8]) -> Option<Self>
Deserializes a ciphertext from bytes.
let ciphertext = ElGamalCiphertext::from_bytes(&bytes)?;

Homomorphic Operations

ElGamal ciphertexts support homomorphic addition and scalar multiplication:
use curve25519_dalek::scalar::Scalar;

let ct1 = pubkey.encrypt(10_u64);
let ct2 = pubkey.encrypt(20_u64);

// Homomorphic addition: encrypts 30
let sum = ct1 + ct2;

// Homomorphic subtraction: encrypts -10
let diff = ct1 - ct2;

// Scalar multiplication: encrypts 50
let scaled = ct1 * Scalar::from(5_u64);

Pedersen Commitments

Base Points

G
RistrettoPoint
Pedersen base point for encoding messages (RISTRETTO_BASEPOINT_POINT)
H
RistrettoPoint
Pedersen base point for encoding openings (derived from hashing G)

Pedersen

Algorithm handle for Pedersen commitments.

Methods

new
<T: Into<Scalar>>(amount: T) -> (PedersenCommitment, PedersenOpening)
Creates a commitment with a random opening.
use solana_zk_sdk::encryption::pedersen::Pedersen;

let (commitment, opening) = Pedersen::new(100_u64);
with
<T: Into<Scalar>>(amount: T, opening: &PedersenOpening) -> PedersenCommitment
Creates a commitment with a specific opening.
let opening = PedersenOpening::new_rand();
let commitment = Pedersen::with(100_u64, &opening);

PedersenCommitment

A Pedersen commitment to a value.

Methods

get_point
(&self) -> &RistrettoPoint
Returns the underlying Ristretto point.
let point = commitment.get_point();
to_bytes
(&self) -> [u8; 32]
Serializes the commitment to bytes.
let bytes = commitment.to_bytes();

PedersenOpening

A Pedersen opening (randomness). Instances are zeroized on drop.

Methods

new_rand
() -> Self
Generates a random opening.
use solana_zk_sdk::encryption::pedersen::PedersenOpening;

let opening = PedersenOpening::new_rand();
get_scalar
(&self) -> &Scalar
Returns the underlying scalar value.
let scalar = opening.get_scalar();
as_bytes
(&self) -> &[u8; 32]
Returns the opening as bytes.
let bytes = opening.as_bytes();

Example: Complete Encryption Flow

use solana_zk_sdk::encryption::{
    elgamal::{ElGamalKeypair, ElGamalCiphertext},
    pedersen::{Pedersen, PedersenOpening},
};

// Generate keypair
let keypair = ElGamalKeypair::new_rand();

// Encrypt a value
let amount = 100_u64;
let ciphertext = keypair.pubkey().encrypt(amount);

// Decrypt
if let Some(decrypted) = keypair.secret().decrypt_u32(&ciphertext) {
    assert_eq!(decrypted, amount);
}

// Homomorphic operations
let ct1 = keypair.pubkey().encrypt(10_u64);
let ct2 = keypair.pubkey().encrypt(20_u64);
let sum = ct1 + ct2;

if let Some(result) = keypair.secret().decrypt_u32(&sum) {
    assert_eq!(result, 30);
}

Build docs developers (and LLMs) love