1use std::collections::BTreeMap;
4use std::fmt;
5use std::io::Cursor;
6
7use anyhow::{Context as _, Result, bail, ensure};
8use base64::Engine as _;
9use deltachat_contact_tools::EmailAddress;
10use pgp::composed::{Deserializable, SignedKeyDetails};
11pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
12use pgp::crypto::aead::AeadAlgorithm;
13use pgp::crypto::hash::HashAlgorithm;
14use pgp::crypto::sym::SymmetricKeyAlgorithm;
15use pgp::packet::{
16 Features, KeyFlags, Notation, PacketTrait as _, SignatureConfig, SignatureType, Subpacket,
17 SubpacketData,
18};
19use pgp::ser::Serialize;
20use pgp::types::{CompressionAlgorithm, KeyDetails, KeyVersion};
21use rand_old::thread_rng;
22use tokio::runtime::Handle;
23
24use crate::context::Context;
25use crate::events::EventType;
26use crate::log::LogExt;
27use crate::tools::{self, time_elapsed};
28
29pub trait DcKey: Serialize + Deserializable + Clone {
35 fn from_slice(bytes: &[u8]) -> Result<Self> {
37 let res = <Self as Deserializable>::from_bytes(Cursor::new(bytes));
38 if let Ok(res) = res {
39 return Ok(res);
40 }
41
42 for garbage_bytes in 3..std::cmp::min(bytes.len(), 10) {
58 let res = <Self as Deserializable>::from_bytes(Cursor::new(
59 bytes
60 .get(..bytes.len().saturating_sub(garbage_bytes))
61 .unwrap_or_default(),
62 ));
63 if let Ok(res) = res {
64 return Ok(res);
65 }
66 }
67
68 Ok(res?)
70 }
71
72 fn from_base64(data: &str) -> Result<Self> {
74 let cleaned: String = data.split_whitespace().collect();
76 let bytes = base64::engine::general_purpose::STANDARD.decode(cleaned.as_bytes())?;
77 Self::from_slice(&bytes)
78 }
79
80 fn from_asc(data: &str) -> Result<Self> {
82 let bytes = data.as_bytes();
83 let res = Self::from_armor_single(Cursor::new(bytes));
84 let (key, _headers) = match res {
85 Err(pgp::errors::Error::NoMatchingPacket { .. }) => match Self::is_private() {
86 true => bail!("No private key packet found"),
87 false => bail!("No public key packet found"),
88 },
89 _ => res.context("rPGP error")?,
90 };
91 Ok(key)
92 }
93
94 fn to_bytes(&self) -> Vec<u8> {
96 let mut buf = Vec::new();
101 self.to_writer(&mut buf).unwrap();
102 buf
103 }
104
105 fn to_base64(&self) -> String {
107 base64::engine::general_purpose::STANDARD.encode(DcKey::to_bytes(self))
108 }
109
110 fn to_asc(&self, header: Option<(&str, &str)>) -> String;
117
118 fn dc_fingerprint(&self) -> Fingerprint;
120
121 fn is_private() -> bool;
123}
124
125pub(crate) fn secret_key_to_public_key(
127 context: &Context,
128 mut signed_secret_key: SignedSecretKey,
129 timestamp: u32,
130 addr: &str,
131 relay_addrs: &str,
132) -> Result<SignedPublicKey> {
133 info!(context, "Converting secret key to public key.");
134 let timestamp = pgp::types::Timestamp::from_secs(timestamp);
135
136 let common_subpackets = || -> Result<Vec<Subpacket>> {
138 let keyflags = {
139 let mut keyflags = KeyFlags::default();
140 keyflags.set_certify(true);
141 keyflags.set_sign(true);
142 keyflags
143 };
144 let features = {
145 let mut features = Features::default();
146 features.set_seipd_v1(true);
147 features.set_seipd_v2(true);
148 features
149 };
150
151 Ok(vec![
152 Subpacket::regular(SubpacketData::SignatureCreationTime(timestamp))?,
153 Subpacket::regular(SubpacketData::IssuerFingerprint(
154 signed_secret_key.fingerprint(),
155 ))?,
156 Subpacket::regular(SubpacketData::KeyFlags(keyflags))?,
157 Subpacket::regular(SubpacketData::Features(features))?,
158 Subpacket::regular(SubpacketData::PreferredSymmetricAlgorithms(smallvec![
159 SymmetricKeyAlgorithm::AES256,
160 SymmetricKeyAlgorithm::AES192,
161 SymmetricKeyAlgorithm::AES128
162 ]))?,
163 Subpacket::regular(SubpacketData::PreferredHashAlgorithms(smallvec![
164 HashAlgorithm::Sha256,
165 HashAlgorithm::Sha384,
166 HashAlgorithm::Sha512,
167 HashAlgorithm::Sha224,
168 ]))?,
169 Subpacket::regular(SubpacketData::PreferredCompressionAlgorithms(smallvec![
170 CompressionAlgorithm::ZLIB,
171 CompressionAlgorithm::ZIP,
172 ]))?,
173 Subpacket::regular(SubpacketData::PreferredAeadAlgorithms(smallvec![(
174 SymmetricKeyAlgorithm::AES256,
175 AeadAlgorithm::Ocb
176 )]))?,
177 Subpacket::regular(SubpacketData::IsPrimary(true))?,
178 ])
179 };
180
181 let users = if signed_secret_key.version() == KeyVersion::V4 {
196 let user_id = format!("<{addr}>");
197
198 let mut rng = thread_rng();
199 let mut user_id_signature_config = SignatureConfig::from_key(
202 &mut rng,
203 &signed_secret_key.primary_key,
204 SignatureType::CertPositive,
205 )?;
206 user_id_signature_config.hashed_subpackets = common_subpackets()?;
207 user_id_signature_config.unhashed_subpackets = vec![Subpacket::regular(
208 SubpacketData::IssuerKeyId(signed_secret_key.legacy_key_id()),
209 )?];
210 let user_id_packet =
211 pgp::packet::UserId::from_str(pgp::types::PacketHeaderVersion::New, &user_id)?;
212 let signature = user_id_signature_config.sign_certification(
213 &signed_secret_key.primary_key,
214 &signed_secret_key.primary_key.public_key(),
215 &pgp::types::Password::empty(),
216 user_id_packet.tag(),
217 &user_id_packet,
218 )?;
219 vec![user_id_packet.into_signed(signature)]
220 } else {
221 vec![]
222 };
223
224 let direct_signatures = {
225 let mut rng = thread_rng();
226 let mut direct_key_signature_config = SignatureConfig::from_key(
227 &mut rng,
228 &signed_secret_key.primary_key,
229 SignatureType::Key,
230 )?;
231 direct_key_signature_config.hashed_subpackets = common_subpackets()?;
232 let notation = Notation {
233 readable: true,
234 name: "relays@chatmail.at".into(),
235 value: relay_addrs.to_string().into(),
236 };
237 direct_key_signature_config
238 .hashed_subpackets
239 .push(Subpacket::regular(SubpacketData::Notation(notation))?);
240 let direct_key_signature = direct_key_signature_config.sign_key(
241 &signed_secret_key.primary_key,
242 &pgp::types::Password::empty(),
243 signed_secret_key.primary_key.public_key(),
244 )?;
245 vec![direct_key_signature]
246 };
247
248 signed_secret_key.details = SignedKeyDetails {
249 revocation_signatures: vec![],
250 direct_signatures,
251 users,
252 user_attributes: vec![],
253 };
254
255 Ok(signed_secret_key.to_public_key())
256}
257
258pub(crate) async fn load_self_public_key_opt(context: &Context) -> Result<Option<SignedPublicKey>> {
262 let mut lock = context.self_public_key.lock().await;
263
264 if let Some(ref public_key) = *lock {
265 return Ok(Some(public_key.clone()));
266 }
267
268 let Some(secret_key_bytes) = context
269 .sql
270 .query_row_optional(
271 "SELECT private_key
272 FROM keypairs
273 WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
274 (),
275 |row| {
276 let bytes: Vec<u8> = row.get(0)?;
277 Ok(bytes)
278 },
279 )
280 .await?
281 else {
282 return Ok(None);
283 };
284 let signed_secret_key = SignedSecretKey::from_slice(&secret_key_bytes)?;
285 let timestamp = context
286 .sql
287 .query_get_value::<u32>(
288 "SELECT MAX(timestamp)
289 FROM (SELECT add_timestamp AS timestamp
290 FROM transports
291 UNION ALL
292 SELECT remove_timestamp AS timestamp
293 FROM removed_transports)",
294 (),
295 )
296 .await?
297 .context("No transports configured")?;
298 let addr = context.get_primary_self_addr().await?;
299 let all_addrs = context.get_published_self_addrs().await?.join(",");
300 let signed_public_key =
301 secret_key_to_public_key(context, signed_secret_key, timestamp, &addr, &all_addrs)?;
302 *lock = Some(signed_public_key.clone());
303
304 Ok(Some(signed_public_key))
305}
306
307pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPublicKey> {
311 match load_self_public_key_opt(context).await? {
312 Some(public_key) => Ok(public_key),
313 None => {
314 generate_keypair(context).await?;
315 let public_key = load_self_public_key_opt(context)
316 .await?
317 .context("Secret key generated, but public key cannot be created")?;
318 Ok(public_key)
319 }
320 }
321}
322
323pub(crate) async fn load_self_public_keyring(context: &Context) -> Result<Vec<SignedPublicKey>> {
327 if let Some(public_key) = load_self_public_key_opt(context).await? {
328 Ok(vec![public_key])
329 } else {
330 Ok(vec![])
331 }
332}
333
334pub(crate) async fn self_fingerprint(context: &Context) -> Result<&str> {
341 if let Some(fp) = context.self_fingerprint.get() {
342 Ok(fp)
343 } else {
344 let fp = load_self_public_key(context).await?.dc_fingerprint().hex();
345 Ok(context.self_fingerprint.get_or_init(|| fp))
346 }
347}
348
349pub(crate) async fn self_fingerprint_opt(context: &Context) -> Result<Option<&str>> {
356 if let Some(fp) = context.self_fingerprint.get() {
357 Ok(Some(fp))
358 } else if let Some(key) = load_self_public_key_opt(context).await? {
359 let fp = key.dc_fingerprint().hex();
360 Ok(Some(context.self_fingerprint.get_or_init(|| fp)))
361 } else {
362 Ok(None)
363 }
364}
365
366pub(crate) async fn load_self_secret_key(context: &Context) -> Result<SignedSecretKey> {
367 let private_key = context
368 .sql
369 .query_row_optional(
370 "SELECT private_key
371 FROM keypairs
372 WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
373 (),
374 |row| {
375 let bytes: Vec<u8> = row.get(0)?;
376 Ok(bytes)
377 },
378 )
379 .await?;
380 match private_key {
381 Some(bytes) => SignedSecretKey::from_slice(&bytes),
382 None => {
383 let secret = generate_keypair(context).await?;
384 Ok(secret)
385 }
386 }
387}
388
389pub(crate) async fn load_self_secret_keyring(context: &Context) -> Result<Vec<SignedSecretKey>> {
390 let keys = context
391 .sql
392 .query_map_vec(
393 r#"SELECT private_key
394 FROM keypairs
395 ORDER BY id=(SELECT value FROM config WHERE keyname='key_id') DESC"#,
396 (),
397 |row| {
398 let bytes: Vec<u8> = row.get(0)?;
399 Ok(bytes)
400 },
401 )
402 .await?
403 .into_iter()
404 .filter_map(|bytes| SignedSecretKey::from_slice(&bytes).log_err(context).ok())
405 .collect();
406 Ok(keys)
407}
408
409impl DcKey for SignedPublicKey {
410 fn to_asc(&self, header: Option<(&str, &str)>) -> String {
411 let headers =
416 header.map(|(key, value)| BTreeMap::from([(key.to_string(), vec![value.to_string()])]));
417 let mut buf = Vec::new();
418 self.to_armored_writer(&mut buf, headers.as_ref().into())
419 .unwrap_or_default();
420 std::string::String::from_utf8(buf).unwrap_or_default()
421 }
422
423 fn is_private() -> bool {
424 false
425 }
426
427 fn dc_fingerprint(&self) -> Fingerprint {
428 self.fingerprint().into()
429 }
430}
431
432impl DcKey for SignedSecretKey {
433 fn to_asc(&self, header: Option<(&str, &str)>) -> String {
434 let headers =
439 header.map(|(key, value)| BTreeMap::from([(key.to_string(), vec![value.to_string()])]));
440 let mut buf = Vec::new();
441 self.to_armored_writer(&mut buf, headers.as_ref().into())
442 .unwrap_or_default();
443 std::string::String::from_utf8(buf).unwrap_or_default()
444 }
445
446 fn is_private() -> bool {
447 true
448 }
449
450 fn dc_fingerprint(&self) -> Fingerprint {
451 self.fingerprint().into()
452 }
453}
454
455async fn generate_keypair(context: &Context) -> Result<SignedSecretKey> {
456 let addr = context.get_primary_self_addr().await?;
457 let addr = EmailAddress::new(&addr)?;
458 let _public_key_guard = context.self_public_key.lock().await;
459
460 match load_keypair(context).await? {
462 Some(key_pair) => Ok(key_pair),
463 None => {
464 let start = tools::Time::now();
465 info!(context, "Generating keypair.");
466 let keypair = Handle::current()
467 .spawn_blocking(move || crate::pgp::create_keypair(addr))
468 .await??;
469
470 store_self_keypair(context, &keypair).await?;
471 info!(
472 context,
473 "Keypair generated in {:.3}s.",
474 time_elapsed(&start).as_secs(),
475 );
476 Ok(keypair)
477 }
478 }
479}
480
481pub(crate) async fn load_keypair(context: &Context) -> Result<Option<SignedSecretKey>> {
482 let res = context
483 .sql
484 .query_row_optional(
485 "SELECT private_key
486 FROM keypairs
487 WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
488 (),
489 |row| {
490 let sec_bytes: Vec<u8> = row.get(0)?;
491 Ok(sec_bytes)
492 },
493 )
494 .await?;
495
496 let signed_secret_key = if let Some(sec_bytes) = res {
497 Some(SignedSecretKey::from_slice(&sec_bytes)?)
498 } else {
499 None
500 };
501
502 Ok(signed_secret_key)
503}
504
505pub(crate) async fn store_self_keypair(
511 context: &Context,
512 signed_secret_key: &SignedSecretKey,
513) -> Result<()> {
514 let signed_public_key = signed_secret_key.to_public_key();
521 let mut config_cache_lock = context.sql.config_cache.write().await;
522 let new_key_id = context
523 .sql
524 .transaction(|transaction| {
525 let public_key = DcKey::to_bytes(&signed_public_key);
526 let secret_key = DcKey::to_bytes(signed_secret_key);
527
528 transaction
532 .execute(
533 "INSERT INTO keypairs (public_key, private_key)
534 VALUES (?,?)",
535 (&public_key, &secret_key),
536 )
537 .context("Failed to insert keypair")?;
538
539 let new_key_id = transaction.last_insert_rowid();
540
541 transaction.execute(
546 "INSERT INTO config (keyname, value) VALUES ('key_id', ?)",
547 (new_key_id,),
548 )?;
549 Ok(new_key_id)
550 })
551 .await?;
552 context.emit_event(EventType::AccountsItemChanged);
553 config_cache_lock.insert("key_id".to_string(), Some(new_key_id.to_string()));
554 Ok(())
555}
556
557pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Result<()> {
563 let secret = SignedSecretKey::from_asc(secret_data)?;
564 store_self_keypair(context, &secret).await?;
565 Ok(())
566}
567
568#[derive(Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
570pub struct Fingerprint(Vec<u8>);
571
572impl Fingerprint {
573 pub fn new(v: Vec<u8>) -> Fingerprint {
575 debug_assert_eq!(v.len(), 20);
576 Fingerprint(v)
577 }
578
579 pub fn hex(&self) -> String {
584 hex::encode_upper(&self.0)
585 }
586}
587
588impl From<pgp::types::Fingerprint> for Fingerprint {
589 fn from(fingerprint: pgp::types::Fingerprint) -> Fingerprint {
590 Self::new(fingerprint.as_bytes().into())
591 }
592}
593
594impl fmt::Debug for Fingerprint {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 f.debug_struct("Fingerprint")
597 .field("hex", &self.hex())
598 .finish()
599 }
600}
601
602impl fmt::Display for Fingerprint {
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605 for (i, c) in self.hex().chars().enumerate() {
607 if i > 0 && i % 20 == 0 {
608 writeln!(f)?;
609 } else if i > 0 && i % 4 == 0 {
610 write!(f, " ")?;
611 }
612 write!(f, "{c}")?;
613 }
614 Ok(())
615 }
616}
617
618impl std::str::FromStr for Fingerprint {
620 type Err = anyhow::Error;
621
622 fn from_str(input: &str) -> Result<Self> {
623 let hex_repr: String = input
624 .to_uppercase()
625 .chars()
626 .filter(|&c| c.is_ascii_hexdigit())
627 .collect();
628 let v: Vec<u8> = hex::decode(&hex_repr)?;
629 ensure!(v.len() == 20, "wrong fingerprint length: {hex_repr}");
630 let fp = Fingerprint::new(v);
631 Ok(fp)
632 }
633}
634
635#[cfg(test)]
636mod tests {
637 use std::sync::{Arc, LazyLock};
638
639 use super::*;
640 use crate::config::Config;
641 use crate::test_utils::{TestContext, alice_keypair};
642
643 static KEYPAIR: LazyLock<SignedSecretKey> = LazyLock::new(alice_keypair);
644
645 #[test]
646 fn test_from_armored_string() {
647 let private_key = SignedSecretKey::from_asc(
648 "-----BEGIN PGP PRIVATE KEY BLOCK-----
649
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
7027yPJeQ==
703=KZk/
704-----END PGP PRIVATE KEY BLOCK-----",
705 )
706 .expect("failed to decode");
707 let binary = DcKey::to_bytes(&private_key);
708 SignedSecretKey::from_slice(&binary).expect("invalid private key");
709 }
710
711 #[test]
712 fn test_asc_roundtrip() {
713 let key = KEYPAIR.clone().to_public_key();
714 let asc = key.to_asc(Some(("spam", "ham")));
715 let key2 = SignedPublicKey::from_asc(&asc).unwrap();
716 assert_eq!(key, key2);
717
718 let key = KEYPAIR.clone();
719 let asc = key.to_asc(Some(("spam", "ham")));
720 let key2 = SignedSecretKey::from_asc(&asc).unwrap();
721 assert_eq!(key, key2);
722 }
723
724 #[test]
725 fn test_from_slice_roundtrip() {
726 let private_key = KEYPAIR.clone();
727 let public_key = KEYPAIR.clone().to_public_key();
728
729 let binary = DcKey::to_bytes(&public_key);
730 let public_key2 = SignedPublicKey::from_slice(&binary).expect("invalid public key");
731 assert_eq!(public_key, public_key2);
732
733 let binary = DcKey::to_bytes(&private_key);
734 let private_key2 = SignedSecretKey::from_slice(&binary).expect("invalid private key");
735 assert_eq!(private_key, private_key2);
736 }
737
738 #[test]
739 fn test_from_slice_bad_data() {
740 let mut bad_data: [u8; 4096] = [0; 4096];
741 for (i, v) in bad_data.iter_mut().enumerate() {
742 *v = (i & 0xff) as u8;
743 }
744 for j in 0..(4096 / 40) {
745 let slice = &bad_data.get(j..j + 4096 / 2 + j).unwrap();
746 assert!(SignedPublicKey::from_slice(slice).is_err());
747 assert!(SignedSecretKey::from_slice(slice).is_err());
748 }
749 }
750
751 #[test]
761 fn test_ignore_trailing_garbage() {
762 for garbage in [
764 b"\x02\xfc\xaa\x38\x4b\x5c".as_slice(),
765 b"\x02\xfc\xaa".as_slice(),
766 b"\x01\x02\x03\x04\x05".as_slice(),
767 ] {
768 let private_key = KEYPAIR.clone();
769
770 let mut binary = DcKey::to_bytes(&private_key);
771 binary.extend(garbage);
772
773 let private_key2 =
774 SignedSecretKey::from_slice(&binary).expect("Failed to ignore garbage");
775
776 assert_eq!(private_key.dc_fingerprint(), private_key2.dc_fingerprint());
777 }
778 }
779
780 #[test]
781 fn test_base64_roundtrip() {
782 let key = KEYPAIR.clone().to_public_key();
783 let base64 = key.to_base64();
784 let key2 = SignedPublicKey::from_base64(&base64).unwrap();
785 assert_eq!(key, key2);
786 }
787
788 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
789 async fn test_load_self_generate_public() {
790 let t = TestContext::new().await;
791 t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
792 .await
793 .unwrap();
794 let key = load_self_public_key(&t).await;
795 assert!(key.is_ok());
796 }
797
798 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
799 async fn test_load_self_generate_secret() {
800 let t = TestContext::new().await;
801 t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
802 .await
803 .unwrap();
804 let key = load_self_secret_key(&t).await;
805 assert!(key.is_ok());
806 }
807
808 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
809 async fn test_load_self_generate_concurrent() {
810 use std::thread;
811
812 let t = TestContext::new().await;
813 t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
814 .await
815 .unwrap();
816 let thr0 = {
817 let ctx = t.clone();
818 thread::spawn(move || {
819 tokio::runtime::Runtime::new()
820 .unwrap()
821 .block_on(load_self_public_key(&ctx))
822 })
823 };
824 let thr1 = {
825 let ctx = t.clone();
826 thread::spawn(move || {
827 tokio::runtime::Runtime::new()
828 .unwrap()
829 .block_on(load_self_public_key(&ctx))
830 })
831 };
832 let res0 = thr0.join().unwrap();
833 let res1 = thr1.join().unwrap();
834 assert_eq!(res0.unwrap(), res1.unwrap());
835 }
836
837 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
839 async fn test_save_self_key_twice() {
840 let t = TestContext::new().await;
843 let ctx = Arc::new(t);
844
845 let nrows = || async {
846 ctx.sql
847 .count("SELECT COUNT(*) FROM keypairs;", ())
848 .await
849 .unwrap()
850 };
851 assert_eq!(nrows().await, 0);
852 store_self_keypair(&ctx, &KEYPAIR).await.unwrap();
853 assert_eq!(nrows().await, 1);
854
855 let res = store_self_keypair(&ctx, &KEYPAIR).await;
857 assert!(res.is_err());
858
859 assert_eq!(nrows().await, 1);
860 }
861
862 #[test]
863 fn test_fingerprint_from_str() {
864 let res = Fingerprint::new(vec![
865 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
866 ]);
867
868 let fp: Fingerprint = "0102030405060708090A0B0c0d0e0F1011121314".parse().unwrap();
869 assert_eq!(fp, res);
870
871 let fp: Fingerprint = "zzzz 0102 0304 0506\n0708090a0b0c0D0E0F1011121314 yyy"
872 .parse()
873 .unwrap();
874 assert_eq!(fp, res);
875
876 assert!("1".parse::<Fingerprint>().is_err());
877 }
878
879 #[test]
880 fn test_fingerprint_hex() {
881 let fp = Fingerprint::new(vec![
882 1, 2, 4, 8, 16, 32, 64, 128, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
883 ]);
884 assert_eq!(fp.hex(), "0102040810204080FF0A0B0C0D0E0F1011121314");
885 }
886
887 #[test]
888 fn test_fingerprint_to_string() {
889 let fp = Fingerprint::new(vec![
890 1, 2, 4, 8, 16, 32, 64, 128, 255, 1, 2, 4, 8, 16, 32, 64, 128, 255, 19, 20,
891 ]);
892 assert_eq!(
893 fp.to_string(),
894 "0102 0408 1020 4080 FF01\n0204 0810 2040 80FF 1314"
895 );
896 }
897}