Cleanup and standardize precompiles (#19918)
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use crate::instruction::Instruction;
|
||||
use crate::{
|
||||
feature_set::{libsecp256k1_0_5_upgrade_enabled, libsecp256k1_fail_on_bad_count, FeatureSet},
|
||||
instruction::Instruction,
|
||||
precompiles::PrecompileError,
|
||||
};
|
||||
use digest::Digest;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Secp256k1Error {
|
||||
InvalidSignature,
|
||||
InvalidRecoveryId,
|
||||
InvalidDataOffsets,
|
||||
InvalidInstructionDataSize,
|
||||
}
|
||||
use std::sync::Arc;
|
||||
|
||||
pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20;
|
||||
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
|
||||
@@ -99,27 +96,27 @@ pub fn construct_eth_pubkey(
|
||||
addr
|
||||
}
|
||||
|
||||
pub fn verify_eth_addresses(
|
||||
pub fn verify(
|
||||
data: &[u8],
|
||||
instruction_datas: &[&[u8]],
|
||||
libsecp256k1_0_5_upgrade_enabled: bool,
|
||||
libsecp256k1_fail_on_bad_count: bool,
|
||||
) -> Result<(), Secp256k1Error> {
|
||||
feature_set: &Arc<FeatureSet>,
|
||||
) -> Result<(), PrecompileError> {
|
||||
if data.is_empty() {
|
||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
let count = data[0] as usize;
|
||||
if libsecp256k1_fail_on_bad_count && count == 0 && data.len() > 1 {
|
||||
if feature_set.is_active(&libsecp256k1_fail_on_bad_count::id()) && count == 0 && data.len() > 1
|
||||
{
|
||||
// count is zero but the instruction data indicates that is probably not
|
||||
// correct, fail the instruction to catch probable invalid secp256k1
|
||||
// instruction construction.
|
||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
let expected_data_size = count
|
||||
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
||||
.saturating_add(1);
|
||||
if data.len() < expected_data_size {
|
||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
for i in 0..count {
|
||||
let start = i
|
||||
@@ -128,21 +125,21 @@ pub fn verify_eth_addresses(
|
||||
let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE);
|
||||
|
||||
let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end])
|
||||
.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
||||
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||
|
||||
// Parse out signature
|
||||
let signature_index = offsets.signature_instruction_index as usize;
|
||||
if signature_index >= instruction_datas.len() {
|
||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
||||
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||
}
|
||||
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(Secp256k1Error::InvalidSignature);
|
||||
return Err(PrecompileError::InvalidSignature);
|
||||
}
|
||||
|
||||
let sig_parse_result = if libsecp256k1_0_5_upgrade_enabled {
|
||||
let sig_parse_result = if feature_set.is_active(&libsecp256k1_0_5_upgrade_enabled::id()) {
|
||||
libsecp256k1::Signature::parse_standard_slice(
|
||||
&signature_instruction[sig_start..sig_end],
|
||||
)
|
||||
@@ -152,10 +149,10 @@ pub fn verify_eth_addresses(
|
||||
)
|
||||
};
|
||||
|
||||
let signature = sig_parse_result.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
||||
let signature = sig_parse_result.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||
|
||||
let recovery_id = libsecp256k1::RecoveryId::parse(signature_instruction[sig_end])
|
||||
.map_err(|_| Secp256k1Error::InvalidRecoveryId)?;
|
||||
.map_err(|_| PrecompileError::InvalidRecoveryId)?;
|
||||
|
||||
// Parse out pubkey
|
||||
let eth_address_slice = get_data_slice(
|
||||
@@ -182,11 +179,11 @@ pub fn verify_eth_addresses(
|
||||
&signature,
|
||||
&recovery_id,
|
||||
)
|
||||
.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
||||
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||
let eth_address = construct_eth_pubkey(&pubkey);
|
||||
|
||||
if eth_address_slice != eth_address {
|
||||
return Err(Secp256k1Error::InvalidSignature);
|
||||
return Err(PrecompileError::InvalidSignature);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -197,16 +194,16 @@ fn get_data_slice<'a>(
|
||||
instruction_index: u8,
|
||||
offset_start: u16,
|
||||
size: usize,
|
||||
) -> Result<&'a [u8], Secp256k1Error> {
|
||||
) -> Result<&'a [u8], PrecompileError> {
|
||||
let signature_index = instruction_index as usize;
|
||||
if signature_index >= instruction_datas.len() {
|
||||
return Err(Secp256k1Error::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(Secp256k1Error::InvalidSignature);
|
||||
return Err(PrecompileError::InvalidSignature);
|
||||
}
|
||||
|
||||
Ok(&instruction_datas[signature_index][start..end])
|
||||
@@ -216,13 +213,23 @@ fn get_data_slice<'a>(
|
||||
pub mod test {
|
||||
use super::*;
|
||||
|
||||
fn test_case(num_signatures: u8, offsets: &SecpSignatureOffsets) -> Result<(), Secp256k1Error> {
|
||||
fn test_case(
|
||||
num_signatures: u8,
|
||||
offsets: &SecpSignatureOffsets,
|
||||
) -> Result<(), PrecompileError> {
|
||||
let mut instruction_data = vec![0u8; DATA_START];
|
||||
instruction_data[0] = num_signatures;
|
||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||
bincode::serialize_into(writer, &offsets).unwrap();
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
feature_set
|
||||
.active
|
||||
.remove(&libsecp256k1_0_5_upgrade_enabled::id());
|
||||
feature_set
|
||||
.inactive
|
||||
.insert(libsecp256k1_0_5_upgrade_enabled::id());
|
||||
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true)
|
||||
verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -235,10 +242,17 @@ pub mod test {
|
||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||
bincode::serialize_into(writer, &offsets).unwrap();
|
||||
instruction_data.truncate(instruction_data.len() - 1);
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
feature_set
|
||||
.active
|
||||
.remove(&libsecp256k1_0_5_upgrade_enabled::id());
|
||||
feature_set
|
||||
.inactive
|
||||
.insert(libsecp256k1_0_5_upgrade_enabled::id());
|
||||
|
||||
assert_eq!(
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
|
||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
||||
verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)),
|
||||
Err(PrecompileError::InvalidInstructionDataSize)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -247,7 +261,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
||||
Err(PrecompileError::InvalidInstructionDataSize)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -256,7 +270,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -265,7 +279,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidDataOffsets)
|
||||
Err(PrecompileError::InvalidDataOffsets)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -278,7 +292,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -288,7 +302,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -298,7 +312,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -308,7 +322,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -320,7 +334,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -329,7 +343,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -341,7 +355,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
|
||||
let offsets = SecpSignatureOffsets {
|
||||
@@ -350,7 +364,7 @@ pub mod test {
|
||||
};
|
||||
assert_eq!(
|
||||
test_case(1, &offsets),
|
||||
Err(Secp256k1Error::InvalidSignature)
|
||||
Err(PrecompileError::InvalidSignature)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -363,9 +377,17 @@ pub mod test {
|
||||
instruction_data[0] = 0;
|
||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||
bincode::serialize_into(writer, &offsets).unwrap();
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
feature_set
|
||||
.active
|
||||
.remove(&libsecp256k1_0_5_upgrade_enabled::id());
|
||||
feature_set
|
||||
.inactive
|
||||
.insert(libsecp256k1_0_5_upgrade_enabled::id());
|
||||
|
||||
assert_eq!(
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
|
||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
||||
verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)),
|
||||
Err(PrecompileError::InvalidInstructionDataSize)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user