wsts/
schnorr.rs

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)]
15/// A general schnorr proof
16pub struct Proof {
17    /// The commitment to the proof randomness
18    pub R: Point,
19    /// The response to the challenge
20    pub s: Scalar,
21}
22
23#[allow(non_snake_case)]
24#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
25/// ID type which encapsulates the ID and a schnorr proof of ownership of the polynomial
26pub struct ID {
27    /// The ID
28    pub id: Scalar,
29    /// The proof
30    pub proof: Proof,
31}
32
33#[allow(non_snake_case)]
34impl ID {
35    /// Construct a new schnorr ID which binds the passed `Scalar` `id` and `Scalar` `a`, with a
36    /// zero-knowledge proof of ownership of `a`.  The `ctx` is a common reference string used to
37    /// prevent replay attacks; it can be any length, but will typically be a `u64` value in
38    /// big endian format.
39    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    /// Compute the schnorr challenge
57    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    /// Verify the proof
71    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}