use hopper_runtime::address;
use hopper_runtime::{error::ProgramError, Address};
use crate::introspect::{instruction_data_range, program_id_at};
pub const ED25519_PROGRAM: Address = address!("Ed25519SigVerify111111111111111111111111111");
const SIG_PARAM_SIZE: usize = 14;
const PUBKEY_LEN: usize = 32;
#[inline]
pub fn check_ed25519_signature(
sysvar_data: &[u8],
ed25519_ix_index: u16,
expected_signer: &[u8; 32],
expected_message: &[u8],
) -> Result<(), ProgramError> {
let program_id = program_id_at(sysvar_data, ed25519_ix_index)?;
if program_id != ED25519_PROGRAM {
return Err(ProgramError::InvalidArgument);
}
let (ix_data_offset, ix_data_len) = instruction_data_range(sysvar_data, ed25519_ix_index)?;
let ix_data = &sysvar_data[ix_data_offset..ix_data_offset + ix_data_len];
if ix_data_len < 2 + SIG_PARAM_SIZE {
return Err(ProgramError::InvalidAccountData);
}
let num_signatures = ix_data[0] as usize;
if num_signatures == 0 {
return Err(ProgramError::InvalidAccountData);
}
let params = &ix_data[2..2 + SIG_PARAM_SIZE];
let pubkey_offset = u16::from_le_bytes([params[4], params[5]]) as usize;
let pubkey_ix_index = u16::from_le_bytes([params[6], params[7]]);
let message_offset = u16::from_le_bytes([params[8], params[9]]) as usize;
let message_size = u16::from_le_bytes([params[10], params[11]]) as usize;
let message_ix_index = u16::from_le_bytes([params[12], params[13]]);
if pubkey_ix_index != 0xFFFF {
return Err(ProgramError::InvalidArgument);
}
if pubkey_offset + PUBKEY_LEN > ix_data_len {
return Err(ProgramError::AccountDataTooSmall);
}
if &ix_data[pubkey_offset..pubkey_offset + PUBKEY_LEN] != expected_signer {
return Err(ProgramError::InvalidArgument);
}
if message_ix_index != 0xFFFF {
return Err(ProgramError::InvalidArgument);
}
if message_offset + message_size > ix_data_len {
return Err(ProgramError::AccountDataTooSmall);
}
if message_size != expected_message.len() {
return Err(ProgramError::InvalidArgument);
}
if &ix_data[message_offset..message_offset + message_size] != expected_message {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
#[inline]
pub fn check_ed25519_signer(
sysvar_data: &[u8],
ed25519_ix_index: u16,
expected_signer: &[u8; 32],
) -> Result<(), ProgramError> {
let program_id = program_id_at(sysvar_data, ed25519_ix_index)?;
if program_id != ED25519_PROGRAM {
return Err(ProgramError::InvalidArgument);
}
let (ix_data_offset, ix_data_len) = instruction_data_range(sysvar_data, ed25519_ix_index)?;
let ix_data = &sysvar_data[ix_data_offset..ix_data_offset + ix_data_len];
if ix_data_len < 2 + SIG_PARAM_SIZE {
return Err(ProgramError::InvalidAccountData);
}
let num_signatures = ix_data[0] as usize;
if num_signatures == 0 {
return Err(ProgramError::InvalidAccountData);
}
let params = &ix_data[2..2 + SIG_PARAM_SIZE];
let pubkey_offset = u16::from_le_bytes([params[4], params[5]]) as usize;
let pubkey_ix_index = u16::from_le_bytes([params[6], params[7]]);
if pubkey_ix_index != 0xFFFF {
return Err(ProgramError::InvalidArgument);
}
if pubkey_offset + PUBKEY_LEN > ix_data_len {
return Err(ProgramError::AccountDataTooSmall);
}
if &ix_data[pubkey_offset..pubkey_offset + PUBKEY_LEN] != expected_signer {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}