xpx_chain_crypto/
public.rs

1// Copyright 2018 ProximaX Limited. All rights reserved.
2// Use of this source code is governed by the Apache 2.0
3// license that can be found in the LICENSE file.
4
5//! ed25519 public keys.
6
7use core::fmt::Debug;
8
9use curve25519_dalek::{
10    constants,
11    digest::{generic_array::typenum::U64, Digest},
12};
13
14use curve25519_dalek::edwards::CompressedEdwardsY;
15use curve25519_dalek::edwards::EdwardsPoint;
16use curve25519_dalek::scalar::Scalar;
17
18pub use sha3::Sha3_512;
19
20#[cfg(feature = "serde")]
21use serde::de::Error as SerdeError;
22#[cfg(feature = "serde")]
23use serde::de::Visitor;
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26#[cfg(feature = "serde")]
27use serde::{Deserializer, Serializer};
28
29use crate::constants::*;
30use crate::errors::*;
31use crate::secret::*;
32use crate::signature::*;
33
34/// An ed25519 public key.
35#[derive(Copy, Clone, Default, Eq, PartialEq)]
36pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint);
37
38impl Debug for PublicKey {
39    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
40        write!(f, "PublicKey({:?}), {:?})", self.0, self.1)
41    }
42}
43
44impl AsRef<[u8]> for PublicKey {
45    fn as_ref(&self) -> &[u8] {
46        self.as_bytes()
47    }
48}
49
50impl<'a> From<&'a SecretKey> for PublicKey {
51    /// Derive this public key from its corresponding `SecretKey`.
52    fn from(secret_key: &SecretKey) -> PublicKey {
53        let mut h: Sha3_512 = Sha3_512::new();
54        let mut hash: [u8; 64] = [0u8; 64];
55        let mut digest: [u8; 32] = [0u8; 32];
56
57        let secret_key = secret_key.to_bytes();
58        h.update(secret_key);
59        hash.copy_from_slice(h.finalize().as_slice());
60
61        digest.copy_from_slice(&hash[..32]);
62
63        PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
64    }
65}
66
67impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
68    /// Derive this public key from its corresponding `ExpandedSecretKey`.
69    fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
70        let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();
71
72        PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
73    }
74}
75
76impl PublicKey {
77    /// Convert this public key to a byte array.
78    #[inline]
79    pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
80        self.0.to_bytes()
81    }
82
83    /// View this public key as a byte array.
84    #[inline]
85    pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
86        &(self.0).0
87    }
88
89    /// Construct a `PublicKey` from a slice of bytes.
90    ///
91    /// # Warning
92    ///
93    /// The caller is responsible for ensuring that the bytes passed into this
94    /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY`
95    /// and that said compressed point is actually a point on the curve.
96    ///
97    /// # Example
98    ///
99    /// ```
100    /// # extern crate xpx_chain_crypto;
101    /// #
102    /// use xpx_chain_crypto::PublicKey;
103    /// use xpx_chain_crypto::PUBLIC_KEY_LENGTH;
104    /// use xpx_chain_crypto::SignatureError;
105    ///
106    /// # fn doctest() -> Result<PublicKey, SignatureError> {
107    /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
108    ///    215,  90, 152,   1, 130, 177,  10, 183, 213,  75, 254, 211, 201, 100,   7,  58,
109    ///     14, 225, 114, 243, 218, 166,  35,  37, 175,   2,  26, 104, 247,   7,   81, 26];
110    ///
111    /// let public_key = PublicKey::from_bytes(&public_key_bytes)?;
112    /// #
113    /// # Ok(public_key)
114    /// # }
115    /// #
116    /// # fn main() {
117    /// #     doctest();
118    /// # }
119    /// ```
120    ///
121    /// # Returns
122    ///
123    /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value
124    /// is an `SignatureError` describing the error that occurred.
125    #[inline]
126    pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
127        if bytes.len() != PUBLIC_KEY_LENGTH {
128            return Err(SignatureError(InternalError::BytesLengthError {
129                name: "PublicKey",
130                length: PUBLIC_KEY_LENGTH,
131            }));
132        }
133        let mut bits: [u8; 32] = [0u8; 32];
134        bits.copy_from_slice(&bytes[..32]);
135
136        let compressed = CompressedEdwardsY(bits);
137        let point = compressed
138            .decompress()
139            .ok_or(SignatureError(InternalError::PointDecompressionError))?;
140
141        Ok(PublicKey(compressed, point))
142    }
143
144    /// Internal utility function for mangling the bits of a (formerly
145    /// mathematically well-defined) "scalar" and multiplying it to produce a
146    /// public key.
147    fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(
148        bits: &mut [u8; 32],
149    ) -> PublicKey {
150        bits[0] &= 248;
151        bits[31] &= 127;
152        bits[31] |= 64;
153
154        let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
155        let compressed = point.compress();
156
157        PublicKey(compressed, point)
158    }
159
160    /// Verify a signature on a message with this keypair's public key.
161    ///
162    /// # Return
163    ///
164    /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
165    #[allow(non_snake_case)]
166    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
167        let mut h: Sha3_512 = Sha3_512::new();
168        let R: EdwardsPoint;
169        let k: Scalar;
170        let minus_A: EdwardsPoint = -self.1;
171
172        h.update(signature.R.as_bytes());
173        h.update(self.as_bytes());
174        h.update(&message);
175
176        k = Scalar::from_hash(h);
177        R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
178
179        if R.compress() == signature.R {
180            Ok(())
181        } else {
182            Err(SignatureError(InternalError::VerifyError))
183        }
184    }
185
186    /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
187    ///
188    /// # Inputs
189    ///
190    /// * `prehashed_message` is an instantiated hash digest with 512-bits of
191    ///   output which has had the message to be signed previously fed into its
192    ///   state.
193    /// * `context` is an optional context string, up to 255 bytes inclusive,
194    ///   which may be used to provide additional domain separation.  If not
195    ///   set, this will default to an empty string.
196    /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`.
197    ///
198    /// # Returns
199    ///
200    /// Returns `true` if the `signature` was a valid signature created by this
201    /// `Keypair` on the `prehashed_message`.
202    ///
203    /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
204    #[allow(non_snake_case)]
205    pub fn verify_prehashed<D>(
206        &self,
207        prehashed_message: D,
208        context: Option<&[u8]>,
209        signature: &Signature,
210    ) -> Result<(), SignatureError>
211    where
212        D: Digest<OutputSize = U64>,
213    {
214        let mut h: Sha3_512 = Sha3_512::default();
215        let R: EdwardsPoint;
216        let k: Scalar;
217
218        let ctx: &[u8] = context.unwrap_or(b"");
219        debug_assert!(
220            ctx.len() <= 255,
221            "The context must not be longer than 255 octets."
222        );
223
224        let minus_A: EdwardsPoint = -self.1;
225
226        h.update(b"SigEd25519 no Ed25519 collisions");
227        h.update(&[1]); // Ed25519ph
228        h.update(&[ctx.len() as u8]);
229        h.update(ctx);
230        h.update(signature.R.as_bytes());
231        h.update(self.as_bytes());
232        h.update(prehashed_message.finalize().as_slice());
233
234        k = Scalar::from_hash(h);
235        R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
236
237        if R.compress() == signature.R {
238            Ok(())
239        } else {
240            Err(SignatureError(InternalError::VerifyError))
241        }
242    }
243}
244
245#[cfg(feature = "serde")]
246impl Serialize for PublicKey {
247    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
248    where
249        S: Serializer,
250    {
251        serializer.serialize_bytes(self.as_bytes())
252    }
253}
254
255#[cfg(feature = "serde")]
256impl<'d> Deserialize<'d> for PublicKey {
257    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258    where
259        D: Deserializer<'d>,
260    {
261        struct PublicKeyVisitor;
262
263        impl<'d> Visitor<'d> for PublicKeyVisitor {
264            type Value = PublicKey;
265
266            fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
267                formatter.write_str(
268                    "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032",
269                )
270            }
271
272            fn visit_bytes<E>(self, bytes: &[u8]) -> Result<PublicKey, E>
273            where
274                E: SerdeError,
275            {
276                PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
277            }
278        }
279        deserializer.deserialize_bytes(PublicKeyVisitor)
280    }
281}