Skip to content

Commit 1353416

Browse files
authored
fix: make sign and verify symmetrical (#10614)
1 parent 0cd3a78 commit 1353416

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

crates/cast/src/cmd/wallet/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ pub enum WalletSubcommands {
147147
#[command(visible_alias = "v")]
148148
Verify {
149149
/// The original message.
150+
///
151+
/// Treats 0x-prefixed strings as hex encoded bytes.
152+
/// Non 0x-prefixed strings are treated as raw input message.
150153
message: String,
151154

152155
/// The signature to verify.
@@ -759,11 +762,17 @@ flag to set your key via:
759762
Ok(())
760763
}
761764

762-
/// Recovers an address from the specified message and signature
765+
/// Recovers an address from the specified message and signature.
766+
///
767+
/// Note: This attempts to decode the message as hex if it starts with 0x.
763768
fn recover_address_from_message(message: &str, signature: &Signature) -> Result<Address> {
769+
let message = Self::hex_str_to_bytes(message)?;
764770
Ok(signature.recover_address_from_msg(message)?)
765771
}
766772

773+
/// Strips the 0x prefix from a hex string and decodes it to bytes.
774+
///
775+
/// Treats the string as raw bytes if it doesn't start with 0x.
767776
fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> {
768777
Ok(match s.strip_prefix("0x") {
769778
Some(data) => hex::decode(data).wrap_err("Could not decode 0x-prefixed string.")?,

crates/cast/tests/cli/main.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,66 @@ casttest!(wallet_sign_message_hex_data, |_prj, cmd| {
290290
"#]]);
291291
});
292292

293+
// <https://github.com/foundry-rs/foundry/issues/10613>
294+
// tests that `cast wallet sign` and `cast wallet verify` work with the same message as input
295+
casttest!(wallet_sign_and_verify_message_hex_data, |_prj, cmd| {
296+
// message="$1"
297+
// mnemonic="test test test test test test test test test test test junk"
298+
// key=$(cast wallet private-key --mnemonic "$mnemonic")
299+
// address=$(cast wallet address --mnemonic "$mnemonic")
300+
// signature=$(cast wallet sign --private-key "$key" "$message")
301+
// cast wallet verify --address "$address" "$message" "$signature"
302+
let mnemonic = "test test test test test test test test test test test junk";
303+
let key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
304+
let address = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
305+
cmd.args(["wallet", "private-key", "--mnemonic", mnemonic]).assert_success().stdout_eq(str![[
306+
r#"
307+
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
308+
309+
"#
310+
]]);
311+
cmd.cast_fuse().args(["wallet", "address", "--mnemonic", mnemonic]).assert_success().stdout_eq(
312+
str![[r#"
313+
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
314+
315+
"#]],
316+
);
317+
318+
let msg_hex = "0x0000000000000000000000000000000000000000000000000000000000000001";
319+
let signature_hex = "0xed769da87f78d0166b30aebf2767ceed5a3867da21b2fba8c6527af256bbcebe24a1e758ec8ad1ffc29cfefa540ea7ba7966c0edf6907af82348f894ba4f40fa1b";
320+
cmd.cast_fuse().args([
321+
"wallet", "sign", "--private-key",key, msg_hex
322+
]).assert_success().stdout_eq(str![[r#"
323+
0xed769da87f78d0166b30aebf2767ceed5a3867da21b2fba8c6527af256bbcebe24a1e758ec8ad1ffc29cfefa540ea7ba7966c0edf6907af82348f894ba4f40fa1b
324+
325+
"#]]);
326+
327+
cmd.cast_fuse()
328+
.args(["wallet", "verify", "--address", address, msg_hex, signature_hex])
329+
.assert_success()
330+
.stdout_eq(str![[r#"
331+
Validation succeeded. Address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 signed this message.
332+
333+
"#]]);
334+
335+
let msg_raw = "0000000000000000000000000000000000000000000000000000000000000001";
336+
let signature_raw = "0x27a97b378477d9d004bd19cbd838d59bbb9847074ae4cc5b5975cc5566065eea76ee5b752fcdd483073e1baba548d82d9accc8603b3781bcc9abf195614cd3411c";
337+
cmd.cast_fuse().args([
338+
"wallet", "sign", "--private-key",key, msg_raw
339+
]).assert_success().stdout_eq(str![[r#"
340+
0x27a97b378477d9d004bd19cbd838d59bbb9847074ae4cc5b5975cc5566065eea76ee5b752fcdd483073e1baba548d82d9accc8603b3781bcc9abf195614cd3411c
341+
342+
"#]]);
343+
344+
cmd.cast_fuse()
345+
.args(["wallet", "verify", "--address", address, msg_raw, signature_raw])
346+
.assert_success()
347+
.stdout_eq(str![[r#"
348+
Validation succeeded. Address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 signed this message.
349+
350+
"#]]);
351+
});
352+
293353
// tests that `cast wallet sign typed-data` outputs the expected signature, given a JSON string
294354
casttest!(wallet_sign_typed_data_string, |_prj, cmd| {
295355
cmd.args([

0 commit comments

Comments
 (0)