solana_zk_token_sdk/instruction/batched_range_proof/
mod.rspub mod batched_range_proof_u128;
pub mod batched_range_proof_u256;
pub mod batched_range_proof_u64;
use crate::zk_token_elgamal::pod;
#[cfg(not(target_os = "solana"))]
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::{ProofGenerationError, ProofVerificationError},
},
bytemuck::{bytes_of, Zeroable},
curve25519_dalek::traits::IsIdentity,
merlin::Transcript,
std::convert::TryInto,
};
const MAX_COMMITMENTS: usize = 8;
#[cfg(not(target_os = "solana"))]
const MAX_SINGLE_BIT_LENGTH: usize = 128;
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
#[repr(C)]
pub struct BatchedRangeProofContext {
pub commitments: [pod::PedersenCommitment; MAX_COMMITMENTS],
pub bit_lengths: [u8; MAX_COMMITMENTS],
}
#[allow(non_snake_case)]
#[cfg(not(target_os = "solana"))]
impl BatchedRangeProofContext {
fn new_transcript(&self) -> Transcript {
let mut transcript = Transcript::new(b"BatchedRangeProof");
transcript.append_message(b"commitments", bytes_of(&self.commitments));
transcript.append_message(b"bit-lengths", bytes_of(&self.bit_lengths));
transcript
}
fn new(
commitments: &[&PedersenCommitment],
amounts: &[u64],
bit_lengths: &[usize],
openings: &[&PedersenOpening],
) -> Result<Self, ProofGenerationError> {
let num_commitments = commitments.len();
if num_commitments > MAX_COMMITMENTS
|| num_commitments != amounts.len()
|| num_commitments != bit_lengths.len()
|| num_commitments != openings.len()
{
return Err(ProofGenerationError::IllegalCommitmentLength);
}
let mut pod_commitments = [pod::PedersenCommitment::zeroed(); MAX_COMMITMENTS];
for (i, commitment) in commitments.iter().enumerate() {
if commitment.get_point().is_identity() {
return Err(ProofGenerationError::InvalidCommitment);
}
pod_commitments[i] = pod::PedersenCommitment(commitment.to_bytes());
}
let mut pod_bit_lengths = [0; MAX_COMMITMENTS];
for (i, bit_length) in bit_lengths.iter().enumerate() {
pod_bit_lengths[i] = (*bit_length)
.try_into()
.map_err(|_| ProofGenerationError::IllegalAmountBitLength)?;
}
Ok(BatchedRangeProofContext {
commitments: pod_commitments,
bit_lengths: pod_bit_lengths,
})
}
}
#[cfg(not(target_os = "solana"))]
impl TryInto<(Vec<PedersenCommitment>, Vec<usize>)> for BatchedRangeProofContext {
type Error = ProofVerificationError;
fn try_into(self) -> Result<(Vec<PedersenCommitment>, Vec<usize>), Self::Error> {
let commitments = self
.commitments
.into_iter()
.take_while(|commitment| *commitment != pod::PedersenCommitment::zeroed())
.map(|commitment| commitment.try_into())
.collect::<Result<Vec<PedersenCommitment>, _>>()
.map_err(|_| ProofVerificationError::ProofContext)?;
let bit_lengths: Vec<_> = self
.bit_lengths
.into_iter()
.take(commitments.len())
.map(|bit_length| bit_length as usize)
.collect();
Ok((commitments, bit_lengths))
}
}