Cleanup and standardize precompiles (#19918)
This commit is contained in:
@@ -1,27 +1,9 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use crate::{decode_error::DecodeError, instruction::Instruction};
|
||||
use crate::{feature_set::FeatureSet, instruction::Instruction, precompiles::PrecompileError};
|
||||
use bytemuck::{bytes_of, Pod, Zeroable};
|
||||
use ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, Clone, PartialEq)]
|
||||
pub enum Ed25519Error {
|
||||
#[error("ed25519 public key is not valid")]
|
||||
InvalidPublicKey,
|
||||
#[error("ed25519 signature is not valid")]
|
||||
InvalidSignature,
|
||||
#[error("offset not valid")]
|
||||
InvalidDataOffsets,
|
||||
#[error("instruction is incorrect size")]
|
||||
InvalidInstructionDataSize,
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for Ed25519Error {
|
||||
fn type_of() -> &'static str {
|
||||
"Ed25519Error"
|
||||
}
|
||||
}
|
||||
use std::sync::Arc;
|
||||
|
||||
pub const PUBKEY_SERIALIZED_SIZE: usize = 32;
|
||||
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
|
||||
@@ -95,19 +77,23 @@ pub fn new_ed25519_instruction(keypair: &ed25519_dalek::Keypair, message: &[u8])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(), Ed25519Error> {
|
||||
pub fn verify(
|
||||
data: &[u8],
|
||||
instruction_datas: &[&[u8]],
|
||||
_feature_set: &Arc<FeatureSet>,
|
||||
) -> Result<(), PrecompileError> {
|
||||
if data.len() < SIGNATURE_OFFSETS_START {
|
||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
let num_signatures = data[0] as usize;
|
||||
if num_signatures == 0 && data.len() > SIGNATURE_OFFSETS_START {
|
||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
let expected_data_size = num_signatures
|
||||
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
||||
.saturating_add(SIGNATURE_OFFSETS_START);
|
||||
if data.len() < expected_data_size {
|
||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
for i in 0..num_signatures {
|
||||
let start = i
|
||||
@@ -117,23 +103,23 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(),
|
||||
|
||||
// bytemuck wants structures aligned
|
||||
let offsets: &Ed25519SignatureOffsets = bytemuck::try_from_bytes(&data[start..end])
|
||||
.map_err(|_| Ed25519Error::InvalidDataOffsets)?;
|
||||
.map_err(|_| PrecompileError::InvalidDataOffsets)?;
|
||||
|
||||
// Parse out signature
|
||||
let signature_index = offsets.signature_instruction_index as usize;
|
||||
if signature_index >= instruction_datas.len() {
|
||||
return Err(Ed25519Error::InvalidDataOffsets);
|
||||
return Err(PrecompileError::InvalidDataOffsets);
|
||||
}
|
||||
let signature_instruction = instruction_datas[signature_index];
|
||||
let sig_start = offsets.signature_offset as usize;
|
||||
let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE);
|
||||
if sig_end >= signature_instruction.len() {
|
||||
return Err(Ed25519Error::InvalidDataOffsets);
|
||||
return Err(PrecompileError::InvalidDataOffsets);
|
||||
}
|
||||
|
||||
let signature =
|
||||
ed25519_dalek::Signature::from_bytes(&signature_instruction[sig_start..sig_end])
|
||||
.map_err(|_| Ed25519Error::InvalidSignature)?;
|
||||
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||
|
||||
// Parse out pubkey
|
||||
let pubkey = get_data_slice(
|
||||
@@ -144,7 +130,7 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(),
|
||||
)?;
|
||||
|
||||
let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey)
|
||||
.map_err(|_| Ed25519Error::InvalidPublicKey)?;
|
||||
.map_err(|_| PrecompileError::InvalidPublicKey)?;
|
||||
|
||||
// Parse out message
|
||||
let message = get_data_slice(
|
||||
@@ -156,7 +142,7 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(),
|
||||
|
||||
publickey
|
||||
.verify(message, &signature)
|
||||
.map_err(|_| Ed25519Error::InvalidSignature)?;
|
||||
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -166,16 +152,16 @@ fn get_data_slice<'a>(
|
||||
instruction_index: u16,
|
||||
offset_start: u16,
|
||||
size: usize,
|
||||
) -> Result<&'a [u8], Ed25519Error> {
|
||||
) -> Result<&'a [u8], PrecompileError> {
|
||||
let signature_index = instruction_index as usize;
|
||||
if signature_index >= instruction_datas.len() {
|
||||
return Err(Ed25519Error::InvalidDataOffsets);
|
||||
return Err(PrecompileError::InvalidDataOffsets);
|
||||
}
|
||||
let signature_instruction = &instruction_datas[signature_index];
|
||||
let start = offset_start as usize;
|
||||
let end = start.saturating_add(size);
|
||||
if end > signature_instruction.len() {
|
||||
return Err(Ed25519Error::InvalidDataOffsets);
|
||||
return Err(PrecompileError::InvalidDataOffsets);
|
||||
}
|
||||
|
||||
Ok(&instruction_datas[signature_index][start..end])
|
||||
@@ -188,7 +174,7 @@ pub mod test {
|
||||
fn test_case(
|
||||
num_signatures: u16,
|
||||
offsets: &Ed25519SignatureOffsets,
|
||||
) -> Result<(), Ed25519Error> {
|
||||
) -> Result<(), PrecompileError> {
|
||||
assert_eq!(
|
||||
bytemuck::bytes_of(offsets).len(),
|
||||
SIGNATURE_OFFSETS_SERIALIZED_SIZE
|
||||
@@ -198,7 +184,11 @@ pub mod test {
|
||||
instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures));
|
||||
instruction_data[SIGNATURE_OFFSETS_START..DATA_START].copy_from_slice(bytes_of(offsets));
|
||||
|
||||
verify_signatures(&instruction_data, &[&[0u8; 100]])
|
||||
verify(
|
||||
&instruction_data,
|
||||
&[&[0u8; 100]],
|
||||
&Arc::new(FeatureSet::all_enabled()),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -212,8 +202,12 @@ pub mod test {
|
||||
instruction_data.truncate(instruction_data.len() - 1);
|
||||
|
||||
assert_eq!(
|
||||
verify_signatures(&instruction_data, &[&[0u8; 100]]),
|
||||
Err(Ed25519Error::InvalidInstructionDataSize)
|
||||
verify(
|
||||
&instruction_data,
|
||||
&[&[0u8; 100]],
|
||||
&Arc::new(FeatureSet::all_enabled()),
|
||||
),
|
||||
Err(PrecompileError::InvalidInstructionDataSize)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -222,7 +216,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -231,7 +225,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -240,7 +234,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -251,7 +245,10 @@ pub mod test {
|
||||
message_data_size: 1,
|
||||
..Ed25519SignatureOffsets::default()
|
||||
};
|
||||
assert_eq!(test_case(1, &offsets), Err(Ed25519Error::InvalidSignature));
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
message_data_offset: 100,
|
||||
@@ -260,7 +257,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -270,7 +267,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -280,7 +277,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -292,7 +289,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -301,7 +298,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -313,7 +310,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = Ed25519SignatureOffsets {
|
||||
@@ -322,7 +319,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Ed25519Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user