I am attempting to confirm signed messages utilizing Rust. lumo AI generated me this:
#[cfg(feature = "derive")]
use bitcoin::util::key::PublicKey;
use secp256k1::{Secp256k1};
pub mod messages {
use bitcoin::{
Handle, PublicKey, handle::Payload, hashes::{Hash, sha256d::{self, Hash as Sha256dHash}}, secp256k1::{
self,
All, // the context kind we’ll use
Message
}
};
use base64::decode;
use secp256k1::{Secp256k1, ecdsa::{RecoverableSignature, RecoveryId}}; // just for comfort; you can use any Base64 lib
/// Flip the primary byte of a legacy signature (27‑34) right into a `RecoveryId`.
fn decode_recovery_byte(byte: u8) -> End result {
if !(27..=34).incorporates(&byte) {
return Err(secp256k1::Error::InvalidRecoveryId);
}
// Low‑order two bits = actual restoration id (0‑3). The additional +4 (for compressed)
// is stripped mechanically by the modulo operation.
RecoveryId::from_i32((byte % 4) as i32)
}
/// Compute the precise double‑SHA‑256 hash that Bitcoin‑CLI/Electrum signal.
///
/// The payload is:
/// <"Bitcoin Signed Message:n">
///
fn bitcoin_message_hash(msg: &str) -> Sha256dHash {
const MAGIC: &str = "Bitcoin Signed Message:n";
// CompactSize (varint) encoder – equivalent to Bitcoin Core.
fn varint_len(s: &str) -> Vec {
let mut v = Vec::new();
let len = s.len() as u64;
if len < 0xfd {
v.push(len as u8);
} else if len <= 0xffff {
v.push(0xfd);
v.extend_from_slice(&(len as u16).to_le_bytes());
} else if len <= 0xffff_ffff {
v.push(0xfe);
v.extend_from_slice(&(len as u32).to_le_bytes());
} else {
v.push(0xff);
v.extend_from_slice(&len.to_le_bytes());
}
v.extend_from_slice(s.as_bytes());
v
}
let mut knowledge = Vec::new();
knowledge.prolong(varint_len(MAGIC));
knowledge.prolong(varint_len(msg));
sha256d::Hash::hash(&knowledge)
}
/// Confirm a traditional Bitcoin‑CLI / Electrum signed‑message **utilizing solely the `bitcoin` crate**.
///
/// * `address_str` – the handle that allegedly signed the message (Base58 `1…` or Bech32 `bc1…`).
/// * `message` – the precise clear‑textual content that was signed.
/// * `sig_base64` – the Base64 string printed by the pockets.
///
/// Returns `Okay(true)` if the signature is legitimate for the provided handle,
/// `Okay(false)` whether it is syntactically appropriate however does **not** match,
/// and `Err(_)` for malformed inputs (dangerous Base64, fallacious size, unsupported handle kind, and so forth.).
pub fn verify_signed_message(
address_str: &str,
message: &str,
sig_base64: &str,
) -> End result> {
// --------------------------------------------------------------
// 1️⃣ Decode the Base64 signature (should be precisely 65 bytes)
// --------------------------------------------------------------
let sig_bytes = decode(sig_base64.trim())?;
if sig_bytes.len() != 65 {
return Err(format!("Signature should be 65 bytes (acquired {})", sig_bytes.len()).into());
}
println!("c111heckingadfdsads for handle");
// --------------------------------------------------------------
// 2️⃣ Break up restoration byte and compact (r|s) signature
// --------------------------------------------------------------
let rec_id = decode_recovery_byte(sig_bytes[0])?;
let is_compressed = sig_bytes[0] >= 31; // true for 31‑34
let compact_sig = &sig_bytes[1..]; // 64‑byte slice (r‖s)
// --------------------------------------------------------------
// 3️⃣ Construct a RecoverableSignature (bundles the rec_id)
// --------------------------------------------------------------
let recoverable = RecoverableSignature::from_compact(compact_sig, rec_id)?;
// --------------------------------------------------------------
// 4️⃣ Compute the double‑SHA‑256 hash of the message (magic prefix)
// --------------------------------------------------------------
let msg_hash = bitcoin_message_hash(message);
let secp_msg = Message::from_slice(msg_hash.as_ref())?;
// --------------------------------------------------------------
// 5️⃣ Recuperate the general public key
// --------------------------------------------------------------
// `Secp256k1::verification_only()` provides us a learn‑solely context.
let secp = Secp256k1::verification_only();
let recovered_secp = secp.recover_ecdsa(&secp_msg, &recoverable)?;
let recovered_pub = PublicKey::new(recovered_secp);
println!("checkingadfdsads for handle");
// --------------------------------------------------------------
// 6️⃣ Parse the provided handle (this additionally tells us the community)
// --------------------------------------------------------------
let supplied_addr: Handle = address_str.parse::<:address>>().unwrap().assume_checked();
println!("checking for handle");
// --------------------------------------------------------------
// 7️⃣ Re‑derive the handle from the recovered public key
// --------------------------------------------------------------
let derived_addr = match supplied_addr.payload {
// ---------- Legacy Base58 (P2PKH) ----------
Payload::PubkeyHash(_) => {
// `p2pkh` mechanically makes use of the compressed kind if the secret's
// compressed; the `is_compressed` flag we extracted earlier is just
// wanted for sanity‑checking, not for handle development.
Handle::p2pkh(&recovered_pub, supplied_addr.community)
}
// // ---------- Native SegWit v0 (bc1q…) ----------
// Payload::WitnessProgram {
// model: 0,
// program: ref prog,
// } if prog.len() == 20 => {
// // SegWit v0 at all times makes use of the **compressed** public key, regardless
// // of the flag within the signature. The `is_compressed` boolean is
// // subsequently irrelevant for handle reconstruction right here.
// Handle::p2wpkh(&recovered_pub, supplied_addr.community)?
// }
// Anything (Taproot `bc1p…`, P2SH‑wrapped, multisig, and so forth.)
// will not be supported by the legacy signed‑message format.
_ => {
return Err(format!(
"Legacy verification solely helps P2PKH (1…) and native SegWit v0 (bc1q…)
addresses. Handle `{}` is of a unique kind.",
address_str
)
.into())
}
};
println!("{:?}", derived_addr);
println!("{:?}", supplied_addr);
// --------------------------------------------------------------
// 8️⃣ Examine the derived handle with the provided one
// --------------------------------------------------------------
Okay(derived_addr == supplied_addr)
}
}
Can anybody inform me why this code is not working? I’ve checked bitcoin-cli verifymessage and returned true. The Rust code is returning false. I am utilizing a P2PKH handle. Signing with the Sparrow pockets.

