1#![allow(dead_code)]
48
49use std::fmt::{self, Debug};
50
51use crc::{extract_crc, push_crc, valid_checksum};
52use ed25519_dalek::{SecretKey, Signer, SigningKey, Verifier, VerifyingKey};
53use rand::prelude::*;
54
55#[cfg(feature = "xkeys")]
56mod xkeys;
57
58#[cfg(feature = "xkeys")]
59pub use xkeys::XKey;
60
61const ENCODED_SEED_LENGTH: usize = 58;
62const ENCODED_PUBKEY_LENGTH: usize = 56;
63
64const PREFIX_BYTE_SEED: u8 = 18 << 3;
65const PREFIX_BYTE_PRIVATE: u8 = 15 << 3;
66const PREFIX_BYTE_SERVER: u8 = 13 << 3;
67const PREFIX_BYTE_CLUSTER: u8 = 2 << 3;
68const PREFIX_BYTE_OPERATOR: u8 = 14 << 3;
69const PREFIX_BYTE_MODULE: u8 = 12 << 3;
70const PREFIX_BYTE_ACCOUNT: u8 = 0;
71const PREFIX_BYTE_USER: u8 = 20 << 3;
72const PREFIX_BYTE_SERVICE: u8 = 21 << 3;
73const PREFIX_BYTE_CURVE: u8 = 23 << 3;
74const PREFIX_BYTE_UNKNOWN: u8 = 25 << 3;
75
76const PUBLIC_KEY_PREFIXES: [u8; 8] = [
77 PREFIX_BYTE_ACCOUNT,
78 PREFIX_BYTE_CLUSTER,
79 PREFIX_BYTE_OPERATOR,
80 PREFIX_BYTE_SERVER,
81 PREFIX_BYTE_USER,
82 PREFIX_BYTE_MODULE,
83 PREFIX_BYTE_SERVICE,
84 PREFIX_BYTE_CURVE,
85];
86
87type Result<T> = std::result::Result<T, crate::error::Error>;
88
89#[derive(Clone)]
92pub struct KeyPair {
93 kp_type: KeyPairType,
94 sk: Option<SecretKey>, signing_key: Option<SigningKey>,
96 pk: VerifyingKey,
97}
98
99impl Debug for KeyPair {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 write!(f, "KeyPair ({:?})", self.kp_type)
102 }
103}
104
105#[derive(Debug, Clone, PartialEq)]
108pub enum KeyPairType {
109 Server,
111 Cluster,
113 Operator,
115 Account,
117 User,
119 Module,
121 Service,
123 Curve,
125}
126
127impl std::str::FromStr for KeyPairType {
128 type Err = crate::error::Error;
129
130 fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
131 let tgt = s.to_uppercase();
132
133 match tgt.as_ref() {
134 "SERVER" => Ok(KeyPairType::Server),
135 "CLUSTER" => Ok(KeyPairType::Cluster),
136 "OPERATOR" => Ok(KeyPairType::Operator),
137 "ACCOUNT" => Ok(KeyPairType::Account),
138 "USER" => Ok(KeyPairType::User),
139 "SERVICE" => Ok(KeyPairType::Service),
140 "MODULE" => Ok(KeyPairType::Module),
141 "CURVE" => Ok(KeyPairType::Curve),
142 _ => Ok(KeyPairType::Module), }
144 }
145}
146
147impl From<u8> for KeyPairType {
148 fn from(prefix_byte: u8) -> KeyPairType {
149 match prefix_byte {
150 PREFIX_BYTE_SERVER => KeyPairType::Server,
151 PREFIX_BYTE_CLUSTER => KeyPairType::Cluster,
152 PREFIX_BYTE_OPERATOR => KeyPairType::Operator,
153 PREFIX_BYTE_ACCOUNT => KeyPairType::Account,
154 PREFIX_BYTE_USER => KeyPairType::User,
155 PREFIX_BYTE_MODULE => KeyPairType::Module,
156 PREFIX_BYTE_SERVICE => KeyPairType::Service,
157 PREFIX_BYTE_CURVE => KeyPairType::Curve,
158 _ => KeyPairType::Operator,
159 }
160 }
161}
162
163impl KeyPair {
164 #[cfg(not(target_arch = "wasm32"))]
169 pub fn new(kp_type: KeyPairType) -> KeyPair {
170 Self::new_from_raw(kp_type, generate_seed_rand()).unwrap()
172 }
173
174 pub fn new_from_raw(kp_type: KeyPairType, random_bytes: [u8; 32]) -> Result<KeyPair> {
179 let signing_key = SigningKey::from_bytes(&random_bytes);
180 Ok(KeyPair {
181 kp_type,
182 pk: signing_key.verifying_key(),
183 signing_key: Some(signing_key),
184 sk: Some(random_bytes),
185 })
186 }
187
188 #[cfg(not(target_arch = "wasm32"))]
193 pub fn new_user() -> KeyPair {
194 Self::new(KeyPairType::User)
195 }
196
197 #[cfg(not(target_arch = "wasm32"))]
202 pub fn new_account() -> KeyPair {
203 Self::new(KeyPairType::Account)
204 }
205
206 #[cfg(not(target_arch = "wasm32"))]
211 pub fn new_operator() -> KeyPair {
212 Self::new(KeyPairType::Operator)
213 }
214
215 #[cfg(not(target_arch = "wasm32"))]
220 pub fn new_cluster() -> KeyPair {
221 Self::new(KeyPairType::Cluster)
222 }
223
224 #[cfg(not(target_arch = "wasm32"))]
229 pub fn new_server() -> KeyPair {
230 Self::new(KeyPairType::Server)
231 }
232
233 #[cfg(not(target_arch = "wasm32"))]
238 pub fn new_module() -> KeyPair {
239 Self::new(KeyPairType::Module)
240 }
241
242 #[cfg(not(target_arch = "wasm32"))]
247 pub fn new_service() -> KeyPair {
248 Self::new(KeyPairType::Service)
249 }
250
251 pub fn public_key(&self) -> String {
253 encode(&self.kp_type, self.pk.as_bytes())
254 }
255
256 pub fn sign(&self, input: &[u8]) -> Result<Vec<u8>> {
258 if let Some(ref seed) = self.signing_key {
259 let sig = seed.sign(input);
260 Ok(sig.to_bytes().to_vec())
261 } else {
262 Err(err!(SignatureError, "Cannot sign without a seed key"))
263 }
264 }
265
266 pub fn verify(&self, input: &[u8], sig: &[u8]) -> Result<()> {
268 if sig.len() != ed25519::Signature::BYTE_SIZE {
269 return Err(err!(
270 InvalidSignatureLength,
271 "Signature did not match expected length"
272 ));
273 }
274
275 let mut fixedsig = [0; ed25519::Signature::BYTE_SIZE];
276 fixedsig.copy_from_slice(sig);
277 let insig = ed25519::Signature::from_bytes(&fixedsig);
278
279 match self.pk.verify(input, &insig) {
280 Ok(()) => Ok(()),
281 Err(e) => Err(e.into()),
282 }
283 }
284
285 pub fn seed(&self) -> Result<String> {
289 if let Some(ref seed) = self.sk {
290 Ok(encode_seed(&self.kp_type, seed))
291 } else {
292 Err(err!(IncorrectKeyType, "This keypair has no seed"))
293 }
294 }
295
296 pub fn from_public_key(source: &str) -> Result<KeyPair> {
298 let (prefix, bytes) = from_public_key(source)?;
299
300 let pk = VerifyingKey::from_bytes(&bytes)
301 .map_err(|_| err!(VerifyError, "Could not read public key"))?;
302
303 Ok(KeyPair {
304 kp_type: KeyPairType::from(prefix),
305 pk,
306 sk: None,
307 signing_key: None,
308 })
309 }
310
311 pub fn from_seed(source: &str) -> Result<KeyPair> {
313 let (ty, seed) = decode_seed(source)?;
314
315 let signing_key = SigningKey::from_bytes(&seed);
316
317 Ok(KeyPair {
318 kp_type: KeyPairType::from(ty),
319 pk: signing_key.verifying_key(),
320 sk: Some(seed),
321 signing_key: Some(signing_key),
322 })
323 }
324
325 pub fn key_pair_type(&self) -> KeyPairType {
327 self.kp_type.clone()
328 }
329}
330
331fn decode_raw(raw: &[u8]) -> Result<Vec<u8>> {
332 let mut b32_decoded = data_encoding::BASE32_NOPAD.decode(raw)?;
333
334 let checksum = extract_crc(&mut b32_decoded)?;
335 let v_checksum = valid_checksum(&b32_decoded, checksum);
336 if !v_checksum {
337 Err(err!(ChecksumFailure, "Checksum mismatch"))
338 } else {
339 Ok(b32_decoded)
340 }
341}
342
343pub fn from_public_key(source: &str) -> Result<(u8, [u8; 32])> {
346 if source.len() != ENCODED_PUBKEY_LENGTH {
347 let l = source.len();
348 return Err(err!(InvalidKeyLength, "Bad key length: {}", l));
349 }
350
351 let source_bytes = source.as_bytes();
352 let mut raw = decode_raw(source_bytes)?;
353
354 let prefix = raw[0];
355 if !valid_public_key_prefix(prefix) {
356 return Err(err!(
357 InvalidPrefix,
358 "Not a valid public key prefix: {}",
359 raw[0]
360 ));
361 }
362 raw.remove(0);
363
364 let mut public_key = [0u8; 32];
365 public_key.copy_from_slice(&raw[..]);
366
367 Ok((prefix, public_key))
368}
369
370pub fn decode_seed(source: &str) -> Result<(u8, [u8; 32])> {
373 if source.len() != ENCODED_SEED_LENGTH {
374 let l = source.len();
375 return Err(err!(InvalidKeyLength, "Bad seed length: {}", l));
376 }
377
378 let source_bytes = source.as_bytes();
379 let raw = decode_raw(source_bytes)?;
380
381 let b1 = raw[0] & 248;
382 if b1 != PREFIX_BYTE_SEED {
383 return Err(err!(
384 InvalidPrefix,
385 "Incorrect byte prefix: {}",
386 source.chars().next().unwrap()
387 ));
388 }
389
390 let b2 = (raw[0] & 7) << 5 | ((raw[1] & 248) >> 3);
391
392 let mut seed = [0u8; 32];
393 seed.copy_from_slice(&raw[2..]);
394
395 Ok((b2, seed))
396}
397
398fn generate_seed_rand() -> [u8; 32] {
399 let mut rng = rand::thread_rng();
400 rng.gen::<[u8; 32]>()
401}
402
403fn get_prefix_byte(kp_type: &KeyPairType) -> u8 {
404 match kp_type {
405 KeyPairType::Server => PREFIX_BYTE_SERVER,
406 KeyPairType::Account => PREFIX_BYTE_ACCOUNT,
407 KeyPairType::Cluster => PREFIX_BYTE_CLUSTER,
408 KeyPairType::Operator => PREFIX_BYTE_OPERATOR,
409 KeyPairType::User => PREFIX_BYTE_USER,
410 KeyPairType::Module => PREFIX_BYTE_MODULE,
411 KeyPairType::Service => PREFIX_BYTE_SERVICE,
412 KeyPairType::Curve => PREFIX_BYTE_CURVE,
413 }
414}
415
416fn valid_public_key_prefix(prefix: u8) -> bool {
417 PUBLIC_KEY_PREFIXES.to_vec().contains(&prefix)
418}
419
420fn encode_seed(ty: &KeyPairType, seed: &[u8]) -> String {
421 let prefix_byte = get_prefix_byte(ty);
422
423 let b1 = PREFIX_BYTE_SEED | prefix_byte >> 5;
424 let b2 = (prefix_byte & 31) << 3;
425
426 encode_prefix(&[b1, b2], seed)
427}
428
429fn encode(ty: &KeyPairType, key: &[u8]) -> String {
430 let prefix_byte = get_prefix_byte(ty);
431 encode_prefix(&[prefix_byte], key)
432}
433
434fn encode_prefix(prefix: &[u8], key: &[u8]) -> String {
435 let mut raw = Vec::with_capacity(prefix.len() + key.len() + 2);
436 raw.extend_from_slice(prefix);
437 raw.extend_from_slice(key);
438 push_crc(&mut raw);
439
440 data_encoding::BASE32_NOPAD.encode(&raw[..])
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446 use crate::error::ErrorKind;
447
448 #[test]
449 fn validate_decode_seed() {
450 let input_bytes = generate_seed_rand();
451 let seed = encode_seed(&KeyPairType::User, input_bytes.as_slice());
452
453 let (prefix, decoded_bytes) = decode_seed(&seed).unwrap();
454
455 assert_eq!(prefix, PREFIX_BYTE_USER);
456 assert_eq!(decoded_bytes, input_bytes);
457 }
458
459 #[test]
460 fn validate_from_public_key() {
461 let input_bytes = generate_seed_rand();
462 let public_key = encode(&KeyPairType::User, input_bytes.as_slice());
463
464 let (prefix, decoded_bytes) = from_public_key(&public_key).unwrap();
465
466 assert_eq!(prefix, PREFIX_BYTE_USER);
467 assert_eq!(decoded_bytes, input_bytes);
468 }
469
470 #[test]
471 fn seed_encode_decode_round_trip() {
472 let pair = KeyPair::new_user();
473 let s = pair.seed().unwrap();
474 let p = pair.public_key();
475
476 let pair2 = KeyPair::from_seed(s.as_str()).unwrap();
477 let s2 = pair2.seed().unwrap();
478
479 assert_eq!(s, s2);
480 assert_eq!(p, pair2.public_key());
481 }
482
483 #[test]
484 fn roundtrip_encoding_go_compat() {
485 let seed = "SAAPN4W3EG6KCJGUQTKTJ5GSB5NHK5CHAJL4DBGFUM3HHROI4XUEP4OBK4";
487 let pk = "ACODERUVFFAWZQDSS6SBIACUA5O6SXF7HJ3YTYXBALHZP3P7R4BUO4J2";
488
489 let pair = KeyPair::from_seed(seed).unwrap();
490
491 assert_eq!(pair.seed().unwrap(), seed);
492 assert_eq!(pair.public_key(), pk);
493 }
494
495 #[test]
496 fn from_seed_rejects_bad_prefix() {
497 let seed = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
498 let pair = KeyPair::from_seed(seed);
499 assert!(pair.is_err());
500 if let Err(e) = pair {
501 assert_eq!(e.kind(), ErrorKind::InvalidPrefix);
502 }
503 }
504
505 #[test]
506 fn from_seed_rejects_bad_checksum() {
507 let seed = "FAAPN4W3EG6KCJGUQTKTJ5GSB5NHK5CHAJL4DBGFUM3HHROI4XUEP4OBK4";
508 let pair = KeyPair::from_seed(seed);
509 assert!(pair.is_err());
510 if let Err(e) = pair {
511 assert_eq!(e.kind(), ErrorKind::ChecksumFailure);
512 }
513 }
514
515 #[test]
516 fn from_seed_rejects_bad_length() {
517 let seed = "SAAPN4W3EG6KCJGUQTKTJ5GSB5NHK5CHAJL4DBGFUM3SAAPN4W3EG6KCJGUQTKTJ5GSB5NHK5";
518 let pair = KeyPair::from_seed(seed);
519 assert!(pair.is_err());
520 if let Err(e) = pair {
521 assert_eq!(e.kind(), ErrorKind::InvalidKeyLength);
522 }
523 }
524
525 #[test]
526 fn from_seed_rejects_invalid_encoding() {
527 let badseed = "SAAPN4W3EG6KCJGUQTKTJ5!#B5NHK5CHAJL4DBGFUM3HHROI4XUEP4OBK4";
528 let pair = KeyPair::from_seed(badseed);
529 assert!(pair.is_err());
530 if let Err(e) = pair {
531 assert_eq!(e.kind(), ErrorKind::CodecFailure);
532 }
533 }
534
535 #[test]
536 fn sign_and_verify() {
537 let user = KeyPair::new_user();
538 let msg = b"this is super secret";
539
540 let sig = user.sign(msg).unwrap();
541
542 let res = user.verify(msg, sig.as_slice());
543 assert!(res.is_ok());
544 }
545
546 #[test]
547 fn sign_and_verify_rejects_mismatched_sig() {
548 let user = KeyPair::new_user();
549 let msg = b"this is super secret";
550
551 let sig = user.sign(msg).unwrap();
552 let res = user.verify(b"this doesn't match the message", sig.as_slice());
553 assert!(res.is_err());
554 }
555
556 #[test]
557 fn sign_and_verify_rejects_invalid_signature_length() {
558 let kp = KeyPair::new_user();
559 let res = kp.verify(&[], &[]);
560 assert!(res.is_err());
561 if let Err(e) = res {
562 assert_eq!(e.kind(), ErrorKind::InvalidSignatureLength);
563 }
564 }
565
566 #[test]
567 fn from_public_key_rejects_bad_length() {
568 let public_key = "ACARVGW77LDNWYXBAH62YKKQRVHYOTKKDDVVJVOISOU75WQPXOO7N3";
569 let pair = KeyPair::from_public_key(public_key);
570 assert!(pair.is_err());
571 if let Err(e) = pair {
572 assert_eq!(e.kind(), ErrorKind::InvalidKeyLength);
573 }
574 }
575
576 #[test]
577 fn from_public_key_rejects_bad_prefix() {
578 let public_key = "ZCO4XYNKEN7ZFQ42BHYCBYI3K7USOGG43C2DIJZYWSQ2YEMBOZWN6PYH";
579 let pair = KeyPair::from_public_key(public_key);
580 assert!(pair.is_err());
581 if let Err(e) = pair {
582 assert_eq!(e.kind(), ErrorKind::InvalidPrefix);
583 }
584 }
585
586 #[test]
587 fn public_key_round_trip() {
588 let account =
589 KeyPair::from_public_key("ACODERUVFFAWZQDSS6SBIACUA5O6SXF7HJ3YTYXBALHZP3P7R4BUO4J2")
590 .unwrap();
591 let pk = account.public_key();
592 assert_eq!(
593 pk,
594 "ACODERUVFFAWZQDSS6SBIACUA5O6SXF7HJ3YTYXBALHZP3P7R4BUO4J2"
595 );
596 }
597
598 #[test]
599 fn module_has_proper_prefix() {
600 let module = KeyPair::new_module();
601 assert!(module.seed().unwrap().starts_with("SM"));
602 assert!(module.public_key().starts_with('M'));
603 }
604
605 #[test]
606 fn service_has_proper_prefix() {
607 let service = KeyPair::new_service();
608 assert!(service.seed().unwrap().starts_with("SV"));
609 assert!(service.public_key().starts_with('V'));
610 }
611
612 #[test]
613 fn can_get_key_type() {
614 let from_pub =
615 KeyPair::from_public_key("UBCXCMGAZQZN55X5TTTWMB5CZNZIKJHEDZJOJ3TV63NKPJ6FRXSR2ZO4")
616 .unwrap();
617 let from_seed =
618 KeyPair::from_seed("SCANU5JGFEPJ2XNFQ6YMDRHMNFAL6ZT3DCU3ZMMHHML7GLFE3YIH5TBM6E")
619 .unwrap();
620
621 assert!(
622 matches!(from_pub.key_pair_type(), KeyPairType::User),
623 "Expected the key type to be {:?}, found {:?}",
624 KeyPairType::User,
625 from_pub.key_pair_type()
626 );
627 assert!(
628 matches!(from_seed.key_pair_type(), KeyPairType::Cluster),
629 "Expected the key type to be {:?}, found {:?}",
630 KeyPairType::Cluster,
631 from_seed.key_pair_type()
632 );
633 }
634}
635
636mod crc;
637pub mod error;