diff --git a/Cargo.lock b/Cargo.lock index 4d1e5ae44..d7f266f66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3287,6 +3287,7 @@ dependencies = [ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "solana-budget-api 0.21.0", "solana-budget-program 0.21.0", "solana-chacha-sys 0.21.0", diff --git a/core/Cargo.toml b/core/Cargo.toml index 50f38f69b..7a3dba2d6 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -44,6 +44,7 @@ rayon = "1.2.0" serde = "1.0.102" serde_derive = "1.0.102" serde_json = "1.0.41" +sha2 = "0.8.0" solana-budget-api = { path = "../programs/budget_api", version = "0.21.0" } solana-budget-program = { path = "../programs/budget_program", version = "0.21.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.21.0" } diff --git a/core/src/cuda_runtime.rs b/core/src/cuda_runtime.rs index 16ed4453a..4bc5b1540 100644 --- a/core/src/cuda_runtime.rs +++ b/core/src/cuda_runtime.rs @@ -67,15 +67,9 @@ pub struct PinnedVec { pinnable: bool, } -impl Reset for PinnedVec { +impl Reset for PinnedVec { fn reset(&mut self) { - self.resize(0, 0u8); - } -} - -impl Reset for PinnedVec { - fn reset(&mut self) { - self.resize(0, 0u32); + self.resize(0, T::default()); } } diff --git a/core/src/packet.rs b/core/src/packet.rs index 97f706e7f..93c05347d 100644 --- a/core/src/packet.rs +++ b/core/src/packet.rs @@ -62,12 +62,6 @@ impl Reset for Packets { } } -impl Reset for PinnedVec { - fn reset(&mut self) { - self.resize(0, Packet::default()); - } -} - //auto derive doesn't support large arrays impl Default for Packets { fn default() -> Packets { diff --git a/core/src/sigverify_shreds.rs b/core/src/sigverify_shreds.rs index 27d42abf9..941d46a43 100644 --- a/core/src/sigverify_shreds.rs +++ b/core/src/sigverify_shreds.rs @@ -2,20 +2,22 @@ use crate::cuda_runtime::PinnedVec; use crate::packet::{Packet, Packets}; use crate::recycler::Recycler; -use crate::recycler::Reset; use crate::sigverify::{self, TxOffset}; use crate::sigverify_stage::SigVerifier; use bincode::deserialize; +use rayon::iter::IndexedParallelIterator; use rayon::iter::IntoParallelIterator; +use rayon::iter::IntoParallelRefMutIterator; use rayon::iter::ParallelIterator; use rayon::ThreadPool; +use sha2::{Digest, Sha512}; +use solana_ed25519_dalek::{Keypair, PublicKey, SecretKey}; use solana_ledger::bank_forks::BankForks; use solana_ledger::leader_schedule_cache::LeaderScheduleCache; use solana_ledger::perf_libs; use solana_ledger::shred::ShredType; use solana_metrics::inc_new_counter_debug; use solana_rayon_threadlimit::get_thread_count; -use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Signature; use std::collections::{HashMap, HashSet}; use std::mem::size_of; @@ -28,7 +30,7 @@ pub struct ShredSigVerifier { bank_forks: Arc>, leader_schedule_cache: Arc, recycler_offsets: Recycler, - recycler_pubkeys: Recycler>, + recycler_keys: Recycler>, recycler_out: Recycler>, } @@ -42,7 +44,7 @@ impl ShredSigVerifier { bank_forks, leader_schedule_cache, recycler_offsets: Recycler::default(), - recycler_pubkeys: Recycler::default(), + recycler_keys: Recycler::default(), recycler_out: Recycler::default(), } } @@ -70,23 +72,22 @@ impl SigVerifier for ShredSigVerifier { fn verify_batch(&self, mut batches: Vec) -> Vec { let r_bank = self.bank_forks.read().unwrap().working_bank(); let slots: HashSet = Self::read_slots(&batches); - let mut leader_slots: HashMap = slots + let mut leader_slots: HashMap = slots .into_iter() .filter_map(|slot| { - Some(( - slot, - self.leader_schedule_cache - .slot_leader_at(slot, Some(&r_bank))?, - )) + let key = self + .leader_schedule_cache + .slot_leader_at(slot, Some(&r_bank))?; + Some((slot, key.to_bytes())) }) .collect(); - leader_slots.insert(std::u64::MAX, Pubkey::default()); + leader_slots.insert(std::u64::MAX, [0u8; 32]); let r = verify_shreds_gpu( &batches, &leader_slots, &self.recycler_offsets, - &self.recycler_pubkeys, + &self.recycler_keys, &self.recycler_out, ); sigverify::mark_disabled(&mut batches, &r); @@ -100,12 +101,6 @@ thread_local!(static PAR_THREAD_POOL: RefCell = RefCell::new(rayon:: .build() .unwrap())); -impl Reset for PinnedVec { - fn reset(&mut self) { - self.resize(0, Pubkey::default()); - } -} - /// Assuming layout is /// signature: Signature /// signed_msg: { @@ -114,7 +109,7 @@ impl Reset for PinnedVec { /// ... /// } /// Signature is the first thing in the packet, and slot is the first thing in the signed message. -fn verify_shred_cpu(packet: &Packet, slot_leaders: &HashMap) -> Option { +fn verify_shred_cpu(packet: &Packet, slot_leaders: &HashMap) -> Option { let sig_start = 0; let sig_end = size_of::(); let slot_start = sig_end + size_of::(); @@ -127,19 +122,19 @@ fn verify_shred_cpu(packet: &Packet, slot_leaders: &HashMap) -> Opt } let slot: u64 = deserialize(&packet.data[slot_start..slot_end]).ok()?; trace!("slot {}", slot); - let pubkey: &Pubkey = slot_leaders.get(&slot)?; + let pubkey = slot_leaders.get(&slot)?; if packet.meta.size < sig_end { return Some(0); } let signature = Signature::new(&packet.data[sig_start..sig_end]); trace!("signature {}", signature); - if !signature.verify(pubkey.as_ref(), &packet.data[msg_start..msg_end]) { + if !signature.verify(pubkey, &packet.data[msg_start..msg_end]) { return Some(0); } Some(1) } -fn verify_shreds_cpu(batches: &[Packets], slot_leaders: &HashMap) -> Vec> { +fn verify_shreds_cpu(batches: &[Packets], slot_leaders: &HashMap) -> Vec> { use rayon::prelude::*; let count = sigverify::batch_size(batches); debug!("CPU SHRED ECDSA for {}", count); @@ -149,7 +144,7 @@ fn verify_shreds_cpu(batches: &[Packets], slot_leaders: &HashMap) - .into_par_iter() .map(|p| { p.packets - .par_iter() + .iter() .map(|p| verify_shred_cpu(p, slot_leaders).unwrap_or(0)) .collect() }) @@ -160,14 +155,17 @@ fn verify_shreds_cpu(batches: &[Packets], slot_leaders: &HashMap) - rv } -fn shred_gpu_pubkeys( +fn slot_key_data_for_gpu< + T: Sync + Sized + Default + std::fmt::Debug + Eq + std::hash::Hash + Clone + Copy, +>( + offset_start: usize, batches: &[Packets], - slot_leaders: &HashMap, + slot_keys: &HashMap, recycler_offsets: &Recycler, - recycler_pubkeys: &Recycler>, -) -> (PinnedVec, TxOffset, usize) { + recycler_keys: &Recycler>, +) -> (PinnedVec, TxOffset, usize) { //TODO: mark Pubkey::default shreds as failed after the GPU returns - assert_eq!(slot_leaders.get(&std::u64::MAX), Some(&Pubkey::default())); + assert_eq!(slot_keys.get(&std::u64::MAX), Some(&T::default())); let slots: Vec> = PAR_THREAD_POOL.with(|thread_pool| { thread_pool.borrow().install(|| { batches @@ -184,7 +182,7 @@ fn shred_gpu_pubkeys( let slot: Option = deserialize(&packet.data[slot_start..slot_end]).ok(); match slot { - Some(slot) if slot_leaders.get(&slot).is_some() => slot, + Some(slot) if slot_keys.get(&slot).is_some() => slot, _ => std::u64::MAX, } }) @@ -193,20 +191,20 @@ fn shred_gpu_pubkeys( .collect() }) }); - let mut keys_to_slots: HashMap> = HashMap::new(); + let mut keys_to_slots: HashMap> = HashMap::new(); for batch in slots.iter() { for slot in batch.iter() { - let key = slot_leaders.get(slot).unwrap(); + let key = slot_keys.get(slot).unwrap(); keys_to_slots .entry(*key) .or_insert_with(|| vec![]) .push(*slot); } } - let mut pubkeys: PinnedVec = recycler_pubkeys.allocate("shred_gpu_pubkeys"); + let mut keyvec = recycler_keys.allocate("shred_gpu_pubkeys"); let mut slot_to_key_ix = HashMap::new(); for (i, (k, slots)) in keys_to_slots.iter().enumerate() { - pubkeys.push(*k); + keyvec.push(*k); for s in slots { slot_to_key_ix.insert(s, i); } @@ -214,33 +212,34 @@ fn shred_gpu_pubkeys( let mut offsets = recycler_offsets.allocate("shred_offsets"); slots.iter().for_each(|packet_slots| { packet_slots.iter().for_each(|slot| { - offsets.push((slot_to_key_ix.get(slot).unwrap() * size_of::()) as u32); + offsets + .push((offset_start + (slot_to_key_ix.get(slot).unwrap() * size_of::())) as u32); }); }); //HACK: Pubkeys vector is passed along as a `Packets` buffer to the GPU //TODO: GPU needs a more opaque interface, which can handle variable sized structures for data //Pad the Pubkeys buffer such that it is bigger than a buffer of Packet sized elems let num_in_packets = - (pubkeys.len() * size_of::() + (size_of::() - 1)) / size_of::(); + (keyvec.len() * size_of::() + (size_of::() - 1)) / size_of::(); trace!("num_in_packets {}", num_in_packets); //number of bytes missing - let missing = num_in_packets * size_of::() - pubkeys.len() * size_of::(); + let missing = num_in_packets * size_of::() - keyvec.len() * size_of::(); trace!("missing {}", missing); //extra Pubkeys needed to fill the buffer - let extra = (missing + size_of::() - 1) / size_of::(); + let extra = (missing + size_of::() - 1) / size_of::(); trace!("extra {}", extra); - trace!("pubkeys {}", pubkeys.len()); + trace!("keyvec {}", keyvec.len()); for _ in 0..extra { - pubkeys.push(Pubkey::default()); - trace!("pubkeys {}", pubkeys.len()); + keyvec.push(T::default()); + trace!("keyvec {}", keyvec.len()); } - trace!("pubkeys {:?}", pubkeys); + trace!("keyvec {:?}", keyvec); trace!("offsets {:?}", offsets); - (pubkeys, offsets, num_in_packets) + (keyvec, offsets, num_in_packets) } fn shred_gpu_offsets( - mut pubkeys_end: u32, + mut pubkeys_end: usize, batches: &[Packets], recycler_offsets: &Recycler, ) -> (TxOffset, TxOffset, TxOffset, Vec>) { @@ -252,19 +251,19 @@ fn shred_gpu_offsets( let mut sig_lens = Vec::new(); for packet in &batch.packets { let sig_start = pubkeys_end; - let sig_end = sig_start + size_of::() as u32; + let sig_end = sig_start + size_of::(); let msg_start = sig_end; - let msg_end = sig_start + packet.meta.size as u32; - signature_offsets.push(sig_start); - msg_start_offsets.push(msg_start); + let msg_end = sig_start + packet.meta.size; + signature_offsets.push(sig_start as u32); + msg_start_offsets.push(msg_start as u32); let msg_size = if msg_end < msg_start { 0 } else { msg_end - msg_start }; - msg_sizes.push(msg_size); + msg_sizes.push(msg_size as u32); sig_lens.push(1); - pubkeys_end += size_of::() as u32; + pubkeys_end += size_of::(); } v_sig_lens.push(sig_lens); } @@ -273,9 +272,9 @@ fn shred_gpu_offsets( fn verify_shreds_gpu( batches: &[Packets], - slot_leaders: &HashMap, + slot_leaders: &HashMap, recycler_offsets: &Recycler, - recycler_pubkeys: &Recycler>, + recycler_pubkeys: &Recycler>, recycler_out: &Recycler>, ) -> Vec> { let api = perf_libs::api(); @@ -288,10 +287,10 @@ fn verify_shreds_gpu( let mut rvs = Vec::new(); let count = sigverify::batch_size(batches); let (pubkeys, pubkey_offsets, mut num_packets) = - shred_gpu_pubkeys(batches, slot_leaders, recycler_offsets, recycler_pubkeys); + slot_key_data_for_gpu(0, batches, slot_leaders, recycler_offsets, recycler_pubkeys); //HACK: Pubkeys vector is passed along as a `Packets` buffer to the GPU //TODO: GPU needs a more opaque interface, which can handle variable sized structures for data - let pubkeys_len = (num_packets * size_of::()) as u32; + let pubkeys_len = num_packets * size_of::(); trace!("num_packets: {}", num_packets); trace!("pubkeys_len: {}", pubkeys_len); let (signature_offsets, msg_start_offsets, msg_sizes, v_sig_lens) = @@ -355,6 +354,217 @@ fn verify_shreds_gpu( rvs } +/// Assuming layout is +/// signature: Signature +/// signed_msg: { +/// type: ShredType +/// slot: u64, +/// ... +/// } +/// Signature is the first thing in the packet, and slot is the first thing in the signed message. +fn sign_shred_cpu( + packet: &mut Packet, + slot_leaders_pubkeys: &HashMap, + slot_leaders_privkeys: &HashMap, +) { + let sig_start = 0; + let sig_end = sig_start + size_of::(); + let slot_start = sig_end + size_of::(); + let slot_end = slot_start + size_of::(); + let msg_start = sig_end; + let msg_end = packet.meta.size; + trace!("slot start and end {} {}", slot_start, slot_end); + assert!( + packet.meta.size >= slot_end, + "packet is not large enough for a slot" + ); + let slot: u64 = + deserialize(&packet.data[slot_start..slot_end]).expect("can't deserialize slot"); + trace!("slot {}", slot); + let pubkey = slot_leaders_pubkeys + .get(&slot) + .expect("slot pubkey missing"); + let privkey = slot_leaders_privkeys + .get(&slot) + .expect("slot privkey missing"); + let keypair = Keypair { + secret: SecretKey::from_bytes(&privkey[0..32]).expect("dalek privkey parser"), + public: PublicKey::from_bytes(&pubkey[0..32]).expect("dalek pubkey parser"), + }; + assert!( + packet.meta.size >= sig_end, + "packet is not large enough for a signature" + ); + let signature = keypair.sign(&packet.data[msg_start..msg_end]); + trace!("signature {:?}", signature); + packet.data[0..sig_end].copy_from_slice(&signature.to_bytes()); +} + +fn sign_shreds_cpu( + batches: &mut [Packets], + slot_leaders_pubkeys: &HashMap, + slot_leaders_privkeys: &HashMap, +) { + use rayon::prelude::*; + let count = sigverify::batch_size(batches); + debug!("CPU SHRED ECDSA for {}", count); + PAR_THREAD_POOL.with(|thread_pool| { + thread_pool.borrow().install(|| { + batches.par_iter_mut().for_each(|p| { + p.packets.iter_mut().for_each(|mut p| { + sign_shred_cpu(&mut p, slot_leaders_pubkeys, slot_leaders_privkeys) + }); + }); + }) + }); + inc_new_counter_debug!("ed25519_shred_verify_cpu", count); +} + +pub fn sign_shreds_gpu( + batches: &mut [Packets], + slot_leaders_pubkeys: &HashMap, + slot_leaders_privkeys: &HashMap, + recycler_offsets: &Recycler, + recycler_pubkeys: &Recycler>, + recycler_secrets: &Recycler>, + recycler_out: &Recycler>, +) { + let sig_size = size_of::(); + let api = perf_libs::api(); + if api.is_none() { + return sign_shreds_cpu(batches, slot_leaders_pubkeys, slot_leaders_privkeys); + } + let slot_leaders_secrets: HashMap = slot_leaders_privkeys + .iter() + .map(|(k, v)| { + if *k == std::u64::MAX { + (*k, Signature::default()) + } else { + let mut hasher = Sha512::default(); + hasher.input(&v); + let mut result = hasher.result(); + result[0] &= 248; + result[31] &= 63; + result[31] |= 64; + let sig = Signature::new(result.as_slice()); + (*k, sig) + } + }) + .collect(); + let api = api.unwrap(); + + let mut elems = Vec::new(); + let count = sigverify::batch_size(batches); + let mut offset: usize = 0; + let mut num_packets = 0; + let (pubkeys, pubkey_offsets, num_pubkey_packets) = slot_key_data_for_gpu( + offset, + batches, + slot_leaders_pubkeys, + recycler_offsets, + recycler_pubkeys, + ); + offset += num_pubkey_packets * size_of::(); + num_packets += num_pubkey_packets; + trace!("offset: {}", offset); + let (secrets, secret_offsets, num_secret_packets) = slot_key_data_for_gpu( + offset, + batches, + &slot_leaders_secrets, + recycler_offsets, + recycler_secrets, + ); + offset += num_secret_packets * size_of::(); + num_packets += num_secret_packets; + //HACK: Pubkeys vector is passed along as a `Packets` buffer to the GPU + //TODO: GPU needs a more opaque interface, which can handle variable sized structures for data + trace!("offset: {}", offset); + let (signature_offsets, msg_start_offsets, msg_sizes, _v_sig_lens) = + shred_gpu_offsets(offset, batches, recycler_offsets); + let total_sigs = signature_offsets.len(); + let mut signatures_out = recycler_out.allocate("ed25519 signatures"); + signatures_out.resize(total_sigs * sig_size, 0); + elems.push( + perf_libs::Elems { + #![allow(clippy::cast_ptr_alignment)] + elems: pubkeys.as_ptr() as *const solana_sdk::packet::Packet, + num: num_pubkey_packets as u32, + }, + ); + + elems.push( + perf_libs::Elems { + #![allow(clippy::cast_ptr_alignment)] + elems: secrets.as_ptr() as *const solana_sdk::packet::Packet, + num: num_secret_packets as u32, + }, + ); + + for p in batches.iter() { + elems.push(perf_libs::Elems { + elems: p.packets.as_ptr(), + num: p.packets.len() as u32, + }); + let mut v = Vec::new(); + v.resize(p.packets.len(), 0); + num_packets += p.packets.len(); + } + + trace!("Starting verify num packets: {}", num_packets); + trace!("elem len: {}", elems.len() as u32); + trace!("packet sizeof: {}", size_of::() as u32); + const USE_NON_DEFAULT_STREAM: u8 = 1; + unsafe { + let res = (api.ed25519_sign_many)( + elems.as_mut_ptr(), + elems.len() as u32, + size_of::() as u32, + num_packets as u32, + total_sigs as u32, + msg_sizes.as_ptr(), + pubkey_offsets.as_ptr(), + secret_offsets.as_ptr(), + msg_start_offsets.as_ptr(), + signatures_out.as_mut_ptr(), + USE_NON_DEFAULT_STREAM, + ); + if res != 0 { + trace!("RETURN!!!: {}", res); + } + } + trace!("done sign"); + let mut sizes: Vec = vec![0]; + sizes.extend(batches.iter().map(|b| b.packets.len())); + PAR_THREAD_POOL.with(|thread_pool| { + thread_pool.borrow().install(|| { + batches + .par_iter_mut() + .enumerate() + .for_each(|(batch_ix, batch)| { + let num_packets = sizes[batch_ix]; + batch + .packets + .iter_mut() + .enumerate() + .for_each(|(packet_ix, packet)| { + let sig_ix = packet_ix + num_packets; + let sig_start = sig_ix * sig_size; + let sig_end = sig_start + sig_size; + packet.data[0..sig_size] + .copy_from_slice(&signatures_out[sig_start..sig_end]); + }); + }); + }); + }); + inc_new_counter_debug!("ed25519_shred_sign_gpu", count); + recycler_out.recycle(signatures_out); + recycler_offsets.recycle(signature_offsets); + recycler_offsets.recycle(pubkey_offsets); + recycler_offsets.recycle(msg_sizes); + recycler_offsets.recycle(msg_start_offsets); + recycler_pubkeys.recycle(pubkeys); +} + #[cfg(test)] pub mod tests { use super::*; @@ -375,12 +585,18 @@ pub mod tests { packet.data[0..shred.payload.len()].copy_from_slice(&shred.payload); packet.meta.size = shred.payload.len(); - let leader_slots = [(slot, keypair.pubkey())].iter().cloned().collect(); + let leader_slots = [(slot, keypair.pubkey().to_bytes())] + .iter() + .cloned() + .collect(); let rv = verify_shred_cpu(&packet, &leader_slots); assert_eq!(rv, Some(1)); let wrong_keypair = Keypair::new(); - let leader_slots = [(slot, wrong_keypair.pubkey())].iter().cloned().collect(); + let leader_slots = [(slot, wrong_keypair.pubkey().to_bytes())] + .iter() + .cloned() + .collect(); let rv = verify_shred_cpu(&packet, &leader_slots); assert_eq!(rv, Some(0)); @@ -401,12 +617,18 @@ pub mod tests { batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload); batch[0].packets[0].meta.size = shred.payload.len(); - let leader_slots = [(slot, keypair.pubkey())].iter().cloned().collect(); + let leader_slots = [(slot, keypair.pubkey().to_bytes())] + .iter() + .cloned() + .collect(); let rv = verify_shreds_cpu(&batch, &leader_slots); assert_eq!(rv, vec![vec![1]]); let wrong_keypair = Keypair::new(); - let leader_slots = [(slot, wrong_keypair.pubkey())].iter().cloned().collect(); + let leader_slots = [(slot, wrong_keypair.pubkey().to_bytes())] + .iter() + .cloned() + .collect(); let rv = verify_shreds_cpu(&batch, &leader_slots); assert_eq!(rv, vec![vec![0]]); @@ -414,7 +636,10 @@ pub mod tests { let rv = verify_shreds_cpu(&batch, &leader_slots); assert_eq!(rv, vec![vec![0]]); - let leader_slots = [(slot, keypair.pubkey())].iter().cloned().collect(); + let leader_slots = [(slot, keypair.pubkey().to_bytes())] + .iter() + .cloned() + .collect(); batch[0].packets[0].meta.size = 0; let rv = verify_shreds_cpu(&batch, &leader_slots); assert_eq!(rv, vec![vec![0]]); @@ -436,10 +661,13 @@ pub mod tests { batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload); batch[0].packets[0].meta.size = shred.payload.len(); - let leader_slots = [(slot, keypair.pubkey()), (std::u64::MAX, Pubkey::default())] - .iter() - .cloned() - .collect(); + let leader_slots = [ + (slot, keypair.pubkey().to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); let rv = verify_shreds_gpu( &batch, &leader_slots, @@ -451,8 +679,8 @@ pub mod tests { let wrong_keypair = Keypair::new(); let leader_slots = [ - (slot, wrong_keypair.pubkey()), - (std::u64::MAX, Pubkey::default()), + (slot, wrong_keypair.pubkey().to_bytes()), + (std::u64::MAX, [0u8; 32]), ] .iter() .cloned() @@ -466,10 +694,7 @@ pub mod tests { ); assert_eq!(rv, vec![vec![0]]); - let leader_slots = [(std::u64::MAX, Pubkey::default())] - .iter() - .cloned() - .collect(); + let leader_slots = [(std::u64::MAX, [0u8; 32])].iter().cloned().collect(); let rv = verify_shreds_gpu( &batch, &leader_slots, @@ -480,10 +705,13 @@ pub mod tests { assert_eq!(rv, vec![vec![0]]); batch[0].packets[0].meta.size = 0; - let leader_slots = [(slot, keypair.pubkey()), (std::u64::MAX, Pubkey::default())] - .iter() - .cloned() - .collect(); + let leader_slots = [ + (slot, keypair.pubkey().to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); let rv = verify_shreds_gpu( &batch, &leader_slots, @@ -494,6 +722,101 @@ pub mod tests { assert_eq!(rv, vec![vec![0]]); } + #[test] + fn test_sigverify_shreds_sign_gpu() { + solana_logger::setup(); + let recycler_offsets = Recycler::default(); + let recycler_pubkeys = Recycler::default(); + let recycler_secrets = Recycler::default(); + let recycler_out = Recycler::default(); + + let mut batch = [Packets::default()]; + let slot = 0xdeadc0de; + let keypair = Keypair::new(); + let shred = Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true); + batch[0].packets.resize(1, Packet::default()); + batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload); + batch[0].packets[0].meta.size = shred.payload.len(); + let pubkeys = [ + (slot, keypair.pubkey().to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); + let privkeys = [ + (slot, keypair.secret.to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); + //unsigned + let rv = verify_shreds_gpu( + &batch, + &pubkeys, + &recycler_offsets, + &recycler_pubkeys, + &recycler_out, + ); + assert_eq!(rv, vec![vec![0]]); + //signed + sign_shreds_gpu( + &mut batch, + &pubkeys, + &privkeys, + &recycler_offsets, + &recycler_pubkeys, + &recycler_secrets, + &recycler_out, + ); + let rv = verify_shreds_cpu(&batch, &pubkeys); + assert_eq!(rv, vec![vec![1]]); + + let rv = verify_shreds_gpu( + &batch, + &pubkeys, + &recycler_offsets, + &recycler_pubkeys, + &recycler_out, + ); + assert_eq!(rv, vec![vec![1]]); + } + + #[test] + fn test_sigverify_shreds_sign_cpu() { + solana_logger::setup(); + + let mut batch = [Packets::default()]; + let slot = 0xdeadc0de; + let keypair = Keypair::new(); + let shred = Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true); + batch[0].packets.resize(1, Packet::default()); + batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload); + batch[0].packets[0].meta.size = shred.payload.len(); + let pubkeys = [ + (slot, keypair.pubkey().to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); + let privkeys = [ + (slot, keypair.secret.to_bytes()), + (std::u64::MAX, [0u8; 32]), + ] + .iter() + .cloned() + .collect(); + //unsigned + let rv = verify_shreds_cpu(&batch, &pubkeys); + assert_eq!(rv, vec![vec![0]]); + //signed + sign_shreds_cpu(&mut batch, &pubkeys, &privkeys); + let rv = verify_shreds_cpu(&batch, &pubkeys); + assert_eq!(rv, vec![vec![1]]); + } + #[test] fn test_sigverify_shreds_read_slots() { solana_logger::setup(); diff --git a/fetch-perf-libs.sh b/fetch-perf-libs.sh index d7c2edb80..1a08c6155 100755 --- a/fetch-perf-libs.sh +++ b/fetch-perf-libs.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PERF_LIBS_VERSION=v0.15.0 +PERF_LIBS_VERSION=v0.16.1 VERSION=$PERF_LIBS_VERSION-1 set -e diff --git a/ledger/src/perf_libs.rs b/ledger/src/perf_libs.rs index f16b27604..a750ce24f 100644 --- a/ledger/src/perf_libs.rs +++ b/ledger/src/perf_libs.rs @@ -39,6 +39,24 @@ pub struct Api<'a> { ) -> u32, >, + #[allow(clippy::type_complexity)] + pub ed25519_sign_many: Symbol< + 'a, + unsafe extern "C" fn( + vecs: *mut Elems, + num: u32, //number of vecs + message_size: u32, //size of each element inside the elems field of the vec + total_packets: u32, + total_signatures: u32, + message_lens: *const u32, + pubkey_offsets: *const u32, + privkey_offsets: *const u32, + signed_message_offsets: *const u32, + sgnatures_out: *mut u8, //combined length of all the items in vecs + use_non_default_stream: u8, + ) -> u32, + >, + pub chacha_cbc_encrypt_many_sample: Symbol< 'a, unsafe extern "C" fn( diff --git a/sdk/src/pubkey.rs b/sdk/src/pubkey.rs index 18e7995dc..da653f667 100644 --- a/sdk/src/pubkey.rs +++ b/sdk/src/pubkey.rs @@ -58,6 +58,9 @@ impl Pubkey { sol_log_64(0, 0, 0, i as u64, u64::from(*k)); } } + pub fn to_bytes(self) -> [u8; 32] { + self.0 + } } impl AsRef<[u8]> for Pubkey {