From 7c610b216b86c796977493b7441e88fd390cb72e Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 22 Oct 2018 21:18:53 -0600 Subject: [PATCH] Migrate from ring to ed25519-dalek Why? * Pure Rust, no BoringSSL (or OpenSSL) dependency * Those avx2 benchmarks * ring includes far more than what we need * ring author won't add release tags: https://github.com/briansmith/ring#versioning--stability --- Cargo.toml | 3 +-- src/bin/bench-tps.rs | 2 +- src/bin/genesis.rs | 1 - src/bin/keygen.rs | 1 - src/budget_program.rs | 17 ++++++++--------- src/fullnode.rs | 7 ++----- src/lib.rs | 3 +-- src/mint.rs | 18 ++++-------------- src/signature.rs | 35 ++++++++++++++++------------------- src/sigverify.rs | 13 +++++-------- src/storage_stage.rs | 7 ++++--- src/transaction.rs | 29 +++++++++++++++-------------- src/wallet.rs | 5 +---- 13 files changed, 58 insertions(+), 83 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 98be14250..561e1b203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ bytes = "0.4" chrono = { version = "0.4.0", features = ["serde"] } clap = "2.31" dirs = "1.0.2" +ed25519-dalek = "1.0.0-pre.0" elf = "0.0.10" env_logger = "0.5.12" generic-array = { version = "0.12.0", default-features = false, features = ["serde"] } @@ -97,7 +98,6 @@ pnet_datalink = "0.21.0" rand = "0.5.1" rayon = "1.0.0" reqwest = "0.9.0" -ring = "0.13.2" sha2 = "0.8.0" serde = "1.0.27" serde_cbor = "0.9.0" @@ -108,7 +108,6 @@ solana-sdk = { path = "sdk", version = "0.11.0" } sys-info = "0.5.6" tokio = "0.1" tokio-codec = "0.1" -untrusted = "0.6.2" solana-bpfloader = { path = "programs/native/bpf_loader", version = "0.11.0" } solana-erc20 = { path = "programs/native/erc20", version = "0.11.0" } solana-lualoader = { path = "programs/native/lua_loader", version = "0.11.0" } diff --git a/src/bin/bench-tps.rs b/src/bin/bench-tps.rs index a5b32fe34..8b5e72b84 100644 --- a/src/bin/bench-tps.rs +++ b/src/bin/bench-tps.rs @@ -643,7 +643,7 @@ fn main() { let mut barrier_client = mk_client(&leader); let mut seed = [0u8; 32]; - seed.copy_from_slice(&id.public_key_bytes()[..32]); + seed.copy_from_slice(&id.to_bytes()[..32]); let mut rnd = GenKeys::new(seed); println!("Creating {} keypairs...", tx_count * 2); diff --git a/src/bin/genesis.rs b/src/bin/genesis.rs index a60dff0e7..481727432 100644 --- a/src/bin/genesis.rs +++ b/src/bin/genesis.rs @@ -5,7 +5,6 @@ extern crate atty; extern crate clap; extern crate serde_json; extern crate solana; -extern crate untrusted; use clap::{App, Arg}; use solana::fullnode::Config; diff --git a/src/bin/keygen.rs b/src/bin/keygen.rs index 10a49ca48..7d26e4ef3 100644 --- a/src/bin/keygen.rs +++ b/src/bin/keygen.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate clap; extern crate dirs; -extern crate ring; extern crate serde_json; extern crate solana; diff --git a/src/budget_program.rs b/src/budget_program.rs index a21eba5d4..c16097d91 100644 --- a/src/budget_program.rs +++ b/src/budget_program.rs @@ -610,15 +610,14 @@ mod test { tx.userdata(0).to_vec(), vec![ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 50, 48, 49, 54, 45, - 48, 55, 45, 48, 56, 84, 48, 57, 58, 49, 48, 58, 49, 49, 90, 32, 253, 186, 201, 177, - 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30, 78, 212, 76, - 16, 252, 180, 72, 134, 137, 247, 161, 68, 192, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, 5, - 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 1, 1, 1, 1, - 0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, - 105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 192, - 0, 0, 0, 0, 0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, - 59, 206, 105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, - 68 + 48, 55, 45, 48, 56, 84, 48, 57, 58, 49, 48, 58, 49, 49, 90, 218, 65, 89, 124, 81, + 87, 72, 141, 119, 36, 224, 63, 184, 216, 74, 55, 106, 67, 184, 244, 21, 24, 161, + 28, 195, 135, 182, 105, 178, 238, 101, 134, 192, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 4, + 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 1, 1, 1, + 1, 0, 0, 0, 218, 65, 89, 124, 81, 87, 72, 141, 119, 36, 224, 63, 184, 216, 74, 55, + 106, 67, 184, 244, 21, 24, 161, 28, 195, 135, 182, 105, 178, 238, 101, 134, 192, 0, + 0, 0, 0, 0, 0, 0, 218, 65, 89, 124, 81, 87, 72, 141, 119, 36, 224, 63, 184, 216, + 74, 55, 106, 67, 184, 244, 21, 24, 161, 28, 195, 135, 182, 105, 178, 238, 101, 134 ] ); diff --git a/src/fullnode.rs b/src/fullnode.rs index e1885bb39..9076d8d34 100644 --- a/src/fullnode.rs +++ b/src/fullnode.rs @@ -18,7 +18,6 @@ use std::sync::{Arc, RwLock}; use std::thread::Result; use tpu::{Tpu, TpuReturnType}; use tvu::{Tvu, TvuReturnType}; -use untrusted::Input; use window::{new_window, SharedWindow}; pub enum NodeRole { @@ -113,15 +112,13 @@ pub struct Config { impl Config { pub fn new(bind_addr: &SocketAddr, pkcs8: Vec) -> Self { - let keypair = - Keypair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in fullnode::Config new"); + let keypair = Keypair::from_bytes(&pkcs8).expect("from_pkcs8 in fullnode::Config new"); let pubkey = keypair.pubkey(); let node_info = NodeInfo::new_with_pubkey_socketaddr(pubkey, bind_addr); Config { node_info, pkcs8 } } pub fn keypair(&self) -> Keypair { - Keypair::from_pkcs8(Input::from(&self.pkcs8)) - .expect("from_pkcs8 in fullnode::Config keypair") + Keypair::from_bytes(&self.pkcs8).expect("from_pkcs8 in fullnode::Config keypair") } } diff --git a/src/lib.rs b/src/lib.rs index 7f2daa5b7..69a16201d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,6 +87,7 @@ extern crate bytes; extern crate chrono; extern crate clap; extern crate dirs; +extern crate ed25519_dalek; extern crate elf; extern crate generic_array; #[cfg(test)] @@ -103,7 +104,6 @@ extern crate nix; extern crate pnet_datalink; extern crate rayon; extern crate reqwest; -extern crate ring; extern crate serde; #[macro_use] extern crate serde_derive; @@ -122,7 +122,6 @@ extern crate solana_sdk; extern crate sys_info; extern crate tokio; extern crate tokio_codec; -extern crate untrusted; #[cfg(test)] #[macro_use] diff --git a/src/mint.rs b/src/mint.rs index e14fac16b..fb413afcd 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -2,12 +2,10 @@ use entry::Entry; use hash::{hash, Hash}; -use ring::rand::SystemRandom; use signature::{Keypair, KeypairUtil}; use solana_sdk::pubkey::Pubkey; use system_transaction::SystemTransaction; use transaction::Transaction; -use untrusted::Input; #[derive(Serialize, Deserialize, Debug)] pub struct Mint { @@ -25,8 +23,7 @@ impl Mint { bootstrap_leader_id: Pubkey, bootstrap_leader_tokens: u64, ) -> Self { - let keypair = - Keypair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in mint pub fn new"); + let keypair = Keypair::from_bytes(&pkcs8).expect("from_pkcs8 in mint pub fn new"); let pubkey = keypair.pubkey(); Mint { pkcs8, @@ -42,19 +39,12 @@ impl Mint { bootstrap_leader: Pubkey, bootstrap_leader_tokens: u64, ) -> Self { - let rnd = SystemRandom::new(); - let pkcs8 = Keypair::generate_pkcs8(&rnd) - .expect("generate_pkcs8 in mint pub fn new") - .to_vec(); + let pkcs8 = Keypair::new().to_bytes().to_vec(); Self::new_with_pkcs8(tokens, pkcs8, bootstrap_leader, bootstrap_leader_tokens) } pub fn new(tokens: u64) -> Self { - let rnd = SystemRandom::new(); - let pkcs8 = Keypair::generate_pkcs8(&rnd) - .expect("generate_pkcs8 in mint pub fn new") - .to_vec(); - Self::new_with_pkcs8(tokens, pkcs8, Pubkey::default(), 0) + Self::new_with_leader(tokens, Pubkey::default(), 0) } pub fn seed(&self) -> Hash { @@ -66,7 +56,7 @@ impl Mint { } pub fn keypair(&self) -> Keypair { - Keypair::from_pkcs8(Input::from(&self.pkcs8)).expect("from_pkcs8 in mint pub fn keypair") + Keypair::from_bytes(&self.pkcs8).expect("from_pkcs8 in mint pub fn keypair") } pub fn pubkey(&self) -> Pubkey { diff --git a/src/signature.rs b/src/signature.rs index 17c24b345..59a2e0d2d 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,20 +1,19 @@ //! The `signature` module provides functionality for public, and private keys. use bs58; +use ed25519_dalek; use generic_array::typenum::U64; use generic_array::GenericArray; -use rand::{ChaChaRng, Rng, SeedableRng}; +use rand::{ChaChaRng, OsRng, Rng, SeedableRng}; use rayon::prelude::*; -use ring::signature::Ed25519KeyPair; -use ring::{rand, signature}; use serde_json; +use sha2::Sha512; use solana_sdk::pubkey::Pubkey; use std::error; use std::fmt; use std::fs::File; -use untrusted::Input; -pub type Keypair = Ed25519KeyPair; +pub type Keypair = ed25519_dalek::Keypair; #[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Signature(GenericArray); @@ -24,10 +23,9 @@ impl Signature { Signature(GenericArray::clone_from_slice(&signature_slice)) } pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool { - let pubkey = Input::from(pubkey_bytes); - let message = Input::from(message_bytes); - let signature = Input::from(self.0.as_slice()); - signature::verify(&signature::ED25519, pubkey, message, signature).is_ok() + let pubkey = ed25519_dalek::PublicKey::from_bytes(pubkey_bytes).unwrap(); + let signature = ed25519_dalek::Signature::from_bytes(self.0.as_slice()).unwrap(); + pubkey.verify::(message_bytes, &signature).is_ok() } } @@ -54,17 +52,16 @@ pub trait KeypairUtil { fn pubkey(&self) -> Pubkey; } -impl KeypairUtil for Ed25519KeyPair { +impl KeypairUtil for Keypair { /// Return a new ED25519 keypair fn new() -> Self { - let rng = rand::SystemRandom::new(); - let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).expect("generate_pkcs8"); - Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8_bytes)).expect("from_pcks8") + let mut rng: OsRng = OsRng::new().unwrap(); + Keypair::generate::(&mut rng) } /// Return the public key for the given keypair fn pubkey(&self) -> Pubkey { - Pubkey::new(self.public_key_bytes()) + Pubkey::new(&self.public.to_bytes()) } } @@ -78,20 +75,20 @@ impl GenKeys { GenKeys { generator } } - fn gen_seed(&mut self) -> [u8; 32] { - let mut seed = [0u8; 32]; + fn gen_seed(&mut self) -> [u8; 64] { + let mut seed = [0u8; 64]; self.generator.fill(&mut seed); seed } - fn gen_n_seeds(&mut self, n: u64) -> Vec<[u8; 32]> { + fn gen_n_seeds(&mut self, n: u64) -> Vec<[u8; 64]> { (0..n).map(|_| self.gen_seed()).collect() } pub fn gen_n_keypairs(&mut self, n: u64) -> Vec { self.gen_n_seeds(n) .into_par_iter() - .map(|seed| Keypair::from_seed_unchecked(Input::from(&seed)).unwrap()) + .map(|seed| Keypair::from_bytes(&seed).unwrap()) .collect() } } @@ -104,7 +101,7 @@ pub fn read_pkcs8(path: &str) -> Result, Box> { pub fn read_keypair(path: &str) -> Result> { let pkcs8 = read_pkcs8(path)?; - let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?; + let keypair = Keypair::from_bytes(&pkcs8).unwrap(); Ok(keypair) } diff --git a/src/sigverify.rs b/src/sigverify.rs index 2ab5618f1..4cd1e4464 100644 --- a/src/sigverify.rs +++ b/src/sigverify.rs @@ -59,10 +59,8 @@ pub fn init() { } fn verify_packet(packet: &Packet) -> u8 { - use ring::signature; use signature::Signature; use solana_sdk::pubkey::Pubkey; - use untrusted; let msg_start = TX_OFFSET + SIGNED_DATA_OFFSET; let sig_start = TX_OFFSET + SIG_OFFSET; @@ -75,12 +73,11 @@ fn verify_packet(packet: &Packet) -> u8 { } let msg_end = packet.meta.size; - signature::verify( - &signature::ED25519, - untrusted::Input::from(&packet.data[pubkey_start..pubkey_end]), - untrusted::Input::from(&packet.data[msg_start..msg_end]), - untrusted::Input::from(&packet.data[sig_start..sig_end]), - ).is_ok() as u8 + let signature = Signature::new(&packet.data[sig_start..sig_end]); + signature.verify( + &packet.data[pubkey_start..pubkey_end], + &packet.data[msg_start..msg_end], + ) as u8 } fn verify_packet_disabled(_packet: &Packet) -> u8 { diff --git a/src/storage_stage.rs b/src/storage_stage.rs index 7cb2f6a12..25a4c3fc7 100644 --- a/src/storage_stage.rs +++ b/src/storage_stage.rs @@ -9,6 +9,7 @@ use hash::Hash; use rand::{ChaChaRng, Rng, SeedableRng}; use result::{Error, Result}; use service::Service; +use sha2::Sha512; use signature::Keypair; use signature::Signature; use solana_sdk::pubkey::Pubkey; @@ -138,9 +139,9 @@ impl StorageStage { entry_height: u64, ) -> Result<()> { let mut seed = [0u8; 32]; - let signature = keypair.sign(&entry_id.as_ref()); + let signature = keypair.sign::(&entry_id.as_ref()); - seed.copy_from_slice(&signature.as_ref()[..32]); + seed.copy_from_slice(&signature.to_bytes()[..32]); let mut rng = ChaChaRng::from_seed(seed); @@ -151,7 +152,7 @@ impl StorageStage { return Ok(()); } // TODO: what if the validator does not have this slice - let slice = signature.as_ref()[0] as usize % num_slices; + let slice = signature.to_bytes()[0] as usize % num_slices; debug!( "storage verifying: slice: {} identities: {}", diff --git a/src/transaction.rs b/src/transaction.rs index beda8a40b..da19a5cc3 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -3,6 +3,7 @@ use bincode::serialize; use hash::{Hash, Hasher}; use serde::Serialize; +use sha2::Sha512; use signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::pubkey::Pubkey; use std::mem::size_of; @@ -158,7 +159,7 @@ impl Transaction { pub fn sign(&mut self, keypair: &Keypair, last_id: Hash) { self.last_id = last_id; let sign_data = self.get_sign_data(); - self.signature = Signature::new(keypair.sign(&sign_data).as_ref()); + self.signature = Signature::new(&keypair.sign::(&sign_data).to_bytes()); } /// Verify only the transaction signature. @@ -301,19 +302,19 @@ mod tests { assert_eq!( serialize(&tx).unwrap(), vec![ - 234, 139, 34, 5, 120, 28, 107, 203, 69, 25, 236, 200, 164, 1, 12, 47, 147, 53, 41, - 143, 23, 116, 230, 203, 59, 228, 153, 14, 22, 241, 103, 226, 186, 169, 181, 65, 49, - 215, 44, 2, 61, 214, 113, 216, 184, 206, 147, 104, 140, 225, 138, 21, 172, 135, - 211, 80, 103, 80, 216, 106, 249, 86, 194, 1, 3, 0, 0, 0, 0, 0, 0, 0, 32, 253, 186, - 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30, - 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 32, 253, 186, 201, 177, 11, - 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30, 78, 212, 76, 16, - 252, 180, 72, 134, 137, 247, 161, 68, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 + 238, 228, 120, 18, 14, 44, 44, 74, 186, 124, 104, 174, 137, 227, 237, 157, 147, 37, + 230, 74, 20, 48, 234, 36, 170, 60, 68, 184, 171, 240, 203, 18, 255, 110, 164, 67, + 212, 206, 115, 182, 13, 90, 38, 215, 191, 51, 79, 183, 57, 102, 248, 221, 114, 72, + 120, 66, 113, 146, 251, 102, 69, 187, 25, 8, 3, 0, 0, 0, 0, 0, 0, 0, 218, 65, 89, + 124, 81, 87, 72, 141, 119, 36, 224, 63, 184, 216, 74, 55, 106, 67, 184, 244, 21, + 24, 161, 28, 195, 135, 182, 105, 178, 238, 101, 134, 218, 65, 89, 124, 81, 87, 72, + 141, 119, 36, 224, 63, 184, 216, 74, 55, 106, 67, 184, 244, 21, 24, 161, 28, 195, + 135, 182, 105, 178, 238, 101, 134, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 ], ); } diff --git a/src/wallet.rs b/src/wallet.rs index f7d61b4a6..97316e46b 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -10,8 +10,6 @@ use elf; use fullnode::Config; use hash::Hash; use loader_transaction::LoaderTransaction; -use ring::rand::SystemRandom; -use ring::signature::Ed25519KeyPair; use rpc::RpcSignatureStatus; use rpc_request::RpcRequest; use serde_json; @@ -693,8 +691,7 @@ pub fn request_airdrop( } pub fn gen_keypair_file(outfile: String) -> Result> { - let rnd = SystemRandom::new(); - let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?; + let pkcs8_bytes = Keypair::new().to_bytes(); let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?; if outfile != "-" {