Skip to content

ristretto255_elgamal - [mainnet]

This module implements an ElGamal encryption API, over the Ristretto255 curve, that can be used with the Bulletproofs module.

An ElGamal ciphertext is an encryption of a value v under a basepoint G and public key Y = sk * G, where sk is the corresponding secret key, is (v * G + r * Y, r * G), for a random scalar r.

Note that we place the value v “in the exponent” of G so that ciphertexts are additively homomorphic: i.e., so that Enc_Y(v, r) + Enc_Y(v’, r’) = Enc_Y(v + v’, r + r’) where v, v’ are plaintext messages, Y is a public key and r, r’ are the randomness of the ciphertexts.

use 0x1::option;
use 0x1::ristretto255;
use 0x1::vector;

Structs

Ciphertext

An ElGamal ciphertext.

struct Ciphertext has drop
Fields
left: ristretto255::RistrettoPoint
right: ristretto255::RistrettoPoint

CompressedCiphertext

A compressed ElGamal ciphertext.

struct CompressedCiphertext has copy, drop, store
Fields
left: ristretto255::CompressedRistretto
right: ristretto255::CompressedRistretto

CompressedPubkey

An ElGamal public key.

struct CompressedPubkey has copy, drop, store
Fields
point: ristretto255::CompressedRistretto

Functions

new_pubkey_from_bytes

Creates a new public key from a serialized Ristretto255 point.

public fun new_pubkey_from_bytes(bytes: vector<u8>): option::Option<ristretto255_elgamal::CompressedPubkey>
Implementation
public fun new_pubkey_from_bytes(bytes: vector<u8>): Option<CompressedPubkey> {
let point = ristretto255::new_compressed_point_from_bytes(bytes);
if (point.is_some()) {
let pk = CompressedPubkey {
point: point.extract()
};
std::option::some(pk)
} else {
std::option::none<CompressedPubkey>()
}
}

pubkey_to_bytes

Given an ElGamal public key pubkey, returns the byte representation of that public key.

public fun pubkey_to_bytes(pubkey: &ristretto255_elgamal::CompressedPubkey): vector<u8>
Implementation
public fun pubkey_to_bytes(pubkey: &CompressedPubkey): vector<u8> {
ristretto255::compressed_point_to_bytes(pubkey.point)
}

pubkey_to_point

Given a public key pubkey, returns the underlying RistrettoPoint representing that key.

public fun pubkey_to_point(pubkey: &ristretto255_elgamal::CompressedPubkey): ristretto255::RistrettoPoint
Implementation
public fun pubkey_to_point(pubkey: &CompressedPubkey): RistrettoPoint {
ristretto255::point_decompress(&pubkey.point)
}

pubkey_to_compressed_point

Given a public key, returns the underlying CompressedRistretto point representing that key.

public fun pubkey_to_compressed_point(pubkey: &ristretto255_elgamal::CompressedPubkey): ristretto255::CompressedRistretto
Implementation
public fun pubkey_to_compressed_point(pubkey: &CompressedPubkey): CompressedRistretto {
pubkey.point
}

new_ciphertext_from_bytes

Creates a new ciphertext from two serialized Ristretto255 points: the first 32 bytes store r * G while the next 32 bytes store v * G + r * Y, where Y is the public key.

public fun new_ciphertext_from_bytes(bytes: vector<u8>): option::Option<ristretto255_elgamal::Ciphertext>
Implementation
public fun new_ciphertext_from_bytes(bytes: vector<u8>): Option<Ciphertext> {
if(bytes.length() != 64) {
return std::option::none<Ciphertext>()
};
let bytes_right = bytes.trim(32);
let left_point = ristretto255::new_point_from_bytes(bytes);
let right_point = ristretto255::new_point_from_bytes(bytes_right);
if (left_point.is_some::<RistrettoPoint>() && right_point.is_some::<RistrettoPoint>()) {
std::option::some<Ciphertext>(Ciphertext {
left: left_point.extract::<RistrettoPoint>(),
right: right_point.extract::<RistrettoPoint>()
})
} else {
std::option::none<Ciphertext>()
}
}

new_ciphertext_no_randomness

Creates a new ciphertext (val * G + 0 * Y, 0 * G) = (val * G, 0 * G) where G is the Ristretto255 basepoint and the randomness is set to zero.

public fun new_ciphertext_no_randomness(val: &ristretto255::Scalar): ristretto255_elgamal::Ciphertext
Implementation
public fun new_ciphertext_no_randomness(val: &Scalar): Ciphertext {
Ciphertext {
left: ristretto255::basepoint_mul(val),
right: ristretto255::point_identity(),
}
}

ciphertext_from_points

Moves a pair of Ristretto points into an ElGamal ciphertext.

public fun ciphertext_from_points(left: ristretto255::RistrettoPoint, right: ristretto255::RistrettoPoint): ristretto255_elgamal::Ciphertext
Implementation
public fun ciphertext_from_points(left: RistrettoPoint, right: RistrettoPoint): Ciphertext {
Ciphertext {
left,
right,
}
}

ciphertext_from_compressed_points

Moves a pair of CompressedRistretto points into an ElGamal ciphertext.

public fun ciphertext_from_compressed_points(left: ristretto255::CompressedRistretto, right: ristretto255::CompressedRistretto): ristretto255_elgamal::CompressedCiphertext
Implementation
public fun ciphertext_from_compressed_points(left: CompressedRistretto, right: CompressedRistretto): CompressedCiphertext {
CompressedCiphertext {
left,
right,
}
}

ciphertext_to_bytes

Given a ciphertext ct, serializes that ciphertext into bytes.

