Move secp256k1 instruction helper to the sdk (#13560)
This commit is contained in:
@ -1,7 +1,5 @@
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
instruction::{Instruction, InstructionError},
|
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
|
||||||
keyed_account::KeyedAccount,
|
|
||||||
process_instruction::InvokeContext,
|
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,74 +13,14 @@ pub fn process_instruction(
|
|||||||
Ok(())
|
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)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use solana_sdk::secp256k1::{SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
|
secp256k1_instruction::{
|
||||||
|
new_secp256k1_instruction, SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE,
|
||||||
|
},
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
@ -98,7 +36,7 @@ pub mod test {
|
|||||||
|
|
||||||
let secp_privkey = secp256k1::SecretKey::random(&mut thread_rng());
|
let secp_privkey = secp256k1::SecretKey::random(&mut thread_rng());
|
||||||
let message_arr = b"hello";
|
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 mint_keypair = Keypair::new();
|
||||||
|
|
||||||
let tx = Transaction::new_signed_with_payer(
|
let tx = Transaction::new_signed_with_payer(
|
||||||
|
@ -34,7 +34,7 @@ pub mod program_utils;
|
|||||||
pub mod pubkey;
|
pub mod pubkey;
|
||||||
pub mod recent_blockhashes_account;
|
pub mod recent_blockhashes_account;
|
||||||
pub mod rpc_port;
|
pub mod rpc_port;
|
||||||
pub mod secp256k1;
|
pub mod secp256k1_instruction;
|
||||||
pub mod shred_version;
|
pub mod shred_version;
|
||||||
pub mod signature;
|
pub mod signature;
|
||||||
pub mod signers;
|
pub mod signers;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![cfg(feature = "full")]
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
|
use crate::instruction::Instruction;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
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_SERIALIZED_SIZE: usize = 64;
|
||||||
pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11;
|
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)]
|
#[derive(Default, Serialize, Deserialize, Debug)]
|
||||||
pub struct SecpSignatureOffsets {
|
pub struct SecpSignatureOffsets {
|
||||||
pub signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytes
|
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,
|
pub message_instruction_index: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data_slice<'a>(
|
pub fn new_secp256k1_instruction(
|
||||||
instruction_datas: &'a [&[u8]],
|
priv_key: &secp256k1::SecretKey,
|
||||||
instruction_index: u8,
|
message_arr: &[u8],
|
||||||
offset_start: u16,
|
) -> Instruction {
|
||||||
size: usize,
|
let secp_pubkey = secp256k1::PublicKey::from_secret_key(priv_key);
|
||||||
) -> Result<&'a [u8], Secp256k1Error> {
|
let eth_pubkey = construct_eth_pubkey(&secp_pubkey);
|
||||||
let signature_index = instruction_index as usize;
|
let mut hasher = sha3::Keccak256::new();
|
||||||
if signature_index >= instruction_datas.len() {
|
hasher.update(&message_arr);
|
||||||
return Err(Secp256k1Error::InvalidDataOffsets);
|
let message_hash = hasher.finalize();
|
||||||
}
|
let mut message_hash_arr = [0u8; 32];
|
||||||
let signature_instruction = &instruction_datas[signature_index];
|
message_hash_arr.copy_from_slice(&message_hash.as_slice());
|
||||||
let start = offset_start as usize;
|
let message = secp256k1::Message::parse(&message_hash_arr);
|
||||||
let end = start + size;
|
let (signature, recovery_id) = secp256k1::sign(&message, priv_key);
|
||||||
if end > signature_instruction.len() {
|
let signature_arr = signature.serialize();
|
||||||
return Err(Secp256k1Error::InvalidSignature);
|
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(
|
pub fn verify_eth_addresses(
|
||||||
@ -125,6 +162,26 @@ pub fn verify_eth_addresses(
|
|||||||
Ok(())
|
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)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use super::*;
|
@ -3,7 +3,7 @@
|
|||||||
#![cfg(feature = "full")]
|
#![cfg(feature = "full")]
|
||||||
|
|
||||||
use crate::sanitize::{Sanitize, SanitizeError};
|
use crate::sanitize::{Sanitize, SanitizeError};
|
||||||
use crate::secp256k1::verify_eth_addresses;
|
use crate::secp256k1_instruction::verify_eth_addresses;
|
||||||
use crate::{
|
use crate::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
|
Reference in New Issue
Block a user