From 48dd9f7efd3fab034ee951582ee6696ca320f583 Mon Sep 17 00:00:00 2001 From: Jack May Date: Thu, 12 Nov 2020 16:58:40 -0800 Subject: [PATCH] Move secp256k1 instruction helper to the sdk (#13560) --- programs/secp256k1/src/lib.rs | 72 +----------- sdk/src/lib.rs | 2 +- ...{secp256k1.rs => secp256k1_instruction.rs} | 105 ++++++++++++++---- sdk/src/transaction.rs | 2 +- 4 files changed, 88 insertions(+), 93 deletions(-) rename sdk/src/{secp256k1.rs => secp256k1_instruction.rs} (79%) diff --git a/programs/secp256k1/src/lib.rs b/programs/secp256k1/src/lib.rs index 2981819c2..9be513ea5 100644 --- a/programs/secp256k1/src/lib.rs +++ b/programs/secp256k1/src/lib.rs @@ -1,7 +1,5 @@ use solana_sdk::{ - instruction::{Instruction, InstructionError}, - keyed_account::KeyedAccount, - process_instruction::InvokeContext, + instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext, pubkey::Pubkey, }; @@ -15,74 +13,14 @@ pub fn process_instruction( Ok(()) } -pub fn new_secp256k1_instruction( - priv_key: &secp256k1::SecretKey, - message_arr: &[u8], -) -> Instruction { - use digest::Digest; - use solana_sdk::secp256k1::{ - construct_eth_pubkey, SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE, - SIGNATURE_SERIALIZED_SIZE, - }; - - let secp_pubkey = secp256k1::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 signature_arr = signature.serialize(); - 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, - 0, - ); - let eth_address_offset = data_start; - instruction_data[eth_address_offset..eth_address_offset + eth_pubkey.len()] - .copy_from_slice(ð_pubkey); - - let signature_offset = data_start + eth_pubkey.len(); - instruction_data[signature_offset..signature_offset + signature_arr.len()] - .copy_from_slice(&signature_arr); - - instruction_data[signature_offset + signature_arr.len()] = recovery_id.serialize(); - - let message_data_offset = signature_offset + signature_arr.len() + 1; - instruction_data[message_data_offset..].copy_from_slice(message_arr); - - let num_signatures = 1; - instruction_data[0] = num_signatures; - let offsets = SecpSignatureOffsets { - signature_offset: signature_offset as u16, - signature_instruction_index: 0, - eth_address_offset: eth_address_offset as u16, - eth_address_instruction_index: 0, - message_data_offset: message_data_offset as u16, - message_data_size: message_arr.len() as u16, - message_instruction_index: 0, - }; - let writer = std::io::Cursor::new(&mut instruction_data[1..data_start]); - bincode::serialize_into(writer, &offsets).unwrap(); - - Instruction { - program_id: solana_sdk::secp256k1_program::id(), - accounts: vec![], - data: instruction_data, - } -} - #[cfg(test)] pub mod test { use rand::{thread_rng, Rng}; - use solana_sdk::secp256k1::{SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE}; use solana_sdk::{ hash::Hash, + secp256k1_instruction::{ + new_secp256k1_instruction, SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE, + }, signature::{Keypair, Signer}, transaction::Transaction, }; @@ -98,7 +36,7 @@ pub mod test { let secp_privkey = secp256k1::SecretKey::random(&mut thread_rng()); let message_arr = b"hello"; - let mut secp_instruction = super::new_secp256k1_instruction(&secp_privkey, message_arr); + let mut secp_instruction = new_secp256k1_instruction(&secp_privkey, message_arr); let mint_keypair = Keypair::new(); let tx = Transaction::new_signed_with_payer( diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 281d1c177..f0b6db4af 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -34,7 +34,7 @@ pub mod program_utils; pub mod pubkey; pub mod recent_blockhashes_account; pub mod rpc_port; -pub mod secp256k1; +pub mod secp256k1_instruction; pub mod shred_version; pub mod signature; pub mod signers; diff --git a/sdk/src/secp256k1.rs b/sdk/src/secp256k1_instruction.rs similarity index 79% rename from sdk/src/secp256k1.rs rename to sdk/src/secp256k1_instruction.rs index efb3492d2..e4e773c53 100644 --- a/sdk/src/secp256k1.rs +++ b/sdk/src/secp256k1_instruction.rs @@ -1,5 +1,6 @@ #![cfg(feature = "full")] +use crate::instruction::Instruction; use digest::Digest; use serde_derive::{Deserialize, Serialize}; @@ -15,13 +16,6 @@ pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20; pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11; -pub fn construct_eth_pubkey(pubkey: &secp256k1::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); - addr -} - #[derive(Default, Serialize, Deserialize, Debug)] pub struct SecpSignatureOffsets { pub signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytes @@ -33,24 +27,67 @@ pub struct SecpSignatureOffsets { pub message_instruction_index: u8, } -fn get_data_slice<'a>( - instruction_datas: &'a [&[u8]], - instruction_index: u8, - offset_start: u16, - size: usize, -) -> Result<&'a [u8], Secp256k1Error> { - let signature_index = instruction_index as usize; - if signature_index >= instruction_datas.len() { - return Err(Secp256k1Error::InvalidDataOffsets); - } - let signature_instruction = &instruction_datas[signature_index]; - let start = offset_start as usize; - let end = start + size; - if end > signature_instruction.len() { - return Err(Secp256k1Error::InvalidSignature); - } +pub fn new_secp256k1_instruction( + priv_key: &secp256k1::SecretKey, + message_arr: &[u8], +) -> Instruction { + let secp_pubkey = secp256k1::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 signature_arr = signature.serialize(); + assert_eq!(signature_arr.len(), SIGNATURE_SERIALIZED_SIZE); - Ok(&instruction_datas[signature_index][start..end]) + 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, + 0, + ); + let eth_address_offset = data_start; + instruction_data[eth_address_offset..eth_address_offset + eth_pubkey.len()] + .copy_from_slice(ð_pubkey); + + let signature_offset = data_start + eth_pubkey.len(); + instruction_data[signature_offset..signature_offset + signature_arr.len()] + .copy_from_slice(&signature_arr); + + instruction_data[signature_offset + signature_arr.len()] = recovery_id.serialize(); + + let message_data_offset = signature_offset + signature_arr.len() + 1; + instruction_data[message_data_offset..].copy_from_slice(message_arr); + + let num_signatures = 1; + instruction_data[0] = num_signatures; + let offsets = SecpSignatureOffsets { + signature_offset: signature_offset as u16, + signature_instruction_index: 0, + eth_address_offset: eth_address_offset as u16, + eth_address_instruction_index: 0, + message_data_offset: message_data_offset as u16, + message_data_size: message_arr.len() as u16, + message_instruction_index: 0, + }; + let writer = std::io::Cursor::new(&mut instruction_data[1..data_start]); + bincode::serialize_into(writer, &offsets).unwrap(); + + Instruction { + program_id: solana_sdk::secp256k1_program::id(), + accounts: vec![], + data: instruction_data, + } +} + +pub fn construct_eth_pubkey(pubkey: &secp256k1::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); + addr } pub fn verify_eth_addresses( @@ -125,6 +162,26 @@ pub fn verify_eth_addresses( Ok(()) } +fn get_data_slice<'a>( + instruction_datas: &'a [&[u8]], + instruction_index: u8, + offset_start: u16, + size: usize, +) -> Result<&'a [u8], Secp256k1Error> { + let signature_index = instruction_index as usize; + if signature_index >= instruction_datas.len() { + return Err(Secp256k1Error::InvalidDataOffsets); + } + let signature_instruction = &instruction_datas[signature_index]; + let start = offset_start as usize; + let end = start + size; + if end > signature_instruction.len() { + return Err(Secp256k1Error::InvalidSignature); + } + + Ok(&instruction_datas[signature_index][start..end]) +} + #[cfg(test)] pub mod test { use super::*; diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index aa23ec624..4a74d50cf 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -3,7 +3,7 @@ #![cfg(feature = "full")] use crate::sanitize::{Sanitize, SanitizeError}; -use crate::secp256k1::verify_eth_addresses; +use crate::secp256k1_instruction::verify_eth_addresses; use crate::{ hash::Hash, instruction::{CompiledInstruction, Instruction, InstructionError},