1use crate::helpers::args::{network_id_parser, parse_private_key};
17
18mod sign;
19use sign::Sign;
20
21use snarkvm::console::{
22 account::{Address, PrivateKey, Signature},
23 network::{CanaryV0, MainnetV0, Network, TestnetV0},
24 prelude::{Environment, Uniform},
25 program::{ToFields, Value},
26 types::Field,
27};
28
29use anyhow::{Result, anyhow, bail};
30use clap::Parser;
31use colored::Colorize;
32use core::str::FromStr;
33use crossterm::ExecutableCommand;
34use rand::SeedableRng;
35use rand_chacha::ChaChaRng;
36use rayon::prelude::*;
37use std::{
38 fs::File,
39 io::{Read, Write},
40};
41
42use zeroize::Zeroize;
43
44#[derive(Debug, Parser, Zeroize)]
46#[command(
47 rename_all = "kebab-case",
50)]
51pub enum Account {
52 New {
54 #[clap(long, default_value_t=MainnetV0::ID, long, value_parser = network_id_parser())]
57 network: u16,
58 #[clap(short = 's', long)]
60 seed: Option<String>,
61 #[clap(short = 'v', long, conflicts_with_all = &["seed", "save_to_file"])]
63 vanity: Option<String>,
64 #[clap(long)]
66 discreet: bool,
67 #[clap(long, conflicts_with = "discreet")]
69 save_to_file: Option<String>,
70 },
71 Import {
73 private_key: Option<String>,
75 #[clap(long, default_value_t=MainnetV0::ID, long, value_parser = network_id_parser())]
78 network: u16,
79 #[clap(long)]
81 discreet: bool,
82 #[clap(long, conflicts_with = "discreet")]
84 save_to_file: Option<String>,
85 },
86 Sign(Sign),
87 Verify {
88 #[clap(long, default_value_t=MainnetV0::ID, long, value_parser = network_id_parser())]
91 network: u16,
92 #[clap(short = 'a', long)]
94 address: String,
95 #[clap(short = 's', long)]
97 signature: String,
98 #[clap(short = 'm', long)]
100 message: String,
101 #[clap(short = 'r', long)]
103 raw: bool,
104 },
105}
106
107fn aleo_literal_to_fields<N: Network>(input: &str) -> Result<Vec<Field<N>>> {
109 Value::<N>::from_str(input)?.to_fields()
110}
111
112impl Account {
113 pub fn parse(self) -> Result<String> {
115 match self {
116 Self::New { network, seed, vanity, discreet, save_to_file } => {
117 match vanity {
118 Some(vanity) => match network {
120 MainnetV0::ID => Self::new_vanity::<MainnetV0>(vanity.as_str(), discreet),
121 TestnetV0::ID => Self::new_vanity::<TestnetV0>(vanity.as_str(), discreet),
122 CanaryV0::ID => Self::new_vanity::<CanaryV0>(vanity.as_str(), discreet),
123 unknown_id => bail!("Unknown network ID ({unknown_id})"),
124 },
125 None => match network {
127 MainnetV0::ID => Self::new_seeded::<MainnetV0>(seed, discreet, save_to_file),
128 TestnetV0::ID => Self::new_seeded::<TestnetV0>(seed, discreet, save_to_file),
129 CanaryV0::ID => Self::new_seeded::<CanaryV0>(seed, discreet, save_to_file),
130 unknown_id => bail!("Unknown network ID ({unknown_id})"),
131 },
132 }
133 }
134 Self::Import { private_key, network, discreet, save_to_file } => {
135 match network {
137 MainnetV0::ID => Self::import::<MainnetV0>(private_key, discreet, save_to_file),
138 TestnetV0::ID => Self::import::<TestnetV0>(private_key, discreet, save_to_file),
139 CanaryV0::ID => Self::import::<CanaryV0>(private_key, discreet, save_to_file),
140 unknown_id => bail!("Unknown network ID ({unknown_id})"),
141 }
142 }
143 Self::Sign(sign) => sign.execute(),
144 Self::Verify { network, address, signature, message, raw } => {
145 match network {
147 MainnetV0::ID => Self::verify::<MainnetV0>(address, signature, message, raw),
148 TestnetV0::ID => Self::verify::<TestnetV0>(address, signature, message, raw),
149 CanaryV0::ID => Self::verify::<CanaryV0>(address, signature, message, raw),
150 unknown_id => bail!("Unknown network ID ({unknown_id})"),
151 }
152 }
153 }
154 }
155
156 fn new_vanity<N: Network>(vanity: &str, discreet: bool) -> Result<String> {
158 let sample_account = || snarkos_account::Account::<N>::new(&mut rand::thread_rng());
160
161 const ITERATIONS: u128 = u16::MAX as u128;
162 const ITERATIONS_STR: &str = "65,535";
163
164 if !crate::helpers::is_in_bech32m_charset(vanity) {
166 bail!(
167 "The vanity string '{vanity}' contains invalid bech32m characters. Try using characters from the bech32m character set: {}",
168 crate::helpers::BECH32M_CHARSET
169 );
170 }
171
172 if vanity.len() > 4 {
174 let message =
175 format!(" The vanity string '{vanity}' contains 5 or more characters and will take a while to find.\n");
176 println!("{}", message.yellow());
177 }
178
179 loop {
180 let timer = std::time::Instant::now();
182
183 let account = (0..ITERATIONS).into_par_iter().find_map_any(|_| {
186 let mut account = None;
188 if let Ok(candidate) = sample_account() {
190 let address = candidate.address().to_string();
192 if crate::helpers::has_vanity_string(&address, vanity) {
195 account = Some(candidate);
196 }
197 }
198 account
200 });
201
202 if let Some(account) = account {
204 println!(); if !discreet {
206 return Ok(account.to_string());
207 }
208 display_string_discreetly(
209 &format!("{:>12} {}", "Private Key".cyan().bold(), account.private_key()),
210 "### Do not share or lose this private key! Press any key to complete. ###",
211 )
212 .unwrap();
213 let account_info = format!(
214 " {:>12} {}\n {:>12} {}",
215 "View Key".cyan().bold(),
216 account.view_key(),
217 "Address".cyan().bold(),
218 account.address()
219 );
220 return Ok(account_info);
221 } else {
222 let rate = ITERATIONS / timer.elapsed().as_millis();
223 let rate = format!("[{rate} a/ms]");
224 println!(" {} Sampled {ITERATIONS_STR} accounts, searching...", rate.dimmed());
225 }
226 }
227 }
228
229 fn new_seeded<N: Network>(seed: Option<String>, discreet: bool, save_to_file: Option<String>) -> Result<String> {
231 let seed = match seed {
233 Some(seed) => {
235 Field::new(<N as Environment>::Field::from_str(&seed).map_err(|e| anyhow!("Invalid seed - {e}"))?)
236 }
237 None => Field::rand(&mut ChaChaRng::from_entropy()),
239 };
240 let private_key =
242 PrivateKey::try_from(seed).map_err(|_| anyhow!("Failed to convert the seed into a valid private key"))?;
243 let account = snarkos_account::Account::<N>::try_from(private_key)?;
245 if let Some(path) = save_to_file {
247 crate::check_parent_permissions(&path)?;
248 let mut file = File::create_new(path)?;
249 file.write_all(account.private_key().to_string().as_bytes())?;
250 crate::set_user_read_only(&file)?;
251 }
252 if !discreet {
254 return Ok(account.to_string());
255 }
256 display_string_discreetly(
257 &format!("{:>12} {}", "Private Key".cyan().bold(), account.private_key()),
258 "### Do not share or lose this private key! Press any key to complete. ###",
259 )
260 .unwrap();
261 let account_info = format!(
262 " {:>12} {}\n {:>12} {}",
263 "View Key".cyan().bold(),
264 account.view_key(),
265 "Address".cyan().bold(),
266 account.address()
267 );
268 Ok(account_info)
269 }
270
271 fn import<N: Network>(private_key: Option<String>, discreet: bool, save_to_file: Option<String>) -> Result<String> {
273 let private_key = match discreet {
275 true => {
276 let private_key_input = rpassword::prompt_password("Please enter your private key: ").unwrap();
277 PrivateKey::from_str(&private_key_input)
278 }
279 false => match private_key {
280 Some(private_key) => PrivateKey::from_str(&private_key),
281 None => bail!("PRIVATE_KEY shouldn't be empty when --discreet is false"),
282 },
283 }?;
284
285 let account = snarkos_account::Account::<N>::try_from(private_key)?;
287 if let Some(path) = save_to_file {
289 crate::check_parent_permissions(&path)?;
290 let mut file = File::create_new(path)?;
291 file.write_all(account.private_key().to_string().as_bytes())?;
292 crate::set_user_read_only(&file)?;
293 }
294 if !discreet {
296 return Ok(account.to_string());
297 }
298 display_string_discreetly(
299 &format!("{:>12} {}", "Private Key".cyan().bold(), account.private_key()),
300 "### Do not share or lose this private key! Press any key to complete. ###",
301 )
302 .unwrap();
303 let account_info = format!(
304 " {:>12} {}\n {:>12} {}",
305 "View Key".cyan().bold(),
306 account.view_key(),
307 "Address".cyan().bold(),
308 account.address()
309 );
310 Ok(account_info)
311 }
312
313 fn verify<N: Network>(address: String, signature: String, message: String, raw: bool) -> Result<String> {
315 let address = Address::<N>::from_str(&address).map_err(|_| anyhow!("Failed to parse a valid address"))?;
317 let signature =
319 Signature::<N>::from_str(&signature).map_err(|_| anyhow!("Failed to parse a valid signature"))?;
320 let verified = if raw {
322 signature.verify_bytes(&address, message.as_bytes())
323 } else {
324 let fields =
325 aleo_literal_to_fields(&message).map_err(|_| anyhow!("Failed to parse a valid Aleo literal"))?;
326 signature.verify(&address, &fields)
327 };
328
329 match verified {
331 true => Ok("✅ The signature is valid".to_string()),
332 false => bail!("❌ The signature is invalid"),
333 }
334 }
335}
336
337fn display_string_discreetly(discreet_string: &str, continue_message: &str) -> Result<()> {
339 use crossterm::{
340 style::Print,
341 terminal::{EnterAlternateScreen, LeaveAlternateScreen},
342 };
343 let mut stdout = std::io::stdout();
344 stdout.execute(EnterAlternateScreen)?;
345 stdout.execute(Print(format!("{discreet_string}\n{continue_message}")))?;
347 stdout.flush()?;
348 wait_for_keypress();
349 stdout.execute(LeaveAlternateScreen)?;
350 Ok(())
351}
352
353fn wait_for_keypress() {
354 let mut single_key = [0u8];
355 std::io::stdin().read_exact(&mut single_key).unwrap();
356}
357
358#[cfg(test)]
359mod tests {
360 use super::{Account, Sign};
361
362 use std::{fs, fs::Permissions, io::Write};
363 use tempfile::{NamedTempFile, TempDir};
364
365 use anyhow::{Context, Result};
366 use colored::Colorize;
367
368 #[test]
369 fn test_new() -> Result<()> {
370 for _ in 0..3 {
371 let account = Account::New { network: 0, seed: None, vanity: None, discreet: false, save_to_file: None };
372 account.parse().with_context(|| "Account creation failed")?;
373 }
374
375 Ok(())
376 }
377
378 #[test]
379 fn test_new_seeded() -> Result<()> {
380 let seed = Some(1231275789u64.to_string());
381
382 let mut expected = format!(
383 " {:>12} {}\n",
384 "Private Key".cyan().bold(),
385 "APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X"
386 );
387 expected += &format!(
388 " {:>12} {}\n",
389 "View Key".cyan().bold(),
390 "AViewKey1pNxZHn79XVJ4D2WG5Vn2YWsAzf5wzAs3dAuQtUAmUFF7"
391 );
392 expected += &format!(
393 " {:>12} {}",
394 "Address".cyan().bold(),
395 "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5"
396 );
397
398 let vanity = None;
399 let account = Account::New { network: 0, seed, vanity, discreet: false, save_to_file: None };
400 let actual = account.parse().with_context(|| "Command execution failed")?;
401 assert_eq!(expected, actual);
402
403 Ok(())
404 }
405
406 #[test]
407 fn test_new_seeded_with_256bits_input() -> anyhow::Result<()> {
408 let seed = Some("38868010450269069756484274649022187108349082664538872491798902858296683054657".to_string());
409
410 let mut expected = format!(
411 " {:>12} {}\n",
412 "Private Key".cyan().bold(),
413 "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p"
414 );
415 expected += &format!(
416 " {:>12} {}\n",
417 "View Key".cyan().bold(),
418 "AViewKey1eYEGtb78FVg38SSYyzAeXnBdnWCba5t5YxUxtkTtvNAE"
419 );
420 expected += &format!(
421 " {:>12} {}",
422 "Address".cyan().bold(),
423 "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j"
424 );
425
426 let vanity = None;
427 let account = Account::New { network: 0, seed, vanity, discreet: false, save_to_file: None };
428
429 let actual = account.parse().with_context(|| "Command execution failed")?;
430 assert_eq!(expected, actual);
431
432 Ok(())
433 }
434
435 #[cfg(unix)]
436 #[test]
437 fn test_new_save_to_file() -> anyhow::Result<()> {
438 use std::os::unix::fs::PermissionsExt;
439
440 let dir = TempDir::new().expect("Failed to create temp folder");
441 let dir_path = dir.path();
442 fs::set_permissions(dir_path, Permissions::from_mode(0o700)).expect("Failed to set permissions");
443
444 let mut file = dir.path().to_owned();
445 file.push("my-private-key-file");
446 let file = file.display().to_string();
447
448 let seed = Some(1231275789u64.to_string());
449 let vanity = None;
450 let discreet = false;
451 let save_to_file = Some(file.clone());
452 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file };
453
454 let actual = account.parse().with_context(|| "Command execution failed")?;
455
456 let expected = "APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X";
457 assert!(actual.contains(expected));
458
459 let content = fs::read_to_string(&file).expect("Failed to read private-key-file");
460 assert_eq!(expected, content);
461
462 let metadata = fs::metadata(file).unwrap();
464 let permissions = metadata.permissions();
465 assert_eq!(permissions.mode() & 0o777, 0o400, "File permissions are not 0o400");
466
467 Ok(())
468 }
469
470 #[cfg(unix)]
471 #[test]
472 fn test_new_prevent_save_to_file_in_non_protected_folder() {
473 use std::os::unix::fs::PermissionsExt;
474
475 let dir = TempDir::new().expect("Failed to create temp folder");
476 let dir_path = dir.path();
477 fs::set_permissions(dir_path, Permissions::from_mode(0o444)).expect("Failed to set permissions");
478
479 let mut file = dir.path().to_owned();
480 file.push("my-private-key-file");
481 let file = file.display().to_string();
482
483 let seed = None;
484 let vanity = None;
485 let discreet = false;
486 let save_to_file = Some(file);
487 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file };
488
489 let res = account.parse();
490 assert!(res.is_err());
491 }
492
493 #[test]
494 fn test_new_prevent_save_to_file_in_non_existing_folder() {
495 let dir = TempDir::new().expect("Failed to create temp folder");
496
497 let mut file = dir.path().to_owned();
498 file.push("missing-folder");
499 file.push("my-private-key-file");
500 let file = file.display().to_string();
501
502 let seed = None;
503 let vanity = None;
504 let discreet = false;
505 let save_to_file = Some(file);
506 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file };
507
508 let res = account.parse();
509 assert!(res.is_err());
510 }
511
512 #[test]
513 fn test_new_prevent_overwrite_existing_file() {
514 let mut file = NamedTempFile::new().expect("Failed to create temp file");
515 write!(file, "don't overwrite me").expect("Failed to write secret to file");
516
517 let seed = None;
518 let vanity = None;
519 let discreet = false;
520 let path = file.path().display().to_string();
521 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file: Some(path) };
522
523 let res = account.parse();
524 assert!(res.is_err());
525
526 let expected = "don't overwrite me";
527 let content = fs::read_to_string(file).expect("Failed to read private-key-file");
528 assert_eq!(expected, content);
529 }
530
531 #[test]
532 fn test_new_disallow_save_to_file_with_discreet() {
533 let seed = None;
534 let vanity = None;
535 let discreet = true;
536 let save_to_file = Some("/tmp/not-important".to_string());
537 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file };
538
539 let res = account.parse();
540 assert!(res.is_err());
541 }
542
543 #[test]
544 fn test_new_disallow_save_to_file_with_vanity() {
545 let seed = None;
546 let vanity = Some("foo".to_string());
547 let discreet = false;
548 let save_to_file = Some("/tmp/not-important".to_string());
549 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file };
550
551 let res = account.parse();
552 assert!(res.is_err());
553 }
554
555 #[test]
556 fn test_import() -> Result<()> {
557 let account = Account::Import { network: 0, private_key: None, discreet: false, save_to_file: None };
558 assert!(account.parse().is_err());
559
560 let mut expected = format!(
561 " {:>12} {}\n",
562 "Private Key".cyan().bold(),
563 "APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X"
564 );
565 expected += &format!(
566 " {:>12} {}\n",
567 "View Key".cyan().bold(),
568 "AViewKey1pNxZHn79XVJ4D2WG5Vn2YWsAzf5wzAs3dAuQtUAmUFF7"
569 );
570 expected += &format!(
571 " {:>12} {}",
572 "Address".cyan().bold(),
573 "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5"
574 );
575
576 let account = Account::Import {
577 network: 0,
578 private_key: Some("APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X".to_string()),
579 discreet: false,
580 save_to_file: None,
581 };
582 let actual = account.parse().with_context(|| "Command execution failed")?;
583 assert_eq!(expected, actual);
584
585 Ok(())
586 }
587
588 #[cfg(unix)]
589 #[test]
590 fn test_import_save_to_file() -> anyhow::Result<()> {
591 use std::os::unix::fs::PermissionsExt;
592
593 let dir = TempDir::new().expect("Failed to create temp folder");
594 let dir_path = dir.path();
595 fs::set_permissions(dir_path, Permissions::from_mode(0o700)).expect("Failed to set permissions");
596
597 let mut file = dir.path().to_owned();
598 file.push("my-private-key-file");
599 let file = file.display().to_string();
600
601 let discreet = false;
602 let save_to_file = Some(file.clone());
603 let account = Account::Import {
604 network: 0,
605 private_key: Some("APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X".to_string()),
606 discreet,
607 save_to_file,
608 };
609
610 let actual = account.parse().with_context(|| "Command execution failed")?;
611
612 let expected = "APrivateKey1zkp2n22c19hNdGF8wuEoQcuiyuWbquY6up4CtG5DYKqPX2X";
613 assert!(actual.contains(expected));
614
615 let content = fs::read_to_string(&file).expect("Failed to read private-key-file");
616 assert_eq!(expected, content);
617
618 let metadata = fs::metadata(file).unwrap();
620 let permissions = metadata.permissions();
621 assert_eq!(permissions.mode() & 0o777, 0o400, "File permissions are not 0o400");
622
623 Ok(())
624 }
625
626 #[test]
627 fn test_signature_raw() -> Result<()> {
628 let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string();
629 let message = "Hello, world!".to_string();
630 let account = Account::Sign(Sign {
631 network: 0,
632 private_key: Some(key),
633 private_key_file: None,
634 message,
635 raw: true,
636 dev_key: None,
637 });
638
639 account.parse().with_context(|| "Command execution failed")?;
640 Ok(())
641 }
642
643 #[test]
644 fn test_signature_raw_using_private_key_file() -> Result<()> {
645 let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string();
646 let message = "Hello, world!".to_string();
647
648 let mut file = NamedTempFile::new().expect("Failed to create temp file");
649 writeln!(file, "{key}").expect("Failed to write key to temp file");
650
651 let path = file.path().display().to_string();
652 let account = Account::Sign(Sign {
653 network: 0,
654 private_key: None,
655 private_key_file: Some(path),
656 message,
657 raw: true,
658 dev_key: None,
659 });
660
661 account.parse().with_context(|| "Command execution failed")?;
662 Ok(())
663 }
664
665 #[cfg(unix)]
666 #[test]
667 fn test_signature_raw_using_private_key_file_from_account_new() -> Result<()> {
668 use std::os::unix::fs::PermissionsExt;
669
670 let message = "Hello, world!".to_string();
671
672 let dir = TempDir::new().expect("Failed to create temp folder");
673 let dir_path = dir.path();
674 fs::set_permissions(dir_path, Permissions::from_mode(0o700)).expect("Failed to set permissions");
675
676 let mut file = dir.path().to_owned();
677 file.push("my-private-key-file");
678 let file = file.display().to_string();
679
680 let seed = None;
681 let vanity = None;
682 let discreet = false;
683 let account = Account::New { network: 0, seed, vanity, discreet, save_to_file: Some(file.clone()) };
684 account.parse().with_context(|| "Command execution failed")?;
685
686 let account = Account::Sign(Sign {
687 network: 0,
688 private_key: None,
689 private_key_file: Some(file),
690 message,
691 raw: true,
692 dev_key: None,
693 });
694
695 account.parse().with_context(|| "Command execution failed")?;
696 Ok(())
697 }
698
699 #[test]
700 fn test_signature() -> Result<()> {
701 let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string();
702 let message = "5field".to_string();
703 let account = Account::Sign(Sign {
704 network: 0,
705 private_key: Some(key),
706 private_key_file: None,
707 message,
708 raw: false,
709 dev_key: None,
710 });
711
712 account.parse().with_context(|| "Command execution failed")?;
713 Ok(())
714 }
715
716 #[test]
717 fn test_signature_fail() {
718 let key = "APrivateKey1zkp61PAYmrYEKLtRWeWhUoDpFnGLNuHrCciSqN49T86dw3p".to_string();
719 let message = "not a literal value".to_string();
720 let account = Account::Sign(Sign {
721 network: 0,
722 private_key: Some(key),
723 private_key_file: None,
724 message,
725 raw: false,
726 dev_key: None,
727 });
728 assert!(account.parse().is_err());
729 }
730
731 #[test]
732 fn test_verify_raw() -> Result<()> {
733 let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j";
735 let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string();
736 let message = "Hello, world!".to_string();
737 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: true };
738
739 account.parse().with_context(|| "Command execution failed")?;
740
741 let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string();
743 let message = "Different Message".to_string();
744 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: true };
745 let actual = account.parse();
746 assert!(actual.is_err());
747
748 let signature = "sign1nnvrjlksrkxdpwsrw8kztjukzhmuhe5zf3srk38h7g32u4kqtqpxn3j5a6k8zrqcfx580a96956nsjvluzt64cqf54pdka9mgksfqp8esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkwsnaqq".to_string();
750 let message = "Hello, world!".to_string();
751 let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".to_string();
752 let account = Account::Verify { network: 0, address: wrong_address, signature, message, raw: true };
753 let actual = account.parse();
754 assert!(actual.is_err());
755
756 let signature = "sign1424ztyt9hcm77nq450gvdszrvtg9kvhc4qadg4nzy9y0ah7wdqq7t36cxal42p9jj8e8pjpmc06lfev9nvffcpqv0cxwyr0a2j2tjqlesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qk3yrr50".to_string();
758 let message = "Different Message".to_string();
759 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: true };
760 account.parse().with_context(|| "Command execution failed")?;
761
762 Ok(())
763 }
764
765 #[test]
766 fn test_verify() -> Result<()> {
767 let address = "aleo1zecnqchckrzw7dlsyf65g6z5le2rmys403ecwmcafrag0e030yxqrnlg8j";
769 let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string();
770 let message = "5field".to_string();
771 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: false };
772 account.parse().with_context(|| "Command execution failed")?;
773
774 let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string();
776 let message = "10field".to_string();
777 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: false };
778 let actual = account.parse();
779 assert!(actual.is_err());
780
781 let signature = "sign1j7swjfnyujt2vme3ulu88wdyh2ddj85arh64qh6c6khvrx8wvsp8z9wtzde0sahqj2qwz8rgzt803c0ceega53l4hks2mf5sfsv36qhesm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qkdetews".to_string();
783 let message = "5field".to_string();
784 let wrong_address = "aleo1uxl69laseuv3876ksh8k0nd7tvpgjt6ccrgccedpjk9qwyfensxst9ftg5".to_string();
785 let account = Account::Verify { network: 0, address: wrong_address, signature, message, raw: false };
786 let actual = account.parse();
787 assert!(actual.is_err());
788
789 let signature = "sign1t9v2t5tljk8pr5t6vkcqgkus0a3v69vryxmfrtwrwg0xtj7yv5qj2nz59e5zcyl50w23lhntxvt6vzeqfyu6dt56698zvfj2l6lz6q0esm5elrqqunzqzmac7kzutl6zk7mqht3c0m9kg4hklv7h2js0qmxavwnpuwyl4lzldl6prs4qeqy9wxyp8y44nnydg3h8sg6ue99qk8rh9kt".to_string();
791 let message = "10field".to_string();
792 let account = Account::Verify { network: 0, address: address.to_string(), signature, message, raw: false };
793
794 account.parse().with_context(|| "Command execution failed")?;
795
796 Ok(())
797 }
798}