arcis_compiler/utils/zkp/range_proof/
mod.rs1use crate::{
4 core::{
5 circuits::boolean::{boolean_value::BooleanValue, byte::Byte},
6 global_value::{
7 curve_value::{CompressedCurveValue, CurveValue},
8 value::FieldValue,
9 },
10 },
11 traits::{GetBit, Invert, Reveal, Select, ToLeBytes},
12 utils::{
13 field::ScalarField,
14 zkp::{
15 generators::RangeProofGens,
16 inner_product::InnerProductProof,
17 pedersen::{Pedersen, PedersenOpening},
18 range_proof::batched_range_proof::MAX_SINGLE_BIT_LENGTH,
19 transcript::Transcript,
20 util::{self, UNIT_LEN},
21 },
22 },
23};
24use std::{iter, sync::LazyLock};
25use zk_elgamal_proof::encryption::pedersen::H;
26
27pub mod batched_range_proof;
28pub mod batched_range_proof_u128;
29pub mod batched_range_proof_u256;
30pub mod batched_range_proof_u64;
31
32#[allow(non_snake_case, dead_code)]
33#[derive(Debug, Clone)]
34pub struct RangeProof {
35 pub(crate) A: CompressedCurveValue, pub(crate) S: CompressedCurveValue, pub(crate) T_1: CompressedCurveValue, pub(crate) T_2: CompressedCurveValue, pub(crate) t_x: FieldValue<ScalarField>, pub(crate) t_x_blinding: FieldValue<ScalarField>, pub(crate) e_blinding: FieldValue<ScalarField>, pub(crate) ipp_proof: InnerProductProof, }
52
53#[allow(non_snake_case)]
54impl RangeProof {
55 pub fn new(
67 amounts: Vec<FieldValue<ScalarField>>,
68 bit_lengths: Vec<usize>,
69 openings: Vec<&PedersenOpening>,
70 transcript: &mut Transcript<BooleanValue>,
71 ) -> Self {
72 let m = amounts.len();
74 assert!(bit_lengths.len() == m && openings.len() == m);
75
76 assert!(bit_lengths
78 .iter()
79 .all(|bit_length| { *bit_length > 0 && *bit_length <= MAX_SINGLE_BIT_LENGTH }));
80
81 let nm: usize = bit_lengths.iter().sum();
83 assert!(nm.is_power_of_two());
84
85 let bp_gens = RangeProofGens::new(nm);
86
87 transcript.range_proof_domain_separator(nm as u64);
88
89 let a_blinding = FieldValue::<ScalarField>::random();
92 let arcis_H = CurveValue::from(*LazyLock::force(&H));
93 let mut A = a_blinding * arcis_H;
94
95 let mut gens_iter = bp_gens.G(nm).zip(bp_gens.H(nm));
96 for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
97 for j in 0..(*n_i) {
98 let (G_ij, H_ij) = gens_iter.next().unwrap();
99 let v_ij = amount_i.get_bit(j, false);
100 let mut point = -*H_ij;
101 point = v_ij.select(*G_ij, point);
103 A += point;
104 }
105 }
106 let A = A.reveal().compress();
107
108 let s_L = (0..nm)
110 .map(|_| FieldValue::<ScalarField>::random())
111 .collect::<Vec<FieldValue<ScalarField>>>();
112 let s_R = (0..nm)
113 .map(|_| FieldValue::<ScalarField>::random())
114 .collect::<Vec<FieldValue<ScalarField>>>();
115
116 let s_blinding = FieldValue::<ScalarField>::random();
119
120 let S = CurveValue::multiscalar_mul(
121 iter::once(&s_blinding)
122 .chain(s_L.iter())
123 .chain(s_R.iter())
124 .copied()
125 .collect::<Vec<FieldValue<ScalarField>>>(),
126 iter::once(&arcis_H)
127 .chain(bp_gens.G(nm))
128 .chain(bp_gens.H(nm))
129 .copied()
130 .collect::<Vec<CurveValue>>(),
131 )
132 .reveal()
133 .compress();
134
135 transcript.append_point(b"A", &A);
137 transcript.append_point(b"S", &S);
138
139 let y = transcript.challenge_scalar(b"y");
140 let z = transcript.challenge_scalar(b"z");
141
142 let mut l_poly = util::VecPoly1::zero(nm);
146 let mut r_poly = util::VecPoly1::zero(nm);
147
148 let mut i = 0;
149 let mut exp_z = z * z;
150 let mut exp_y = FieldValue::<ScalarField>::from(1);
151
152 for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
153 let mut exp_2 = FieldValue::<ScalarField>::from(1);
154
155 for j in 0..(*n_i) {
156 let a_L_j = FieldValue::<ScalarField>::from(amount_i.get_bit(j, false));
157 let a_R_j = a_L_j - FieldValue::<ScalarField>::from(1);
158
159 l_poly.0[i] = a_L_j - z;
160 l_poly.1[i] = s_L[i];
161 r_poly.0[i] = exp_y * (a_R_j + z) + exp_z * exp_2;
162 r_poly.1[i] = exp_y * s_R[i];
163
164 exp_y *= y;
165 exp_2 = exp_2 + exp_2;
166
167 i = i.checked_add(1).unwrap();
169 }
170 exp_z *= z;
171 }
172
173 let t_poly = l_poly.inner_product(&r_poly).unwrap();
175
176 let (T_1, t_1_blinding) = Pedersen::new(t_poly.1);
178 let (T_2, t_2_blinding) = Pedersen::new(t_poly.2);
179
180 let T_1 = T_1.get_point().reveal().compress();
181 let T_2 = T_2.get_point().reveal().compress();
182
183 transcript.append_point(b"T_1", &T_1);
184 transcript.append_point(b"T_2", &T_2);
185
186 let x = transcript.challenge_scalar(b"x");
188
189 let mut agg_opening = FieldValue::<ScalarField>::from(0);
191 let mut exp_z = z;
192 for opening in openings {
193 exp_z *= z;
194 agg_opening += exp_z * *opening.get_scalar();
195 }
196
197 let t_blinding_poly = util::Poly2(
198 agg_opening,
199 *t_1_blinding.get_scalar(),
200 *t_2_blinding.get_scalar(),
201 );
202
203 let t_x = t_poly.eval(x).reveal();
204 let t_x_blinding = t_blinding_poly.eval(x).reveal();
205
206 transcript.append_scalar(b"t_x", &t_x);
207 transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
208
209 let e_blinding = (a_blinding + s_blinding * x).reveal();
211
212 let l_vec = l_poly.eval(x);
214 let r_vec = r_poly.eval(x);
215
216 transcript.append_scalar(b"e_blinding", &e_blinding);
217
218 let w = transcript.challenge_scalar(b"w");
221 let Q = w * CurveValue::generator();
222
223 let G_factors = iter::repeat_n(FieldValue::<ScalarField>::from(1), nm)
224 .collect::<Vec<FieldValue<ScalarField>>>();
225 let H_factors = util::exp_iter(y.invert(true))
227 .take(nm)
228 .collect::<Vec<FieldValue<ScalarField>>>();
229
230 let _c = transcript.challenge_scalar(b"c");
232
233 let ipp_proof = InnerProductProof::new(
234 &Q,
235 &G_factors,
236 &H_factors,
237 bp_gens.G(nm).cloned().collect(),
238 bp_gens.H(nm).cloned().collect(),
239 l_vec,
240 r_vec,
241 transcript,
242 );
243
244 transcript.append_scalar(b"ipp_a", &ipp_proof.a);
246 transcript.append_scalar(b"ipp_b", &ipp_proof.b);
247 let _d = transcript.challenge_scalar(b"d");
248
249 RangeProof {
250 A,
251 S,
252 T_1,
253 T_2,
254 t_x,
255 t_x_blinding,
256 e_blinding,
257 ipp_proof,
258 }
259 }
260
261 pub fn to_bytes(&self) -> Vec<Byte<BooleanValue>> {
262 let mut buf = Vec::with_capacity(7 * UNIT_LEN + self.ipp_proof.serialized_size());
263 buf.extend_from_slice(&self.A.to_bytes());
264 buf.extend_from_slice(&self.S.to_bytes());
265 buf.extend_from_slice(&self.T_1.to_bytes());
266 buf.extend_from_slice(&self.T_2.to_bytes());
267 buf.extend_from_slice(&self.t_x.to_le_bytes());
268 buf.extend_from_slice(&self.t_x_blinding.to_le_bytes());
269 buf.extend_from_slice(&self.e_blinding.to_le_bytes());
270 buf.extend_from_slice(&self.ipp_proof.to_bytes());
271 buf
272 }
273}