decaf377_rdsa/
verification_key.rs

1use core::{
2    cmp::{self, Ord},
3    hash::{Hash, Hasher},
4    marker::PhantomData,
5};
6
7use decaf377::Fr;
8
9use crate::{domain::Sealed, Domain, Error, Signature, SpendAuth};
10
11/// A refinement type for `[u8; 32]` indicating that the bytes represent
12/// an encoding of a `decaf377-rdsa` verification key.
13///
14/// This is useful for representing a compressed verification key; the
15/// [`VerificationKey`] type in this library holds other decompressed state
16/// used in signature verification.
17#[derive(Copy, Clone)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct VerificationKeyBytes<D: Domain> {
20    pub(crate) bytes: [u8; 32],
21    pub(crate) _marker: PhantomData<D>,
22}
23
24impl<D: Domain> AsRef<[u8; 32]> for VerificationKeyBytes<D> {
25    fn as_ref(&self) -> &[u8; 32] {
26        &self.bytes
27    }
28}
29
30impl<D: Domain> From<[u8; 32]> for VerificationKeyBytes<D> {
31    fn from(bytes: [u8; 32]) -> VerificationKeyBytes<D> {
32        VerificationKeyBytes {
33            bytes,
34            _marker: PhantomData,
35        }
36    }
37}
38
39impl<D: Domain> From<VerificationKeyBytes<D>> for [u8; 32] {
40    fn from(refined: VerificationKeyBytes<D>) -> [u8; 32] {
41        refined.bytes
42    }
43}
44
45impl<D: Domain> Hash for VerificationKeyBytes<D> {
46    fn hash<H: Hasher>(&self, state: &mut H) {
47        self.bytes.hash(state);
48        self._marker.hash(state);
49    }
50}
51
52impl<D: Domain> PartialOrd for VerificationKeyBytes<D> {
53    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
54        self.bytes.partial_cmp(&other.bytes)
55    }
56}
57
58impl<D: Domain> Ord for VerificationKeyBytes<D> {
59    fn cmp(&self, other: &Self) -> cmp::Ordering {
60        self.bytes.cmp(&other.bytes)
61    }
62}
63
64/// A valid `decaf377-rdsa` verification key.
65///
66/// This type holds decompressed state used in signature verification; if the
67/// verification key may not be used immediately, it is probably better to use
68/// [`VerificationKeyBytes`], which is a refinement type for `[u8; 32]`.
69#[derive(Copy, Clone)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71#[cfg_attr(feature = "serde", serde(try_from = "VerificationKeyBytes<D>"))]
72#[cfg_attr(feature = "serde", serde(into = "VerificationKeyBytes<D>"))]
73#[cfg_attr(feature = "serde", serde(bound = "D: Domain"))]
74pub struct VerificationKey<D: Domain> {
75    pub(crate) point: decaf377::Element,
76    pub(crate) bytes: VerificationKeyBytes<D>,
77}
78
79impl<D: Domain> Hash for VerificationKey<D> {
80    fn hash<H: Hasher>(&self, state: &mut H) {
81        self.bytes.hash(state);
82    }
83}
84
85impl<D: Domain> PartialOrd for VerificationKey<D> {
86    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
87        self.bytes.partial_cmp(&other.bytes)
88    }
89}
90
91impl<D: Domain> Ord for VerificationKey<D> {
92    fn cmp(&self, other: &Self) -> cmp::Ordering {
93        self.bytes.cmp(&other.bytes)
94    }
95}
96
97impl<D: Domain> From<VerificationKey<D>> for VerificationKeyBytes<D> {
98    fn from(pk: VerificationKey<D>) -> VerificationKeyBytes<D> {
99        pk.bytes
100    }
101}
102
103impl<D: Domain> VerificationKey<D> {
104    /// Returns the byte encoding of the verification key.
105    ///
106    /// This is the same as `.into()`, but does not require type inference.
107    pub fn to_bytes(&self) -> [u8; 32] {
108        self.bytes.bytes
109    }
110}
111
112impl<D: Domain> From<VerificationKey<D>> for [u8; 32] {
113    fn from(pk: VerificationKey<D>) -> [u8; 32] {
114        pk.bytes.bytes
115    }
116}
117
118impl<'a, D: Domain> From<&'a VerificationKey<D>> for [u8; 32] {
119    fn from(pk: &'a VerificationKey<D>) -> [u8; 32] {
120        pk.bytes.bytes
121    }
122}
123
124impl<D: Domain> TryFrom<VerificationKeyBytes<D>> for VerificationKey<D> {
125    type Error = Error;
126
127    fn try_from(bytes: VerificationKeyBytes<D>) -> Result<Self, Self::Error> {
128        // Note: the identity element is allowed as a verification key.
129        let point = decaf377::Encoding(bytes.bytes)
130            .vartime_decompress()
131            .map_err(|_| Error::MalformedVerificationKey)?;
132
133        Ok(VerificationKey { point, bytes })
134    }
135}
136
137impl<D: Domain> TryFrom<[u8; 32]> for VerificationKey<D> {
138    type Error = Error;
139
140    fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
141        VerificationKeyBytes::from(bytes).try_into()
142    }
143}
144
145impl<D: Domain> TryFrom<&[u8]> for VerificationKeyBytes<D> {
146    type Error = Error;
147
148    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
149        if bytes.len() == 32 {
150            let mut bytes32 = [0u8; 32];
151            bytes32.copy_from_slice(&bytes);
152            Ok(bytes32.into())
153        } else {
154            Err(Error::WrongSliceLength {
155                expected: 32,
156                found: bytes.len(),
157            })
158        }
159    }
160}
161
162impl<D: Domain> TryFrom<&[u8]> for VerificationKey<D> {
163    type Error = Error;
164
165    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
166        VerificationKeyBytes::try_from(bytes)?.try_into()
167    }
168}
169
170impl<D: Domain> AsRef<[u8; 32]> for VerificationKey<D> {
171    fn as_ref(&self) -> &[u8; 32] {
172        self.bytes.as_ref()
173    }
174}
175
176impl VerificationKey<SpendAuth> {
177    /// Randomize this verification key with the given `randomizer`.
178    ///
179    /// Randomization is only supported for `SpendAuth` keys.
180    pub fn randomize(&self, randomizer: &Fr) -> VerificationKey<SpendAuth> {
181        let point = self.point + (SpendAuth::basepoint() * randomizer);
182        let bytes = VerificationKeyBytes {
183            bytes: point.vartime_compress().into(),
184            _marker: PhantomData,
185        };
186        VerificationKey { bytes, point }
187    }
188}
189
190impl<D: Domain> VerificationKey<D> {
191    pub(crate) fn from(s: &Fr) -> VerificationKey<D> {
192        let point = &D::basepoint() * s;
193        let bytes = VerificationKeyBytes {
194            bytes: point.vartime_compress().into(),
195            _marker: PhantomData,
196        };
197        VerificationKey { bytes, point }
198    }
199
200    /// Verify a purported `signature` over `msg` made by this verification key.
201    // This is similar to impl signature::Verifier but without boxed errors
202    pub fn verify(&self, msg: &[u8], signature: &Signature<D>) -> Result<(), Error> {
203        use crate::HStar;
204        let c = HStar::default()
205            .update(&signature.r_bytes()[..])
206            .update(&self.bytes.bytes[..]) // XXX ugly
207            .update(msg)
208            .finalize();
209        self.verify_prehashed(signature, c)
210    }
211
212    /// Convenience method for identity checks.
213    pub fn is_identity(&self) -> bool {
214        self.point == decaf377::Element::IDENTITY
215    }
216
217    /// Verify a purported `signature` with a prehashed challenge.
218    #[allow(non_snake_case)]
219    pub(crate) fn verify_prehashed(&self, signature: &Signature<D>, c: Fr) -> Result<(), Error> {
220        let R = decaf377::Encoding(signature.r_bytes())
221            .vartime_decompress()
222            .map_err(|_| Error::InvalidSignature)?;
223
224        let s =
225            Fr::from_bytes_checked(&signature.s_bytes()).map_err(|_| Error::InvalidSignature)?;
226
227        // XXX rewrite as normal double scalar mul
228        // Verify check is h * ( - s * B + R  + c * A) == 0
229        //                 h * ( s * B - c * A - R) == 0
230        let sB = D::basepoint() * s;
231        let cA = self.point * c;
232        let check = sB - cA - R;
233
234        if check == decaf377::Element::IDENTITY {
235            Ok(())
236        } else {
237            Err(Error::InvalidSignature)
238        }
239    }
240}
241
242impl<D: Domain> PartialEq for VerificationKey<D> {
243    fn eq(&self, other: &Self) -> bool {
244        self.bytes.eq(&other.bytes)
245    }
246}
247
248impl<D: Domain> PartialEq for VerificationKeyBytes<D> {
249    fn eq(&self, other: &Self) -> bool {
250        self.bytes.eq(&other.bytes)
251    }
252}
253
254impl<D: Domain> Eq for VerificationKey<D> {}
255impl<D: Domain> Eq for VerificationKeyBytes<D> {}
256
257#[cfg(feature = "std")]
258mod std_only {
259    use super::*;
260
261    use crate::Binding;
262
263    impl std::fmt::Debug for VerificationKey<Binding> {
264        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265            f.debug_tuple("VerificationKey<Binding>")
266                .field(&hex::encode(&<[u8; 32]>::from(*self)))
267                .finish()
268        }
269    }
270
271    impl std::fmt::Debug for VerificationKey<SpendAuth> {
272        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273            f.debug_tuple("VerificationKey<SpendAuth>")
274                .field(&hex::encode(&<[u8; 32]>::from(*self)))
275                .finish()
276        }
277    }
278
279    impl std::fmt::Debug for VerificationKeyBytes<Binding> {
280        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281            f.debug_tuple("VerificationKeyBytes<Binding>")
282                .field(&hex::encode(&<[u8; 32]>::from(*self)))
283                .finish()
284        }
285    }
286
287    impl std::fmt::Debug for VerificationKeyBytes<SpendAuth> {
288        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289            f.debug_tuple("VerificationKeyBytes<SpendAuth>")
290                .field(&hex::encode(&<[u8; 32]>::from(*self)))
291                .finish()
292        }
293    }
294}
295
296#[cfg(feature = "std")]
297pub use std_only::*;