Improve message-signing ergonomics

This commit is contained in:
Greg Fitzgerald
2019-01-25 23:41:20 -07:00
parent 1bae87d4b3
commit 33f921235d
8 changed files with 36 additions and 39 deletions

View File

@ -35,7 +35,7 @@ impl Signature {
pub trait Signable { pub trait Signable {
fn sign(&mut self, keypair: &Keypair) { fn sign(&mut self, keypair: &Keypair) {
let data = self.signable_data(); let data = self.signable_data();
self.set_signature(Signature::new(&keypair.sign(&data).as_ref())); self.set_signature(keypair.sign_message(&data));
} }
fn verify(&self) -> bool { fn verify(&self) -> bool {
self.get_signature() self.get_signature()
@ -69,6 +69,7 @@ impl fmt::Display for Signature {
pub trait KeypairUtil { pub trait KeypairUtil {
fn new() -> Self; fn new() -> Self;
fn pubkey(&self) -> Pubkey; fn pubkey(&self) -> Pubkey;
fn sign_message(&self, message: &[u8]) -> Signature;
} }
impl KeypairUtil for Ed25519KeyPair { impl KeypairUtil for Ed25519KeyPair {
@ -83,6 +84,10 @@ impl KeypairUtil for Ed25519KeyPair {
fn pubkey(&self) -> Pubkey { fn pubkey(&self) -> Pubkey {
Pubkey::new(self.public_key_bytes()) Pubkey::new(self.public_key_bytes())
} }
fn sign_message(&self, message: &[u8]) -> Signature {
Signature::new(self.sign(message).as_ref())
}
} }
pub fn read_pkcs8(path: &str) -> Result<Vec<u8>, Box<error::Error>> { pub fn read_pkcs8(path: &str) -> Result<Vec<u8>, Box<error::Error>> {

View File

@ -193,7 +193,7 @@ impl Transaction {
&self.program_ids[program_ids_index as usize] &self.program_ids[program_ids_index as usize]
} }
/// Get the transaction data to sign. /// Get the transaction data to sign.
pub fn get_sign_data(&self) -> Vec<u8> { pub fn message(&self) -> Vec<u8> {
let mut buf = vec![0u8; PACKET_DATA_SIZE]; let mut buf = vec![0u8; PACKET_DATA_SIZE];
let mut wr = Cursor::new(&mut buf[..]); let mut wr = Cursor::new(&mut buf[..]);
serialize_vec_with(&mut wr, &self.account_keys, Transaction::serialize_pubkey) serialize_vec_with(&mut wr, &self.account_keys, Transaction::serialize_pubkey)
@ -213,10 +213,10 @@ impl Transaction {
/// Sign this transaction. /// Sign this transaction.
pub fn sign(&mut self, keypairs: &[&Keypair], last_id: Hash) { pub fn sign(&mut self, keypairs: &[&Keypair], last_id: Hash) {
self.last_id = last_id; self.last_id = last_id;
let sign_data = self.get_sign_data(); let message = self.message();
self.signatures = keypairs self.signatures = keypairs
.iter() .iter()
.map(|keypair| Signature::new(&keypair.sign(&sign_data).as_ref())) .map(|keypair| keypair.sign_message(&message))
.collect(); .collect();
} }
@ -224,7 +224,7 @@ impl Transaction {
pub fn verify_signature(&self) -> bool { pub fn verify_signature(&self) -> bool {
self.signatures self.signatures
.iter() .iter()
.all(|s| s.verify(&self.from().as_ref(), &self.get_sign_data())) .all(|s| s.verify(&self.from().as_ref(), &self.message()))
} }
/// Verify that references in the instructions are valid /// Verify that references in the instructions are valid

View File

@ -486,7 +486,7 @@ mod tests {
use crate::packet::{to_blobs, BLOB_DATA_SIZE, PACKET_DATA_SIZE}; use crate::packet::{to_blobs, BLOB_DATA_SIZE, PACKET_DATA_SIZE};
use solana_sdk::budget_transaction::BudgetTransaction; use solana_sdk::budget_transaction::BudgetTransaction;
use solana_sdk::hash::hash; use solana_sdk::hash::hash;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction; use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
@ -608,8 +608,7 @@ mod tests {
let keypair = Keypair::new(); let keypair = Keypair::new();
let vote_account = Keypair::new(); let vote_account = Keypair::new();
let tx = Transaction::vote_new(&vote_account.pubkey(), Vote { tick_height: 1 }, one, 1); let tx = Transaction::vote_new(&vote_account.pubkey(), Vote { tick_height: 1 }, one, 1);
let msg = tx.get_sign_data(); let sig = vote_account.sign_message(&tx.message());
let sig = Signature::new(&vote_account.sign(&msg).as_ref());
let tx0 = Transaction { let tx0 = Transaction {
signatures: vec![sig], signatures: vec![sig],
account_keys: tx.account_keys, account_keys: tx.account_keys,
@ -666,8 +665,7 @@ mod tests {
let keypair = Keypair::new(); let keypair = Keypair::new();
let vote_account = Keypair::new(); let vote_account = Keypair::new();
let tx = Transaction::vote_new(&vote_account.pubkey(), Vote { tick_height: 1 }, next_id, 2); let tx = Transaction::vote_new(&vote_account.pubkey(), Vote { tick_height: 1 }, next_id, 2);
let msg = tx.get_sign_data(); let sig = vote_account.sign_message(&tx.message());
let sig = Signature::new(&vote_account.sign(&msg).as_ref());
let tx_small = Transaction { let tx_small = Transaction {
signatures: vec![sig], signatures: vec![sig],
account_keys: tx.account_keys, account_keys: tx.account_keys,

View File

@ -10,7 +10,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use hashbrown::HashSet; use hashbrown::HashSet;
use solana_sdk::hash::{hash, Hash}; use solana_sdk::hash::{hash, Hash};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction; use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program::{self, Vote, VoteProgram}; use solana_sdk::vote_program::{self, Vote, VoteProgram};
@ -505,8 +505,7 @@ pub fn make_active_set_entries(
// 3) Create vote entry // 3) Create vote entry
let vote = Vote { tick_height: 1 }; let vote = Vote { tick_height: 1 };
let tx = Transaction::vote_new(&vote_account_id, vote, *last_tick_id, 0); let tx = Transaction::vote_new(&vote_account_id, vote, *last_tick_id, 0);
let msg = tx.get_sign_data(); let sig = active_keypair.sign_message(&tx.message());
let sig = Signature::new(&active_keypair.sign(&msg).as_ref());
let vote_tx = Transaction { let vote_tx = Transaction {
signatures: vec![sig], signatures: vec![sig],
account_keys: tx.account_keys, account_keys: tx.account_keys,

View File

@ -370,7 +370,7 @@ mod tests {
fn test_system_transaction_layout() { fn test_system_transaction_layout() {
let tx = test_tx(); let tx = test_tx();
let tx_bytes = serialize(&tx).unwrap(); let tx_bytes = serialize(&tx).unwrap();
let sign_data = tx.get_sign_data(); let message = tx.message();
let packet = sigverify::make_packet_from_transaction(tx.clone()); let packet = sigverify::make_packet_from_transaction(tx.clone());
let (sig_len, sig_start, msg_start_offset, pubkey_offset) = let (sig_len, sig_start, msg_start_offset, pubkey_offset) =
@ -385,7 +385,7 @@ mod tests {
Some(pubkey_offset as usize) Some(pubkey_offset as usize)
); );
assert_eq!( assert_eq!(
memfind(&tx_bytes, &sign_data), memfind(&tx_bytes, &message),
Some(msg_start_offset as usize) Some(msg_start_offset as usize)
); );
assert_eq!( assert_eq!(
@ -401,7 +401,7 @@ mod tests {
use crate::packet::PACKET_DATA_SIZE; use crate::packet::PACKET_DATA_SIZE;
let mut tx0 = test_tx(); let mut tx0 = test_tx();
tx0.instructions[0].userdata = vec![1, 2, 3]; tx0.instructions[0].userdata = vec![1, 2, 3];
let sign_data0a = tx0.get_sign_data(); let message0a = tx0.message();
let tx_bytes = serialize(&tx0).unwrap(); let tx_bytes = serialize(&tx0).unwrap();
assert!(tx_bytes.len() < PACKET_DATA_SIZE); assert!(tx_bytes.len() < PACKET_DATA_SIZE);
assert_eq!( assert_eq!(
@ -413,8 +413,8 @@ mod tests {
assert_eq!(tx1.instructions[0].userdata, vec![1, 2, 3]); assert_eq!(tx1.instructions[0].userdata, vec![1, 2, 3]);
tx0.instructions[0].userdata = vec![1, 2, 4]; tx0.instructions[0].userdata = vec![1, 2, 4];
let sign_data0b = tx0.get_sign_data(); let message0b = tx0.message();
assert_ne!(sign_data0a, sign_data0b); assert_ne!(message0a, message0b);
} }
#[test] #[test]

View File

@ -452,7 +452,7 @@ mod tests {
use solana_sdk::hash::Hash; use solana_sdk::hash::Hash;
use solana_sdk::hash::Hasher; use solana_sdk::hash::Hasher;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program::Vote; use solana_sdk::vote_program::Vote;
use solana_sdk::vote_transaction::VoteTransaction; use solana_sdk::vote_transaction::VoteTransaction;
@ -531,7 +531,7 @@ mod tests {
let keypair = Keypair::new(); let keypair = Keypair::new();
let hash = Hash::default(); let hash = Hash::default();
let signature = Signature::new(keypair.sign(&hash.as_ref()).as_ref()); let signature = keypair.sign_message(&hash.as_ref());
let mut result = storage_state.get_mining_result(&signature); let mut result = storage_state.get_mining_result(&signature);
assert_eq!(result, Hash::default()); assert_eq!(result, Hash::default());
@ -609,8 +609,7 @@ mod tests {
}; };
let keypair = Keypair::new(); let keypair = Keypair::new();
let tx = Transaction::vote_new(&keypair.pubkey(), vote, Hash::default(), 1); let tx = Transaction::vote_new(&keypair.pubkey(), vote, Hash::default(), 1);
let msg = tx.get_sign_data(); let sig = keypair.sign_message(&tx.message());
let sig = Signature::new(&keypair.sign(&msg).as_ref());
let vote_tx = Transaction { let vote_tx = Transaction {
signatures: vec![sig], signatures: vec![sig],
account_keys: tx.account_keys, account_keys: tx.account_keys,
@ -661,7 +660,7 @@ mod tests {
.for_each(move |_| { .for_each(move |_| {
let keypair = Keypair::new(); let keypair = Keypair::new();
let hash = hasher.clone().result(); let hash = hasher.clone().result();
let signature = Signature::new(keypair.sign(&hash.as_ref()).as_ref()); let signature = keypair.sign_message(&hash.as_ref());
let ix = get_identity_index_from_signature(&signature); let ix = get_identity_index_from_signature(&signature);
hist[ix].fetch_add(1, Ordering::Relaxed); hist[ix].fetch_add(1, Ordering::Relaxed);
}); });

View File

@ -86,7 +86,7 @@ pub struct VoteSignerProxy {
impl VoteSignerProxy { impl VoteSignerProxy {
pub fn new(keypair: &Arc<Keypair>, signer: Box<VoteSigner + Send + Sync>) -> Self { pub fn new(keypair: &Arc<Keypair>, signer: Box<VoteSigner + Send + Sync>) -> Self {
let msg = "Registering a new node"; let msg = "Registering a new node";
let sig = Signature::new(&keypair.sign(msg.as_bytes()).as_ref()); let sig = keypair.sign_message(msg.as_bytes());
let vote_account = signer let vote_account = signer
.register(keypair.pubkey(), &sig, msg.as_bytes()) .register(keypair.pubkey(), &sig, msg.as_bytes())
.unwrap(); .unwrap();
@ -161,9 +161,8 @@ impl VoteSignerProxy {
pub fn new_signed_vote_transaction(&self, last_id: &Hash, tick_height: u64) -> Transaction { pub fn new_signed_vote_transaction(&self, last_id: &Hash, tick_height: u64) -> Transaction {
let vote = Vote { tick_height }; let vote = Vote { tick_height };
let tx = Transaction::vote_new(&self.vote_account, vote, *last_id, 0); let tx = Transaction::vote_new(&self.vote_account, vote, *last_id, 0);
let msg = tx.message();
let msg = tx.get_sign_data(); let sig = self.keypair.sign_message(&msg);
let sig = Signature::new(&self.keypair.sign(&msg).as_ref());
let keypair = self.keypair.clone(); let keypair = self.keypair.clone();
let vote_signature = self.signer.sign(keypair.pubkey(), &sig, &msg).unwrap(); let vote_signature = self.signer.sign(keypair.pubkey(), &sig, &msg).unwrap();

View File

@ -156,10 +156,7 @@ impl VoteSigner for LocalVoteSigner {
fn sign(&self, pubkey: Pubkey, sig: &Signature, msg: &[u8]) -> Result<Signature> { fn sign(&self, pubkey: Pubkey, sig: &Signature, msg: &[u8]) -> Result<Signature> {
verify_signature(&sig, &pubkey, &msg)?; verify_signature(&sig, &pubkey, &msg)?;
match self.nodes.read().unwrap().get(&pubkey) { match self.nodes.read().unwrap().get(&pubkey) {
Some(voting_keypair) => { Some(voting_keypair) => Ok(voting_keypair.sign_message(&msg)),
let sig = Signature::new(&voting_keypair.sign(&msg).as_ref());
Ok(sig)
}
None => Err(Error::invalid_request()), None => Err(Error::invalid_request()),
} }
} }
@ -201,7 +198,7 @@ mod tests {
let node_keypair = Keypair::new(); let node_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
@ -238,7 +235,7 @@ mod tests {
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let msg1 = "This is a Test1"; let msg1 = "This is a Test1";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
@ -269,7 +266,7 @@ mod tests {
let node_keypair = Keypair::new(); let node_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
@ -301,7 +298,7 @@ mod tests {
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let msg1 = "This is a Test1"; let msg1 = "This is a Test1";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
@ -332,7 +329,7 @@ mod tests {
let node_keypair = Keypair::new(); let node_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
@ -396,7 +393,7 @@ mod tests {
let node_keypair = Keypair::new(); let node_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"id": 1, "id": 1,
@ -427,7 +424,7 @@ mod tests {
let node_keypair = Keypair::new(); let node_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
@ -476,7 +473,7 @@ mod tests {
let node_pubkey = node_keypair.pubkey(); let node_pubkey = node_keypair.pubkey();
let msg = "This is a test"; let msg = "This is a test";
let msg1 = "This is a Test"; let msg1 = "This is a Test";
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref()); let sig = node_keypair.sign_message(msg.as_bytes());
let req = json!({ let req = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",