bc_components/x25519/
x25519_public_key.rs

1use std::rc::Rc;
2
3use bc_ur::prelude::*;
4
5use crate::{EncapsulationPublicKey, Encrypter, Error, Result, tags};
6
7/// A public key for X25519 key agreement operations.
8///
9/// X25519 is an elliptic-curve Diffie-Hellman key exchange protocol based on
10/// Curve25519 as defined in [RFC 7748](https://datatracker.ietf.org/doc/html/rfc7748). It allows
11/// two parties to establish a shared secret key over an insecure channel.
12///
13/// The X25519 public key is generated from a corresponding private key and is
14/// designed to be:
15/// - Compact (32 bytes)
16/// - Fast to use in key agreement operations
17/// - Resistant to various cryptographic attacks
18///
19/// This implementation provides:
20/// - Creation of X25519 public keys from raw data
21/// - CBOR serialization and deserialization
22/// - Support for the Encrypter trait for key encapsulation
23/// - Various utility and conversion methods
24#[derive(Clone, PartialEq, Eq, Hash)]
25pub struct X25519PublicKey([u8; Self::KEY_SIZE]);
26
27impl X25519PublicKey {
28    pub const KEY_SIZE: usize = 32;
29
30    /// Restore an `X25519PublicKey` from a fixed-size array of bytes.
31    pub const fn from_data(data: [u8; Self::KEY_SIZE]) -> Self { Self(data) }
32
33    /// Restore an `X25519PublicKey` from a reference to an array of bytes.
34    pub fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self> {
35        let data = data.as_ref();
36        if data.len() != Self::KEY_SIZE {
37            return Err(Error::invalid_size(
38                "X25519 public key",
39                Self::KEY_SIZE,
40                data.len(),
41            ));
42        }
43        let mut arr = [0u8; Self::KEY_SIZE];
44        arr.copy_from_slice(data);
45        Ok(Self::from_data(arr))
46    }
47
48    /// Get a reference to the fixed-size array of bytes.
49    pub fn data(&self) -> &[u8; Self::KEY_SIZE] { self.into() }
50
51    /// Get the X25519 public key as a byte slice.
52    pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
53
54    /// Restore an `X25519PublicKey` from a hex string.
55    ///
56    /// # Panics
57    ///
58    /// Panics if the hex string is invalid or the length is not
59    /// `X25519PublicKey::KEY_SIZE * 2`.
60    pub fn from_hex(hex: impl AsRef<str>) -> Self {
61        Self::from_data_ref(hex::decode(hex.as_ref()).unwrap()).unwrap()
62    }
63
64    /// Get the hex string representation of the `X25519PublicKey`.
65    pub fn hex(&self) -> String { hex::encode(self.data()) }
66}
67
68impl AsRef<[u8]> for X25519PublicKey {
69    fn as_ref(&self) -> &[u8] { &self.0 }
70}
71
72/// Implements conversion from a reference-counted X25519PublicKey to an owned
73/// X25519PublicKey.
74impl From<Rc<X25519PublicKey>> for X25519PublicKey {
75    fn from(value: Rc<X25519PublicKey>) -> Self { value.as_ref().clone() }
76}
77
78/// Implements conversion from an X25519PublicKey reference to a byte array
79/// reference.
80impl<'a> From<&'a X25519PublicKey> for &'a [u8; X25519PublicKey::KEY_SIZE] {
81    fn from(value: &'a X25519PublicKey) -> Self { &value.0 }
82}
83
84/// Implements `AsRef<X25519PublicKey>` to allow self-reference.
85impl AsRef<X25519PublicKey> for X25519PublicKey {
86    fn as_ref(&self) -> &X25519PublicKey { self }
87}
88
89/// Implements the CBORTagged trait to provide CBOR tag information.
90impl CBORTagged for X25519PublicKey {
91    fn cbor_tags() -> Vec<Tag> {
92        tags_for_values(&[tags::TAG_X25519_PUBLIC_KEY])
93    }
94}
95
96/// Implements conversion from X25519PublicKey to CBOR for serialization.
97impl From<X25519PublicKey> for CBOR {
98    fn from(value: X25519PublicKey) -> Self { value.tagged_cbor() }
99}
100
101/// Implements CBORTaggedEncodable to provide CBOR encoding functionality.
102impl CBORTaggedEncodable for X25519PublicKey {
103    fn untagged_cbor(&self) -> CBOR { CBOR::to_byte_string(self.data()) }
104}
105
106/// Implements `TryFrom<CBOR>` for X25519PublicKey to support conversion from
107/// CBOR data.
108impl TryFrom<CBOR> for X25519PublicKey {
109    type Error = dcbor::Error;
110
111    fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
112        Self::from_tagged_cbor(cbor)
113    }
114}
115
116/// Implements CBORTaggedDecodable to provide CBOR decoding functionality.
117impl CBORTaggedDecodable for X25519PublicKey {
118    fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
119        let data = CBOR::try_into_byte_string(untagged_cbor)?;
120        Ok(Self::from_data_ref(data)?)
121    }
122}
123
124/// Implements Debug to output the key with a type label.
125impl std::fmt::Debug for X25519PublicKey {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        write!(f, "X25519PublicKey({})", self.hex())
128    }
129}
130
131/// Implements conversion from an X25519PublicKey reference to an owned
132/// X25519PublicKey.
133impl From<&X25519PublicKey> for X25519PublicKey {
134    fn from(key: &X25519PublicKey) -> Self { key.clone() }
135}
136
137/// Implements conversion from an X25519PublicKey to a byte vector.
138impl From<X25519PublicKey> for Vec<u8> {
139    fn from(key: X25519PublicKey) -> Self { key.0.to_vec() }
140}
141
142/// Implements conversion from an X25519PublicKey reference to a byte vector.
143impl From<&X25519PublicKey> for Vec<u8> {
144    fn from(key: &X25519PublicKey) -> Self { key.0.to_vec() }
145}
146
147/// Implements the Encrypter trait to support key encapsulation mechanisms.
148impl Encrypter for X25519PublicKey {
149    fn encapsulation_public_key(&self) -> EncapsulationPublicKey {
150        EncapsulationPublicKey::X25519(self.clone())
151    }
152}