1use curve25519_dalek::ristretto::RistrettoBasepointTable;
32use curve25519_dalek::ristretto::RistrettoPoint;
33use curve25519_dalek::scalar::Scalar;
34use curve25519_dalek::traits::IsIdentity;
35
36use lox_zkp::CompactProof;
37use lox_zkp::ProofError;
38use lox_zkp::Transcript;
39
40use serde::{Deserialize, Serialize};
41use serde_with::serde_as;
42
43use std::collections::HashMap;
44
45use super::super::cred;
46#[cfg(feature = "bridgeauth")]
47use super::super::dup_filter::SeenType;
48use super::super::migration_table;
49use super::super::scalar_u32;
50#[cfg(feature = "bridgeauth")]
51use super::super::BridgeAuth;
52use super::super::IssuerPubKey;
53use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
54
55use super::errors::CredentialError;
56
57pub const MIN_TRUST_LEVEL: u32 = 3;
60
61#[derive(Serialize, Deserialize)]
62pub struct Request {
63 P: RistrettoPoint,
65 id: Scalar,
66 CBucket: RistrettoPoint,
67 level: Scalar,
68 CSince: RistrettoPoint,
69 CInvRemain: RistrettoPoint,
70 CBlockages: RistrettoPoint,
71 CQ: RistrettoPoint,
72
73 D: RistrettoPoint,
75 EncBucket: (RistrettoPoint, RistrettoPoint),
76
77 piUser: CompactProof,
79}
80
81#[derive(Debug, Serialize, Deserialize)]
82pub struct State {
83 d: Scalar,
84 D: RistrettoPoint,
85 EncBucket: (RistrettoPoint, RistrettoPoint),
86 id: Scalar,
87 bucket: Scalar,
88}
89
90#[serde_as]
91#[derive(Serialize, Deserialize, Debug)]
92pub struct Response {
93 Pk: RistrettoPoint,
95 EncQk: (RistrettoPoint, RistrettoPoint),
96
97 #[serde_as(as = "Vec<(_,[_; migration_table::ENC_MIGRATION_BYTES])>")]
101 enc_migration_table: HashMap<[u8; 16], [u8; migration_table::ENC_MIGRATION_BYTES]>,
102}
103
104define_proof! {
105 requestproof,
106 "Check Blockage Request",
107 (bucket, since, invremain, blockages, zbucket, zsince, zinvremain,
108 zblockages, negzQ,
109 d, ebucket),
110 (P, CBucket, CSince, CInvRemain, CBlockages, V, Xbucket, Xsince,
111 Xinvremain, Xblockages,
112 D, EncBucket0, EncBucket1),
113 (A, B):
114 CBucket = (bucket*P + zbucket*A),
116 CSince = (since*P + zsince*A),
117 CInvRemain = (invremain*P + zinvremain*A),
118 CBlockages = (blockages*P + zblockages*A),
119 V = (zbucket*Xbucket + zsince*Xsince + zinvremain*Xinvremain
120 + zblockages*Xblockages + negzQ*A),
121 D = (d*B),
123 EncBucket0 = (ebucket*B),
124 EncBucket1 = (bucket*B + ebucket*D)
125}
126
127pub fn request(
128 lox_cred: &cred::Lox,
129 lox_pub: &IssuerPubKey,
130) -> Result<(Request, State), CredentialError> {
131 let A: &RistrettoPoint = &CMZ_A;
132 let B: &RistrettoPoint = &CMZ_B;
133 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
134 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
135
136 let level: u32 = match scalar_u32(&lox_cred.trust_level) {
139 Some(v) => v,
140 None => {
141 return Err(CredentialError::InvalidField(
142 String::from("trust_level"),
143 String::from("could not be converted to u32"),
144 ))
145 }
146 };
147 if level < MIN_TRUST_LEVEL {
148 return Err(CredentialError::InvalidField(
149 String::from("trust_level"),
150 format!("level {:?} not in range", level),
151 ));
152 }
153
154 let mut rng = rand::thread_rng();
158 let t = Scalar::random(&mut rng);
159 let P = t * lox_cred.P;
160 let Q = t * lox_cred.Q;
161
162 let zbucket = Scalar::random(&mut rng);
164 let zsince = Scalar::random(&mut rng);
165 let zinvremain = Scalar::random(&mut rng);
166 let zblockages = Scalar::random(&mut rng);
167 let CBucket = lox_cred.bucket * P + &zbucket * Atable;
168 let CSince = lox_cred.level_since * P + &zsince * Atable;
169 let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
170 let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
171
172 let negzQ = Scalar::random(&mut rng);
177 let CQ = Q - &negzQ * Atable;
178
179 let V = zbucket * lox_pub.X[2]
181 + zsince * lox_pub.X[4]
182 + zinvremain * lox_pub.X[5]
183 + zblockages * lox_pub.X[6]
184 + &negzQ * Atable;
185
186 let d = Scalar::random(&mut rng);
190 let D = &d * Btable;
191
192 let ebucket = Scalar::random(&mut rng);
195 let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
196
197 let mut transcript = Transcript::new(b"check blockage request");
199 let piUser = requestproof::prove_compact(
200 &mut transcript,
201 requestproof::ProveAssignments {
202 A,
203 B,
204 P: &P,
205 CBucket: &CBucket,
206 CSince: &CSince,
207 CInvRemain: &CInvRemain,
208 CBlockages: &CBlockages,
209 V: &V,
210 Xbucket: &lox_pub.X[2],
211 Xsince: &lox_pub.X[4],
212 Xinvremain: &lox_pub.X[5],
213 Xblockages: &lox_pub.X[6],
214 D: &D,
215 EncBucket0: &EncBucket.0,
216 EncBucket1: &EncBucket.1,
217 bucket: &lox_cred.bucket,
218 since: &lox_cred.level_since,
219 invremain: &lox_cred.invites_remaining,
220 blockages: &lox_cred.blockages,
221 zbucket: &zbucket,
222 zsince: &zsince,
223 zinvremain: &zinvremain,
224 zblockages: &zblockages,
225 negzQ: &negzQ,
226 d: &d,
227 ebucket: &ebucket,
228 },
229 )
230 .0;
231
232 Ok((
233 Request {
234 P,
235 id: lox_cred.id,
236 CBucket,
237 level: lox_cred.trust_level,
238 CSince,
239 CInvRemain,
240 CBlockages,
241 CQ,
242 D,
243 EncBucket,
244 piUser,
245 },
246 State {
247 d,
248 D,
249 EncBucket,
250 id: lox_cred.id,
251 bucket: lox_cred.bucket,
252 },
253 ))
254}
255
256#[cfg(feature = "bridgeauth")]
257impl BridgeAuth {
258 pub fn handle_check_blockage(&mut self, req: Request) -> Result<Response, ProofError> {
260 let A: &RistrettoPoint = &CMZ_A;
261 let B: &RistrettoPoint = &CMZ_B;
262 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
263
264 let level: u32 = match scalar_u32(&req.level) {
265 Some(v) => v,
266 None => return Err(ProofError::VerificationFailure),
267 };
268
269 if req.P.is_identity() || level < MIN_TRUST_LEVEL {
270 return Err(ProofError::VerificationFailure);
271 }
272
273 let Vprime =
277 (self.lox_priv.x[0] + self.lox_priv.x[1] * req.id + self.lox_priv.x[3] * req.level)
278 * req.P
279 + self.lox_priv.x[2] * req.CBucket
280 + self.lox_priv.x[4] * req.CSince
281 + self.lox_priv.x[5] * req.CInvRemain
282 + self.lox_priv.x[6] * req.CBlockages
283 - req.CQ;
284
285 let mut transcript = Transcript::new(b"check blockage request");
287 requestproof::verify_compact(
288 &req.piUser,
289 &mut transcript,
290 requestproof::VerifyAssignments {
291 A: &A.compress(),
292 B: &B.compress(),
293 P: &req.P.compress(),
294 CBucket: &req.CBucket.compress(),
295 CSince: &req.CSince.compress(),
296 CInvRemain: &req.CInvRemain.compress(),
297 CBlockages: &req.CBlockages.compress(),
298 V: &Vprime.compress(),
299 Xbucket: &self.lox_pub.X[2].compress(),
300 Xsince: &self.lox_pub.X[4].compress(),
301 Xinvremain: &self.lox_pub.X[5].compress(),
302 Xblockages: &self.lox_pub.X[6].compress(),
303 D: &req.D.compress(),
304 EncBucket0: &req.EncBucket.0.compress(),
305 EncBucket1: &req.EncBucket.1.compress(),
306 },
307 )?;
308
309 if self.id_filter.check(&req.id) == SeenType::Seen {
313 return Err(ProofError::VerificationFailure);
314 }
315
316 let mut rng = rand::thread_rng();
321 let b = Scalar::random(&mut rng);
322 let Pk = &b * Btable;
323 let Pktable = RistrettoBasepointTable::create(&Pk);
324 let Qid = &(self.migrationkey_priv.x[0] + self.migrationkey_priv.x[1] * req.id) * &Pktable;
325
326 let s = Scalar::random(&mut rng);
328 let EncQkid = (&s * Btable, Qid + s * req.D);
329
330 let tbucket = self.migrationkey_priv.x[2] * b;
333 let EncQkBucket = (tbucket * req.EncBucket.0, tbucket * req.EncBucket.1);
334
335 let EncQk = (EncQkid.0 + EncQkBucket.0, EncQkid.1 + EncQkBucket.1);
336
337 Ok(Response {
338 Pk,
339 EncQk,
340 enc_migration_table: self.blockage_migration_table.encrypt_table(
341 &req.id,
342 &self.bridge_table,
343 &Pktable,
344 &self.migration_priv,
345 &self.migrationkey_priv,
346 ),
347 })
348 }
349}
350
351pub fn handle_response(state: State, resp: Response) -> Result<cred::Migration, ProofError> {
357 if resp.Pk.is_identity() {
358 return Err(ProofError::VerificationFailure);
359 }
360
361 let Qk = resp.EncQk.1 - (state.d * resp.EncQk.0);
363
364 match migration_table::decrypt_cred(
366 &Qk,
367 &state.id,
368 &state.bucket,
369 migration_table::MigrationType::Blockage,
370 &resp.enc_migration_table,
371 ) {
372 Some(m) => Ok(m),
373 None => Err(ProofError::VerificationFailure),
374 }
375}