spl_token_confidential_transfer_proof_generation/
lib.rs

1use {
2    curve25519_dalek::scalar::Scalar,
3    solana_zk_sdk::{
4        encryption::{
5            elgamal::ElGamalCiphertext,
6            pedersen::{PedersenCommitment, PedersenOpening},
7            pod::elgamal::PodElGamalCiphertext,
8        },
9        zk_elgamal_proof_program::proof_data::BatchedGroupedCiphertext3HandlesValidityProofData,
10    },
11};
12
13pub mod burn;
14pub mod encryption;
15pub mod errors;
16pub mod mint;
17pub mod transfer;
18pub mod transfer_with_fee;
19pub mod withdraw;
20
21/// The low bit length of the encrypted transfer amount
22pub const TRANSFER_AMOUNT_LO_BITS: usize = 16;
23/// The high bit length of the encrypted transfer amount
24pub const TRANSFER_AMOUNT_HI_BITS: usize = 32;
25/// The bit length of the encrypted remaining balance in a token account
26pub const REMAINING_BALANCE_BIT_LENGTH: usize = 64;
27
28/// Takes in a 64-bit number `amount` and a bit length `bit_length`. It returns:
29/// - the `bit_length` low bits of `amount` interpreted as `u64`
30/// - the `(64 - bit_length)` high bits of `amount` interpreted as `u64`
31pub fn try_split_u64(amount: u64, bit_length: usize) -> Option<(u64, u64)> {
32    match bit_length {
33        0 => Some((0, amount)),
34        1..=63 => {
35            let bit_length_complement = u64::BITS.checked_sub(bit_length as u32).unwrap();
36            // shifts are safe as long as `bit_length` and `bit_length_complement` < 64
37            let lo = amount
38                .checked_shl(bit_length_complement)?
39                .checked_shr(bit_length_complement)?;
40            let hi = amount.checked_shr(bit_length as u32)?;
41            Some((lo, hi))
42        }
43        64 => Some((amount, 0)),
44        _ => None,
45    }
46}
47
48/// Combine two numbers that are interpreted as the low and high bits of a
49/// target number. The `bit_length` parameter specifies the number of bits that
50/// `amount_hi` is to be shifted by.
51#[deprecated(
52    since = "0.6.0",
53    note = "This function is deprecated as it contains logical errors and is unused in the crate"
54)]
55pub fn try_combine_lo_hi_u64(amount_lo: u64, amount_hi: u64, bit_length: usize) -> Option<u64> {
56    match bit_length {
57        0 => Some(amount_hi),
58        1..=63 => {
59            // shifts are safe as long as `bit_length` < 64
60            amount_hi
61                .checked_shl(bit_length as u32)?
62                .checked_add(amount_hi)
63        }
64        64 => Some(amount_lo),
65        _ => None,
66    }
67}
68
69#[allow(clippy::arithmetic_side_effects)]
70pub fn try_combine_lo_hi_ciphertexts(
71    ciphertext_lo: &ElGamalCiphertext,
72    ciphertext_hi: &ElGamalCiphertext,
73    bit_length: usize,
74) -> Option<ElGamalCiphertext> {
75    let two_power = 1_u64.checked_shl(bit_length as u32)?;
76    Some(ciphertext_lo + ciphertext_hi * Scalar::from(two_power))
77}
78
79#[allow(clippy::arithmetic_side_effects)]
80pub fn try_combine_lo_hi_commitments(
81    comm_lo: &PedersenCommitment,
82    comm_hi: &PedersenCommitment,
83    bit_length: usize,
84) -> Option<PedersenCommitment> {
85    let two_power = 1_u64.checked_shl(bit_length as u32)?;
86    Some(comm_lo + comm_hi * Scalar::from(two_power))
87}
88
89#[allow(clippy::arithmetic_side_effects)]
90pub fn try_combine_lo_hi_openings(
91    opening_lo: &PedersenOpening,
92    opening_hi: &PedersenOpening,
93    bit_length: usize,
94) -> Option<PedersenOpening> {
95    let two_power = 1_u64.checked_shl(bit_length as u32)?;
96    Some(opening_lo + opening_hi * Scalar::from(two_power))
97}
98
99/// A type that wraps a ciphertext validity proof along with two `lo` and `hi`
100/// ciphertexts.
101///
102/// Ciphertext validity proof data contains grouped ElGamal ciphertexts (`lo`
103/// and `hi`) and a proof containing the validity of these ciphertexts. Token
104/// client-side logic often requires a function to extract specific forms of
105/// the grouped ElGamal ciphertexts. This type is a convenience type that
106/// contains the proof data and the extracted ciphertexts.
107#[derive(Clone, Copy)]
108pub struct CiphertextValidityProofWithAuditorCiphertext {
109    pub proof_data: BatchedGroupedCiphertext3HandlesValidityProofData,
110    pub ciphertext_lo: PodElGamalCiphertext,
111    pub ciphertext_hi: PodElGamalCiphertext,
112}