From 5b2b824a53cef8f12d256fc93e6198bdbf384496 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 17 Mar 2021 19:33:50 -0600 Subject: [PATCH] Sdk: remove integer arithmetic (#15962) * Fix timing * Fix secp256k1_instruction * Fix secp256k1 tests --- sdk/src/secp256k1_instruction.rs | 44 ++++++++++++++++++++------------ sdk/src/timing.rs | 19 ++++++++++---- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/sdk/src/secp256k1_instruction.rs b/sdk/src/secp256k1_instruction.rs index 24d2c0d64b..6ad7c7a365 100644 --- a/sdk/src/secp256k1_instruction.rs +++ b/sdk/src/secp256k1_instruction.rs @@ -1,4 +1,3 @@ -#![allow(clippy::integer_arithmetic)] #![cfg(feature = "full")] use crate::instruction::Instruction; @@ -16,6 +15,7 @@ pub enum Secp256k1Error { pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20; pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11; +pub const DATA_START: usize = SIGNATURE_OFFSETS_SERIALIZED_SIZE + 1; #[derive(Default, Serialize, Deserialize, Debug)] pub struct SecpSignatureOffsets { @@ -45,22 +45,28 @@ pub fn new_secp256k1_instruction( assert_eq!(signature_arr.len(), SIGNATURE_SERIALIZED_SIZE); let mut instruction_data = vec![]; - let data_start = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE; instruction_data.resize( - data_start + eth_pubkey.len() + signature_arr.len() + message_arr.len() + 1, + DATA_START + .saturating_add(eth_pubkey.len()) + .saturating_add(signature_arr.len()) + .saturating_add(message_arr.len()) + .saturating_add(1), 0, ); - let eth_address_offset = data_start; - instruction_data[eth_address_offset..eth_address_offset + eth_pubkey.len()] + let eth_address_offset = DATA_START; + instruction_data[eth_address_offset..eth_address_offset.saturating_add(eth_pubkey.len())] .copy_from_slice(ð_pubkey); - let signature_offset = data_start + eth_pubkey.len(); - instruction_data[signature_offset..signature_offset + signature_arr.len()] + let signature_offset = DATA_START.saturating_add(eth_pubkey.len()); + instruction_data[signature_offset..signature_offset.saturating_add(signature_arr.len())] .copy_from_slice(&signature_arr); - instruction_data[signature_offset + signature_arr.len()] = recovery_id.serialize(); + instruction_data[signature_offset.saturating_add(signature_arr.len())] = + recovery_id.serialize(); - let message_data_offset = signature_offset + signature_arr.len() + 1; + let message_data_offset = signature_offset + .saturating_add(signature_arr.len()) + .saturating_add(1); instruction_data[message_data_offset..].copy_from_slice(message_arr); let num_signatures = 1; @@ -74,7 +80,7 @@ pub fn new_secp256k1_instruction( message_data_size: message_arr.len() as u16, message_instruction_index: 0, }; - let writer = std::io::Cursor::new(&mut instruction_data[1..data_start]); + let writer = std::io::Cursor::new(&mut instruction_data[1..DATA_START]); bincode::serialize_into(writer, &offsets).unwrap(); Instruction { @@ -99,13 +105,17 @@ pub fn verify_eth_addresses( return Err(Secp256k1Error::InvalidInstructionDataSize); } let count = data[0] as usize; - let expected_data_size = 1 + count * SIGNATURE_OFFSETS_SERIALIZED_SIZE; + let expected_data_size = count + .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) + .saturating_add(1); if data.len() < expected_data_size { return Err(Secp256k1Error::InvalidInstructionDataSize); } for i in 0..count { - let start = 1 + i * SIGNATURE_OFFSETS_SERIALIZED_SIZE; - let end = start + SIGNATURE_OFFSETS_SERIALIZED_SIZE; + let start = i + .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) + .saturating_add(1); + let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE); let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end]) .map_err(|_| Secp256k1Error::InvalidSignature)?; @@ -117,7 +127,7 @@ pub fn verify_eth_addresses( } let signature_instruction = instruction_datas[signature_index]; let sig_start = offsets.signature_offset as usize; - let sig_end = sig_start + SIGNATURE_SERIALIZED_SIZE; + let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE); if sig_end >= signature_instruction.len() { return Err(Secp256k1Error::InvalidSignature); } @@ -175,7 +185,7 @@ fn get_data_slice<'a>( } let signature_instruction = &instruction_datas[signature_index]; let start = offset_start as usize; - let end = start + size; + let end = start.saturating_add(size); if end > signature_instruction.len() { return Err(Secp256k1Error::InvalidSignature); } @@ -188,7 +198,7 @@ pub mod test { use super::*; fn test_case(num_signatures: u8, offsets: &SecpSignatureOffsets) -> Result<(), Secp256k1Error> { - let mut instruction_data = vec![0u8; 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE]; + 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(); @@ -200,7 +210,7 @@ pub mod test { fn test_invalid_offsets() { solana_logger::setup(); - let mut instruction_data = vec![0u8; 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE]; + let mut instruction_data = vec![0u8; DATA_START]; let offsets = SecpSignatureOffsets::default(); instruction_data[0] = 1; let writer = std::io::Cursor::new(&mut instruction_data[1..]); diff --git a/sdk/src/timing.rs b/sdk/src/timing.rs index adb0259c27..1edc1de325 100644 --- a/sdk/src/timing.rs +++ b/sdk/src/timing.rs @@ -1,17 +1,26 @@ -#![allow(clippy::integer_arithmetic)] //! The `timing` module provides std::time utility functions. +use crate::unchecked_div_by_const; use std::time::{Duration, SystemTime, UNIX_EPOCH}; pub fn duration_as_ns(d: &Duration) -> u64 { - d.as_secs() * 1_000_000_000 + u64::from(d.subsec_nanos()) + d.as_secs() + .saturating_mul(1_000_000_000) + .saturating_add(u64::from(d.subsec_nanos())) } pub fn duration_as_us(d: &Duration) -> u64 { - (d.as_secs() * 1000 * 1000) + (u64::from(d.subsec_nanos()) / 1_000) + d.as_secs() + .saturating_mul(1_000_000) + .saturating_add(unchecked_div_by_const!(u64::from(d.subsec_nanos()), 1_000)) } pub fn duration_as_ms(d: &Duration) -> u64 { - (d.as_secs() * 1000) + (u64::from(d.subsec_nanos()) / 1_000_000) + d.as_secs() + .saturating_mul(1000) + .saturating_add(unchecked_div_by_const!( + u64::from(d.subsec_nanos()), + 1_000_000 + )) } pub fn duration_as_s(d: &Duration) -> f32 { @@ -34,7 +43,7 @@ pub fn years_as_slots(years: f64, tick_duration: &Duration, ticks_per_slot: u64) // slots/year is seconds/year ... SECONDS_PER_YEAR // * (ns/s)/(ns/tick) / ticks/slot = 1/s/1/tick = ticks/s - *(1_000_000_000.0 / duration_as_ns(tick_duration) as f64) + * (1_000_000_000.0 / duration_as_ns(tick_duration) as f64) // / ticks/slot / ticks_per_slot as f64 }