1#[macro_use]
11extern crate lazy_static;
12
13pub mod types;
14
15pub mod bip39;
16
17pub mod emojis;
18
19pub mod permissions;
20
21use std::{collections::HashMap, io::Cursor};
22
23use aes_gcm_siv::{
24 aead::{heapless::Vec as HeaplessVec, AeadInPlace, KeyInit},
25 Aes256GcmSiv, Nonce,
26};
27use argon2::{Algorithm, Argon2, AssociatedData, ParamsBuilder, Version};
28use chacha20poly1305::XChaCha20Poly1305;
29use image::{imageops::FilterType, io::Reader as ImageReader, ImageOutputFormat};
30use ng_net::types::Locator;
31use rand::distributions::{Distribution, Uniform};
32use rand::prelude::*;
33use safe_transmute::transmute_to_bytes;
34use serde_bare::{from_slice, to_vec};
35#[cfg(debug_assertions)]
36use web_time::Instant;
37use zeroize::Zeroize;
38
39use ng_repo::types::*;
40use ng_repo::utils::{generate_keypair, now_timestamp, sign, verify};
41use ng_repo::{log::*, types::PrivKey};
42
43use ng_verifier::{site::SiteV0, verifier::Verifier};
44
45use crate::bip39::bip39_wordlist;
46use crate::types::*;
47
48impl Wallet {
49 pub fn id(&self) -> WalletId {
50 match self {
51 Wallet::V0(v0) => v0.id,
52 _ => unimplemented!(),
53 }
54 }
55 pub fn content_as_bytes(&self) -> Vec<u8> {
56 match self {
57 Wallet::V0(v0) => serde_bare::to_vec(&v0.content).unwrap(),
58 _ => unimplemented!(),
59 }
60 }
61 pub fn sig(&self) -> Sig {
62 match self {
63 Wallet::V0(v0) => v0.sig,
64 _ => unimplemented!(),
65 }
66 }
67 pub fn pazzle_length(&self) -> u8 {
68 match self {
69 Wallet::V0(v0) => v0.content.pazzle_length,
70 _ => unimplemented!(),
71 }
72 }
73 pub fn name(&self) -> String {
74 match self {
75 Wallet::V0(v0) => v0.id.to_string(),
76 _ => unimplemented!(),
77 }
78 }
79
80 pub fn encrypt(
87 &self,
88 wallet_log: &WalletLog,
89 master_key: &[u8; 32],
90 peer_id: PubKey,
91 nonce: u64,
92 wallet_privkey: PrivKey,
93 ) -> Result<Self, NgWalletError> {
94 let timestamp = now_timestamp();
95 let wallet_id = self.id();
96 let encrypted =
97 enc_wallet_log(wallet_log, master_key, peer_id, nonce, timestamp, wallet_id)?;
98
99 let mut wallet_content = match self {
100 Wallet::V0(v0) => v0.content.clone(),
101 _ => unimplemented!(),
102 };
103
104 wallet_content.timestamp = timestamp;
105 wallet_content.peer_id = peer_id;
106 wallet_content.nonce = nonce;
107 wallet_content.encrypted = encrypted;
108
109 let ser_wallet = serde_bare::to_vec(&wallet_content).unwrap();
110
111 let sig = sign(&wallet_privkey, &wallet_id, &ser_wallet).unwrap();
112
113 let wallet_v0 = WalletV0 {
114 id: wallet_id,
116 content: wallet_content,
118 sig,
120 };
121
122 Ok(Wallet::V0(wallet_v0))
133 }
134}
135
136pub fn enc_master_key(
137 master_key: &[u8; 32],
138 key: &[u8; 32],
139 nonce: u8,
140 wallet_id: WalletId,
141) -> Result<[u8; 48], NgWalletError> {
142 let cipher = Aes256GcmSiv::new(key.into());
143 let mut nonce_buffer = [0u8; 12];
144 nonce_buffer[0] = nonce;
145 let nonce = Nonce::from_slice(&nonce_buffer);
146
147 let mut buffer: HeaplessVec<u8, 48> = HeaplessVec::new(); buffer
149 .extend_from_slice(master_key)
150 .map_err(|_| NgWalletError::InternalError)?;
151
152 cipher
154 .encrypt_in_place(nonce, &to_vec(&wallet_id).unwrap(), &mut buffer)
155 .map_err(|_e| NgWalletError::EncryptionError)?;
156
157 Ok(buffer.into_array::<48>().unwrap())
160}
161
162pub fn dec_master_key(
163 ciphertext: [u8; 48],
164 key: &[u8; 32],
165 nonce: u8,
166 wallet_id: WalletId,
167) -> Result<[u8; 32], NgWalletError> {
168 let cipher = Aes256GcmSiv::new(key.into());
169 let mut nonce_buffer = [0u8; 12];
170 nonce_buffer[0] = nonce;
171 let nonce = Nonce::from_slice(&nonce_buffer);
172
173 let mut buffer: HeaplessVec<u8, 48> = HeaplessVec::from_slice(&ciphertext).unwrap(); cipher
177 .decrypt_in_place(nonce, &to_vec(&wallet_id).unwrap(), &mut buffer)
178 .map_err(|_e| NgWalletError::DecryptionError)?;
179 Ok(buffer.into_array::<32>().unwrap())
180}
181
182fn gen_nonce(peer_id: PubKey, nonce: u64) -> [u8; 24] {
183 let mut buffer = Vec::with_capacity(24);
184 buffer.extend_from_slice(&peer_id.slice()[0..16]);
185 buffer.extend_from_slice(&nonce.to_be_bytes());
186 buffer.try_into().unwrap()
187}
188
189fn gen_associated_data(timestamp: Timestamp, wallet_id: WalletId) -> Vec<u8> {
190 let ser_wallet = to_vec(&wallet_id).unwrap();
191 [ser_wallet, timestamp.to_be_bytes().to_vec()].concat()
192}
193
194pub fn enc_wallet_log(
195 log: &WalletLog,
196 master_key: &[u8; 32],
197 peer_id: PubKey,
198 nonce: u64,
199 timestamp: Timestamp,
200 wallet_id: WalletId,
201) -> Result<Vec<u8>, NgWalletError> {
202 let ser_log = to_vec(log).map_err(|_e| NgWalletError::InternalError)?;
203
204 let nonce_buffer: [u8; 24] = gen_nonce(peer_id, nonce);
205
206 let cipher = XChaCha20Poly1305::new(master_key.into());
207
208 let mut buffer: Vec<u8> = Vec::with_capacity(ser_log.len() + 16); buffer.extend_from_slice(&ser_log);
210
211 cipher
213 .encrypt_in_place(
214 &nonce_buffer.into(),
215 &gen_associated_data(timestamp, wallet_id),
216 &mut buffer,
217 )
218 .map_err(|_e| NgWalletError::EncryptionError)?;
219
220 Ok(buffer)
224}
225
226pub fn dec_encrypted_block(
255 mut ciphertext: Vec<u8>,
256 master_key: [u8; 32],
257 peer_id: PubKey,
258 nonce: u64,
259 timestamp: Timestamp,
260 wallet_id: WalletId,
261) -> Result<SensitiveWalletV0, NgWalletError> {
262 let nonce_buffer: [u8; 24] = gen_nonce(peer_id, nonce);
263
264 let cipher = XChaCha20Poly1305::new(master_key.as_ref().into());
265
266 cipher
268 .decrypt_in_place(
269 &nonce_buffer.into(),
270 &gen_associated_data(timestamp, wallet_id),
271 &mut ciphertext,
272 )
273 .map_err(|_e| NgWalletError::DecryptionError)?;
274
275 let decrypted_log =
276 from_slice::<WalletLog>(&ciphertext).map_err(|_e| NgWalletError::DecryptionError)?;
277
278 ciphertext.zeroize();
283
284 match decrypted_log {
285 WalletLog::V0(v0) => v0.reduce(master_key),
286 }
287}
288
289pub fn derive_key_from_pass(mut pass: Vec<u8>, salt: [u8; 16], wallet_id: WalletId) -> [u8; 32] {
300 let params = ParamsBuilder::new()
301 .m_cost(40 * 1024)
302 .t_cost(40)
303 .p_cost(1)
304 .data(AssociatedData::new(wallet_id.slice()).unwrap())
305 .output_len(32)
306 .build()
307 .unwrap();
308 let argon = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
309 let mut out = [0u8; 32];
310 argon.hash_password_into(&pass, &salt, &mut out).unwrap();
311 pass.zeroize();
312 out
313}
314
315pub fn open_wallet_with_pazzle(
316 wallet: &Wallet,
317 mut pazzle: Vec<u8>,
318 mut pin: [u8; 4],
319) -> Result<SensitiveWallet, NgWalletError> {
320 if pin[0] > 9 || pin[1] > 9 || pin[2] > 9 || pin[3] > 9 {
322 return Err(NgWalletError::InvalidPin);
323 }
324
325 #[cfg(debug_assertions)]
328 let opening_pazzle = Instant::now();
329
330 verify(&wallet.content_as_bytes(), wallet.sig(), wallet.id())
331 .map_err(|_e| NgWalletError::InvalidSignature)?;
332
333 match wallet {
334 Wallet::V0(v0) => {
335 pazzle.extend_from_slice(&pin);
336 let mut pazzle_key = derive_key_from_pass(pazzle, v0.content.salt_pazzle, v0.id);
337 pin.zeroize();
339
340 let master_key = dec_master_key(
341 v0.content.enc_master_key_pazzle,
342 &pazzle_key,
343 v0.content.master_nonce,
344 v0.id,
345 )?;
346 pazzle_key.zeroize();
347
348 #[cfg(debug_assertions)]
349 log_debug!(
350 "opening of wallet with pazzle took: {} ms",
351 opening_pazzle.elapsed().as_millis()
352 );
353 let cipher = v0.content.encrypted.clone();
354 Ok(SensitiveWallet::V0(dec_encrypted_block(
355 cipher,
356 master_key,
357 v0.content.peer_id,
358 v0.content.nonce,
359 v0.content.timestamp,
360 v0.id,
361 )?))
362 }
363 _ => unimplemented!(),
364 }
365}
366
367pub fn open_wallet_with_mnemonic(
368 wallet: &Wallet,
369 mut mnemonic: [u16; 12],
370 mut pin: [u8; 4],
371) -> Result<SensitiveWallet, NgWalletError> {
372 verify(&wallet.content_as_bytes(), wallet.sig(), wallet.id())
373 .map_err(|_e| NgWalletError::InvalidSignature)?;
374
375 match wallet {
376 Wallet::V0(v0) => {
377 let mut mnemonic_key = derive_key_from_pass(
378 [transmute_to_bytes(&mnemonic), &pin].concat(),
379 v0.content.salt_mnemonic,
380 v0.id,
381 );
382 mnemonic.zeroize();
383 pin.zeroize();
384
385 let master_key = dec_master_key(
386 v0.content.enc_master_key_mnemonic,
387 &mnemonic_key,
388 v0.content.master_nonce,
389 v0.id,
390 )?;
391 mnemonic_key.zeroize();
392
393 Ok(SensitiveWallet::V0(dec_encrypted_block(
394 v0.content.encrypted.clone(),
395 master_key,
396 v0.content.peer_id,
397 v0.content.nonce,
398 v0.content.timestamp,
399 v0.id,
400 )?))
401 }
402 _ => unimplemented!(),
403 }
404}
405
406pub fn display_mnemonic(mnemonic: &[u16; 12]) -> Vec<String> {
407 let res: Vec<String> = mnemonic
408 .into_iter()
409 .map(|i| String::from(bip39_wordlist[*i as usize]))
410 .collect();
411 res
412}
413
414pub fn gen_shuffle_for_pazzle_opening(pazzle_length: u8) -> ShuffledPazzle {
415 let mut rng = rand::thread_rng();
416 let mut category_indices: Vec<u8> = (0..pazzle_length).collect();
417 category_indices.shuffle(&mut rng);
419 let mut emoji_indices: Vec<Vec<u8>> = Vec::with_capacity(pazzle_length.into());
422 for _ in 0..pazzle_length {
423 let mut idx: Vec<u8> = (0..15).collect();
424 idx.shuffle(&mut rng);
426 emoji_indices.push(idx)
428 }
429 ShuffledPazzle {
430 category_indices,
431 emoji_indices,
432 }
433}
434
435pub fn gen_shuffle_for_pin() -> Vec<u8> {
436 let mut rng = rand::thread_rng();
437 let mut digits: Vec<u8> = (0..10).collect();
438 digits.shuffle(&mut rng);
440 digits
442}
443
444pub fn create_wallet_first_step_v0(
447 params: CreateWalletV0,
448) -> Result<CreateWalletIntermediaryV0, NgWalletError> {
449 if params.pazzle_length != 9
451 && params.pazzle_length != 0
454 {
455 return Err(NgWalletError::InvalidPazzleLength);
456 }
457
458 if params.pin[0] > 9 || params.pin[1] > 9 || params.pin[2] > 9 || params.pin[3] > 9 {
467 return Err(NgWalletError::InvalidPin);
468 }
469
470 if (params.pin[0] == params.pin[1] && params.pin[0] == params.pin[2])
472 || (params.pin[0] == params.pin[1] && params.pin[0] == params.pin[3])
473 || (params.pin[0] == params.pin[2] && params.pin[0] == params.pin[3])
474 || (params.pin[1] == params.pin[2] && params.pin[1] == params.pin[3])
475 {
476 return Err(NgWalletError::InvalidPin);
477 }
478
479 if params.pin[1] == params.pin[0] + 1
481 && params.pin[2] == params.pin[1] + 1
482 && params.pin[3] == params.pin[2] + 1
483 {
484 return Err(NgWalletError::InvalidPin);
485 }
486
487 if params.pin[3] >= 3
489 && params.pin[2] == params.pin[3] - 1
490 && params.pin[1] == params.pin[2] - 1
491 && params.pin[0] == params.pin[1] - 1
492 {
493 return Err(NgWalletError::InvalidPin);
494 }
495
496 let words: Vec<_> = params.security_txt.split_whitespace().collect();
498 let new_string = words.join(" ");
499 let count = new_string.chars().count();
500 if count < 10 || count > 100 {
501 return Err(NgWalletError::InvalidSecurityText);
502 }
503
504 let decoded_img = ImageReader::new(Cursor::new(¶ms.security_img))
506 .with_guessed_format()
507 .map_err(|_e| NgWalletError::InvalidSecurityImage)?
508 .decode()
509 .map_err(|_e| NgWalletError::InvalidSecurityImage)?;
510
511 if decoded_img.height() < 150 || decoded_img.width() < 150 {
512 return Err(NgWalletError::InvalidSecurityImage);
513 }
514
515 let resized_img = if decoded_img.height() == 400 && decoded_img.width() == 400 {
516 decoded_img
517 } else {
518 decoded_img.resize_to_fill(400, 400, FilterType::Triangle)
519 };
520
521 let buffer: Vec<u8> = Vec::with_capacity(100000);
522 let mut cursor = Cursor::new(buffer);
523 resized_img
524 .write_to(&mut cursor, ImageOutputFormat::Jpeg(72))
525 .map_err(|_e| NgWalletError::InvalidSecurityImage)?;
526
527 let (wallet_privkey, wallet_id) = generate_keypair();
530
531 let user_privkey = PrivKey::random_ed();
533
534 let user = user_privkey.to_pub();
535
536 let client = ClientV0::new_with_auto_open(user);
537
538 let intermediary = CreateWalletIntermediaryV0 {
539 wallet_privkey,
540 wallet_name: wallet_id.to_string(),
541 client,
542 user_privkey,
543 in_memory: !params.local_save,
544 security_img: cursor.into_inner(),
545 security_txt: new_string,
546 pazzle_length: params.pazzle_length,
547 pin: params.pin,
548 send_bootstrap: params.send_bootstrap,
549 send_wallet: params.send_wallet,
550 result_with_wallet_file: params.result_with_wallet_file,
551 core_bootstrap: params.core_bootstrap.clone(),
552 core_registration: params.core_registration,
553 additional_bootstrap: params.additional_bootstrap.clone(),
554 pdf: params.pdf,
555 };
556 Ok(intermediary)
557}
558
559pub async fn create_wallet_second_step_v0(
560 mut params: CreateWalletIntermediaryV0,
561 verifier: &mut Verifier,
562) -> Result<
563 (
564 CreateWalletResultV0,
565 SiteV0,
566 HashMap<String, Vec<BrokerInfoV0>>,
567 ),
568 NgWalletError,
569> {
570 #[cfg(debug_assertions)]
571 let creating_pazzle = Instant::now();
572
573 let mut site = SiteV0::create_personal(params.user_privkey.clone(), verifier)
574 .await
575 .map_err(|e| {
576 log_err!("create_personal failed with {e}");
577 NgWalletError::InternalError
578 })?;
579
580 let user = params.user_privkey.to_pub();
581
582 let wallet_id = params.wallet_privkey.to_pub();
583
584 let mut ran = thread_rng();
585
586 let mut category_indices: Vec<u8> = (0..params.pazzle_length).collect();
587 category_indices.shuffle(&mut ran);
588
589 let between = Uniform::try_from(0..15).unwrap();
590 let mut pazzle = vec![0u8; params.pazzle_length.into()];
591 for (ix, i) in pazzle.iter_mut().enumerate() {
592 *i = between.sample(&mut ran) + (category_indices[ix] << 4);
594 }
595
596 let between = Uniform::try_from(0..2048).unwrap();
598 let mut mnemonic = [0u16; 12];
599 for i in &mut mnemonic {
600 *i = between.sample(&mut ran);
602 }
603
604 let create_op = WalletOpCreateV0 {
611 wallet_privkey: params.wallet_privkey.clone(),
612 personal_site: site.clone(),
616 save_recovery_kit: if params.send_wallet {
617 SaveToNGOne::Wallet
618 } else if params.send_bootstrap {
619 SaveToNGOne::Bootstrap
620 } else {
621 SaveToNGOne::No
622 },
623 };
625
626 let mut wallet_log = WalletLog::new_v0(create_op);
630
631 let mut brokers: HashMap<String, Vec<BrokerInfoV0>> = HashMap::new();
640
641 let core_pubkey = params
642 .core_bootstrap
643 .get_first_peer_id()
644 .ok_or(NgWalletError::InvalidBootstrap)?;
645 wallet_log.add(WalletOperation::AddSiteCoreV0((
646 user,
647 core_pubkey,
648 params.core_registration,
649 )));
650
651 site.cores.push((core_pubkey, params.core_registration));
652
653 if let Some(additional) = ¶ms.additional_bootstrap {
654 params.core_bootstrap.merge(additional);
655 }
656 let mut locator = Locator::empty();
657 for server in ¶ms.core_bootstrap.servers {
658 locator.add(server.clone());
659
660 wallet_log.add(WalletOperation::AddBrokerServerV0(server.clone()));
661 wallet_log.add(WalletOperation::AddSiteBootstrapV0((user, server.peer_id)));
662 site.bootstraps.push(server.peer_id);
663
664 let broker = BrokerInfoV0::ServerV0(server.clone());
665 let key = broker.get_id().to_string();
666 let mut list = brokers.get_mut(&key);
667 if list.is_none() {
668 let new_list = vec![];
669 brokers.insert(key.clone(), new_list);
670 list = brokers.get_mut(&key);
671 }
672 list.unwrap().push(broker);
673 }
674 verifier.update_locator(locator);
675
676 let mut master_key = [0u8; 32];
677 getrandom::getrandom(&mut master_key).map_err(|_e| NgWalletError::InternalError)?;
678
679 let mut salt_pazzle = [0u8; 16];
680 let mut enc_master_key_pazzle = [0u8; 48];
681 if params.pazzle_length > 0 {
682 getrandom::getrandom(&mut salt_pazzle).map_err(|_e| NgWalletError::InternalError)?;
683
684 let mut pazzle_key = derive_key_from_pass(
685 [pazzle.clone(), params.pin.to_vec()].concat(),
686 salt_pazzle,
687 wallet_id,
688 );
689
690 enc_master_key_pazzle = enc_master_key(&master_key, &pazzle_key, 0, wallet_id)?;
691 pazzle_key.zeroize();
692 }
693
694 let mut salt_mnemonic = [0u8; 16];
695 getrandom::getrandom(&mut salt_mnemonic).map_err(|_e| NgWalletError::InternalError)?;
696
697 let mut mnemonic_key = derive_key_from_pass(
701 [transmute_to_bytes(&mnemonic), ¶ms.pin].concat(),
702 salt_mnemonic,
703 wallet_id,
704 );
705
706 let enc_master_key_mnemonic = enc_master_key(&master_key, &mnemonic_key, 0, wallet_id)?;
707 mnemonic_key.zeroize();
708
709 let timestamp = now_timestamp();
710
711 let encrypted = enc_wallet_log(
712 &wallet_log,
713 &master_key,
714 PubKey::nil(),
716 0,
717 timestamp,
718 wallet_id,
719 )?;
720 master_key.zeroize();
721
722 let wallet_content = WalletContentV0 {
723 security_img: params.security_img.clone(),
724 security_txt: params.security_txt.clone(),
725 pazzle_length: params.pazzle_length,
726 salt_pazzle,
727 salt_mnemonic,
728 enc_master_key_pazzle,
729 enc_master_key_mnemonic,
730 master_nonce: 0,
731 timestamp,
732 peer_id: PubKey::nil(),
733 nonce: 0,
734 encrypted,
735 };
736
737 let ser_wallet = serde_bare::to_vec(&wallet_content).unwrap();
738
739 let sig = sign(¶ms.wallet_privkey, &wallet_id, &ser_wallet).unwrap();
740
741 let wallet_v0 = WalletV0 {
742 id: wallet_id,
744 content: wallet_content,
746 sig,
748 };
749
750 #[cfg(debug_assertions)]
761 log_debug!(
762 "creating of wallet took: {} ms",
763 creating_pazzle.elapsed().as_millis()
764 );
765
766 let wallet = Wallet::V0(wallet_v0);
767 let wallet_file = match params.result_with_wallet_file {
768 false => vec![],
769 true => to_vec(&NgFile::V0(NgFileV0::Wallet(wallet.clone()))).unwrap(),
770 };
771 Ok((
772 CreateWalletResultV0 {
773 wallet: wallet,
774 wallet_file,
775 pazzle,
776 mnemonic: mnemonic.clone(),
777 mnemonic_str: display_mnemonic(&mnemonic),
778 wallet_name: params.wallet_name.clone(),
779 client: params.client.clone(),
780 user,
781 in_memory: params.in_memory,
782 session_id: 0,
783 pdf_file: vec![],
784 },
785 site,
786 brokers,
787 ))
788}
789
790#[cfg(test)]
791mod test {
792 use crate::emojis::display_pazzle_one;
793
794 use super::*;
795 use ng_net::types::BootstrapContentV0;
796 use std::fs::File;
797 use std::io::BufReader;
798 use std::io::Read;
799 use std::io::Write;
800 use std::time::Instant;
801
802 #[test]
808 fn test_gen_shuffle() {
809 let _shuffle = gen_shuffle_for_pazzle_opening(9);
810 log_debug!("{:?}", _shuffle);
811 let _shuffle = gen_shuffle_for_pazzle_opening(12);
812 log_debug!("{:?}", _shuffle);
813 let _shuffle = gen_shuffle_for_pazzle_opening(15);
814 log_debug!("{:?}", _shuffle);
815 let _digits = gen_shuffle_for_pin();
816 log_debug!("{:?}", _digits);
817 }
818
819 #[async_std::test]
820 async fn create_wallet() {
821 let f = File::open("tests/valid_security_image.jpg")
823 .expect("open of tests/valid_security_image.jpg");
824 let mut reader = BufReader::new(f);
825 let mut img_buffer = Vec::new();
826 reader
828 .read_to_end(&mut img_buffer)
829 .expect("read of valid_security_image.jpg");
830
831 let pin = [5, 2, 9, 1];
832
833 let _creation = Instant::now();
834
835 let res = create_wallet_first_step_v0(CreateWalletV0::new(
836 img_buffer,
837 " know yourself ".to_string(),
838 pin,
839 9,
840 false,
841 false,
842 BootstrapContentV0::new_localhost(PubKey::nil()),
843 None,
844 None,
845 false,
846 "test".to_string(),
847 ))
848 .expect("create_wallet_first_step_v0");
849
850 let mut verifier = Verifier::new_dummy();
851 let (res, _, _) = create_wallet_second_step_v0(res, &mut verifier)
852 .await
853 .expect("create_wallet_second_step_v0");
854
855 log_info!(
856 "creation of wallet took: {} ms",
857 _creation.elapsed().as_millis()
858 );
859 log_debug!("-----------------------------");
860
861 let mut file = File::create("tests/wallet.ngw").expect("open wallet write file");
862 let ser_wallet = to_vec(&NgFile::V0(NgFileV0::Wallet(res.wallet.clone()))).unwrap();
863 let _ = file.write_all(&ser_wallet);
864
865 log_debug!("wallet id: {}", res.wallet.id());
866 log_debug!("pazzle {:?}", display_pazzle_one(&res.pazzle));
867 log_debug!("mnemonic {:?}", display_mnemonic(&res.mnemonic));
868 log_debug!("pin {:?}", pin);
869
870 if let Wallet::V0(v0) = &res.wallet {
871 log_debug!("security text: {:?}", v0.content.security_txt);
872
873 let mut file =
874 File::create("tests/generated_security_image.jpg").expect("open write file");
875 let _ = file.write_all(&v0.content.security_img);
876
877 let f = File::open("tests/generated_security_image.jpg.compare")
878 .expect("open of generated_security_image.jpg.compare");
879 let mut reader = BufReader::new(f);
880 let mut generated_security_image_compare = Vec::new();
881 reader
883 .read_to_end(&mut generated_security_image_compare)
884 .expect("read of generated_security_image.jpg.compare");
885
886 assert_eq!(v0.content.security_img, generated_security_image_compare);
887
888 let _opening_mnemonic = Instant::now();
889
890 let _w = open_wallet_with_mnemonic(&Wallet::V0(v0.clone()), res.mnemonic, pin.clone())
891 .expect("open with mnemonic");
892 log_info!(
895 "opening of wallet with mnemonic took: {} ms",
896 _opening_mnemonic.elapsed().as_millis()
897 );
898
899 if v0.content.pazzle_length > 0 {
900 let _opening_pazzle = Instant::now();
901 let _w = open_wallet_with_pazzle(&Wallet::V0(v0.clone()), res.pazzle.clone(), pin)
902 .expect("open with pazzle");
903 log_info!(
904 "opening of wallet with pazzle took: {} ms",
905 _opening_pazzle.elapsed().as_millis()
906 );
907 }
908 log_debug!("encrypted part {:?}", _w);
909 }
910 }
911}