1use crate::ietf::IetfSuite;
33use crate::*;
34
35pub const PEDERSEN_BASE_SEED: &[u8] =
39 b"basis caecans lucis occultae quae mentem fugit et tenebras iis qui vident creat";
40
41pub trait PedersenSuite: IetfSuite {
42 const BLINDING_BASE: AffinePoint<Self>;
44
45 fn blinding(
50 secret: &ScalarField<Self>,
51 input: &AffinePoint<Self>,
52 aux: &[u8],
53 ) -> ScalarField<Self> {
54 const DOM_SEP_START: u8 = 0xCC;
55 const DOM_SEP_END: u8 = 0x00;
56 let mut buf = [Self::SUITE_ID, &[DOM_SEP_START]].concat();
57 Self::Codec::scalar_encode_into(secret, &mut buf);
58 Self::Codec::point_encode_into(input, &mut buf);
59 buf.extend_from_slice(aux);
60 buf.push(DOM_SEP_END);
61 let hash = &utils::hash::<Self::Hasher>(&buf);
62 ScalarField::<Self>::from_be_bytes_mod_order(hash)
63 }
64}
65
66#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
75pub struct Proof<S: PedersenSuite> {
76 pk_com: AffinePoint<S>,
77 r: AffinePoint<S>,
78 ok: AffinePoint<S>,
79 s: ScalarField<S>,
80 sb: ScalarField<S>,
81}
82
83impl<S: PedersenSuite> Proof<S> {
84 pub fn key_commitment(&self) -> AffinePoint<S> {
86 self.pk_com
87 }
88}
89
90pub trait Prover<S: PedersenSuite> {
96 fn prove(
107 &self,
108 input: Input<S>,
109 output: Output<S>,
110 ad: impl AsRef<[u8]>,
111 ) -> (Proof<S>, ScalarField<S>);
112}
113
114pub trait Verifier<S: PedersenSuite> {
119 fn verify(
133 input: Input<S>,
134 output: Output<S>,
135 ad: impl AsRef<[u8]>,
136 proof: &Proof<S>,
137 ) -> Result<(), Error>;
138}
139
140impl<S: PedersenSuite> Prover<S> for Secret<S> {
141 fn prove(
142 &self,
143 input: Input<S>,
144 output: Output<S>,
145 ad: impl AsRef<[u8]>,
146 ) -> (Proof<S>, ScalarField<S>) {
147 let blinding = S::blinding(&self.scalar, &input.0, ad.as_ref());
149
150 let k = S::nonce(&self.scalar, input);
152 let kb = S::nonce(&blinding, input);
153
154 let xg = smul!(S::generator(), self.scalar);
156 let bb = smul!(S::BLINDING_BASE, blinding);
157 let pk_com = (xg + bb).into_affine();
158
159 let kg = smul!(S::generator(), k);
161 let kbb = smul!(S::BLINDING_BASE, kb);
162 let r = (kg + kbb).into_affine();
163
164 let ok = smul!(input.0, k).into_affine();
166
167 let c = S::challenge(&[&pk_com, &input.0, &output.0, &r, &ok], ad.as_ref());
169
170 let s = k + c * self.scalar;
172 let sb = kb + c * blinding;
174
175 let proof = Proof {
176 pk_com,
177 r,
178 ok,
179 s,
180 sb,
181 };
182 (proof, blinding)
183 }
184}
185
186impl<S: PedersenSuite> Verifier<S> for Public<S> {
187 fn verify(
188 input: Input<S>,
189 output: Output<S>,
190 ad: impl AsRef<[u8]>,
191 proof: &Proof<S>,
192 ) -> Result<(), Error> {
193 let Proof {
194 pk_com,
195 r,
196 ok,
197 s,
198 sb,
199 } = proof;
200
201 let c = S::challenge(&[pk_com, &input.0, &output.0, r, ok], ad.as_ref());
203
204 if output.0 * c + ok != input.0 * s {
206 return Err(Error::VerificationFailure);
207 }
208
209 if *pk_com * c + r != S::generator() * s + S::BLINDING_BASE * sb {
211 return Err(Error::VerificationFailure);
212 }
213
214 Ok(())
215 }
216}
217
218#[cfg(test)]
219pub(crate) mod testing {
220 use super::*;
221 use crate::testing::{self as common, CheckPoint, SuiteExt, TEST_SEED, random_val};
222
223 pub fn prove_verify<S: PedersenSuite>() {
224 use pedersen::{Prover, Verifier};
225
226 let secret = Secret::<S>::from_seed(TEST_SEED);
227 let input = Input::from(random_val(None));
228 let output = secret.output(input);
229
230 let (proof, blinding) = secret.prove(input, output, b"foo");
231 let result = Public::verify(input, output, b"foo", &proof);
232 assert!(result.is_ok());
233
234 assert_eq!(
235 proof.key_commitment(),
236 (secret.public().0 + S::BLINDING_BASE * blinding).into()
237 );
238 }
239
240 pub fn blinding_base_check<S: PedersenSuite>()
241 where
242 AffinePoint<S>: CheckPoint,
243 {
244 assert_eq!(
246 S::BLINDING_BASE,
247 S::data_to_point(PEDERSEN_BASE_SEED).unwrap()
248 );
249 assert!(S::BLINDING_BASE.check(true).is_ok());
251 }
252
253 #[macro_export]
254 macro_rules! pedersen_suite_tests {
255 ($suite:ty) => {
256 mod pedersen {
257 use super::*;
258
259 #[test]
260 fn prove_verify() {
261 $crate::pedersen::testing::prove_verify::<$suite>();
262 }
263
264 #[test]
265 fn blinding_base_check() {
266 $crate::pedersen::testing::blinding_base_check::<$suite>();
267 }
268
269 $crate::test_vectors!($crate::pedersen::testing::TestVector<$suite>);
270 }
271 };
272 }
273
274 pub struct TestVector<S: PedersenSuite> {
275 pub base: common::TestVector<S>,
276 pub blind: ScalarField<S>,
277 pub proof: Proof<S>,
278 }
279
280 impl<S: PedersenSuite> core::fmt::Debug for TestVector<S> {
281 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
282 f.debug_struct("TestVector")
283 .field("base", &self.base)
284 .field("blinding", &self.blind)
285 .field("proof_pk_com", &self.proof.pk_com)
286 .field("proof_r", &self.proof.r)
287 .field("proof_ok", &self.proof.ok)
288 .field("proof_s", &self.proof.s)
289 .field("proof_sb", &self.proof.sb)
290 .finish()
291 }
292 }
293
294 impl<S> common::TestVectorTrait for TestVector<S>
295 where
296 S: PedersenSuite + SuiteExt + std::fmt::Debug,
297 {
298 fn name() -> String {
299 S::suite_name() + "_pedersen"
300 }
301
302 fn new(comment: &str, seed: &[u8], alpha: &[u8], salt: &[u8], ad: &[u8]) -> Self {
303 use super::Prover;
304 let base = common::TestVector::new(comment, seed, alpha, salt, ad);
305 let input = Input::<S>::from(base.h);
306 let output = Output::from(base.gamma);
307 let secret = Secret::from_scalar(base.sk);
308 let (proof, blind) = secret.prove(input, output, ad);
309 Self { base, blind, proof }
310 }
311
312 fn from_map(map: &common::TestVectorMap) -> Self {
313 let base = common::TestVector::from_map(map);
314 let blind = S::Codec::scalar_decode(&map.get_bytes("blinding"));
315 let pk_com = S::Codec::point_decode(&map.get_bytes("proof_pk_com")).unwrap();
316 let r = codec::point_decode::<S>(&map.get_bytes("proof_r")).unwrap();
317 let ok = codec::point_decode::<S>(&map.get_bytes("proof_ok")).unwrap();
318 let s = S::Codec::scalar_decode(&map.get_bytes("proof_s"));
319 let sb = S::Codec::scalar_decode(&map.get_bytes("proof_sb"));
320 let proof = Proof {
321 pk_com,
322 r,
323 ok,
324 s,
325 sb,
326 };
327 Self { base, blind, proof }
328 }
329
330 fn to_map(&self) -> common::TestVectorMap {
331 let items = [
332 (
333 "blinding",
334 hex::encode(codec::scalar_encode::<S>(&self.blind)),
335 ),
336 (
337 "proof_pk_com",
338 hex::encode(codec::point_encode::<S>(&self.proof.pk_com)),
339 ),
340 (
341 "proof_r",
342 hex::encode(codec::point_encode::<S>(&self.proof.r)),
343 ),
344 (
345 "proof_ok",
346 hex::encode(codec::point_encode::<S>(&self.proof.ok)),
347 ),
348 (
349 "proof_s",
350 hex::encode(codec::scalar_encode::<S>(&self.proof.s)),
351 ),
352 (
353 "proof_sb",
354 hex::encode(codec::scalar_encode::<S>(&self.proof.sb)),
355 ),
356 ];
357 let mut map = self.base.to_map();
358 items.into_iter().for_each(|(name, value)| {
359 map.0.insert(name.to_string(), value);
360 });
361 map
362 }
363
364 fn run(&self) {
365 self.base.run();
366 let input = Input::<S>::from(self.base.h);
367 let output = Output::from(self.base.gamma);
368 let sk = Secret::from_scalar(self.base.sk);
369 let (proof, blind) = sk.prove(input, output, &self.base.ad);
370 assert_eq!(self.blind, blind, "Blinding factor mismatch");
371 assert_eq!(self.proof.pk_com, proof.pk_com, "Proof pkb mismatch");
372 assert_eq!(self.proof.r, proof.r, "Proof r mismatch");
373 assert_eq!(self.proof.ok, proof.ok, "Proof ok mismatch");
374 assert_eq!(self.proof.s, proof.s, "Proof s mismatch");
375 assert_eq!(self.proof.sb, proof.sb, "Proof sb mismatch");
376
377 assert!(Public::verify(input, output, &self.base.ad, &proof).is_ok());
378 }
379 }
380}