Overview
The encryption module provides implementations of:
- Pedersen commitments using Ristretto/Curve25519
- Twisted ElGamal public-key encryption
- AES-GCM-SIV authenticated encryption
Constants
Byte length of an authenticated encryption secret key
Byte length of a complete authenticated encryption ciphertext (includes ciphertext and nonce)
Byte length of a decrypt handle
Byte length of an ElGamal ciphertext (commitment + decrypt handle)
Byte length of an ElGamal public key
Byte length of an ElGamal secret key
Byte length of an ElGamal keypair (public key + secret key)
Byte length of a Pedersen opening
Byte length of a Pedersen commitment
ElGamal Encryption
ElGamalKeypair
An ElGamal encryption keypair containing public and secret keys.
Methods
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);
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
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
The Pedersen commitment encoding the encrypted message
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);
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
Pedersen base point for encoding messages (RISTRETTO_BASEPOINT_POINT)
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();
Serializes the commitment to bytes.let bytes = commitment.to_bytes();
PedersenOpening
A Pedersen opening (randomness). Instances are zeroized on drop.
Methods
Generates a random opening.use solana_zk_sdk::encryption::pedersen::PedersenOpening;
let opening = PedersenOpening::new_rand();
Returns the underlying scalar value.let scalar = opening.get_scalar();
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);
}