Cleanup and standardize precompiles (#19918)

This commit is contained in:
Jack May
2021-09-17 11:36:57 -07:00
committed by GitHub
parent 99f5684dc4
commit fc2bf2d3b6
7 changed files with 250 additions and 156 deletions

View File

@@ -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)
);
}
}