frost_core/
verifying_key.rs

1use core::fmt::{self, Debug};
2
3use alloc::{string::ToString, vec::Vec};
4
5#[cfg(any(test, feature = "test-impl"))]
6use hex::FromHex;
7
8use crate::{serialization::SerializableElement, Challenge, Ciphersuite, Error, Group, Signature};
9
10/// A valid verifying key for Schnorr signatures over a FROST [`Ciphersuite::Group`].
11#[derive(Copy, Clone, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
14#[cfg_attr(feature = "serde", serde(transparent))]
15pub struct VerifyingKey<C>
16where
17    C: Ciphersuite,
18{
19    pub(crate) element: SerializableElement<C>,
20}
21
22impl<C> VerifyingKey<C>
23where
24    C: Ciphersuite,
25{
26    /// Create a new VerifyingKey from the given element.
27    #[cfg_attr(feature = "internals", visibility::make(pub))]
28    #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
29    pub(crate) fn new(element: <C::Group as Group>::Element) -> Self {
30        Self {
31            element: SerializableElement(element),
32        }
33    }
34
35    /// Return the underlying element.
36    #[cfg_attr(feature = "internals", visibility::make(pub))]
37    #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
38    pub(crate) fn to_element(self) -> <C::Group as Group>::Element {
39        self.element.0
40    }
41
42    /// Deserialize from bytes
43    pub fn deserialize(bytes: &[u8]) -> Result<VerifyingKey<C>, Error<C>> {
44        Ok(Self::new(SerializableElement::deserialize(bytes)?.0))
45    }
46
47    /// Serialize `VerifyingKey` to bytes
48    pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
49        self.element.serialize()
50    }
51
52    /// Verify a purported `signature` with a pre-hashed [`Challenge`] made by this verification
53    /// key.
54    #[cfg_attr(feature = "internals", visibility::make(pub))]
55    #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
56    pub(crate) fn verify_prehashed(
57        &self,
58        challenge: Challenge<C>,
59        signature: &Signature<C>,
60    ) -> Result<(), Error<C>> {
61        // Verify check is h * ( - z * B + R  + c * A) == 0
62        //                 h * ( z * B - c * A - R) == 0
63        //
64        // where h is the cofactor
65        let zB = C::Group::generator() * signature.z;
66        let cA = self.element.0 * challenge.0;
67        let check = (zB - cA - signature.R) * C::Group::cofactor();
68
69        if check == C::Group::identity() {
70            Ok(())
71        } else {
72            Err(Error::InvalidSignature)
73        }
74    }
75
76    /// Verify a purported `signature` over `msg` made by this verification key.
77    pub fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<(), Error<C>> {
78        C::verify_signature(msg, signature, self)
79    }
80
81    /// Computes the group public key given the group commitment.
82    #[cfg_attr(feature = "internals", visibility::make(pub))]
83    pub(crate) fn from_commitment(
84        commitment: &crate::keys::VerifiableSecretSharingCommitment<C>,
85    ) -> Result<VerifyingKey<C>, Error<C>> {
86        Ok(VerifyingKey::new(
87            commitment
88                .coefficients()
89                .first()
90                .ok_or(Error::IncorrectCommitment)?
91                .value(),
92        ))
93    }
94}
95
96impl<C> Debug for VerifyingKey<C>
97where
98    C: Ciphersuite,
99{
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        f.debug_tuple("VerifyingKey")
102            .field(
103                &self
104                    .serialize()
105                    .map(hex::encode)
106                    .unwrap_or("<invalid>".to_string()),
107            )
108            .finish()
109    }
110}
111
112#[cfg(any(test, feature = "test-impl"))]
113impl<C> FromHex for VerifyingKey<C>
114where
115    C: Ciphersuite,
116{
117    type Error = &'static str;
118
119    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
120        let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
121        Self::deserialize(&v).map_err(|_| "malformed verifying key encoding")
122    }
123}