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 transcript::Transcript,
19 util::{self, UNIT_LEN},
20 },
21 },
22};
23use std::{iter, sync::LazyLock};
24use zk_elgamal_proof::encryption::pedersen::H;
25
26pub mod batched_range_proof;
27pub mod batched_range_proof_u128;
28pub mod batched_range_proof_u64;
29
30#[allow(non_snake_case, dead_code)]
31#[derive(Debug, Clone)]
32pub struct RangeProof {
33 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, }
50
51#[allow(non_snake_case)]
52impl RangeProof {
53 pub fn new(
65 amounts: Vec<FieldValue<ScalarField>>,
66 bit_lengths: Vec<usize>,
67 openings: Vec<&PedersenOpening>,
68 transcript: &mut Transcript<BooleanValue>,
69 ) -> Self {
70 let m = amounts.len();
72 assert!(bit_lengths.len() == m && openings.len() == m);
73
74 assert!(bit_lengths
76 .iter()
77 .all(|bit_length| { *bit_length > 0 && *bit_length <= u64::BITS as usize }));
78
79 let nm: usize = bit_lengths.iter().sum();
81 assert!(nm.is_power_of_two());
82
83 let bp_gens = RangeProofGens::new(nm);
84
85 transcript.range_proof_domain_separator(nm as u64);
86
87 let a_blinding = FieldValue::<ScalarField>::random();
90 let arcis_H = CurveValue::from(*LazyLock::force(&H));
91 let mut A = a_blinding * arcis_H;
92
93 let mut gens_iter = bp_gens.G(nm).zip(bp_gens.H(nm));
94 for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
95 for j in 0..(*n_i) {
96 let (G_ij, H_ij) = gens_iter.next().unwrap();
97 let v_ij = amount_i.get_bit(j, false);
98 let mut point = -*H_ij;
99 point = v_ij.select(*G_ij, point);
101 A += point;
102 }
103 }
104 let A = A.reveal().compress();
105
106 let s_L = (0..nm)
108 .map(|_| FieldValue::<ScalarField>::random())
109 .collect::<Vec<FieldValue<ScalarField>>>();
110 let s_R = (0..nm)
111 .map(|_| FieldValue::<ScalarField>::random())
112 .collect::<Vec<FieldValue<ScalarField>>>();
113
114 let s_blinding = FieldValue::<ScalarField>::random();
117
118 let S = CurveValue::multiscalar_mul(
119 iter::once(&s_blinding)
120 .chain(s_L.iter())
121 .chain(s_R.iter())
122 .copied()
123 .collect::<Vec<FieldValue<ScalarField>>>(),
124 iter::once(&arcis_H)
125 .chain(bp_gens.G(nm))
126 .chain(bp_gens.H(nm))
127 .copied()
128 .collect::<Vec<CurveValue>>(),
129 )
130 .reveal()
131 .compress();
132
133 transcript.append_point(b"A", &A);
135 transcript.append_point(b"S", &S);
136
137 let y = transcript.challenge_scalar(b"y");
138 let z = transcript.challenge_scalar(b"z");
139
140 let mut l_poly = util::VecPoly1::zero(nm);
144 let mut r_poly = util::VecPoly1::zero(nm);
145
146 let mut i = 0;
147 let mut exp_z = z * z;
148 let mut exp_y = FieldValue::<ScalarField>::from(1);
149
150 for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
151 let mut exp_2 = FieldValue::<ScalarField>::from(1);
152
153 for j in 0..(*n_i) {
154 let a_L_j = FieldValue::<ScalarField>::from(amount_i.get_bit(j, false));
155 let a_R_j = a_L_j - FieldValue::<ScalarField>::from(1);
156
157 l_poly.0[i] = a_L_j - z;
158 l_poly.1[i] = s_L[i];
159 r_poly.0[i] = exp_y * (a_R_j + z) + exp_z * exp_2;
160 r_poly.1[i] = exp_y * s_R[i];
161
162 exp_y *= y;
163 exp_2 = exp_2 + exp_2;
164
165 i = i.checked_add(1).unwrap();
167 }
168 exp_z *= z;
169 }
170
171 let t_poly = l_poly.inner_product(&r_poly).unwrap();
173
174 let (T_1, t_1_blinding) = Pedersen::new(t_poly.1);
176 let (T_2, t_2_blinding) = Pedersen::new(t_poly.2);
177
178 let T_1 = T_1.get_point().reveal().compress();
179 let T_2 = T_2.get_point().reveal().compress();
180
181 transcript.append_point(b"T_1", &T_1);
182 transcript.append_point(b"T_2", &T_2);
183
184 let x = transcript.challenge_scalar(b"x");
186
187 let mut agg_opening = FieldValue::<ScalarField>::from(0);
189 let mut exp_z = z;
190 for opening in openings {
191 exp_z *= z;
192 agg_opening += exp_z * *opening.get_scalar();
193 }
194
195 let t_blinding_poly = util::Poly2(
196 agg_opening,
197 *t_1_blinding.get_scalar(),
198 *t_2_blinding.get_scalar(),
199 );
200
201 let t_x = t_poly.eval(x).reveal();
202 let t_x_blinding = t_blinding_poly.eval(x).reveal();
203
204 transcript.append_scalar(b"t_x", &t_x);
205 transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
206
207 let e_blinding = (a_blinding + s_blinding * x).reveal();
209
210 let l_vec = l_poly.eval(x);
212 let r_vec = r_poly.eval(x);
213
214 transcript.append_scalar(b"e_blinding", &e_blinding);
215
216 let w = transcript.challenge_scalar(b"w");
219 let Q = w * CurveValue::generator();
220
221 let G_factors = iter::repeat_n(FieldValue::<ScalarField>::from(1), nm)
222 .collect::<Vec<FieldValue<ScalarField>>>();
223 let H_factors = util::exp_iter(y.invert(true))
225 .take(nm)
226 .collect::<Vec<FieldValue<ScalarField>>>();
227
228 let _c = transcript.challenge_scalar(b"c");
230
231 let ipp_proof = InnerProductProof::new(
232 &Q,
233 &G_factors,
234 &H_factors,
235 bp_gens.G(nm).cloned().collect(),
236 bp_gens.H(nm).cloned().collect(),
237 l_vec,
238 r_vec,
239 transcript,
240 );
241
242 transcript.append_scalar(b"ipp_a", &ipp_proof.a);
244 transcript.append_scalar(b"ipp_b", &ipp_proof.b);
245 let _d = transcript.challenge_scalar(b"d");
246
247 RangeProof {
248 A,
249 S,
250 T_1,
251 T_2,
252 t_x,
253 t_x_blinding,
254 e_blinding,
255 ipp_proof,
256 }
257 }
258
259 pub fn to_bytes(&self) -> Vec<Byte<BooleanValue>> {
260 let mut buf = Vec::with_capacity(7 * UNIT_LEN + self.ipp_proof.serialized_size());
261 buf.extend_from_slice(&self.A.to_bytes());
262 buf.extend_from_slice(&self.S.to_bytes());
263 buf.extend_from_slice(&self.T_1.to_bytes());
264 buf.extend_from_slice(&self.T_2.to_bytes());
265 buf.extend_from_slice(&self.t_x.to_le_bytes());
266 buf.extend_from_slice(&self.t_x_blinding.to_le_bytes());
267 buf.extend_from_slice(&self.e_blinding.to_le_bytes());
268 buf.extend_from_slice(&self.ipp_proof.to_bytes());
269 buf
270 }
271}