concordium_base/sigma_protocols/
com_eq.rs1use super::common::*;
12use crate::{
13 common::*,
14 curve_arithmetic::{multiexp, Curve, Field},
15 pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value},
16 random_oracle::RandomOracle,
17};
18
19#[derive(Clone, Debug, Eq, PartialEq, Serialize, SerdeBase16Serialize)]
20pub struct Response<T: Curve> {
21 pub response: (T::Scalar, T::Scalar),
28}
29
30#[derive(Debug, Serialize)]
31pub struct CommittedMessages<C: Curve, D: Curve> {
32 pub u: C,
33 pub v: Commitment<D>,
34}
35
36pub struct ComEq<C: Curve, D: Curve<Scalar = C::Scalar>> {
37 pub commitment: Commitment<D>,
39 pub y: C,
41 pub cmm_key: CommitmentKey<D>,
44 pub g: C,
46}
47
48pub struct ComEqSecret<C: Curve> {
49 pub r: Randomness<C>,
50 pub a: Value<C>,
51}
52
53#[allow(non_snake_case)]
54impl<C: Curve, D: Curve<Scalar = C::Scalar>> SigmaProtocol for ComEq<C, D> {
55 type CommitMessage = CommittedMessages<C, D>;
56 type ProtocolChallenge = C::Scalar;
57 type ProverState = (Value<D>, Randomness<D>);
59 type Response = Response<C>;
60 type SecretData = ComEqSecret<D>;
61
62 fn public(&self, ro: &mut RandomOracle) {
63 ro.append_message("commitment", &self.commitment);
64 ro.append_message("y", &self.y);
65 ro.append_message("cmm_key", &self.cmm_key);
66 ro.append_message("g", &self.g)
67 }
68
69 fn compute_commit_message<R: rand::Rng>(
70 &self,
71 csprng: &mut R,
72 ) -> Option<(Self::CommitMessage, Self::ProverState)> {
73 let mut u = C::zero_point();
74
75 let alpha = Value::<D>::generate_non_zero(csprng);
76 let (v, cR) = self.cmm_key.commit(&alpha, csprng);
78 u = u.plus_point(&self.g.mul_by_scalar(&alpha));
79 Some((CommittedMessages { u, v }, (alpha, cR)))
80 }
81
82 fn get_challenge(
83 &self,
84 challenge: &crate::random_oracle::Challenge,
85 ) -> Self::ProtocolChallenge {
86 C::scalar_from_bytes(challenge)
87 }
88
89 fn compute_response(
90 &self,
91 secret: Self::SecretData,
92 state: Self::ProverState,
93 challenge: &Self::ProtocolChallenge,
94 ) -> Option<Self::Response> {
95 let (ref alpha, ref cR) = state;
96 let mut s = *challenge;
98 s.mul_assign(&secret.a);
99 s.negate();
100 s.add_assign(alpha);
101 let mut t: C::Scalar = *challenge;
103 t.mul_assign(&secret.r);
104 t.negate();
105 t.add_assign(cR);
106 Some(Response { response: (s, t) })
107 }
108
109 fn extract_commit_message(
110 &self,
111 challenge: &Self::ProtocolChallenge,
112 response: &Self::Response,
113 ) -> Option<Self::CommitMessage> {
114 let u = multiexp(&[self.y, self.g], &[*challenge, response.response.0]);
119
120 let v = self.commitment.mul_by_scalar(challenge).plus_point(
121 &self
122 .cmm_key
123 .hide_worker(&response.response.0, &response.response.1),
124 );
125 Some(CommittedMessages {
126 u,
127 v: Commitment(v),
128 })
129 }
130
131 #[cfg(test)]
132 #[allow(clippy::many_single_char_names)]
133 fn with_valid_data<R: rand::Rng>(
134 _data_size: usize,
135 csprng: &mut R,
136 f: impl FnOnce(Self, Self::SecretData, &mut R),
137 ) {
138 let comm_key = CommitmentKey::generate(csprng);
139 let a = Value::<D>::generate_non_zero(csprng);
140 let (c, randomness) = comm_key.commit(&a, csprng);
141 let g = C::generate(csprng);
142 let mut y = C::zero_point();
143 y = y.plus_point(&g.mul_by_scalar(&a));
144 let com_eq = ComEq {
145 commitment: c,
146 y,
147 cmm_key: comm_key,
148 g,
149 };
150 let secret = ComEqSecret { r: randomness, a };
151 f(com_eq, secret, csprng)
152 }
153}
154
155#[cfg(test)]
156mod test {
157 use crate::curve_arithmetic::arkworks_instances::ArkGroup;
158
159 use super::*;
160 use ark_bls12_381::{G1Projective, G2Projective};
161
162 type G1 = ArkGroup<G1Projective>;
163 type G2 = ArkGroup<G2Projective>;
164
165 #[test]
166 pub fn test_com_eq_correctness() {
167 let mut csprng = rand::thread_rng();
168 for _i in 1..20 {
169 ComEq::<G1, G2>::with_valid_data(0, &mut csprng, |com_eq, secret, csprng| {
170 let challenge_prefix = generate_challenge_prefix(csprng);
171 let mut ro = RandomOracle::domain(challenge_prefix);
172 let proof = prove(&mut ro.split(), &com_eq, secret, csprng)
173 .expect("Proving should succeed.");
174 let res = verify(&mut ro, &com_eq, &proof);
175 assert!(res, "Verification of produced proof.");
176 })
177 }
178 }
179
180 #[test]
181 pub fn test_com_eq_soundness() {
182 let mut csprng = rand::thread_rng();
183 for i in 1..20 {
184 ComEq::<G1, G2>::with_valid_data(i, &mut csprng, |com_eq, secret, csprng| {
185 let challenge_prefix = generate_challenge_prefix(csprng);
186 let ro = RandomOracle::domain(challenge_prefix);
187 let proof = prove(&mut ro.split(), &com_eq, secret, csprng)
188 .expect("Proving should succeed.");
189
190 let mut wrong_ro = RandomOracle::domain(generate_challenge_prefix(csprng));
191 if verify(&mut wrong_ro, &com_eq, &proof) {
192 assert_eq!(wrong_ro, ro);
193 }
194 let mut wrong_com_eq = com_eq;
195 {
196 let tmp = wrong_com_eq.commitment;
197 let v = Value::<G1>::generate(csprng);
198 wrong_com_eq.commitment = wrong_com_eq.cmm_key.commit(&v, csprng).0;
199 assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
200 wrong_com_eq.commitment = tmp;
201 }
202
203 {
204 let tmp = wrong_com_eq.y;
205 wrong_com_eq.y = G1::generate(csprng);
206 assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
207 wrong_com_eq.y = tmp;
208 }
209
210 {
211 let tmp = wrong_com_eq.cmm_key;
212 wrong_com_eq.cmm_key = CommitmentKey::generate(csprng);
213 assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
214 wrong_com_eq.cmm_key = tmp;
215 }
216
217 {
218 let tmp = wrong_com_eq.g;
219 wrong_com_eq.g = G1::generate(csprng);
220 assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
221 wrong_com_eq.g = tmp;
222 }
223 })
224 }
225 }
226}