xrpl/core/keypairs/algorithms.rs
1//! Ed25519 elliptic curve cryptography interface.
2//! SECP256K1 elliptic curve cryptography interface.
3//!
4//! Note: The process for using SECP256k1 is complex and
5//! more involved than ED25519.
6//!
7//! See SECP256K1 Key Derivation:
8//! `<https://xrpl.org/cryptographic-keys.html#secp256k1-key-derivation>`
9
10use crate::constants::CryptoAlgorithm;
11use crate::core::exceptions::XRPLCoreResult;
12use crate::core::keypairs::exceptions::XRPLKeypairsException;
13use crate::core::keypairs::utils::*;
14use crate::core::keypairs::CryptoImplementation;
15use alloc::format;
16use alloc::string::String;
17use alloc::vec::Vec;
18use core::convert::TryInto;
19use core::str::FromStr;
20use crypto_bigint::Encoding;
21use crypto_bigint::U256;
22use ed25519_dalek::ed25519::signature::SignerMut;
23use ed25519_dalek::Verifier;
24use ed25519_dalek::SECRET_KEY_LENGTH;
25use secp256k1::ecdsa;
26use secp256k1::Scalar;
27
28/// Methods for using the ECDSA cryptographic system with
29/// the SECP256K1 elliptic curve.
30pub struct Secp256k1;
31
32/// Methods for using the ED25519 cryptographic system.
33pub struct Ed25519;
34
35impl Secp256k1 {
36 /// Hex encode the private key.
37 fn _private_key_to_str(key: secp256k1::SecretKey) -> String {
38 hex::encode_upper(key.as_ref())
39 }
40
41 /// Hex encode the public key.
42 fn _public_key_to_str(key: secp256k1::PublicKey) -> String {
43 hex::encode_upper(key.serialize())
44 }
45
46 /// Format a provided key.
47 fn _format_key(keystr: &str) -> String {
48 format!("{keystr:0>SECP256K1_KEY_LENGTH$}")
49 }
50
51 /// Format the public and private keys.
52 /// TODO Make function constant time
53 fn _format_keys(
54 public: secp256k1::PublicKey,
55 private: secp256k1::SecretKey,
56 ) -> (String, String) {
57 (
58 Secp256k1::_format_key(&Secp256k1::_public_key_to_str(public)),
59 Secp256k1::_format_key(&Secp256k1::_private_key_to_str(private)),
60 )
61 }
62
63 /// Hash the message to prevent insecure signing.
64 fn _get_message(message: &[u8]) -> secp256k1::Message {
65 secp256k1::Message::from_digest(sha512_first_half(message))
66 }
67
68 /// Determing if the provided secret key is valid.
69 /// TODO Make function constant time
70 fn _is_secret_valid(key: [u8; u32::BITS as usize]) -> bool {
71 let key_bytes = U256::from_be_bytes(key);
72 key_bytes >= U256::ONE
73 && key_bytes <= U256::from_be_bytes(secp256k1::constants::CURVE_ORDER)
74 }
75
76 /// Concat candidate key.
77 fn _candidate_merger(input: &[u8], candidate: &[u8], phase: &Secp256k1Phase) -> Vec<u8> {
78 if phase == &Secp256k1Phase::Root {
79 [input, candidate].concat()
80 } else {
81 [input, &SECP256K1_INTERMEDIATE_KEYPAIR_PADDING, candidate].concat()
82 }
83 }
84
85 /// Given bytes_input determine public/private keypair
86 /// for a given phase of this algorithm. The difference
87 /// between generating the root and intermediate keypairs
88 /// is just what bytes are input by the caller and that
89 /// the intermediate keypair needs to inject
90 /// SECP256K1_INTERMEDIATE_KEYPAIR_PADDING into the value
91 /// to hash to get the raw private key.
92 fn _derive_part(
93 bytes: &[u8],
94 phase: Secp256k1Phase,
95 ) -> XRPLCoreResult<(secp256k1::PublicKey, secp256k1::SecretKey)> {
96 let raw_private = Self::_get_secret(bytes, &phase)?;
97 let secp = secp256k1::Secp256k1::new();
98 let wrapped_private = secp256k1::SecretKey::from_slice(&raw_private)
99 .map_err(XRPLKeypairsException::SECP256K1Error)?;
100 let wrapped_public = secp256k1::PublicKey::from_secret_key(&secp, &wrapped_private);
101
102 Ok((wrapped_public, wrapped_private))
103 }
104
105 /// Derive the final public/private keys.
106 fn _derive_final(
107 root_public: secp256k1::PublicKey,
108 root_private: secp256k1::SecretKey,
109 mid_public: secp256k1::PublicKey,
110 mid_private: secp256k1::SecretKey,
111 ) -> XRPLCoreResult<(secp256k1::PublicKey, secp256k1::SecretKey)> {
112 let wrapped_private = root_private
113 .add_tweak(&Scalar::from(mid_private))
114 .map_err(XRPLKeypairsException::SECP256K1Error)?;
115 let wrapped_public = root_public
116 .combine(&mid_public)
117 .map_err(XRPLKeypairsException::SECP256K1Error)?;
118
119 Ok((wrapped_public, wrapped_private))
120 }
121
122 /// Given a function `candidate_merger` that knows how
123 /// to prepare a sequence candidate bytestring into a
124 /// possible full candidate secret, returns the first
125 /// sequence value that is valid. If none are valid,
126 /// raises; however this should be so exceedingly rare
127 /// as to ignore.
128 fn _get_secret(
129 input: &[u8],
130 phase: &Secp256k1Phase,
131 ) -> XRPLCoreResult<[u8; SHA512_HASH_LENGTH]> {
132 for raw_root in 0..SECP256K1_SEQUENCE_MAX {
133 let root = (raw_root as u32).to_be_bytes();
134 let candidate = sha512_first_half(&Self::_candidate_merger(input, &root, phase));
135
136 if Self::_is_secret_valid(candidate) {
137 return Ok(candidate);
138 } else {
139 continue;
140 }
141 }
142
143 Err(XRPLKeypairsException::InvalidSecret.into())
144 }
145}
146
147impl Ed25519 {
148 /// Hex encode the private key.
149 fn _private_key_to_str(key: ed25519_dalek::SecretKey) -> String {
150 hex::encode(key)
151 }
152
153 /// Hex encode the public key.
154 fn _public_key_to_str(key: ed25519_dalek::VerifyingKey) -> String {
155 hex::encode(key.as_ref())
156 }
157
158 /// Format a provided key.
159 /// TODO Determine security implications
160 fn _format_key(keystr: &str) -> String {
161 format!("{}{}", ED25519_PREFIX, keystr.to_uppercase())
162 }
163
164 /// Format the public and private keys.
165 fn _format_keys(
166 public: ed25519_dalek::VerifyingKey,
167 private: ed25519_dalek::SecretKey,
168 ) -> (String, String) {
169 (
170 Ed25519::_format_key(&Ed25519::_public_key_to_str(public)),
171 Ed25519::_format_key(&Ed25519::_private_key_to_str(private)),
172 )
173 }
174}
175
176impl CryptoImplementation for Secp256k1 {
177 /// Derives a key pair for use with the XRP Ledger
178 /// from a seed value.
179 ///
180 /// # Examples
181 ///
182 /// ## Basic usage
183 ///
184 /// ```
185 /// use xrpl::core::keypairs::Secp256k1;
186 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
187 /// use xrpl::core::keypairs::CryptoImplementation;
188 /// use xrpl::core::exceptions::XRPLCoreException;
189 ///
190 /// let decoded_seed: &[u8] = &[
191 /// 207, 45, 227, 120, 251, 221, 126, 46,
192 /// 232, 125, 72, 109, 251, 90, 123, 255
193 /// ];
194 /// let validator: bool = false;
195 /// let tuple: (String, String) = (
196 /// "0203F2D90BC50012EC7CB20B07A1B818D6863636FB1E945D17449092CFB5495E1E".into(),
197 /// "0048D93A3B5948E5F9B323BF654BFAD6E8FF75B5FCAB03C5A55AD30CB2515B461F".into(),
198 /// );
199 ///
200 /// let derivation: Option<(String, String)> = match Secp256k1.derive_keypair(
201 /// decoded_seed,
202 /// validator,
203 /// ) {
204 /// Ok((public, private)) => Some((public, private)),
205 /// Err(e) => match e {
206 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::InvalidSignature) => None,
207 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::InvalidSecret) => None,
208 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::SECP256K1Error(_)) => None,
209 /// _ => None,
210 /// },
211 /// };
212 ///
213 /// assert_eq!(Some(tuple), derivation);
214 /// ```
215 fn derive_keypair(
216 &self,
217 decoded_seed: &[u8],
218 is_validator: bool,
219 ) -> XRPLCoreResult<(String, String)> {
220 let (root_public, root_secret) = Self::_derive_part(decoded_seed, Secp256k1Phase::Root)?;
221 if is_validator {
222 Ok(Secp256k1::_format_keys(root_public, root_secret))
223 } else {
224 let (mid_public, mid_secret) =
225 Self::_derive_part(&root_public.serialize(), Secp256k1Phase::Mid)?;
226 let (final_public, final_secret) =
227 Self::_derive_final(root_public, root_secret, mid_public, mid_secret)?;
228
229 Ok(Secp256k1::_format_keys(final_public, final_secret))
230 }
231 }
232
233 /// Signs a message using a given private key.
234 /// * `message` - Text about foo.
235 /// * `private_key` - Text about bar.
236 ///
237 /// # Examples
238 ///
239 /// ## Basic usage
240 ///
241 /// ```
242 /// use xrpl::core::keypairs::Secp256k1;
243 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
244 /// use xrpl::core::keypairs::CryptoImplementation;
245 /// use xrpl::core::exceptions::XRPLCoreException;
246 ///
247 /// let message: &[u8] = "test message".as_bytes();
248 /// let private_key: &str = "00D78B9735C3F26501C7337B8A5727FD5\
249 /// 3A6EFDBC6AA55984F098488561F985E23";
250 /// let signature: Vec<u8> = vec![
251 /// 48, 68, 2, 32, 88, 58, 145, 201, 94, 84, 230, 166, 81, 196,
252 /// 123, 236, 34, 116, 78, 11, 16, 30, 44, 64, 96, 231, 176, 143,
253 /// 99, 65, 101, 125, 173, 155, 195, 238, 2, 32, 125, 20, 137,
254 /// 199, 57, 93, 176, 24, 141, 58, 86, 169, 119, 236, 186, 84,
255 /// 179, 111, 169, 55, 27, 64, 49, 150, 85, 177, 180, 66, 158,
256 /// 51, 239, 45,
257 /// ];
258 ///
259 /// let signing: Option<Vec<u8>> = match Secp256k1.sign(
260 /// message,
261 /// private_key,
262 /// ) {
263 /// Ok(signature) => Some(signature),
264 /// Err(e) => match e {
265 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::SECP256K1Error(_)) => None,
266 /// _ => None,
267 /// },
268 /// };
269 ///
270 /// assert_eq!(Some(signature), signing);
271 /// ```
272 fn sign(&self, message_bytes: &[u8], private_key: &str) -> XRPLCoreResult<Vec<u8>> {
273 let secp = secp256k1::Secp256k1::<secp256k1::SignOnly>::signing_only();
274 let message = Self::_get_message(message_bytes);
275 let trimmed_key = private_key.trim_start_matches(SECP256K1_PREFIX);
276 let private = secp256k1::SecretKey::from_str(trimmed_key)
277 .map_err(XRPLKeypairsException::SECP256K1Error)?;
278 let signature = secp.sign_ecdsa(&message, &private);
279
280 Ok(signature.serialize_der().to_vec())
281 }
282
283 /// Verifies the signature on a given message.
284 ///
285 /// # Examples
286 ///
287 /// ## Basic usage
288 ///
289 /// ```
290 /// use xrpl::core::keypairs::Secp256k1;
291 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
292 /// use xrpl::core::keypairs::CryptoImplementation;
293 ///
294 /// let message: &[u8] = "test message".as_bytes();
295 /// let signature: &str = "30440220583A91C95E54E6A651C47BEC\
296 /// 22744E0B101E2C4060E7B08F6341657D\
297 /// AD9BC3EE02207D1489C7395DB0188D3A\
298 /// 56A977ECBA54B36FA9371B40319655B1\
299 /// B4429E33EF2D";
300 /// let public_key: &str = "030D58EB48B4420B1F7B9DF55087E0E\
301 /// 29FEF0E8468F9A6825B01CA2C361042D435";
302 ///
303 /// assert!(Secp256k1.is_valid_message(
304 /// message,
305 /// signature,
306 /// public_key,
307 /// ));
308 /// ```
309 fn is_valid_message(&self, message_bytes: &[u8], signature: &str, public_key: &str) -> bool {
310 let secp = secp256k1::Secp256k1::<secp256k1::VerifyOnly>::verification_only();
311 let msg = Self::_get_message(message_bytes);
312
313 if let Ok(value) = hex::decode(signature) {
314 let sig = ecdsa::Signature::from_der(&value);
315 let public = secp256k1::PublicKey::from_str(public_key);
316
317 if let (&Ok(s), &Ok(p)) = (&sig.as_ref(), &public.as_ref()) {
318 secp.verify_ecdsa(&msg, s, p).is_ok()
319 } else {
320 false
321 }
322 } else {
323 false
324 }
325 }
326}
327
328impl CryptoImplementation for Ed25519 {
329 /// Derives a key pair for use with the XRP Ledger
330 /// from a seed value.
331 ///
332 /// # Examples
333 ///
334 /// ## Basic usage
335 ///
336 /// ```
337 /// use xrpl::core::keypairs::Ed25519;
338 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
339 /// use xrpl::core::keypairs::CryptoImplementation;
340 /// use xrpl::core::exceptions::XRPLCoreException;
341 ///
342 /// let decoded_seed: &[u8] = &[
343 /// 207, 45, 227, 120, 251, 221, 126, 46,
344 /// 232, 125, 72, 109, 251, 90, 123, 255
345 /// ];
346 /// let validator: bool = false;
347 /// let tuple: (String, String) = (
348 /// "ED60292139838CB86E719134F848F055057CA5BDA61F5A529729F1697502D53E1C".into(),
349 /// "ED009F66528611A0D400946A01FA01F8AF4FF4C1D0C744AE3F193317DCA77598F1".into(),
350 /// );
351 ///
352 /// let derivation: Option<(String, String)> = match Ed25519.derive_keypair(
353 /// decoded_seed,
354 /// validator,
355 /// ) {
356 /// Ok((public, private)) => Some((public, private)),
357 /// Err(e) => match e {
358 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::InvalidSignature) => None,
359 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::ED25519Error) => None,
360 /// XRPLCoreException::XRPLKeypairsError(XRPLKeypairsException::UnsupportedValidatorAlgorithm { expected: _ }) => None,
361 /// _ => None,
362 /// },
363 /// };
364 ///
365 /// assert_eq!(Some(tuple), derivation);
366 /// ```
367 fn derive_keypair(
368 &self,
369 decoded_seed: &[u8],
370 is_validator: bool,
371 ) -> XRPLCoreResult<(String, String)> {
372 if is_validator {
373 Err(XRPLKeypairsException::UnsupportedValidatorAlgorithm {
374 expected: CryptoAlgorithm::ED25519,
375 }
376 .into())
377 } else {
378 let raw_private = sha512_first_half(decoded_seed);
379 let private: [u8; SECRET_KEY_LENGTH] = ed25519_dalek::SecretKey::from(raw_private);
380 let signing_key: ed25519_dalek::SigningKey = private.into();
381 let public = (&signing_key).into();
382
383 Ok(Ed25519::_format_keys(public, private))
384 }
385 }
386
387 /// Signs a message using a given private key.
388 /// * `message` - Text about foo.
389 /// * `private_key` - Text about bar.
390 ///
391 /// # Examples
392 ///
393 /// ## Basic usage
394 ///
395 /// ```
396 /// use xrpl::core::keypairs::Ed25519;
397 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
398 /// use xrpl::core::keypairs::CryptoImplementation;
399 ///
400 /// let message: &[u8] = "test message".as_bytes();
401 /// let private_key: &str = "EDB4C4E046826BD26190D09715FC31F4E\
402 /// 6A728204EADD112905B08B14B7F15C4F3";
403 /// let signature: Vec<u8> = vec![
404 /// 203, 25, 158, 27, 253, 78, 61, 170, 16, 94, 72, 50, 238, 223,
405 /// 163, 100, 19, 225, 244, 66, 5,228, 239, 185, 226, 126, 130, 96,
406 /// 68, 194, 30, 62, 46, 132, 139, 188, 129, 149, 232, 149, 155,
407 /// 173, 248, 135, 89, 155, 115, 16, 173, 27, 112, 71, 239, 17,
408 /// 182, 130, 224, 208, 104, 247, 55,73, 117, 14,
409 /// ];
410 ///
411 /// let signing: Option<Vec<u8>> = Some(Ed25519.sign(
412 /// message,
413 /// private_key,
414 /// ).unwrap());
415 ///
416 /// assert_eq!(Some(signature), signing);
417 /// ```
418 fn sign(&self, message: &[u8], private_key: &str) -> XRPLCoreResult<Vec<u8>> {
419 let raw_private = hex::decode(&private_key[ED25519_PREFIX.len()..])?;
420 let raw_private_slice: &[u8; SECRET_KEY_LENGTH] = raw_private
421 .as_slice()
422 .try_into()
423 .map_err(|_| XRPLKeypairsException::InvalidSecret)?;
424 let private: ed25519_dalek::SecretKey = *raw_private_slice;
425 let mut signing_key: ed25519_dalek::SigningKey = private.into();
426 let signature = signing_key.sign(message);
427
428 Ok(signature.to_bytes().to_vec())
429 }
430
431 /// Verifies the signature on a given message.
432 ///
433 /// # Examples
434 ///
435 /// ## Basic usage
436 ///
437 /// ```
438 /// use xrpl::core::keypairs::Ed25519;
439 /// use xrpl::core::keypairs::exceptions::XRPLKeypairsException;
440 /// use xrpl::core::keypairs::CryptoImplementation;
441 ///
442 /// let message: &[u8] = "test message".as_bytes();
443 /// let signature: &str = "CB199E1BFD4E3DAA105E4832EEDFA3641\
444 /// 3E1F44205E4EFB9E27E826044C21E3E2E\
445 /// 848BBC8195E8959BADF887599B7310AD1\
446 /// B7047EF11B682E0D068F73749750E";
447 /// let public_key: &str = "ED01FA53FA5A7E77798F882ECE20B1AB\
448 /// C00BB358A9E55A202D0D0676BD0CE37A63";
449 ///
450 /// assert!(Ed25519.is_valid_message(
451 /// message,
452 /// signature,
453 /// public_key,
454 /// ));
455 /// ```
456 fn is_valid_message(&self, message: &[u8], signature: &str, public_key: &str) -> bool {
457 let raw_public = hex::decode(&public_key[ED25519_PREFIX.len()..]);
458 let decoded_sig = hex::decode(signature);
459
460 if raw_public.is_err() || decoded_sig.is_err() {
461 return false;
462 };
463
464 if let (Ok(rpub), Ok(dsig)) = (raw_public, decoded_sig) {
465 let rpub = rpub.as_slice().try_into().unwrap();
466 let public = ed25519_dalek::VerifyingKey::from_bytes(rpub);
467
468 if dsig.len() != ED25519_SIGNATURE_LENGTH {
469 return false;
470 };
471
472 if let Ok(value) = public {
473 let sig: [u8; ED25519_SIGNATURE_LENGTH] =
474 dsig.try_into().expect("is_valid_message");
475 let converted = &ed25519_dalek::Signature::from(sig);
476
477 value.verify(message, converted).is_ok()
478 } else {
479 false
480 }
481 } else {
482 false
483 }
484 }
485}
486
487#[cfg(test)]
488mod test {
489 use super::*;
490 use crate::core::keypairs::test_cases::*;
491
492 #[test]
493 fn test_secp256k1_derive_keypair() {
494 let seed: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
495 let validator = Secp256k1.derive_keypair(seed, true);
496 let (public, private) = Secp256k1.derive_keypair(seed, false).unwrap();
497
498 assert!(validator.is_ok());
499 assert_eq!(PRIVATE_SECP256K1, private);
500 assert_eq!(PUBLIC_SECP256K1, public);
501 }
502
503 #[test]
504 fn test_secp256k1_sign() {
505 let success = Secp256k1.sign(TEST_MESSAGE.as_bytes(), PRIVATE_SECP256K1);
506 let error = Secp256k1.sign(TEST_MESSAGE.as_bytes(), "abc123");
507
508 assert!(success.is_ok());
509 assert!(error.is_err());
510 }
511
512 #[test]
513 fn test_secp256k1_is_valid_message() {
514 let signature: &str = &hex::encode_upper(SIGNATURE_SECP256K1);
515 let message: &[u8] = TEST_MESSAGE.as_bytes();
516
517 assert!(Secp256k1.is_valid_message(message, signature, PUBLIC_SECP256K1));
518 }
519
520 #[test]
521 fn test_ed25519_derive_keypair() {
522 let seed: &[u8] = SEED_ED25519.as_bytes();
523 let validator = Ed25519.derive_keypair(seed, true);
524 let (public, private) = Ed25519.derive_keypair(seed, false).unwrap();
525
526 assert!(validator.is_err());
527 assert_eq!(RAW_PRIVATE_ED25519, public);
528 assert_eq!(RAW_PUBLIC_ED25519, private);
529 }
530
531 #[test]
532 fn test_ed25519_sign() {
533 let success = Ed25519.sign(TEST_MESSAGE.as_bytes(), RAW_PRIVATE_ED25519);
534 let error = Ed25519.sign(TEST_MESSAGE.as_bytes(), "abc123");
535
536 assert!(success.is_ok());
537 assert!(error.is_err());
538 }
539
540 #[test]
541 fn test_ed25519_is_valid_message() {
542 let signature: &str = &hex::encode_upper(SIGNATURE_ED25519);
543 let message: &[u8] = TEST_MESSAGE.as_bytes();
544
545 assert!(Ed25519.is_valid_message(message, signature, PUBLIC_ED25519));
546 }
547}