|
1 | | -use std::collections::HashMap; |
2 | | - |
3 | | -use ff::Field; |
| 1 | +use ff::{Field, PrimeField}; |
4 | 2 | use group::prime::PrimeGroup; |
5 | 3 | use rand::rngs::OsRng; |
6 | 4 | use rand::RngCore; |
7 | 5 |
|
| 6 | +use crate::codec::Shake128DuplexSponge; |
8 | 7 | use crate::fiat_shamir::Nizk; |
9 | | -use crate::{ |
10 | | - codec::Shake128DuplexSponge, linear_relation::CanonicalLinearRelation, |
11 | | - schnorr_protocol::SchnorrProof, |
12 | | -}; |
13 | | -use ff::PrimeField; |
| 8 | +use crate::linear_relation::CanonicalLinearRelation; |
| 9 | +use crate::schnorr_protocol::SchnorrProof; |
14 | 10 |
|
15 | 11 | use crate::linear_relation::{msm_pr, LinearRelation}; |
16 | 12 |
|
@@ -155,7 +151,10 @@ pub fn twisted_pedersen_commitment<G: PrimeGroup, R: RngCore>( |
155 | 151 | let [var_x, var_r] = relation.allocate_scalars(); |
156 | 152 | let [var_G, var_H] = relation.allocate_elements(); |
157 | 153 |
|
158 | | - relation.allocate_eq((var_x * G::Scalar::from(3)) * var_G + (var_r * G::Scalar::from(2) + G::Scalar::from(3)) * var_H); |
| 154 | + relation.allocate_eq( |
| 155 | + (var_x * G::Scalar::from(3)) * var_G |
| 156 | + + (var_r * G::Scalar::from(2) + G::Scalar::from(3)) * var_H, |
| 157 | + ); |
159 | 158 |
|
160 | 159 | relation.set_elements([(var_H, H), (var_G, G::generator())]); |
161 | 160 | relation.compute_image(&[x, r]).unwrap(); |
@@ -202,7 +201,6 @@ pub fn pedersen_commitment_dleq<G: PrimeGroup, R: RngCore>( |
202 | 201 | (instance, witness_vec) |
203 | 202 | } |
204 | 203 |
|
205 | | - |
206 | 204 | /// LinearMap for knowledge of an opening for use in a BBS commitment. |
207 | 205 | // BBS message length is 3 |
208 | 206 | #[allow(non_snake_case)] |
@@ -270,8 +268,7 @@ pub fn weird_linear_combination<G: PrimeGroup, R: RngCore>( |
270 | 268 | let A = sigma__lr.allocate_element(); |
271 | 269 | let var_B = sigma__lr.allocate_element(); |
272 | 270 |
|
273 | | - let sigma__eq1 = |
274 | | - sigma__lr.allocate_eq(A * G::Scalar::from(1) + gen__disj1_x_r_var * var_B); |
| 271 | + let sigma__eq1 = sigma__lr.allocate_eq(A * G::Scalar::from(1) + gen__disj1_x_r_var * var_B); |
275 | 272 |
|
276 | 273 | // Set the group elements |
277 | 274 | sigma__lr.set_elements([(A, G::generator()), (var_B, B)]); |
@@ -327,34 +324,92 @@ fn subtractions_with_shift<G: PrimeGroup, R: RngCore>( |
327 | 324 | (instance, witness) |
328 | 325 | } |
329 | 326 |
|
| 327 | +/// LinearMap for the failing relation from cmz wallet test: W.balance = N.balance + I.price + fee |
| 328 | +#[allow(non_snake_case)] |
| 329 | +fn cmz_wallet_spend_relation<G: PrimeGroup, R: RngCore>( |
| 330 | + mut rng: &mut R, |
| 331 | +) -> (CanonicalLinearRelation<G>, Vec<G::Scalar>) { |
| 332 | + // Simulate the wallet spend relation from cmz |
| 333 | + let P_W = G::random(&mut rng); |
| 334 | + let P_I = G::random(&mut rng); |
| 335 | + let A = G::random(&mut rng); |
| 336 | + |
| 337 | + // Secret values |
| 338 | + let n_balance = G::Scalar::random(&mut rng); |
| 339 | + let i_price = G::Scalar::random(&mut rng); |
| 340 | + let fee = G::Scalar::from(5u64); |
| 341 | + let z_w_balance = G::Scalar::random(&mut rng); |
| 342 | + |
| 343 | + // W.balance = N.balance + I.price + fee |
| 344 | + let w_balance = n_balance + i_price + fee; |
| 345 | + |
| 346 | + let mut relation = LinearRelation::new(); |
| 347 | + |
| 348 | + // Allocate variables |
| 349 | + let var_n_balance = relation.allocate_scalar(); |
| 350 | + let var_i_price = relation.allocate_scalar(); |
| 351 | + let var_z_w_balance = relation.allocate_scalar(); |
| 352 | + |
| 353 | + let var_P_W = relation.allocate_element(); |
| 354 | + let var_P_I = relation.allocate_element(); |
| 355 | + let var_A = relation.allocate_element(); |
| 356 | + |
| 357 | + // C_show_Hattr_W_balance = (N.balance + I.price + fee) * P_W + z_w_balance * A |
| 358 | + // This is the problematic expression that fails in cmz |
| 359 | + let var_C = relation.allocate_eq( |
| 360 | + (var_n_balance + var_i_price + G::Scalar::from(5u64)) * var_P_W + var_z_w_balance * var_A, |
| 361 | + ); |
| 362 | + |
| 363 | + relation.set_elements([(var_P_W, P_W), (var_P_I, P_I), (var_A, A)]); |
| 364 | + |
| 365 | + relation |
| 366 | + .compute_image(&[n_balance, i_price, z_w_balance]) |
| 367 | + .unwrap(); |
| 368 | + |
| 369 | + let C = relation.linear_map.group_elements.get(var_C).unwrap(); |
| 370 | + let expected = P_W * w_balance + A * z_w_balance; |
| 371 | + assert_eq!(C, expected); |
| 372 | + |
| 373 | + let witness = vec![n_balance, i_price, z_w_balance]; |
| 374 | + let instance = (&relation).try_into().unwrap(); |
| 375 | + (instance, witness) |
| 376 | +} |
| 377 | + |
330 | 378 | /// Generic helper function to test both relation correctness and NIZK functionality |
331 | 379 | #[test] |
332 | | -fn test_common_relations() { |
| 380 | +fn test_relations() { |
333 | 381 | use group::Group; |
334 | 382 | type G = bls12_381::G1Projective; |
335 | 383 |
|
336 | | - let mut instance_generators = HashMap::< |
| 384 | + let instance_generators: Vec<( |
337 | 385 | &str, |
338 | 386 | Box<dyn Fn(&mut OsRng) -> (CanonicalLinearRelation<G>, Vec<<G as Group>::Scalar>)>, |
339 | | - >::new(); |
340 | | - |
341 | | - instance_generators.insert("dlog", Box::new(discrete_logarithm)); |
342 | | - instance_generators.insert("shifted_dlog", Box::new(shifted_dlog)); |
343 | | - instance_generators.insert("dleq", Box::new(dleq)); |
344 | | - instance_generators.insert("shifted_dleq", Box::new(shifted_dleq)); |
345 | | - instance_generators.insert("pedersen_commitment", Box::new(pedersen_commitment)); |
346 | | - instance_generators.insert("twisted_pedersen_commitment", Box::new(twisted_pedersen_commitment)); |
347 | | - instance_generators.insert( |
348 | | - "pedersen_commitment_dleq", |
349 | | - Box::new(pedersen_commitment_dleq), |
350 | | - ); |
351 | | - instance_generators.insert("bbs_blind_commitment", Box::new(bbs_blind_commitment)); |
352 | | - instance_generators.insert( |
353 | | - "weird_linear_combination", |
354 | | - Box::new(weird_linear_combination), |
355 | | - ); |
356 | | - instance_generators.insert("simple_subtractions", Box::new(simple_subtractions)); |
357 | | - instance_generators.insert("subtractions_with_shift", Box::new(subtractions_with_shift)); |
| 387 | + )> = vec![ |
| 388 | + ("dlog", Box::new(discrete_logarithm)), |
| 389 | + ("shifted_dlog", Box::new(shifted_dlog)), |
| 390 | + ("dleq", Box::new(dleq)), |
| 391 | + ("shifted_dleq", Box::new(shifted_dleq)), |
| 392 | + ("pedersen_commitment", Box::new(pedersen_commitment)), |
| 393 | + ( |
| 394 | + "twisted_pedersen_commitment", |
| 395 | + Box::new(twisted_pedersen_commitment), |
| 396 | + ), |
| 397 | + ( |
| 398 | + "pedersen_commitment_dleq", |
| 399 | + Box::new(pedersen_commitment_dleq), |
| 400 | + ), |
| 401 | + ("bbs_blind_commitment", Box::new(bbs_blind_commitment)), |
| 402 | + ( |
| 403 | + "weird_linear_combination", |
| 404 | + Box::new(weird_linear_combination), |
| 405 | + ), |
| 406 | + ("simple_subtractions", Box::new(simple_subtractions)), |
| 407 | + ("subtractions_with_shift", Box::new(subtractions_with_shift)), |
| 408 | + ( |
| 409 | + "cmz_wallet_spend_relation", |
| 410 | + Box::new(cmz_wallet_spend_relation), |
| 411 | + ), |
| 412 | + ]; |
358 | 413 |
|
359 | 414 | for (relation_name, relation_sampler) in instance_generators.iter() { |
360 | 415 | let mut rng = OsRng; |
|
0 commit comments