xpx_chain_crypto/
public.rs1use core::fmt::Debug;
8
9use curve25519_dalek::{
10 constants,
11 digest::{generic_array::typenum::U64, Digest},
12};
13
14use curve25519_dalek::edwards::CompressedEdwardsY;
15use curve25519_dalek::edwards::EdwardsPoint;
16use curve25519_dalek::scalar::Scalar;
17
18pub use sha3::Sha3_512;
19
20#[cfg(feature = "serde")]
21use serde::de::Error as SerdeError;
22#[cfg(feature = "serde")]
23use serde::de::Visitor;
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26#[cfg(feature = "serde")]
27use serde::{Deserializer, Serializer};
28
29use crate::constants::*;
30use crate::errors::*;
31use crate::secret::*;
32use crate::signature::*;
33
34#[derive(Copy, Clone, Default, Eq, PartialEq)]
36pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint);
37
38impl Debug for PublicKey {
39 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
40 write!(f, "PublicKey({:?}), {:?})", self.0, self.1)
41 }
42}
43
44impl AsRef<[u8]> for PublicKey {
45 fn as_ref(&self) -> &[u8] {
46 self.as_bytes()
47 }
48}
49
50impl<'a> From<&'a SecretKey> for PublicKey {
51 fn from(secret_key: &SecretKey) -> PublicKey {
53 let mut h: Sha3_512 = Sha3_512::new();
54 let mut hash: [u8; 64] = [0u8; 64];
55 let mut digest: [u8; 32] = [0u8; 32];
56
57 let secret_key = secret_key.to_bytes();
58 h.update(secret_key);
59 hash.copy_from_slice(h.finalize().as_slice());
60
61 digest.copy_from_slice(&hash[..32]);
62
63 PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
64 }
65}
66
67impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
68 fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
70 let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();
71
72 PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
73 }
74}
75
76impl PublicKey {
77 #[inline]
79 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
80 self.0.to_bytes()
81 }
82
83 #[inline]
85 pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
86 &(self.0).0
87 }
88
89 #[inline]
126 pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SignatureError> {
127 if bytes.len() != PUBLIC_KEY_LENGTH {
128 return Err(SignatureError(InternalError::BytesLengthError {
129 name: "PublicKey",
130 length: PUBLIC_KEY_LENGTH,
131 }));
132 }
133 let mut bits: [u8; 32] = [0u8; 32];
134 bits.copy_from_slice(&bytes[..32]);
135
136 let compressed = CompressedEdwardsY(bits);
137 let point = compressed
138 .decompress()
139 .ok_or(SignatureError(InternalError::PointDecompressionError))?;
140
141 Ok(PublicKey(compressed, point))
142 }
143
144 fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(
148 bits: &mut [u8; 32],
149 ) -> PublicKey {
150 bits[0] &= 248;
151 bits[31] &= 127;
152 bits[31] |= 64;
153
154 let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
155 let compressed = point.compress();
156
157 PublicKey(compressed, point)
158 }
159
160 #[allow(non_snake_case)]
166 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
167 let mut h: Sha3_512 = Sha3_512::new();
168 let R: EdwardsPoint;
169 let k: Scalar;
170 let minus_A: EdwardsPoint = -self.1;
171
172 h.update(signature.R.as_bytes());
173 h.update(self.as_bytes());
174 h.update(&message);
175
176 k = Scalar::from_hash(h);
177 R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
178
179 if R.compress() == signature.R {
180 Ok(())
181 } else {
182 Err(SignatureError(InternalError::VerifyError))
183 }
184 }
185
186 #[allow(non_snake_case)]
205 pub fn verify_prehashed<D>(
206 &self,
207 prehashed_message: D,
208 context: Option<&[u8]>,
209 signature: &Signature,
210 ) -> Result<(), SignatureError>
211 where
212 D: Digest<OutputSize = U64>,
213 {
214 let mut h: Sha3_512 = Sha3_512::default();
215 let R: EdwardsPoint;
216 let k: Scalar;
217
218 let ctx: &[u8] = context.unwrap_or(b"");
219 debug_assert!(
220 ctx.len() <= 255,
221 "The context must not be longer than 255 octets."
222 );
223
224 let minus_A: EdwardsPoint = -self.1;
225
226 h.update(b"SigEd25519 no Ed25519 collisions");
227 h.update(&[1]); h.update(&[ctx.len() as u8]);
229 h.update(ctx);
230 h.update(signature.R.as_bytes());
231 h.update(self.as_bytes());
232 h.update(prehashed_message.finalize().as_slice());
233
234 k = Scalar::from_hash(h);
235 R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
236
237 if R.compress() == signature.R {
238 Ok(())
239 } else {
240 Err(SignatureError(InternalError::VerifyError))
241 }
242 }
243}
244
245#[cfg(feature = "serde")]
246impl Serialize for PublicKey {
247 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
248 where
249 S: Serializer,
250 {
251 serializer.serialize_bytes(self.as_bytes())
252 }
253}
254
255#[cfg(feature = "serde")]
256impl<'d> Deserialize<'d> for PublicKey {
257 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258 where
259 D: Deserializer<'d>,
260 {
261 struct PublicKeyVisitor;
262
263 impl<'d> Visitor<'d> for PublicKeyVisitor {
264 type Value = PublicKey;
265
266 fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
267 formatter.write_str(
268 "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032",
269 )
270 }
271
272 fn visit_bytes<E>(self, bytes: &[u8]) -> Result<PublicKey, E>
273 where
274 E: SerdeError,
275 {
276 PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
277 }
278 }
279 deserializer.deserialize_bytes(PublicKeyVisitor)
280 }
281}