1use rand_core::{CryptoRng, RngCore};
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4
5use crate::{
6 curve::{
7 point::{Point, G},
8 scalar::Scalar,
9 },
10 util::hash_to_scalar,
11};
12
13#[allow(non_snake_case)]
14#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
15pub struct Proof {
17 pub R: Point,
19 pub s: Scalar,
21}
22
23#[allow(non_snake_case)]
24#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
25pub struct ID {
27 pub id: Scalar,
29 pub proof: Proof,
31}
32
33#[allow(non_snake_case)]
34impl ID {
35 pub fn new<RNG: RngCore + CryptoRng>(
40 id: &Scalar,
41 a: &Scalar,
42 ctx: &[u8],
43 rng: &mut RNG,
44 ) -> Self {
45 let r = Scalar::random(rng);
46 let R = r * G;
47 let c = Self::challenge(id, &R, &(a * &G), ctx);
48 let s = r + c * a;
49
50 Self {
51 id: *id,
52 proof: Proof { R, s },
53 }
54 }
55
56 pub fn challenge(id: &Scalar, R: &Point, A: &Point, ctx: &[u8]) -> Scalar {
58 let mut hasher = Sha256::new();
59 let tag = "WSTS/polynomial-constant";
60
61 hasher.update(tag.as_bytes());
62 hasher.update(id.to_bytes());
63 hasher.update(R.compress().as_bytes());
64 hasher.update(A.compress().as_bytes());
65 hasher.update(ctx);
66
67 hash_to_scalar(&mut hasher)
68 }
69
70 pub fn verify(&self, A: &Point, ctx: &[u8]) -> bool {
72 let c = Self::challenge(&self.id, &self.proof.R, A, ctx);
73 &self.proof.s * &G == &self.proof.R + c * A
74 }
75}