bc_components/x25519/
x25519_public_key.rs

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