bc_components/x25519/
x25519_private_key.rs

1use std::rc::Rc;
2use bc_crypto::x25519_new_private_key_using;
3use bc_ur::prelude::*;
4use crate::{ tags, Decrypter, EncapsulationPrivateKey, SymmetricKey, X25519PublicKey };
5use bc_rand::{ SecureRandomNumberGenerator, RandomNumberGenerator };
6use anyhow::{ bail, Result };
7
8/// A private key for X25519 key agreement operations.
9///
10/// X25519 is an elliptic-curve Diffie-Hellman key exchange protocol based on Curve25519
11/// 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/// Key features of X25519:
15/// - High security (128-bit security level)
16/// - High performance
17/// - Small key sizes (32 bytes)
18/// - Protection against various side-channel attacks
19/// - Relatively simple implementation compared to other elliptic curve systems
20///
21/// This implementation provides:
22/// - Generation of random X25519 private keys
23/// - Derivation of the corresponding public key
24/// - Shared key generation with another party's public key
25/// - CBOR serialization and deserialization
26/// - Various utility and conversion methods
27#[derive(Clone, PartialEq, Eq, Hash)]
28pub struct X25519PrivateKey([u8; Self::KEY_SIZE]);
29
30impl X25519PrivateKey {
31    pub const KEY_SIZE: usize = 32;
32
33    /// Generate a new random `X25519PrivateKey`.
34    pub fn new() -> Self {
35        let mut rng = SecureRandomNumberGenerator;
36        Self::new_using(&mut rng)
37    }
38
39    /// Generate a new random `X25519PrivateKey` and corresponding `X25519PublicKey`.
40    pub fn keypair() -> (X25519PrivateKey, X25519PublicKey) {
41        let private_key = X25519PrivateKey::new();
42        let public_key = private_key.public_key();
43        (private_key, public_key)
44    }
45
46    /// Generate a new random `X25519PrivateKey` and corresponding `X25519PublicKey` using the given random number generator.
47    pub fn keypair_using(rng: &mut impl RandomNumberGenerator) -> (X25519PrivateKey, X25519PublicKey) {
48        let private_key = X25519PrivateKey::new_using(rng);
49        let public_key = private_key.public_key();
50        (private_key, public_key)
51    }
52
53    /// Generate a new random `X25519PrivateKey` using the given random number generator.
54    pub fn new_using(rng: &mut impl RandomNumberGenerator) -> Self {
55        Self(x25519_new_private_key_using(rng))
56    }
57
58    /// Restore an `X25519PrivateKey` from a fixed-size array of bytes.
59    pub const fn from_data(data: [u8; Self::KEY_SIZE]) -> Self {
60        Self(data)
61    }
62
63    /// Restore an `X25519PrivateKey` from a reference to an array of bytes.
64    pub fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self> {
65        let data = data.as_ref();
66        if data.len() != Self::KEY_SIZE {
67            bail!("Invalid X25519 private key size");
68        }
69        let mut arr = [0u8; Self::KEY_SIZE];
70        arr.copy_from_slice(data);
71        Ok(Self::from_data(arr))
72    }
73
74    /// Get a reference to the fixed-size array of bytes.
75    pub fn data(&self) -> &[u8; Self::KEY_SIZE] {
76        self.into()
77    }
78
79    /// Restore an `X25519PrivateKey` from a hex string.
80    ///
81    /// # Panics
82    ///
83    /// Panics if the hex string is invalid or the length is not `X25519PrivateKey::KEY_SIZE * 2`.
84    pub fn from_hex(hex: impl AsRef<str>) -> Self {
85        Self::from_data_ref(hex::decode(hex.as_ref()).unwrap()).unwrap()
86    }
87
88    /// Get the hex string representation of the `X25519PrivateKey`.
89    pub fn hex(&self) -> String {
90        hex::encode(self.data())
91    }
92
93    /// Get the `X25519PublicKey` corresponding to this `X25519PrivateKey`.
94    pub fn public_key(&self) -> X25519PublicKey {
95        X25519PublicKey::from_data(
96            bc_crypto::x25519_public_key_from_private_key(self.into())
97        )
98    }
99
100    /// Derive an `X25519PrivateKey` from the given key material.
101    pub fn derive_from_key_material(key_material: impl AsRef<[u8]>) -> Self {
102        Self::from_data(bc_crypto::x25519_derive_private_key(key_material))
103    }
104
105    /// Derive a shared symmetric key from this `X25519PrivateKey` and the given `X25519PublicKey`.
106    pub fn shared_key_with(&self, public_key: &X25519PublicKey) -> SymmetricKey {
107        SymmetricKey::from_data(bc_crypto::x25519_shared_key(self.into(), public_key.into()))
108    }
109}
110
111/// Implements the Decrypter trait to support key encapsulation mechanisms.
112impl Decrypter for X25519PrivateKey{
113    fn encapsulation_private_key(&self) -> EncapsulationPrivateKey {
114        EncapsulationPrivateKey::X25519(self.clone())
115    }
116}
117
118/// Implements Default to create a new random X25519PrivateKey.
119impl Default for X25519PrivateKey {
120    fn default() -> Self {
121        Self::new()
122    }
123}
124
125/// Implements conversion from an X25519PrivateKey reference to a byte array reference.
126impl<'a> From<&'a X25519PrivateKey> for &'a [u8; X25519PrivateKey::KEY_SIZE] {
127    fn from(value: &'a X25519PrivateKey) -> Self {
128        &value.0
129    }
130}
131
132/// Implements conversion from a reference-counted X25519PrivateKey to an owned X25519PrivateKey.
133impl From<Rc<X25519PrivateKey>> for X25519PrivateKey {
134    fn from(value: Rc<X25519PrivateKey>) -> Self {
135        value.as_ref().clone()
136    }
137}
138
139/// Implements `AsRef<X25519PrivateKey>` to allow self-reference.
140impl AsRef<X25519PrivateKey> for X25519PrivateKey {
141    fn as_ref(&self) -> &Self {
142        self
143    }
144}
145
146/// Implements the CBORTagged trait to provide CBOR tag information.
147impl CBORTagged for X25519PrivateKey {
148    fn cbor_tags() -> Vec<Tag> {
149        tags_for_values(&[tags::TAG_X25519_PRIVATE_KEY])
150    }
151}
152
153/// Implements conversion from X25519PrivateKey to CBOR for serialization.
154impl From<X25519PrivateKey> for CBOR {
155    fn from(value: X25519PrivateKey) -> Self {
156        value.tagged_cbor()
157    }
158}
159
160/// Implements CBORTaggedEncodable to provide CBOR encoding functionality.
161impl CBORTaggedEncodable for X25519PrivateKey {
162    fn untagged_cbor(&self) -> CBOR {
163        CBOR::to_byte_string(self.data())
164    }
165}
166
167/// Implements `TryFrom<CBOR>` for X25519PrivateKey to support conversion from CBOR data.
168impl TryFrom<CBOR> for X25519PrivateKey {
169    type Error = dcbor::Error;
170
171    fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
172        Self::from_tagged_cbor(cbor)
173    }
174}
175
176/// Implements CBORTaggedDecodable to provide CBOR decoding functionality.
177impl CBORTaggedDecodable for X25519PrivateKey {
178    fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
179        let data = CBOR::try_into_byte_string(untagged_cbor)?;
180        Ok(Self::from_data_ref(data)?)
181    }
182}
183
184/// Implements Debug to output the key with a type label.
185impl std::fmt::Debug for X25519PrivateKey {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        write!(f, "X25519PrivateKey({})", self.hex())
188    }
189}
190
191/// Implements conversion from an X25519PrivateKey reference to an owned X25519PrivateKey.
192impl From<&X25519PrivateKey> for X25519PrivateKey {
193    fn from(key: &X25519PrivateKey) -> Self {
194        key.clone()
195    }
196}
197
198/// Implements conversion from an X25519PrivateKey to a byte vector.
199impl From<X25519PrivateKey> for Vec<u8> {
200    fn from(key: X25519PrivateKey) -> Self {
201        key.0.to_vec()
202    }
203}
204
205/// Implements conversion from an X25519PrivateKey reference to a byte vector.
206impl From<&X25519PrivateKey> for Vec<u8> {
207    fn from(key: &X25519PrivateKey) -> Self {
208        key.0.to_vec()
209    }
210}