I made a signature on solana
solana verify-offchain-signature --signer DR2BCjL1yX5HnuTSYVMeRY5tsHd8ZJZz2vFf5zs5aYop "55f04639-d058-407a-8b38-7df7b20b39a0" 2XP1mHvXaRHzp6ZNSQHMgr2bgDEpHwWkW4fBLCzzWxCkRi99ryyUAbUVFratTjhhw1nQxj4WQhZhxnjA7cEnncBV
Signature is valid
Next, I wrote code in Rust to verify this signature
use std::str::FromStr;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signature;
async fn main() -> std::io::Result<()> {
let nonce= "55f04639-d058-407a-8b38-7df7b20b39a0";
let pubkey= "DR2BCjL1yX5HnuTSYVMeRY5tsHd8ZJZz2vFf5zs5aYop";
let signature= "2XP1mHvXaRHzp6ZNSQHMgr2bgDEpHwWkW4fBLCzzWxCkRi99ryyUAbUVFratTjhhw1nQxj4WQhZhxnjA7cEnncBV";
let pubkey = solana_sdk::pubkey::Pubkey::from_str(pubkey).unwrap();
let signature = solana_sdk::signature::Signature::from_str(signature).unwrap();
if signature.verify(pubkey.as_ref(), nonce.as_ref()) {
println!("✅ Valid");
} else {
println!("❌ Invalid");
}
}
But I get ❌ Invalid, why? What do I have to do to verify it correctly?
It worked for me
use ed25519_dalek::{VerifyingKey, Signature, Verifier};
use bs58;
use thiserror::Error;
use std::convert::TryInto;
use byteorder::{LittleEndian, WriteBytesExt};
#[derive(Debug, Error)]
pub enum AuthError {
#[error("Base58 decoding error: {0}")]
DecodeError(#[from] bs58::decode::Error),
#[error("Invalid public key length")]
PublicKeyLength,
#[error("Invalid signature length")]
SignatureLength,
#[error("Signature verification failed")]
VerificationFailed(#[from] ed25519_dalek::SignatureError),
}
pub fn verify_offchain_signature(
pubkey_b58: &str,
sig_b58: &str,
message: &str,
) -> Result<(), AuthError> {
// decode base58
let pubkey_vec = bs58::decode(pubkey_b58).into_vec()?;
let sig_vec = bs58::decode(sig_b58).into_vec()?;
// vec u8 -> array with normal size
let pubkey_bytes: [u8; 32] = pubkey_vec
.try_into()
.map_err(|_| AuthError::PublicKeyLength)?;
let sig_bytes: [u8; 64] = sig_vec
.try_into()
.map_err(|_| AuthError::SignatureLength)?;
// create objects for verify
let verifying_key = VerifyingKey::from_bytes(&pubkey_bytes)
.map_err(|_| AuthError::PublicKeyLength)?;
let signature = Signature::from_bytes(&sig_bytes);
// do solana like buffer
let mut buf = Vec::new();
// prefix for 2 zeros in the end
buf.extend_from_slice(b"\xffsolana offchain\x00\x00");
// little endian size
buf.write_u16::<LittleEndian>(message.len() as u16).unwrap();
// message bytes
buf.extend_from_slice(message.as_bytes());
// verify wrapped message
verifying_key
.verify(&buf, &signature)
.map_err(AuthError::VerificationFailed)?;
Ok(())
}
fn main() {
let nonce = "55f04639-d058-407a-8b38-7df7b20b39a0";
let pubkey = "DR2BCjL1yX5HnuTSYVMeRY5tsHd8ZJZz2vFf5zs5aYop";
let signature = "2XP1mHvXaRHzp6ZNSQHMgr2bgDEpHwWkW4fBLCzzWxCkRi99ryyUAbUVFratTjhhw1nQxj4WQhZhxnjA7cEnncBV";
match verify_offchain_signature(pubkey, signature, nonce) {
Ok(()) => println!("Signature is valid!"),
Err(e) => println!("Verification error: {}", e),
}
}