bc_components/x25519/
x25519_public_key.rs

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