Sdk: remove integer arithmetic (#15962)
* Fix timing * Fix secp256k1_instruction * Fix secp256k1 tests
This commit is contained in:
		@@ -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..]);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user