solana_zk_token_sdk/zk_token_elgamal/pod/
range_proof.rs

1//! Plain Old Data types for range proofs.
2
3#[cfg(not(target_os = "solana"))]
4use crate::{
5    range_proof::{self as decoded, errors::RangeProofVerificationError},
6    UNIT_LEN,
7};
8use {
9    crate::{RISTRETTO_POINT_LEN, SCALAR_LEN},
10    bytemuck::{Pod, Zeroable},
11};
12
13/// Byte length of a range proof excluding the inner-product proof component
14const RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN: usize = 5 * RISTRETTO_POINT_LEN + 2 * SCALAR_LEN;
15
16/// Byte length of an inner-product proof for a vector of length 64
17const INNER_PRODUCT_PROOF_U64_LEN: usize = 448;
18
19/// Byte length of a range proof for an unsigned 64-bit number
20const RANGE_PROOF_U64_LEN: usize =
21    INNER_PRODUCT_PROOF_U64_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
22
23/// Byte length of an inner-product proof for a vector of length 128
24const INNER_PRODUCT_PROOF_U128_LEN: usize = 512;
25
26/// Byte length of a range proof for an unsigned 128-bit number
27const RANGE_PROOF_U128_LEN: usize =
28    INNER_PRODUCT_PROOF_U128_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
29
30/// Byte length of an inner-product proof for a vector of length 256
31const INNER_PRODUCT_PROOF_U256_LEN: usize = 576;
32
33/// Byte length of a range proof for an unsigned 256-bit number
34const RANGE_PROOF_U256_LEN: usize =
35    INNER_PRODUCT_PROOF_U256_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
36
37/// The `RangeProof` type as a `Pod` restricted to proofs on 64-bit numbers.
38#[derive(Clone, Copy)]
39#[repr(transparent)]
40pub struct RangeProofU64(pub [u8; RANGE_PROOF_U64_LEN]);
41
42#[cfg(not(target_os = "solana"))]
43impl TryFrom<decoded::RangeProof> for RangeProofU64 {
44    type Error = RangeProofVerificationError;
45
46    fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
47        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U64_LEN {
48            return Err(RangeProofVerificationError::Deserialization);
49        }
50
51        let mut buf = [0_u8; RANGE_PROOF_U64_LEN];
52        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
53        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U64_LEN]
54            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
55        Ok(RangeProofU64(buf))
56    }
57}
58
59#[cfg(not(target_os = "solana"))]
60impl TryFrom<RangeProofU64> for decoded::RangeProof {
61    type Error = RangeProofVerificationError;
62
63    fn try_from(pod_proof: RangeProofU64) -> Result<Self, Self::Error> {
64        Self::from_bytes(&pod_proof.0)
65    }
66}
67
68/// The `RangeProof` type as a `Pod` restricted to proofs on 128-bit numbers.
69#[derive(Clone, Copy)]
70#[repr(transparent)]
71pub struct RangeProofU128(pub [u8; RANGE_PROOF_U128_LEN]);
72
73#[cfg(not(target_os = "solana"))]
74impl TryFrom<decoded::RangeProof> for RangeProofU128 {
75    type Error = RangeProofVerificationError;
76
77    fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
78        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U128_LEN {
79            return Err(RangeProofVerificationError::Deserialization);
80        }
81
82        let mut buf = [0_u8; RANGE_PROOF_U128_LEN];
83        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
84        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U128_LEN]
85            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
86        Ok(RangeProofU128(buf))
87    }
88}
89
90#[cfg(not(target_os = "solana"))]
91impl TryFrom<RangeProofU128> for decoded::RangeProof {
92    type Error = RangeProofVerificationError;
93
94    fn try_from(pod_proof: RangeProofU128) -> Result<Self, Self::Error> {
95        Self::from_bytes(&pod_proof.0)
96    }
97}
98
99/// The `RangeProof` type as a `Pod` restricted to proofs on 256-bit numbers.
100#[derive(Clone, Copy)]
101#[repr(transparent)]
102pub struct RangeProofU256(pub [u8; RANGE_PROOF_U256_LEN]);
103
104#[cfg(not(target_os = "solana"))]
105impl TryFrom<decoded::RangeProof> for RangeProofU256 {
106    type Error = RangeProofVerificationError;
107
108    fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
109        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U256_LEN {
110            return Err(RangeProofVerificationError::Deserialization);
111        }
112
113        let mut buf = [0_u8; RANGE_PROOF_U256_LEN];
114        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
115        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U256_LEN]
116            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
117        Ok(RangeProofU256(buf))
118    }
119}
120
121#[cfg(not(target_os = "solana"))]
122impl TryFrom<RangeProofU256> for decoded::RangeProof {
123    type Error = RangeProofVerificationError;
124
125    fn try_from(pod_proof: RangeProofU256) -> Result<Self, Self::Error> {
126        Self::from_bytes(&pod_proof.0)
127    }
128}
129
130#[cfg(not(target_os = "solana"))]
131fn copy_range_proof_modulo_inner_product_proof(proof: &decoded::RangeProof, buf: &mut [u8]) {
132    let mut chunks = buf.chunks_mut(UNIT_LEN);
133    chunks.next().unwrap().copy_from_slice(proof.A.as_bytes());
134    chunks.next().unwrap().copy_from_slice(proof.S.as_bytes());
135    chunks.next().unwrap().copy_from_slice(proof.T_1.as_bytes());
136    chunks.next().unwrap().copy_from_slice(proof.T_2.as_bytes());
137    chunks.next().unwrap().copy_from_slice(proof.t_x.as_bytes());
138    chunks
139        .next()
140        .unwrap()
141        .copy_from_slice(proof.t_x_blinding.as_bytes());
142    chunks
143        .next()
144        .unwrap()
145        .copy_from_slice(proof.e_blinding.as_bytes());
146}
147
148// The range proof pod types are wrappers for byte arrays, which are both `Pod` and `Zeroable`. However,
149// the marker traits `bytemuck::Pod` and `bytemuck::Zeroable` can only be derived for power-of-two
150// length byte arrays. Directly implement these traits for the range proof pod types.
151unsafe impl Zeroable for RangeProofU64 {}
152unsafe impl Pod for RangeProofU64 {}
153
154unsafe impl Zeroable for RangeProofU128 {}
155unsafe impl Pod for RangeProofU128 {}
156
157unsafe impl Zeroable for RangeProofU256 {}
158unsafe impl Pod for RangeProofU256 {}