solana_zk_token_sdk/instruction/batched_range_proof/
mod.rs1pub mod batched_range_proof_u128;
20pub mod batched_range_proof_u256;
21pub mod batched_range_proof_u64;
22
23use crate::zk_token_elgamal::pod;
24#[cfg(not(target_os = "solana"))]
25use {
26 crate::{
27 encryption::pedersen::{PedersenCommitment, PedersenOpening},
28 errors::{ProofGenerationError, ProofVerificationError},
29 },
30 bytemuck::{bytes_of, Zeroable},
31 curve25519_dalek::traits::IsIdentity,
32 merlin::Transcript,
33 std::convert::TryInto,
34};
35
36const MAX_COMMITMENTS: usize = 8;
37
38#[cfg(not(target_os = "solana"))]
43const MAX_SINGLE_BIT_LENGTH: usize = 128;
44
45#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
49#[repr(C)]
50pub struct BatchedRangeProofContext {
51 pub commitments: [pod::PedersenCommitment; MAX_COMMITMENTS],
52 pub bit_lengths: [u8; MAX_COMMITMENTS],
53}
54
55#[allow(non_snake_case)]
56#[cfg(not(target_os = "solana"))]
57impl BatchedRangeProofContext {
58 fn new_transcript(&self) -> Transcript {
59 let mut transcript = Transcript::new(b"BatchedRangeProof");
60 transcript.append_message(b"commitments", bytes_of(&self.commitments));
61 transcript.append_message(b"bit-lengths", bytes_of(&self.bit_lengths));
62 transcript
63 }
64
65 fn new(
66 commitments: &[&PedersenCommitment],
67 amounts: &[u64],
68 bit_lengths: &[usize],
69 openings: &[&PedersenOpening],
70 ) -> Result<Self, ProofGenerationError> {
71 let num_commitments = commitments.len();
73 if num_commitments > MAX_COMMITMENTS
74 || num_commitments != amounts.len()
75 || num_commitments != bit_lengths.len()
76 || num_commitments != openings.len()
77 {
78 return Err(ProofGenerationError::IllegalCommitmentLength);
79 }
80
81 let mut pod_commitments = [pod::PedersenCommitment::zeroed(); MAX_COMMITMENTS];
82 for (i, commitment) in commitments.iter().enumerate() {
83 if commitment.get_point().is_identity() {
85 return Err(ProofGenerationError::InvalidCommitment);
86 }
87 pod_commitments[i] = pod::PedersenCommitment(commitment.to_bytes());
88 }
89
90 let mut pod_bit_lengths = [0; MAX_COMMITMENTS];
91 for (i, bit_length) in bit_lengths.iter().enumerate() {
92 pod_bit_lengths[i] = (*bit_length)
93 .try_into()
94 .map_err(|_| ProofGenerationError::IllegalAmountBitLength)?;
95 }
96
97 Ok(BatchedRangeProofContext {
98 commitments: pod_commitments,
99 bit_lengths: pod_bit_lengths,
100 })
101 }
102}
103
104#[cfg(not(target_os = "solana"))]
105impl TryInto<(Vec<PedersenCommitment>, Vec<usize>)> for BatchedRangeProofContext {
106 type Error = ProofVerificationError;
107
108 fn try_into(self) -> Result<(Vec<PedersenCommitment>, Vec<usize>), Self::Error> {
109 let commitments = self
110 .commitments
111 .into_iter()
112 .take_while(|commitment| *commitment != pod::PedersenCommitment::zeroed())
113 .map(|commitment| commitment.try_into())
114 .collect::<Result<Vec<PedersenCommitment>, _>>()
115 .map_err(|_| ProofVerificationError::ProofContext)?;
116
117 let bit_lengths: Vec<_> = self
118 .bit_lengths
119 .into_iter()
120 .take(commitments.len())
121 .map(|bit_length| bit_length as usize)
122 .collect();
123
124 Ok((commitments, bit_lengths))
125 }
126}