Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add recover public key from message and signature #152

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
account::{Account, Accounts},
import::import_wallet_cli,
new::new_wallet_cli,
sign::Sign,
sign::{Recover, Sign},
};
use anyhow::Result;
use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -64,6 +64,8 @@ enum Command {
/// Only includes accounts that have been previously derived, i.e. those
/// that show under `forc-wallet accounts`.
Balance(Balance),
///Recover the public key from a message and signature
Recover(Recover),
}

const ABOUT: &str = "A forc plugin for generating or importing wallets using BIP39 phrases.";
Expand Down Expand Up @@ -115,6 +117,10 @@ EXAMPLES:
# Transfer 1 token of the base asset id to a hex address at the gas price of 1.
forc wallet account 0 transfer --to 0x0b8d0f6a7f271919708530d11bdd9398205137e012424b611e9d97118c180bea
--amount 1 --asset-id 0x0000000000000000000000000000000000000000000000000000000000000000 --gas-price 1

# Recover a public key from signature and hash
forc wallet recover --message "Blah blah blah" --signature 0xb0b2f29b52d95c1cba47ea7c7edeec6c84a0bd196df489e219f6f388b69d760479b994f4bae2d5f2abef7d5faf7d9f5ee3ea47ada4d15b7a7ee2777dcd7b36bb

"#;

#[tokio::main]
Expand All @@ -127,6 +133,7 @@ async fn main() -> Result<()> {
Command::Accounts(accounts) => account::print_accounts_cli(&wallet_path, accounts)?,
Command::Account(account) => account::cli(&wallet_path, account).await?,
Command::Sign(sign) => sign::cli(&wallet_path, sign)?,
Command::Recover(recover) => sign::recover_public_key_cli(recover)?,
Command::Balance(balance) => balance::cli(&wallet_path, &balance).await?,
}
Ok(())
Expand Down
37 changes: 36 additions & 1 deletion src/sign.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::account;
use anyhow::{bail, Context, Result};
use clap::{Args, Subcommand};
use fuel_crypto::{Message, SecretKey, Signature};
use fuel_crypto::{Message, PublicKey, SecretKey, Signature};
use fuel_types::Bytes32;
use rpassword::prompt_password;
use std::{
Expand Down Expand Up @@ -60,6 +60,18 @@ pub enum Data {
Hex { hex_string: String },
}

/// Recover pubkey
#[derive(Debug, Args)]
pub struct Recover {
/// Uses a discrete interactive prompt for password input.
#[clap(long)]
pub message: String,
/// Sign using a private key.
/// Uses a discrete interactive prompt for collecting the private key.
#[clap(long)]
pub signature: Signature,
}

pub fn cli(wallet_path: &Path, sign: Sign) -> Result<()> {
let Sign {
account,
Expand Down Expand Up @@ -179,6 +191,17 @@ fn bytes_from_hex_str(mut hex_str: &str) -> Result<Vec<u8>> {
hex::decode(hex_str).context("failed to decode bytes from hex string")
}

pub fn recover_public_key_cli(recover: Recover) -> Result<()> {
let msg = Message::new(&recover.message);
let public_key = recover_public_key(msg, recover.signature)?;
println!("Public key: {}", public_key);
Ok(())
}
fn recover_public_key(message: Message, sig: Signature) -> Result<PublicKey> {
let public_key = Signature::recover(&sig, &message)?;
Ok(public_key)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -238,4 +261,16 @@ mod tests {
assert_eq!(sig.to_string(), EXPECTED_SIG);
});
}
#[test]
fn recover_key() {
with_tmp_dir_and_wallet(|_dir, wallet_path| {
let msg = Message::new(TEST_STR);
let account_ix = 0;
let sig =
sign_msg_with_wallet_account(wallet_path, account_ix, &msg, TEST_PASSWORD).unwrap();
let public_key = recover_public_key(msg, sig).unwrap();

assert_eq!(public_key.to_string(), "13858749b644c470791c21f87f6aeca8c5583ca29295a55b4579de643e16f57ecc1869925c49bdcf43f06c459b6c3c1aeaf54ad835cc638c869c1015c5c17d5a");
});
}
}
Loading