crypto_box/
public_key.rs

1use crate::{SecretKey, KEY_SIZE};
2use core::{array::TryFromSliceError, cmp::Ordering};
3use curve25519_dalek::MontgomeryPoint;
4
5#[cfg(feature = "seal")]
6use {
7    crate::{get_seal_nonce, SalsaBox, TAG_SIZE},
8    aead::{rand_core::CryptoRngCore, Aead},
9    alloc::vec::Vec,
10};
11
12#[cfg(feature = "serde")]
13use serdect::serde::{de, ser, Deserialize, Serialize};
14
15/// A `crypto_box` public key.
16///
17/// This type can be serialized if the `serde` feature is enabled.
18#[derive(Clone, Debug, Eq, PartialEq, Hash)]
19pub struct PublicKey(pub(crate) MontgomeryPoint);
20
21impl PublicKey {
22    /// Initialize [`PublicKey`] from a byte array.
23    pub fn from_bytes(bytes: [u8; KEY_SIZE]) -> Self {
24        PublicKey(MontgomeryPoint(bytes))
25    }
26
27    /// Initialize [`PublicKey`] from a byte slice.
28    ///
29    /// Returns [`TryFromSliceError`] if the slice length is not exactly equal
30    /// to [`KEY_SIZE`].
31    pub fn from_slice(slice: &[u8]) -> Result<Self, TryFromSliceError> {
32        slice.try_into().map(Self::from_bytes)
33    }
34
35    /// Borrow the public key as bytes.
36    pub fn as_bytes(&self) -> &[u8; KEY_SIZE] {
37        self.0.as_bytes()
38    }
39
40    /// Serialize this public key as bytes.
41    pub fn to_bytes(&self) -> [u8; KEY_SIZE] {
42        self.0.to_bytes()
43    }
44
45    /// Implementation of `crypto_box_seal` function from [libsodium "sealed boxes"].
46    ///
47    /// Sealed boxes are designed to anonymously send messages to a recipient given their public key.
48    ///
49    /// [libsodium "sealed boxes"]: https://doc.libsodium.org/public-key_cryptography/sealed_boxes
50    #[cfg(feature = "seal")]
51    pub fn seal(
52        &self,
53        csprng: &mut impl CryptoRngCore,
54        plaintext: &[u8],
55    ) -> Result<Vec<u8>, aead::Error> {
56        let mut out = Vec::with_capacity(KEY_SIZE + TAG_SIZE + plaintext.len());
57        let ephemeral_sk = SecretKey::generate(csprng);
58        let ephemeral_pk = ephemeral_sk.public_key();
59        out.extend_from_slice(ephemeral_pk.as_bytes());
60
61        let nonce = get_seal_nonce(&ephemeral_pk, self);
62        let salsabox = SalsaBox::new(self, &ephemeral_sk);
63        let encrypted = salsabox.encrypt(&nonce, plaintext)?;
64        out.extend_from_slice(&encrypted);
65
66        Ok(out)
67    }
68}
69
70impl AsRef<[u8]> for PublicKey {
71    fn as_ref(&self) -> &[u8] {
72        self.as_bytes()
73    }
74}
75
76impl From<&SecretKey> for PublicKey {
77    fn from(secret_key: &SecretKey) -> PublicKey {
78        secret_key.public_key()
79    }
80}
81
82impl From<[u8; KEY_SIZE]> for PublicKey {
83    fn from(bytes: [u8; KEY_SIZE]) -> PublicKey {
84        Self::from_bytes(bytes)
85    }
86}
87
88impl TryFrom<&[u8]> for PublicKey {
89    type Error = TryFromSliceError;
90
91    fn try_from(slice: &[u8]) -> Result<Self, TryFromSliceError> {
92        Self::from_slice(slice)
93    }
94}
95
96impl PartialOrd for PublicKey {
97    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98        Some(self.cmp(other))
99    }
100}
101
102impl Ord for PublicKey {
103    fn cmp(&self, other: &Self) -> Ordering {
104        self.as_bytes().cmp(other.as_bytes())
105    }
106}
107
108impl From<MontgomeryPoint> for PublicKey {
109    fn from(value: MontgomeryPoint) -> Self {
110        PublicKey(value)
111    }
112}
113
114#[cfg(feature = "serde")]
115impl Serialize for PublicKey {
116    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: ser::Serializer,
119    {
120        serdect::array::serialize_hex_upper_or_bin(self.as_bytes(), serializer)
121    }
122}
123
124#[cfg(feature = "serde")]
125impl<'de> Deserialize<'de> for PublicKey {
126    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127    where
128        D: de::Deserializer<'de>,
129    {
130        let mut bytes = [0u8; KEY_SIZE];
131        serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
132        Ok(PublicKey::from(bytes)) // TODO(tarcieri): validate key
133    }
134}