arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/nizk/mod.rs
src/nizk/mod.rsRaw
  1#![allow(clippy::too_many_arguments)]
  2use super::commitments::{Commitments, MultiCommitGens};
  3use super::errors::ProofVerifyError;
  4use super::group::{CompressedGroup, CompressedGroupExt};
  5use super::random::RandomTape;
  6use super::scalar::Scalar;
  7use super::transcript::{AppendToTranscript, ProofTranscript};
  8use merlin::Transcript;
  9use serde::{Deserialize, Serialize};
 10
 11mod bullet;
 12use bullet::BulletReductionProof;
 13
 14#[derive(Serialize, Deserialize, Debug)]
 15pub struct KnowledgeProof {
 16  alpha: CompressedGroup,
 17  z1: Scalar,
 18  z2: Scalar,
 19}
 20
 21impl KnowledgeProof {
 22  fn protocol_name() -> &'static [u8] {
 23    b"knowledge proof"
 24  }
 25
 26  pub fn prove(
 27    gens_n: &MultiCommitGens,
 28    transcript: &mut Transcript,
 29    random_tape: &mut RandomTape,
 30    x: &Scalar,
 31    r: &Scalar,
 32  ) -> (KnowledgeProof, CompressedGroup) {
 33    transcript.append_protocol_name(KnowledgeProof::protocol_name());
 34
 35    // produce two random Scalars
 36    let t1 = random_tape.random_scalar(b"t1");
 37    let t2 = random_tape.random_scalar(b"t2");
 38
 39    let C = x.commit(r, gens_n).compress();
 40    C.append_to_transcript(b"C", transcript);
 41
 42    let alpha = t1.commit(&t2, gens_n).compress();
 43    alpha.append_to_transcript(b"alpha", transcript);
 44
 45    let c = transcript.challenge_scalar(b"c");
 46
 47    let z1 = x * c + t1;
 48    let z2 = r * c + t2;
 49
 50    (KnowledgeProof { alpha, z1, z2 }, C)
 51  }
 52
 53  pub fn verify(
 54    &self,
 55    gens_n: &MultiCommitGens,
 56    transcript: &mut Transcript,
 57    C: &CompressedGroup,
 58  ) -> Result<(), ProofVerifyError> {
 59    transcript.append_protocol_name(KnowledgeProof::protocol_name());
 60    C.append_to_transcript(b"C", transcript);
 61    self.alpha.append_to_transcript(b"alpha", transcript);
 62
 63    let c = transcript.challenge_scalar(b"c");
 64
 65    let lhs = self.z1.commit(&self.z2, gens_n).compress();
 66    let rhs = (c * C.unpack()? + self.alpha.unpack()?).compress();
 67
 68    if lhs == rhs {
 69      Ok(())
 70    } else {
 71      Err(ProofVerifyError::InternalError)
 72    }
 73  }
 74}
 75
 76#[derive(Serialize, Deserialize, Debug)]
 77pub struct EqualityProof {
 78  alpha: CompressedGroup,
 79  z: Scalar,
 80}
 81
 82impl EqualityProof {
 83  fn protocol_name() -> &'static [u8] {
 84    b"equality proof"
 85  }
 86
 87  pub fn prove(
 88    gens_n: &MultiCommitGens,
 89    transcript: &mut Transcript,
 90    random_tape: &mut RandomTape,
 91    v1: &Scalar,
 92    s1: &Scalar,
 93    v2: &Scalar,
 94    s2: &Scalar,
 95  ) -> (EqualityProof, CompressedGroup, CompressedGroup) {
 96    transcript.append_protocol_name(EqualityProof::protocol_name());
 97
 98    // produce a random Scalar
 99    let r = random_tape.random_scalar(b"r");
100
101    let C1 = v1.commit(s1, gens_n).compress();
102    C1.append_to_transcript(b"C1", transcript);
103
104    let C2 = v2.commit(s2, gens_n).compress();
105    C2.append_to_transcript(b"C2", transcript);
106
107    let alpha = (r * gens_n.h).compress();
108    alpha.append_to_transcript(b"alpha", transcript);
109
110    let c = transcript.challenge_scalar(b"c");
111
112    let z = c * (s1 - s2) + r;
113
114    (EqualityProof { alpha, z }, C1, C2)
115  }
116
117  pub fn verify(
118    &self,
119    gens_n: &MultiCommitGens,
120    transcript: &mut Transcript,
121    C1: &CompressedGroup,
122    C2: &CompressedGroup,
123  ) -> Result<(), ProofVerifyError> {
124    transcript.append_protocol_name(EqualityProof::protocol_name());
125    C1.append_to_transcript(b"C1", transcript);
126    C2.append_to_transcript(b"C2", transcript);
127    self.alpha.append_to_transcript(b"alpha", transcript);
128
129    let c = transcript.challenge_scalar(b"c");
130    let rhs = {
131      let C = C1.unpack()? - C2.unpack()?;
132      (c * C + self.alpha.unpack()?).compress()
133    };
134
135    let lhs = (self.z * gens_n.h).compress();
136
137    if lhs == rhs {
138      Ok(())
139    } else {
140      Err(ProofVerifyError::InternalError)
141    }
142  }
143}
144
145#[derive(Serialize, Deserialize, Debug)]
146pub struct ProductProof {
147  alpha: CompressedGroup,
148  beta: CompressedGroup,
149  delta: CompressedGroup,
150  z: [Scalar; 5],
151}
152
153impl ProductProof {
154  fn protocol_name() -> &'static [u8] {
155    b"product proof"
156  }
157
158  pub fn prove(
159    gens_n: &MultiCommitGens,
160    transcript: &mut Transcript,
161    random_tape: &mut RandomTape,
162    x: &Scalar,
163    rX: &Scalar,
164    y: &Scalar,
165    rY: &Scalar,
166    z: &Scalar,
167    rZ: &Scalar,
168  ) -> (
169    ProductProof,
170    CompressedGroup,
171    CompressedGroup,
172    CompressedGroup,
173  ) {
174    transcript.append_protocol_name(ProductProof::protocol_name());
175
176    // produce five random Scalar
177    let b1 = random_tape.random_scalar(b"b1");
178    let b2 = random_tape.random_scalar(b"b2");
179    let b3 = random_tape.random_scalar(b"b3");
180    let b4 = random_tape.random_scalar(b"b4");
181    let b5 = random_tape.random_scalar(b"b5");
182
183    let X = x.commit(rX, gens_n).compress();
184    X.append_to_transcript(b"X", transcript);
185
186    let Y = y.commit(rY, gens_n).compress();
187    Y.append_to_transcript(b"Y", transcript);
188
189    let Z = z.commit(rZ, gens_n).compress();
190    Z.append_to_transcript(b"Z", transcript);
191
192    let alpha = b1.commit(&b2, gens_n).compress();
193    alpha.append_to_transcript(b"alpha", transcript);
194
195    let beta = b3.commit(&b4, gens_n).compress();
196    beta.append_to_transcript(b"beta", transcript);
197
198    let delta = {
199      let gens_X = &MultiCommitGens {
200        n: 1,
201        G: vec![X.decompress().unwrap()],
202        h: gens_n.h,
203      };
204      b3.commit(&b5, gens_X).compress()
205    };
206    delta.append_to_transcript(b"delta", transcript);
207
208    let c = transcript.challenge_scalar(b"c");
209
210    let z1 = b1 + c * x;
211    let z2 = b2 + c * rX;
212    let z3 = b3 + c * y;
213    let z4 = b4 + c * rY;
214    let z5 = b5 + c * (rZ - rX * y);
215    let z = [z1, z2, z3, z4, z5];
216
217    (
218      ProductProof {
219        alpha,
220        beta,
221        delta,
222        z,
223      },
224      X,
225      Y,
226      Z,
227    )
228  }
229
230  fn check_equality(
231    P: &CompressedGroup,
232    X: &CompressedGroup,
233    c: &Scalar,
234    gens_n: &MultiCommitGens,
235    z1: &Scalar,
236    z2: &Scalar,
237  ) -> bool {
238    let lhs = (P.decompress().unwrap() + c * X.decompress().unwrap()).compress();
239    let rhs = z1.commit(z2, gens_n).compress();
240
241    lhs == rhs
242  }
243
244  pub fn verify(
245    &self,
246    gens_n: &MultiCommitGens,
247    transcript: &mut Transcript,
248    X: &CompressedGroup,
249    Y: &CompressedGroup,
250    Z: &CompressedGroup,
251  ) -> Result<(), ProofVerifyError> {
252    transcript.append_protocol_name(ProductProof::protocol_name());
253
254    X.append_to_transcript(b"X", transcript);
255    Y.append_to_transcript(b"Y", transcript);
256    Z.append_to_transcript(b"Z", transcript);
257    self.alpha.append_to_transcript(b"alpha", transcript);
258    self.beta.append_to_transcript(b"beta", transcript);
259    self.delta.append_to_transcript(b"delta", transcript);
260
261    let z1 = self.z[0];
262    let z2 = self.z[1];
263    let z3 = self.z[2];
264    let z4 = self.z[3];
265    let z5 = self.z[4];
266
267    let c = transcript.challenge_scalar(b"c");
268
269    if ProductProof::check_equality(&self.alpha, X, &c, gens_n, &z1, &z2)
270      && ProductProof::check_equality(&self.beta, Y, &c, gens_n, &z3, &z4)
271      && ProductProof::check_equality(
272        &self.delta,
273        Z,
274        &c,
275        &MultiCommitGens {
276          n: 1,
277          G: vec![X.unpack()?],
278          h: gens_n.h,
279        },
280        &z3,
281        &z5,
282      )
283    {
284      Ok(())
285    } else {
286      Err(ProofVerifyError::InternalError)
287    }
288  }
289}
290
291#[derive(Debug, Serialize, Deserialize)]
292pub struct DotProductProof {
293  delta: CompressedGroup,
294  beta: CompressedGroup,
295  z: Vec<Scalar>,
296  z_delta: Scalar,
297  z_beta: Scalar,
298}
299
300impl DotProductProof {
301  fn protocol_name() -> &'static [u8] {
302    b"dot product proof"
303  }
304
305  pub fn compute_dotproduct(a: &[Scalar], b: &[Scalar]) -> Scalar {
306    assert_eq!(a.len(), b.len());
307    (0..a.len()).map(|i| a[i] * b[i]).sum()
308  }
309
310  pub fn prove(
311    gens_1: &MultiCommitGens,
312    gens_n: &MultiCommitGens,
313    transcript: &mut Transcript,
314    random_tape: &mut RandomTape,
315    x_vec: &[Scalar],
316    blind_x: &Scalar,
317    a_vec: &[Scalar],
318    y: &Scalar,
319    blind_y: &Scalar,
320  ) -> (DotProductProof, CompressedGroup, CompressedGroup) {
321    transcript.append_protocol_name(DotProductProof::protocol_name());
322
323    let n = x_vec.len();
324    assert_eq!(x_vec.len(), a_vec.len());
325    assert_eq!(gens_n.n, a_vec.len());
326    assert_eq!(gens_1.n, 1);
327
328    // produce randomness for the proofs
329    let d_vec = random_tape.random_vector(b"d_vec", n);
330    let r_delta = random_tape.random_scalar(b"r_delta");
331    let r_beta = random_tape.random_scalar(b"r_beta");
332
333    let Cx = x_vec.commit(blind_x, gens_n).compress();
334    Cx.append_to_transcript(b"Cx", transcript);
335
336    let Cy = y.commit(blind_y, gens_1).compress();
337    Cy.append_to_transcript(b"Cy", transcript);
338
339    let delta = d_vec.commit(&r_delta, gens_n).compress();
340    delta.append_to_transcript(b"delta", transcript);
341
342    let dotproduct_a_d = DotProductProof::compute_dotproduct(a_vec, &d_vec);
343
344    let beta = dotproduct_a_d.commit(&r_beta, gens_1).compress();
345    beta.append_to_transcript(b"beta", transcript);
346
347    let c = transcript.challenge_scalar(b"c");
348
349    let z = (0..d_vec.len())
350      .map(|i| c * x_vec[i] + d_vec[i])
351      .collect::<Vec<Scalar>>();
352
353    let z_delta = c * blind_x + r_delta;
354    let z_beta = c * blind_y + r_beta;
355
356    (
357      DotProductProof {
358        delta,
359        beta,
360        z,
361        z_delta,
362        z_beta,
363      },
364      Cx,
365      Cy,
366    )
367  }
368
369  pub fn verify(
370    &self,
371    gens_1: &MultiCommitGens,
372    gens_n: &MultiCommitGens,
373    transcript: &mut Transcript,
374    a: &[Scalar],
375    Cx: &CompressedGroup,
376    Cy: &CompressedGroup,
377  ) -> Result<(), ProofVerifyError> {
378    assert_eq!(gens_n.n, a.len());
379    assert_eq!(gens_1.n, 1);
380
381    transcript.append_protocol_name(DotProductProof::protocol_name());
382    Cx.append_to_transcript(b"Cx", transcript);
383    Cy.append_to_transcript(b"Cy", transcript);
384    self.delta.append_to_transcript(b"delta", transcript);
385    self.beta.append_to_transcript(b"beta", transcript);
386
387    let c = transcript.challenge_scalar(b"c");
388
389    let mut result =
390      c * Cx.unpack()? + self.delta.unpack()? == self.z.commit(&self.z_delta, gens_n);
391
392    let dotproduct_z_a = DotProductProof::compute_dotproduct(&self.z, a);
393    result &= c * Cy.unpack()? + self.beta.unpack()? == dotproduct_z_a.commit(&self.z_beta, gens_1);
394
395    if result {
396      Ok(())
397    } else {
398      Err(ProofVerifyError::InternalError)
399    }
400  }
401}
402
403pub struct DotProductProofGens {
404  n: usize,
405  pub gens_n: MultiCommitGens,
406  pub gens_1: MultiCommitGens,
407}
408
409impl DotProductProofGens {
410  pub fn new(n: usize, label: &[u8]) -> Self {
411    let (gens_n, gens_1) = MultiCommitGens::new(n + 1, label).split_at(n);
412    DotProductProofGens { n, gens_n, gens_1 }
413  }
414}
415
416#[derive(Debug, Serialize, Deserialize)]
417pub struct DotProductProofLog {
418  bullet_reduction_proof: BulletReductionProof,
419  delta: CompressedGroup,
420  beta: CompressedGroup,
421  z1: Scalar,
422  z2: Scalar,
423}
424
425impl DotProductProofLog {
426  fn protocol_name() -> &'static [u8] {
427    b"dot product proof (log)"
428  }
429
430  pub fn compute_dotproduct(a: &[Scalar], b: &[Scalar]) -> Scalar {
431    assert_eq!(a.len(), b.len());
432    (0..a.len()).map(|i| a[i] * b[i]).sum()
433  }
434
435  pub fn prove(
436    gens: &DotProductProofGens,
437    transcript: &mut Transcript,
438    random_tape: &mut RandomTape,
439    x_vec: &[Scalar],
440    blind_x: &Scalar,
441    a_vec: &[Scalar],
442    y: &Scalar,
443    blind_y: &Scalar,
444  ) -> (DotProductProofLog, CompressedGroup, CompressedGroup) {
445    transcript.append_protocol_name(DotProductProofLog::protocol_name());
446
447    let n = x_vec.len();
448    assert_eq!(x_vec.len(), a_vec.len());
449    assert_eq!(gens.n, n);
450
451    // produce randomness for generating a proof
452    let d = random_tape.random_scalar(b"d");
453    let r_delta = random_tape.random_scalar(b"r_delta");
454    let r_beta = random_tape.random_scalar(b"r_delta");
455    let blinds_vec = {
456      let v1 = random_tape.random_vector(b"blinds_vec_1", 2 * n.log2() as usize);
457      let v2 = random_tape.random_vector(b"blinds_vec_2", 2 * n.log2() as usize);
458      (0..v1.len())
459        .map(|i| (v1[i], v2[i]))
460        .collect::<Vec<(Scalar, Scalar)>>()
461    };
462
463    let Cx = x_vec.commit(blind_x, &gens.gens_n).compress();
464    Cx.append_to_transcript(b"Cx", transcript);
465
466    let Cy = y.commit(blind_y, &gens.gens_1).compress();
467    Cy.append_to_transcript(b"Cy", transcript);
468
469    let blind_Gamma = blind_x + blind_y;
470    let (bullet_reduction_proof, _Gamma_hat, x_hat, a_hat, g_hat, rhat_Gamma) =
471      BulletReductionProof::prove(
472        transcript,
473        &gens.gens_1.G[0],
474        &gens.gens_n.G,
475        &gens.gens_n.h,
476        x_vec,
477        a_vec,
478        &blind_Gamma,
479        &blinds_vec,
480      );
481    let y_hat = x_hat * a_hat;
482
483    let delta = {
484      let gens_hat = MultiCommitGens {
485        n: 1,
486        G: vec![g_hat],
487        h: gens.gens_1.h,
488      };
489      d.commit(&r_delta, &gens_hat).compress()
490    };
491    delta.append_to_transcript(b"delta", transcript);
492
493    let beta = d.commit(&r_beta, &gens.gens_1).compress();
494    beta.append_to_transcript(b"beta", transcript);
495
496    let c = transcript.challenge_scalar(b"c");
497
498    let z1 = d + c * y_hat;
499    let z2 = a_hat * (c * rhat_Gamma + r_beta) + r_delta;
500
501    (
502      DotProductProofLog {
503        bullet_reduction_proof,
504        delta,
505        beta,
506        z1,
507        z2,
508      },
509      Cx,
510      Cy,
511    )
512  }
513
514  pub fn verify(
515    &self,
516    n: usize,
517    gens: &DotProductProofGens,
518    transcript: &mut Transcript,
519    a: &[Scalar],
520    Cx: &CompressedGroup,
521    Cy: &CompressedGroup,
522  ) -> Result<(), ProofVerifyError> {
523    assert_eq!(gens.n, n);
524    assert_eq!(a.len(), n);
525
526    transcript.append_protocol_name(DotProductProofLog::protocol_name());
527    Cx.append_to_transcript(b"Cx", transcript);
528    Cy.append_to_transcript(b"Cy", transcript);
529
530    let Gamma = Cx.unpack()? + Cy.unpack()?;
531
532    let (g_hat, Gamma_hat, a_hat) =
533      self
534        .bullet_reduction_proof
535        .verify(n, a, transcript, &Gamma, &gens.gens_n.G)?;
536    self.delta.append_to_transcript(b"delta", transcript);
537    self.beta.append_to_transcript(b"beta", transcript);
538
539    let c = transcript.challenge_scalar(b"c");
540
541    let c_s = &c;
542    let beta_s = self.beta.unpack()?;
543    let a_hat_s = &a_hat;
544    let delta_s = self.delta.unpack()?;
545    let z1_s = &self.z1;
546    let z2_s = &self.z2;
547
548    let lhs = ((Gamma_hat * c_s + beta_s) * a_hat_s + delta_s).compress();
549    let rhs = ((g_hat + gens.gens_1.G[0] * a_hat_s) * z1_s + gens.gens_1.h * z2_s).compress();
550
551    assert_eq!(lhs, rhs);
552
553    if lhs == rhs {
554      Ok(())
555    } else {
556      Err(ProofVerifyError::InternalError)
557    }
558  }
559}
560
561#[cfg(test)]
562mod tests {
563  use super::*;
564  use rand::rngs::OsRng;
565  #[test]
566  fn check_knowledgeproof() {
567    let mut csprng: OsRng = OsRng;
568
569    let gens_1 = MultiCommitGens::new(1, b"test-knowledgeproof");
570
571    let x = Scalar::random(&mut csprng);
572    let r = Scalar::random(&mut csprng);
573
574    let mut random_tape = RandomTape::new(b"proof");
575    let mut prover_transcript = Transcript::new(b"example");
576    let (proof, committed_value) =
577      KnowledgeProof::prove(&gens_1, &mut prover_transcript, &mut random_tape, &x, &r);
578
579    let mut verifier_transcript = Transcript::new(b"example");
580    assert!(proof
581      .verify(&gens_1, &mut verifier_transcript, &committed_value)
582      .is_ok());
583  }
584
585  #[test]
586  fn check_equalityproof() {
587    let mut csprng: OsRng = OsRng;
588
589    let gens_1 = MultiCommitGens::new(1, b"test-equalityproof");
590    let v1 = Scalar::random(&mut csprng);
591    let v2 = v1;
592    let s1 = Scalar::random(&mut csprng);
593    let s2 = Scalar::random(&mut csprng);
594
595    let mut random_tape = RandomTape::new(b"proof");
596    let mut prover_transcript = Transcript::new(b"example");
597    let (proof, C1, C2) = EqualityProof::prove(
598      &gens_1,
599      &mut prover_transcript,
600      &mut random_tape,
601      &v1,
602      &s1,
603      &v2,
604      &s2,
605    );
606
607    let mut verifier_transcript = Transcript::new(b"example");
608    assert!(proof
609      .verify(&gens_1, &mut verifier_transcript, &C1, &C2)
610      .is_ok());
611  }
612
613  #[test]
614  fn check_productproof() {
615    let mut csprng: OsRng = OsRng;
616
617    let gens_1 = MultiCommitGens::new(1, b"test-productproof");
618    let x = Scalar::random(&mut csprng);
619    let rX = Scalar::random(&mut csprng);
620    let y = Scalar::random(&mut csprng);
621    let rY = Scalar::random(&mut csprng);
622    let z = x * y;
623    let rZ = Scalar::random(&mut csprng);
624
625    let mut random_tape = RandomTape::new(b"proof");
626    let mut prover_transcript = Transcript::new(b"example");
627    let (proof, X, Y, Z) = ProductProof::prove(
628      &gens_1,
629      &mut prover_transcript,
630      &mut random_tape,
631      &x,
632      &rX,
633      &y,
634      &rY,
635      &z,
636      &rZ,
637    );
638
639    let mut verifier_transcript = Transcript::new(b"example");
640    assert!(proof
641      .verify(&gens_1, &mut verifier_transcript, &X, &Y, &Z)
642      .is_ok());
643  }
644
645  #[test]
646  fn check_dotproductproof() {
647    let mut csprng: OsRng = OsRng;
648
649    let n = 1024;
650
651    let gens_1 = MultiCommitGens::new(1, b"test-two");
652    let gens_1024 = MultiCommitGens::new(n, b"test-1024");
653
654    let mut x: Vec<Scalar> = Vec::new();
655    let mut a: Vec<Scalar> = Vec::new();
656    for _ in 0..n {
657      x.push(Scalar::random(&mut csprng));
658      a.push(Scalar::random(&mut csprng));
659    }
660    let y = DotProductProofLog::compute_dotproduct(&x, &a);
661    let r_x = Scalar::random(&mut csprng);
662    let r_y = Scalar::random(&mut csprng);
663
664    let mut random_tape = RandomTape::new(b"proof");
665    let mut prover_transcript = Transcript::new(b"example");
666    let (proof, Cx, Cy) = DotProductProof::prove(
667      &gens_1,
668      &gens_1024,
669      &mut prover_transcript,
670      &mut random_tape,
671      &x,
672      &r_x,
673      &a,
674      &y,
675      &r_y,
676    );
677
678    let mut verifier_transcript = Transcript::new(b"example");
679    assert!(proof
680      .verify(&gens_1, &gens_1024, &mut verifier_transcript, &a, &Cx, &Cy)
681      .is_ok());
682  }
683
684  #[test]
685  fn check_dotproductproof_log() {
686    let mut csprng: OsRng = OsRng;
687
688    let n = 1024;
689
690    let gens = DotProductProofGens::new(n, b"test-1024");
691
692    let x: Vec<Scalar> = (0..n).map(|_i| Scalar::random(&mut csprng)).collect();
693    let a: Vec<Scalar> = (0..n).map(|_i| Scalar::random(&mut csprng)).collect();
694    let y = DotProductProof::compute_dotproduct(&x, &a);
695
696    let r_x = Scalar::random(&mut csprng);
697    let r_y = Scalar::random(&mut csprng);
698
699    let mut random_tape = RandomTape::new(b"proof");
700    let mut prover_transcript = Transcript::new(b"example");
701    let (proof, Cx, Cy) = DotProductProofLog::prove(
702      &gens,
703      &mut prover_transcript,
704      &mut random_tape,
705      &x,
706      &r_x,
707      &a,
708      &y,
709      &r_y,
710    );
711
712    let mut verifier_transcript = Transcript::new(b"example");
713    assert!(proof
714      .verify(n, &gens, &mut verifier_transcript, &a, &Cx, &Cy)
715      .is_ok());
716  }
717}