solana_zk_token_sdk/instruction/
range_proof.rs1#[cfg(not(target_os = "solana"))]
8use {
9 crate::{
10 encryption::pedersen::{PedersenCommitment, PedersenOpening},
11 errors::{ProofGenerationError, ProofVerificationError},
12 range_proof::RangeProof,
13 transcript::TranscriptProtocol,
14 },
15 merlin::Transcript,
16 std::convert::TryInto,
17};
18use {
19 crate::{
20 instruction::{ProofType, ZkProofData},
21 zk_token_elgamal::pod,
22 },
23 bytemuck_derive::{Pod, Zeroable},
24};
25
26#[derive(Clone, Copy, Pod, Zeroable)]
28#[repr(C)]
29pub struct RangeProofContext {
30 pub commitment: pod::PedersenCommitment, }
32
33#[derive(Clone, Copy, Pod, Zeroable)]
38#[repr(C)]
39pub struct RangeProofU64Data {
40 pub context: RangeProofContext,
42
43 pub proof: pod::RangeProofU64,
45}
46
47#[cfg(not(target_os = "solana"))]
48impl RangeProofU64Data {
49 pub fn new(
50 commitment: &PedersenCommitment,
51 amount: u64,
52 opening: &PedersenOpening,
53 ) -> Result<Self, ProofGenerationError> {
54 let pod_commitment = pod::PedersenCommitment(commitment.to_bytes());
55
56 let context = RangeProofContext {
57 commitment: pod_commitment,
58 };
59
60 let mut transcript = context.new_transcript();
61
62 let bit_size = usize::try_from(u64::BITS).unwrap();
66
67 let proof = RangeProof::new(vec![amount], vec![bit_size], vec![opening], &mut transcript)?
68 .try_into()
69 .map_err(|_| ProofGenerationError::ProofLength)?;
70
71 Ok(Self { context, proof })
72 }
73}
74
75impl ZkProofData<RangeProofContext> for RangeProofU64Data {
76 const PROOF_TYPE: ProofType = ProofType::RangeProofU64;
77
78 fn context_data(&self) -> &RangeProofContext {
79 &self.context
80 }
81
82 #[cfg(not(target_os = "solana"))]
83 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
84 let mut transcript = self.context_data().new_transcript();
85 let commitment = self.context.commitment.try_into()?;
86 let proof: RangeProof = self.proof.try_into()?;
87
88 let bit_size = usize::try_from(u64::BITS).unwrap();
89 proof
90 .verify(vec![&commitment], vec![bit_size], &mut transcript)
91 .map_err(|e| e.into())
92 }
93}
94
95#[allow(non_snake_case)]
96#[cfg(not(target_os = "solana"))]
97impl RangeProofContext {
98 fn new_transcript(&self) -> Transcript {
99 let mut transcript = Transcript::new(b"RangeProof");
100 transcript.append_commitment(b"commitment", &self.commitment);
101 transcript
102 }
103}
104
105#[cfg(test)]
106mod test {
107 use {super::*, crate::encryption::pedersen::Pedersen};
108
109 #[test]
110 fn test_range_proof_64_instruction_correctness() {
111 let amount = u64::MAX;
112 let (commitment, opening) = Pedersen::new(amount);
113
114 let proof_data = RangeProofU64Data::new(&commitment, amount, &opening).unwrap();
115 assert!(proof_data.verify_proof().is_ok());
116 }
117}