zk_paillier/zkproofs/
correct_ciphertext.rs1use std::iter;
2
3use serde::{Deserialize, Serialize};
4
5use curv::arithmetic::traits::{Modulo, Samplable};
6use curv::BigInt;
7use paillier::traits::{Add, Mul};
8use paillier::EncryptWithChosenRandomness;
9use paillier::Paillier;
10use paillier::{EncryptionKey, Randomness, RawCiphertext, RawPlaintext};
11
12use super::errors::IncorrectProof;
13
14#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
23pub struct CiphertextProof {
24 pub z1: BigInt,
25 pub z2: BigInt,
26 pub c_prime: BigInt,
27}
28
29#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
30pub struct CiphertextWitness {
31 pub x: BigInt,
32 pub r: BigInt,
33}
34
35#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
36pub struct CiphertextStatement {
37 pub ek: EncryptionKey,
38 pub c: BigInt,
39}
40
41impl CiphertextProof {
42 pub fn prove(witness: &CiphertextWitness, statement: &CiphertextStatement) -> Self {
43 let x_prime = BigInt::sample_below(&statement.ek.n);
44 let r_prime = BigInt::sample_below(&statement.ek.n);
45 let c_prime = Paillier::encrypt_with_chosen_randomness(
46 &statement.ek,
47 RawPlaintext::from(x_prime.clone()),
48 &Randomness(r_prime.clone()),
49 )
50 .0
51 .into_owned();
52
53 let e = super::compute_digest(
54 iter::once(&statement.ek.n)
55 .chain(iter::once(&statement.c))
56 .chain(iter::once(&c_prime)),
57 );
58
59 let z1 = &x_prime + &witness.x * &e;
60 let r_e = BigInt::mod_pow(&witness.r, &e, &statement.ek.nn);
61 let z2 = BigInt::mod_mul(&r_prime, &r_e, &statement.ek.nn);
62
63 CiphertextProof { z1, z2, c_prime }
64 }
65
66 pub fn verify(&self, statement: &CiphertextStatement) -> Result<(), IncorrectProof> {
67 let e = super::compute_digest(
68 iter::once(&statement.ek.n)
69 .chain(iter::once(&statement.c))
70 .chain(iter::once(&self.c_prime)),
71 );
72
73 let c_z = Paillier::encrypt_with_chosen_randomness(
74 &statement.ek,
75 RawPlaintext::from(self.z1.clone()),
76 &Randomness(self.z2.clone()),
77 )
78 .0
79 .into_owned();
80
81 let c_e = Paillier::mul(
82 &statement.ek,
83 RawPlaintext::from(e),
84 RawCiphertext::from(statement.c.clone()),
85 );
86 let c_z_test = Paillier::add(
87 &statement.ek,
88 c_e,
89 RawCiphertext::from(self.c_prime.clone()),
90 )
91 .0
92 .into_owned();
93
94 match c_z == c_z_test {
95 true => Ok(()),
96 false => Err(IncorrectProof),
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use curv::arithmetic::traits::*;
104 use curv::BigInt;
105 use paillier::core::Randomness;
106 use paillier::traits::EncryptWithChosenRandomness;
107 use paillier::traits::KeyGeneration;
108 use paillier::Paillier;
109 use paillier::RawPlaintext;
110
111 use crate::zkproofs::correct_ciphertext::CiphertextProof;
112 use crate::zkproofs::correct_ciphertext::CiphertextStatement;
113 use crate::zkproofs::correct_ciphertext::CiphertextWitness;
114
115 #[test]
116 fn test_ciphertext_proof() {
117 let (ek, _) = Paillier::keypair().keys();
118 let x = BigInt::sample_below(&ek.n);
119 let r = BigInt::sample_below(&ek.n);
120
121 let c = Paillier::encrypt_with_chosen_randomness(
122 &ek,
123 RawPlaintext::from(x.clone()),
124 &Randomness(r.clone()),
125 )
126 .0
127 .into_owned();
128
129 let witness = CiphertextWitness { x, r };
130
131 let statement = CiphertextStatement { ek, c };
132
133 let proof = CiphertextProof::prove(&witness, &statement);
134 let verify = proof.verify(&statement);
135 assert!(verify.is_ok());
136 }
137
138 #[test]
139 #[should_panic]
140 fn test_bad_ciphertext_proof() {
141 let (ek, _) = Paillier::keypair().keys();
142 let x = BigInt::sample_below(&ek.n);
143 let r = BigInt::sample_below(&ek.n);
144
145 let c = Paillier::encrypt_with_chosen_randomness(
146 &ek,
147 RawPlaintext::from(x.clone()),
148 &Randomness(r.clone()),
149 )
150 .0
151 .into_owned();
152
153 let witness = CiphertextWitness {
154 x,
155 r: r + BigInt::one(),
156 };
157
158 let statement = CiphertextStatement { ek, c };
159
160 let proof = CiphertextProof::prove(&witness, &statement);
161 let verify = proof.verify(&statement);
162 assert!(verify.is_ok());
163 }
164}