* hijack secp256k1 enablement feature plumbing for libsecp256k1 upgrade * Bump libsecp256k1 to v0.5.0 * gate libsecp256k1 upgrade to v0.5.0 Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
@@ -53,7 +53,7 @@ hex = "0.4.2"
|
||||
hmac = "0.10.1"
|
||||
itertools = "0.9.0"
|
||||
lazy_static = "1.4.0"
|
||||
libsecp256k1 = { version = "0.3.5", optional = true }
|
||||
libsecp256k1 = { version = "0.5.0", optional = true }
|
||||
log = "0.4.11"
|
||||
memmap2 = { version = "0.1.0", optional = true }
|
||||
num-derive = "0.3"
|
||||
|
@@ -19,18 +19,6 @@ impl Default for FeeCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FeeConfig {
|
||||
pub secp256k1_program_enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for FeeConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
secp256k1_program_enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FeeCalculator {
|
||||
pub fn new(lamports_per_signature: u64) -> Self {
|
||||
Self {
|
||||
@@ -39,20 +27,14 @@ impl FeeCalculator {
|
||||
}
|
||||
|
||||
pub fn calculate_fee(&self, message: &Message) -> u64 {
|
||||
self.calculate_fee_with_config(message, &FeeConfig::default())
|
||||
}
|
||||
|
||||
pub fn calculate_fee_with_config(&self, message: &Message, fee_config: &FeeConfig) -> u64 {
|
||||
let mut num_secp256k1_signatures: u64 = 0;
|
||||
if fee_config.secp256k1_program_enabled {
|
||||
for instruction in &message.instructions {
|
||||
let program_index = instruction.program_id_index as usize;
|
||||
// Transaction may not be sanitized here
|
||||
if program_index < message.account_keys.len() {
|
||||
let id = message.account_keys[program_index];
|
||||
if secp256k1_program::check_id(&id) && !instruction.data.is_empty() {
|
||||
num_secp256k1_signatures += instruction.data[0] as u64;
|
||||
}
|
||||
for instruction in &message.instructions {
|
||||
let program_index = instruction.program_id_index as usize;
|
||||
// Transaction may not be sanitized here
|
||||
if program_index < message.account_keys.len() {
|
||||
let id = message.account_keys[program_index];
|
||||
if secp256k1_program::check_id(&id) && !instruction.data.is_empty() {
|
||||
num_secp256k1_signatures += instruction.data[0] as u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,15 +240,6 @@ mod tests {
|
||||
Some(&pubkey0),
|
||||
);
|
||||
assert_eq!(FeeCalculator::new(1).calculate_fee(&message), 2);
|
||||
assert_eq!(
|
||||
FeeCalculator::new(1).calculate_fee_with_config(
|
||||
&message,
|
||||
&FeeConfig {
|
||||
secp256k1_program_enabled: false
|
||||
}
|
||||
),
|
||||
1
|
||||
);
|
||||
|
||||
secp_instruction.data = vec![0];
|
||||
secp_instruction2.data = vec![10];
|
||||
|
@@ -10,10 +10,6 @@ pub mod instructions_sysvar_enabled {
|
||||
solana_sdk::declare_id!("EnvhHCLvg55P7PDtbvR1NwuTuAeodqpusV3MR5QEK8gs");
|
||||
}
|
||||
|
||||
pub mod secp256k1_program_enabled {
|
||||
solana_sdk::declare_id!("E3PHP7w8kB7np3CTQ1qQ2tW3KCtjRSXBQgW9vM2mWv2Y");
|
||||
}
|
||||
|
||||
pub mod consistent_recent_blockhashes_sysvar {
|
||||
solana_sdk::declare_id!("3h1BQWPDS5veRsq6mDBWruEpgPxRJkfwGexg5iiQ9mYg");
|
||||
}
|
||||
@@ -162,11 +158,14 @@ pub mod updated_verify_policy {
|
||||
solana_sdk::declare_id!("k15tVxtkgsmo7dy6iJ56N5hBCxuQAtqRgYwoTDuwbia");
|
||||
}
|
||||
|
||||
pub mod libsecp256k1_0_5_upgrade_enabled {
|
||||
solana_sdk::declare_id!("DhsYfRjxfnh2g7HKJYSzT79r74Afa1wbHkAgHndrA1oy");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
(instructions_sysvar_enabled::id(), "instructions sysvar"),
|
||||
(secp256k1_program_enabled::id(), "secp256k1 program"),
|
||||
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
||||
(deprecate_rewards_sysvar::id(), "deprecate unused rewards sysvar"),
|
||||
(pico_inflation::id(), "pico inflation"),
|
||||
@@ -201,6 +200,7 @@ lazy_static! {
|
||||
(dedupe_config_program_signers::id(), "dedupe config program signers"),
|
||||
(vote_stake_checked_instructions::id(), "vote/state program checked instructions #18345"),
|
||||
(updated_verify_policy::id(), "Update verify policy"),
|
||||
(libsecp256k1_0_5_upgrade_enabled::id(), "upgrade libsecp256k1 to v0.5.0"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
@@ -29,18 +29,18 @@ pub struct SecpSignatureOffsets {
|
||||
}
|
||||
|
||||
pub fn new_secp256k1_instruction(
|
||||
priv_key: &secp256k1::SecretKey,
|
||||
priv_key: &libsecp256k1::SecretKey,
|
||||
message_arr: &[u8],
|
||||
) -> Instruction {
|
||||
let secp_pubkey = secp256k1::PublicKey::from_secret_key(priv_key);
|
||||
let secp_pubkey = libsecp256k1::PublicKey::from_secret_key(priv_key);
|
||||
let eth_pubkey = construct_eth_pubkey(&secp_pubkey);
|
||||
let mut hasher = sha3::Keccak256::new();
|
||||
hasher.update(&message_arr);
|
||||
let message_hash = hasher.finalize();
|
||||
let mut message_hash_arr = [0u8; 32];
|
||||
message_hash_arr.copy_from_slice(&message_hash.as_slice());
|
||||
let message = secp256k1::Message::parse(&message_hash_arr);
|
||||
let (signature, recovery_id) = secp256k1::sign(&message, priv_key);
|
||||
let message = libsecp256k1::Message::parse(&message_hash_arr);
|
||||
let (signature, recovery_id) = libsecp256k1::sign(&message, priv_key);
|
||||
let signature_arr = signature.serialize();
|
||||
assert_eq!(signature_arr.len(), SIGNATURE_SERIALIZED_SIZE);
|
||||
|
||||
@@ -84,7 +84,9 @@ pub fn new_secp256k1_instruction(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_eth_pubkey(pubkey: &secp256k1::PublicKey) -> [u8; HASHED_PUBKEY_SERIALIZED_SIZE] {
|
||||
pub fn construct_eth_pubkey(
|
||||
pubkey: &libsecp256k1::PublicKey,
|
||||
) -> [u8; HASHED_PUBKEY_SERIALIZED_SIZE] {
|
||||
let mut addr = [0u8; HASHED_PUBKEY_SERIALIZED_SIZE];
|
||||
addr.copy_from_slice(&sha3::Keccak256::digest(&pubkey.serialize()[1..])[12..]);
|
||||
assert_eq!(addr.len(), HASHED_PUBKEY_SERIALIZED_SIZE);
|
||||
@@ -94,6 +96,7 @@ pub fn construct_eth_pubkey(pubkey: &secp256k1::PublicKey) -> [u8; HASHED_PUBKEY
|
||||
pub fn verify_eth_addresses(
|
||||
data: &[u8],
|
||||
instruction_datas: &[&[u8]],
|
||||
libsecp256k1_0_5_upgrade_enabled: bool,
|
||||
) -> Result<(), Secp256k1Error> {
|
||||
if data.is_empty() {
|
||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
||||
@@ -121,11 +124,20 @@ pub fn verify_eth_addresses(
|
||||
if sig_end >= signature_instruction.len() {
|
||||
return Err(Secp256k1Error::InvalidSignature);
|
||||
}
|
||||
let signature =
|
||||
secp256k1::Signature::parse_slice(&signature_instruction[sig_start..sig_end])
|
||||
.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
||||
|
||||
let recovery_id = secp256k1::RecoveryId::parse(signature_instruction[sig_end])
|
||||
let sig_parse_result = if libsecp256k1_0_5_upgrade_enabled {
|
||||
libsecp256k1::Signature::parse_standard_slice(
|
||||
&signature_instruction[sig_start..sig_end],
|
||||
)
|
||||
} else {
|
||||
libsecp256k1::Signature::parse_overflowing_slice(
|
||||
&signature_instruction[sig_start..sig_end],
|
||||
)
|
||||
};
|
||||
|
||||
let signature = sig_parse_result.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
||||
|
||||
let recovery_id = libsecp256k1::RecoveryId::parse(signature_instruction[sig_end])
|
||||
.map_err(|_| Secp256k1Error::InvalidRecoveryId)?;
|
||||
|
||||
// Parse out pubkey
|
||||
@@ -148,8 +160,8 @@ pub fn verify_eth_addresses(
|
||||
hasher.update(message_slice);
|
||||
let message_hash = hasher.finalize();
|
||||
|
||||
let pubkey = secp256k1::recover(
|
||||
&secp256k1::Message::parse_slice(&message_hash).unwrap(),
|
||||
let pubkey = libsecp256k1::recover(
|
||||
&libsecp256k1::Message::parse_slice(&message_hash).unwrap(),
|
||||
&signature,
|
||||
&recovery_id,
|
||||
)
|
||||
@@ -193,7 +205,7 @@ pub mod test {
|
||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||
bincode::serialize_into(writer, &offsets).unwrap();
|
||||
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]])
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -208,7 +220,7 @@ pub mod test {
|
||||
instruction_data.truncate(instruction_data.len() - 1);
|
||||
|
||||
assert_eq!(
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]]),
|
||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false),
|
||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
||||
);
|
||||
|
||||
|
@@ -387,7 +387,7 @@ impl Transaction {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn verify_precompiles(&self) -> Result<()> {
|
||||
pub fn verify_precompiles(&self, libsecp256k1_0_5_upgrade_enabled: bool) -> Result<()> {
|
||||
for instruction in &self.message().instructions {
|
||||
// The Transaction may not be sanitized at this point
|
||||
if instruction.program_id_index as usize >= self.message().account_keys.len() {
|
||||
@@ -402,7 +402,11 @@ impl Transaction {
|
||||
.map(|instruction| instruction.data.as_ref())
|
||||
.collect();
|
||||
let data = &instruction.data;
|
||||
let e = verify_eth_addresses(data, &instruction_datas);
|
||||
let e = verify_eth_addresses(
|
||||
data,
|
||||
&instruction_datas,
|
||||
libsecp256k1_0_5_upgrade_enabled,
|
||||
);
|
||||
e.map_err(|_| TransactionError::InvalidAccountIndex)?;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user