public fun ciphertext_to_bytes(ct: &ristretto255_elgamal::Ciphertext): vector<u8>
Implementation
public fun ciphertext_to_bytes(ct: &Ciphertext): vector<u8> {
let bytes_left = ristretto255::point_to_bytes(&ristretto255::point_compress(&ct.left));
let bytes_right = ristretto255::point_to_bytes(&ristretto255::point_compress(&ct.right));
let bytes = vector::empty<u8>();
bytes.append::<u8>(bytes_left);
bytes.append::<u8>(bytes_right);
bytes
}

ciphertext_into_points

Moves the ciphertext into a pair of RistrettoPoint’s.

public fun ciphertext_into_points(c: ristretto255_elgamal::Ciphertext): (ristretto255::RistrettoPoint, ristretto255::RistrettoPoint)
Implementation
public fun ciphertext_into_points(c: Ciphertext): (RistrettoPoint, RistrettoPoint) {
let Ciphertext { left, right } = c;
(left, right)
}

ciphertext_as_points

Returns the pair of RistrettoPoint’s representing the ciphertext.

public fun ciphertext_as_points(c: &ristretto255_elgamal::Ciphertext): (&ristretto255::RistrettoPoint, &ristretto255::RistrettoPoint)
Implementation
public fun ciphertext_as_points(c: &Ciphertext): (&RistrettoPoint, &RistrettoPoint) {
(&c.left, &c.right)
}

compress_ciphertext

Creates a new compressed ciphertext from a decompressed ciphertext.

public fun compress_ciphertext(ct: &ristretto255_elgamal::Ciphertext): ristretto255_elgamal::CompressedCiphertext
Implementation
public fun compress_ciphertext(ct: &Ciphertext): CompressedCiphertext {
CompressedCiphertext {
left: point_compress(&ct.left),
right: point_compress(&ct.right),
}
}

decompress_ciphertext

Creates a new decompressed ciphertext from a compressed ciphertext.

public fun decompress_ciphertext(ct: &ristretto255_elgamal::CompressedCiphertext): ristretto255_elgamal::Ciphertext
Implementation
public fun decompress_ciphertext(ct: &CompressedCiphertext): Ciphertext {
Ciphertext {
left: ristretto255::point_decompress(&ct.left),
right: ristretto255::point_decompress(&ct.right),
}
}

ciphertext_add

Homomorphically combines two ciphertexts lhs and rhs as lhs + rhs. Useful for re-randomizing the ciphertext or updating the committed value.

public fun ciphertext_add(lhs: &ristretto255_elgamal::Ciphertext, rhs: &ristretto255_elgamal::Ciphertext): ristretto255_elgamal::Ciphertext
Implementation
public fun ciphertext_add(lhs: &Ciphertext, rhs: &Ciphertext): Ciphertext {
Ciphertext {
left: ristretto255::point_add(&lhs.left, &rhs.left),
right: ristretto255::point_add(&lhs.right, &rhs.right),
}
}

ciphertext_add_assign

Like ciphertext_add but assigns lhs = lhs + rhs.

public fun ciphertext_add_assign(lhs: &mut ristretto255_elgamal::Ciphertext, rhs: &ristretto255_elgamal::Ciphertext)
Implementation
public fun ciphertext_add_assign(lhs: &mut Ciphertext, rhs: &Ciphertext) {
ristretto255::point_add_assign(&mut lhs.left, &rhs.left);
ristretto255::point_add_assign(&mut lhs.right, &rhs.right);
}

ciphertext_sub

Homomorphically combines two ciphertexts lhs and rhs as lhs - rhs. Useful for re-randomizing the ciphertext or updating the committed value.

public fun ciphertext_sub(lhs: &ristretto255_elgamal::Ciphertext, rhs: &ristretto255_elgamal::Ciphertext): ristretto255_elgamal::Ciphertext
Implementation
public fun ciphertext_sub(lhs: &Ciphertext, rhs: &Ciphertext): Ciphertext {
Ciphertext {
left: ristretto255::point_sub(&lhs.left, &rhs.left),
right: ristretto255::point_sub(&lhs.right, &rhs.right),
}
}

ciphertext_sub_assign

Like ciphertext_add but assigns lhs = lhs - rhs.

public fun ciphertext_sub_assign(lhs: &mut ristretto255_elgamal::Ciphertext, rhs: &ristretto255_elgamal::Ciphertext)
Implementation
public fun ciphertext_sub_assign(lhs: &mut Ciphertext, rhs: &Ciphertext) {
ristretto255::point_sub_assign(&mut lhs.left, &rhs.left);
ristretto255::point_sub_assign(&mut lhs.right, &rhs.right);
}

ciphertext_clone

Creates a copy of this ciphertext.

public fun ciphertext_clone(c: &ristretto255_elgamal::Ciphertext): ristretto255_elgamal::Ciphertext
Implementation
public fun ciphertext_clone(c: &Ciphertext): Ciphertext {
Ciphertext {
left: ristretto255::point_clone(&c.left),
right: ristretto255::point_clone(&c.right),
}
}

ciphertext_equals

Returns true if the two ciphertexts are identical: i.e., same value and same randomness.

public fun ciphertext_equals(lhs: &ristretto255_elgamal::Ciphertext, rhs: &ristretto255_elgamal::Ciphertext): bool
Implementation
public fun ciphertext_equals(lhs: &Ciphertext, rhs: &Ciphertext): bool {
ristretto255::point_equals(&lhs.left, &rhs.left) &&
ristretto255::point_equals(&lhs.right, &rhs.right)
}

get_value_component

Returns the RistrettoPoint in the ciphertext which contains the encrypted value in the exponent.

public fun get_value_component(ct: &ristretto255_elgamal::Ciphertext): &ristretto255::RistrettoPoint
Implementation
public fun get_value_component(ct: &Ciphertext): &RistrettoPoint {
&ct.left
}