use crate::error::{Result, SolanaError};
use crate::types::{Pubkey, SignatureBytes, Transaction};
use ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey};
use sha2::{Digest, Sha256};
pub fn get_public_key(private_key: &[u8]) -> Result<[u8; 32]> {
if private_key.len() != 32 {
return Err(SolanaError::InvalidSignature(format!(
"invalid private key length: {}, expected: 32",
private_key.len()
)));
}
let signing_key = SigningKey::try_from(private_key)
.map_err(|_| SolanaError::InvalidSignature("failed to create signing key".to_string()))?;
Ok(signing_key.verifying_key().to_bytes())
}
pub fn get_address(private_key: &[u8]) -> Result<String> {
let public_key = get_public_key(private_key)?;
let pubkey = Pubkey::new(public_key);
Ok(pubkey.to_base58())
}
pub fn get_address_from_public_key(public_key: &[u8]) -> Result<String> {
if public_key.len() != 32 {
return Err(SolanaError::InvalidPubkey(format!(
"invalid public key length: {}, expected: 32",
public_key.len()
)));
}
let mut pk_bytes = [0u8; 32];
pk_bytes.copy_from_slice(public_key);
let pubkey = Pubkey::new(pk_bytes);
Ok(pubkey.to_base58())
}
pub fn verify_transaction(transaction: &Transaction) -> Result<()> {
let message_bytes = borsh::to_vec(&transaction.message)
.map_err(|e| SolanaError::SerializationError(e.to_string()))?;
for (i, signature) in transaction.signatures.iter().enumerate() {
let signer_pubkey = &transaction.message.account_keys[i];
let verifying_key = VerifyingKey::from_bytes(signer_pubkey.as_bytes()).map_err(|_| {
SolanaError::InvalidPubkey("failed to create verifying key from pubkey".to_string())
})?;
let sig_bytes = signature.as_bytes();
if sig_bytes.len() != 64 {
return Err(SolanaError::InvalidSignature(format!(
"invalid signature length: {}, expected: 64",
sig_bytes.len()
)));
}
let mut sig_array = [0u8; 64];
sig_array.copy_from_slice(sig_bytes);
let dalek_signature = ed25519_dalek::Signature::from_bytes(&sig_array);
verifying_key
.verify(&message_bytes, &dalek_signature)
.map_err(|_| {
SolanaError::InvalidSignature("signature verification failed".to_string())
})?;
}
Ok(())
}
pub fn sign_message(private_key: &[u8], message: &[u8]) -> Result<SignatureBytes> {
if private_key.len() != 32 {
return Err(SolanaError::InvalidSignature(format!(
"invalid private key length: {}, expected: 32",
private_key.len()
)));
}
let signing_key = SigningKey::try_from(private_key)
.map_err(|_| SolanaError::InvalidSignature("failed to create signing key".to_string()))?;
let signature = signing_key.sign(message);
Ok(SignatureBytes::new(signature.to_bytes()))
}
pub fn hash_data(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
let mut output = [0u8; 32];
output.copy_from_slice(&result);
output
}