1#![allow(non_snake_case)]
2
3use std::ops::{Add, Mul};
6use k256::{AffinePoint, ProjectivePoint, Scalar};
7use k256::elliptic_curve::ops::Invert;
8use k256::elliptic_curve::rand_core::{CryptoRng, RngCore};
9use merlin::Transcript;
10use serde::{Deserialize, Serialize};
11use crate::util::*;
12use crate::{circuit, transcript};
13use crate::circuit::{ArithmeticCircuit, PartitionType};
14
15#[derive(Clone, Debug)]
17pub struct Witness {
18 pub x: Scalar,
20 pub s: Scalar,
22 pub m: Vec<Scalar>,
24 pub digits: Vec<Scalar>,
26}
27
28#[derive(Clone, Debug)]
30pub struct Proof {
31 pub circuit_proof: circuit::Proof,
32 pub r: ProjectivePoint,
33}
34
35#[derive(Serialize, Deserialize, Clone, Debug)]
38pub struct SerializableProof {
39 pub circuit_proof: circuit::SerializableProof,
40 pub r: AffinePoint,
41}
42
43impl From<&SerializableProof> for Proof {
44 fn from(value: &SerializableProof) -> Self {
45 Proof {
46 circuit_proof: circuit::Proof::from(&value.circuit_proof),
47 r: ProjectivePoint::from(value.r),
48 }
49 }
50}
51
52impl From<&Proof> for SerializableProof {
53 fn from(value: &Proof) -> Self {
54 SerializableProof {
55 circuit_proof: circuit::SerializableProof::from(&value.circuit_proof),
56 r: value.r.to_affine(),
57 }
58 }
59}
60
61#[derive(Clone, Debug)]
64pub struct ReciprocalRangeProofProtocol {
65 pub dim_nd: usize,
67 pub dim_np: usize,
69
70 pub g: ProjectivePoint,
72
73 pub g_vec: Vec<ProjectivePoint>,
75 pub h_vec: Vec<ProjectivePoint>,
78
79 pub g_vec_: Vec<ProjectivePoint>,
82 pub h_vec_: Vec<ProjectivePoint>,
84}
85
86impl ReciprocalRangeProofProtocol {
87 pub fn commit_value(&self, x: &Scalar, s: &Scalar) -> ProjectivePoint {
89 self.g.mul(x).add(&self.h_vec[0].mul(s))
90 }
91
92 pub fn commit_poles(&self, r: &[Scalar], s: &Scalar) -> ProjectivePoint {
94 self.h_vec[0].mul(s).add(&vector_mul(&self.h_vec[9..], r))
95 }
96
97 pub fn verify(&self, commitment: &ProjectivePoint, proof: Proof, t: &mut Transcript) -> bool {
99 transcript::app_point(b"reciprocal_commitment", commitment, t);
100 let e = transcript::get_challenge(b"reciprocal_challenge", t);
101
102 let circuit = self.make_circuit(e);
103
104 let circuit_commitment = commitment.add(&proof.r);
105
106 circuit.verify(&[circuit_commitment], t, proof.circuit_proof)
107 }
108
109 pub fn prove<R>(&self, commitment: &ProjectivePoint, witness: Witness, t: &mut Transcript, rng: &mut R) -> Proof
111 where
112 R: RngCore + CryptoRng
113 {
114 transcript::app_point(b"reciprocal_commitment", commitment, t);
115 let e = transcript::get_challenge(b"reciprocal_challenge", t);
116
117 let r = (0..self.dim_nd).map(|i|
118 witness.digits[i].add(&e).invert().unwrap()
119 ).collect::<Vec<Scalar>>();
120
121 let r_blind = Scalar::generate_biased(rng);
122 let r_com = self.commit_poles(&r, &r_blind);
123
124 let mut v = vec![witness.x];
125 r.iter().for_each(|r_val| v.push(*r_val));
126
127 let w_l = witness.digits;
128 let w_r = r;
129 let w_o = witness.m;
130
131 let circuit = self.make_circuit(e);
132
133 let circuit_witness = circuit::Witness {
134 v: vec![v],
135 s_v: vec![witness.s.add(r_blind)],
136 w_l,
137 w_r,
138 w_o,
139 };
140
141 let circuit_commitment = circuit.commit(&circuit_witness.v[0], &circuit_witness.s_v[0]);
142 Proof {
143 circuit_proof: circuit.prove::<R>(&[circuit_commitment], circuit_witness, t, rng),
144 r: r_com,
145 }
146 }
147
148 #[inline(always)]
150 pub fn make_circuit(&self, e: Scalar) -> ArithmeticCircuit<impl Fn(PartitionType, usize) -> Option<usize> + '_>
151 {
152 let dim_nm = self.dim_nd;
153 let dim_no = self.dim_np;
154
155 let dim_nv = self.dim_nd + 1;
156 let dim_nl = dim_nv;
157 let dim_nw = self.dim_nd * 2 + self.dim_np;
158
159 let a_m = vec![Scalar::ONE; dim_nm];
160
161 let mut W_m = vec![vec![Scalar::ZERO; dim_nw]; dim_nm];
162 (0..dim_nm).for_each(|i| W_m[i][i + dim_nm] = minus(&e));
163
164 let a_l = vec![Scalar::ZERO; dim_nl];
165 let base = Scalar::from(self.dim_np as u32);
166
167 let mut W_l = vec![vec![Scalar::ZERO; dim_nw]; dim_nl];
168
169 (0..dim_nm).for_each(|i| W_l[0][i] = minus(&pow(&base, i)));
171
172 (0..dim_nm).for_each(|i|
174 (0..dim_nm).for_each(|j| W_l[i + 1][j + dim_nm] = Scalar::ONE)
175 );
176
177 (0..dim_nm).for_each(|i| W_l[i + 1][i + dim_nm] = Scalar::ZERO);
178
179 (0..dim_nm).for_each(|i|
180 (0..dim_no).for_each(|j|
181 W_l[i + 1][j + 2 * dim_nm] = minus(&(e.add(Scalar::from(j as u32)).invert_vartime().unwrap()))
182 )
183 );
184
185 let partition = |typ: PartitionType, index: usize| -> Option<usize>{
187 if typ == PartitionType::LL && index < self.dim_np {
188 Some(index)
189 } else {
190 None
191 }
192 };
193
194 ArithmeticCircuit {
195 dim_nm,
196 dim_no,
197 k: 1,
198 dim_nl,
199 dim_nv,
200 dim_nw,
201 g: self.g,
202 g_vec: self.g_vec.clone(),
203 h_vec: self.h_vec.clone(),
204 W_m,
205 W_l,
206 a_m,
207 a_l,
208 f_l: true,
209 f_m: false,
210 g_vec_: self.g_vec_.clone(),
211 h_vec_: self.h_vec_.clone(),
212 partition,
213 }
214 }
215}
216
217