-
Notifications
You must be signed in to change notification settings - Fork 182
[ciphertext-arithmetic, program, interface] Add add_to_with_offset and update tests
#1116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ use { | |
| ristretto::{add_ristretto, multiply_ristretto, subtract_ristretto, PodRistrettoPoint}, | ||
| scalar::PodScalar, | ||
| }, | ||
| solana_zk_sdk::encryption::pod::elgamal::PodElGamalCiphertext, | ||
| solana_zk_sdk::encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey}, | ||
| }; | ||
|
|
||
| const SHIFT_BITS: usize = 16; | ||
|
|
@@ -14,6 +14,11 @@ const G: PodRistrettoPoint = PodRistrettoPoint([ | |
| 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118, | ||
| ]); | ||
|
|
||
| const H: PodRistrettoPoint = PodRistrettoPoint([ | ||
| 140, 146, 64, 180, 86, 169, 230, 220, 101, 195, 119, 161, 4, 141, 116, 95, 148, 160, 140, 219, | ||
| 127, 68, 203, 205, 123, 70, 243, 64, 72, 135, 17, 52, | ||
| ]); | ||
|
|
||
| /// Add two ElGamal ciphertexts | ||
| pub fn add( | ||
| left_ciphertext: &PodElGamalCiphertext, | ||
|
|
@@ -132,6 +137,28 @@ pub fn add_to(ciphertext: &PodElGamalCiphertext, amount: u64) -> Option<PodElGam | |
| Some(ristretto_to_elgamal_ciphertext(&result_commitment, &handle)) | ||
| } | ||
|
|
||
| /// Add a constant amount to a ciphertext with a fixed offset | ||
| pub fn add_to_with_offset( | ||
| pubkey: &PodElGamalPubkey, | ||
| ciphertext: &PodElGamalCiphertext, | ||
| amount: u64, | ||
| ) -> Option<PodElGamalCiphertext> { | ||
| let amount_scalar = u64_to_scalar(amount); | ||
| let amount_point = multiply_ristretto(&amount_scalar, &G)?; | ||
| let amount_point_with_offset = add_ristretto(&amount_point, &H)?; | ||
| let pubkey_point = elgamal_pubkey_to_ristretto(pubkey); | ||
|
|
||
| let (commitment, handle) = elgamal_ciphertext_to_ristretto(ciphertext); | ||
|
|
||
| let result_commitment = add_ristretto(&commitment, &amount_point_with_offset)?; | ||
| let result_handle = add_ristretto(&handle, &pubkey_point)?; | ||
|
|
||
| Some(ristretto_to_elgamal_ciphertext( | ||
| &result_commitment, | ||
| &result_handle, | ||
| )) | ||
| } | ||
|
|
||
| /// Subtract a constant amount to a ciphertext | ||
| pub fn subtract_from( | ||
| ciphertext: &PodElGamalCiphertext, | ||
|
|
@@ -154,6 +181,12 @@ fn u64_to_scalar(amount: u64) -> PodScalar { | |
| PodScalar(amount_bytes) | ||
| } | ||
|
|
||
| /// Convert a `PodElGamalPubkey` into `PodRistrettoPoint` | ||
| fn elgamal_pubkey_to_ristretto(pubkey: &PodElGamalPubkey) -> PodRistrettoPoint { | ||
| let bytes = bytes_of(pubkey); | ||
| PodRistrettoPoint(bytes.try_into().unwrap()) | ||
| } | ||
|
Comment on lines
+184
to
+188
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Layperson here again: I've never seen a conversion from the encryption key to a ristretto point in our code before -- is the idea to use that as the randomness since it'll never be 0?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's right. A Twisted ElGamal ciphertext consists of two halves, the commitment ( Here, we want to intentionally use a fixed randomness of The representation that the addition syscall expects is
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! |
||
|
|
||
| /// Convert a `PodElGamalCiphertext` into a tuple of commitment and decrypt | ||
| /// handle `PodRistrettoPoint` | ||
| fn elgamal_ciphertext_to_ristretto( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my layperson brain here -- is
Htypically the term for0? If so, all good! If not, can you add a comment to that effect? (Assuming I've correctly understood this as0)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I can definitely add a clarifying comment here (but let me do it in a follow-up 🙏 ).
Hactually isn't0. In Pedersen commitments,GandHare the two standard generator points on the curve.Gis used for the token amount, andHis used for the randomness (blinding factor).A commitment is mathematically calculated as
(amount & G) + (randomness * H). Because we want to create a dummy ciphertext that encrypts an amount of0with a fixed randomness of1(so the resulting ciphertext isn't an all-zero identity point), the commitment part evaluates to0 * G + 1 * H, which just leaves us with exactlyH.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation!