1#[cfg(feature = "rustcrypto-ec")]
5use elliptic_curve::{
6 point::PointCompression,
7 sec1::{CompressedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
8 AffinePoint, Curve, CurveArithmetic,
9};
10use rand_core::CryptoRngCore;
11
12use crate::{curves, curves::KeyPair, error::*};
13#[cfg(feature = "dalek")]
14use curves::{dalek, X25519};
15#[cfg(feature = "rustcrypto-ec")]
16use curves::{rcec, EllipticCurve};
17
18#[derive(Clone, Debug)]
21pub struct BlindedPublicKey<K: KeyPair> {
22 pub inner: K::PublicKey,
24 pub blinding_factor: K::PublicKey,
30}
31
32#[cfg(feature = "dalek")]
33impl Blinded for BlindedPublicKey<X25519> {
34 type BytesArray = [u8; 64];
35
36 fn from_bytes(bytes: &Self::BytesArray) -> Result<Self> {
37 let inner_bytes: [u8; 32] = bytes[0..32].try_into().map_err(|_| Error::Decoding)?;
38 let inner = dalek::PublicKey::from(inner_bytes);
39 let blinding_factor_bytes: [u8; 32] =
40 bytes[32..64].try_into().map_err(|_| Error::Decoding)?;
41 let blinding_factor = dalek::PublicKey::from(blinding_factor_bytes);
42
43 Ok(Self {
44 inner,
45 blinding_factor,
46 })
47 }
48
49 fn to_bytes(&self) -> Self::BytesArray {
50 let mut output = [0u8; 64];
51 output[0..32].copy_from_slice(self.inner.as_bytes());
52 output[32..64].copy_from_slice(self.blinding_factor.as_bytes());
53
54 output
55 }
56}
57
58#[cfg(feature = "rustcrypto-ec")]
59impl<C: CurveArithmetic + PointCompression> Blinded for BlindedPublicKey<EllipticCurve<C>>
60where
61 <C as Curve>::FieldBytesSize: ModulusSize,
62 <C as CurveArithmetic>::AffinePoint: ToEncodedPoint<C> + FromEncodedPoint<C>,
63{
64 type BytesArray = [u8; 66];
65
66 fn from_bytes(bytes: &Self::BytesArray) -> Result<Self> {
67 let inner =
68 rcec::PublicKey::<C>::from_sec1_bytes(&bytes[0..33]).map_err(|_| Error::Decoding)?;
69 let blinding_factor =
70 rcec::PublicKey::<C>::from_sec1_bytes(&bytes[33..66]).map_err(|_| Error::Decoding)?;
71
72 Ok(Self {
73 inner,
74 blinding_factor,
75 })
76 }
77
78 fn to_bytes(&self) -> [u8; 66] {
79 let inner_cp = CompressedPoint::<C>::from(&self.inner);
80 let blinding_factor_cp = CompressedPoint::<C>::from(&self.blinding_factor);
81
82 let mut output = [0u8; 66];
83 output[0..33].copy_from_slice(inner_cp.as_slice());
84 output[33..66].copy_from_slice(blinding_factor_cp.as_slice());
85
86 output
87 }
88}
89
90pub trait Blind<K: KeyPair> {
92 fn blind(&self, csprng: &mut impl CryptoRngCore) -> BlindedPublicKey<K>;
94}
95
96pub trait Blinded: Sized {
98 type BytesArray;
100 fn from_bytes(bytes: &Self::BytesArray) -> Result<Self>;
102 fn to_bytes(&self) -> Self::BytesArray;
104}
105
106impl<'a, K: KeyPair> TryFrom<&'a [u8]> for BlindedPublicKey<K>
107where
108 Self: Blinded,
109 <Self as Blinded>::BytesArray: TryFrom<&'a [u8]>,
110{
111 type Error = Error;
112
113 fn try_from(bytes: &'a [u8]) -> Result<Self> {
114 Self::from_bytes(
115 &<Self as Blinded>::BytesArray::try_from(bytes).map_err(|_| Error::Decoding)?,
116 )
117 }
118}
119
120#[cfg(feature = "dalek")]
121pub(crate) fn random_blind_dalek(
122 public_key: &dalek::PublicKey,
123 return_blinding_factor: bool,
124 csprng: &mut impl CryptoRngCore,
125) -> (
126 dalek::PublicKey,
127 Option<dalek::PublicKey>,
128 dalek::StaticSecret,
129) {
130 let blinding_factor_secret = dalek::StaticSecret::random_from_rng(csprng);
131 let blinding_factor = if return_blinding_factor {
132 Some(dalek::PublicKey::from(&blinding_factor_secret))
133 } else {
134 None
135 };
136 let blinded_public_key = blind_dalek(public_key, &blinding_factor_secret);
137
138 (blinded_public_key, blinding_factor, blinding_factor_secret)
139}
140
141#[cfg(feature = "dalek")]
142pub(crate) fn blind_dalek(
143 public_key: &dalek::PublicKey,
144 blinding_factor_secret: &dalek::StaticSecret,
145) -> dalek::PublicKey {
146 let blinded_shared_secret = blinding_factor_secret.diffie_hellman(public_key);
147
148 dalek::PublicKey::from(*blinded_shared_secret.as_bytes())
149}
150
151#[cfg(feature = "dalek")]
152impl Blind<X25519> for dalek::PublicKey {
153 fn blind(&self, csprng: &mut impl CryptoRngCore) -> BlindedPublicKey<X25519> {
154 let (inner, blinding_factor, _) = random_blind_dalek(self, true, csprng);
155
156 BlindedPublicKey {
157 inner,
158 blinding_factor: blinding_factor.expect("Infallible"),
159 }
160 }
161}
162
163#[cfg(feature = "rustcrypto-ec")]
164fn diffie_hellman_affine<C: CurveArithmetic>(
165 secret_key: &rcec::SecretKey<C>,
166 public_key: &rcec::PublicKey<C>,
167) -> AffinePoint<C> {
168 use elliptic_curve::{group::Curve, ProjectivePoint};
169
170 let public_point = ProjectivePoint::<C>::from(*public_key.as_affine());
171
172 (public_point * secret_key.to_nonzero_scalar().as_ref()).to_affine()
173}
174
175#[cfg(feature = "rustcrypto-ec")]
176pub(crate) fn random_blind_rcec<C: CurveArithmetic>(
177 public_key: &rcec::PublicKey<C>,
178 return_blinding_factor: bool,
179 csprng: &mut impl CryptoRngCore,
180) -> (
181 rcec::PublicKey<C>,
182 Option<rcec::PublicKey<C>>,
183 rcec::SecretKey<C>,
184) {
185 let blinding_factor_secret = rcec::SecretKey::<C>::random(csprng);
186 let blinding_factor = if return_blinding_factor {
187 Some(blinding_factor_secret.public_key())
188 } else {
189 None
190 };
191 let blinded_public_key = blind_rcec(public_key, &blinding_factor_secret);
192
193 (blinded_public_key, blinding_factor, blinding_factor_secret)
194}
195
196#[cfg(feature = "rustcrypto-ec")]
197pub(crate) fn blind_rcec<C: CurveArithmetic>(
198 public_key: &rcec::PublicKey<C>,
199 blinding_factor_secret: &rcec::SecretKey<C>,
200) -> rcec::PublicKey<C> {
201 let blinded_shared_secret = diffie_hellman_affine(blinding_factor_secret, public_key);
202
203 rcec::PublicKey::<C>::from_affine(blinded_shared_secret)
204 .expect("Should not be an identity point")
205}
206
207#[cfg(feature = "rustcrypto-ec")]
208impl<C: CurveArithmetic> Blind<EllipticCurve<C>> for rcec::PublicKey<C> {
209 fn blind(&self, csprng: &mut impl CryptoRngCore) -> BlindedPublicKey<EllipticCurve<C>> {
210 let (inner, blinding_factor, _) = random_blind_rcec(self, true, csprng);
211
212 BlindedPublicKey {
213 inner,
214 blinding_factor: blinding_factor.expect("Infallible"),
215 }
216 }
217}