diff --git a/Cargo.lock b/Cargo.lock index ddd13c0c..7b514a8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2169,6 +2169,7 @@ dependencies = [ name = "ethlambda-storage" version = "0.1.0" dependencies = [ + "ethlambda-crypto", "ethlambda-types", "leansig", "libssz", @@ -2201,7 +2202,6 @@ dependencies = [ "datatest-stable 0.3.3", "ethlambda-test-fixtures", "hex", - "leansig", "libssz", "libssz-derive", "libssz-merkle", diff --git a/bin/ethlambda/src/main.rs b/bin/ethlambda/src/main.rs index 33e242e9..df4893e6 100644 --- a/bin/ethlambda/src/main.rs +++ b/bin/ethlambda/src/main.rs @@ -36,6 +36,7 @@ use cli::CliOptions; use ethlambda_blockchain::MILLISECONDS_PER_SLOT; use ethlambda_blockchain::block_builder::ProposerConfig; use ethlambda_blockchain::key_manager::ValidatorKeyPair; +use ethlambda_crypto::signature::ValidatorSecretKey; use ethlambda_network_api::{InitBlockChain, InitP2P, ToBlockChainToP2PRef, ToP2PToBlockChainRef}; use ethlambda_p2p::{ Bootnode, P2P, PeerId, SwarmConfig, attestation_subscription_subnets, build_swarm, parse_enrs, @@ -44,7 +45,6 @@ use ethlambda_types::primitives::{H256, HashTreeRoot as _}; use ethlambda_types::{ aggregator::AggregatorController, genesis::GenesisConfig, - signature::ValidatorSecretKey, state::{State, ValidatorPubkeyBytes}, }; use eyre::WrapErr; diff --git a/crates/blockchain/src/aggregation.rs b/crates/blockchain/src/aggregation.rs index 2a62b2a6..f3ec6bbe 100644 --- a/crates/blockchain/src/aggregation.rs +++ b/crates/blockchain/src/aggregation.rs @@ -20,13 +20,13 @@ use std::collections::{HashMap, HashSet}; use std::time::{Duration, Instant, SystemTime}; use ethlambda_crypto::aggregate_mixed; +use ethlambda_crypto::signature::{ValidatorPubkeys, ValidatorPublicKey, ValidatorSignature}; use ethlambda_storage::Store; use ethlambda_types::{ ShortRoot, attestation::{AggregationBits, AttestationData, HashedAttestationData}, block::{ByteList512KiB, SingleMessageAggregate}, primitives::H256, - signature::{ValidatorPublicKey, ValidatorSignature}, state::Validator, }; use spawned_concurrency::message::Message; @@ -796,7 +796,7 @@ mod tests { /// never checks signature validity, only that it clones and carries a /// resolvable id — mirrors `ethlambda_storage::store::tests::make_dummy_sig`. fn dummy_sig() -> ValidatorSignature { - use ethlambda_types::signature::LeanSignatureScheme; + use ethlambda_crypto::signature::LeanSignatureScheme; use leansig::{serialization::Serializable, signature::SignatureScheme}; use rand::{SeedableRng, rngs::StdRng}; diff --git a/crates/blockchain/src/block_builder.rs b/crates/blockchain/src/block_builder.rs index 787c55b4..b6adec9f 100644 --- a/crates/blockchain/src/block_builder.rs +++ b/crates/blockchain/src/block_builder.rs @@ -15,7 +15,7 @@ use std::{ time::Instant, }; -use ethlambda_crypto::aggregate_proofs; +use ethlambda_crypto::{aggregate_proofs, signature::ValidatorPubkeys}; use ethlambda_state_transition::{ attestation_data_matches_chain, justified_slots_ops, process_block, process_slots, slot_is_justifiable_after, diff --git a/crates/blockchain/src/key_manager.rs b/crates/blockchain/src/key_manager.rs index cb58c354..eb2777a8 100644 --- a/crates/blockchain/src/key_manager.rs +++ b/crates/blockchain/src/key_manager.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::time::Instant; +use ethlambda_crypto::signature::{ValidatorSecretKey, ValidatorSignature}; use ethlambda_types::{ attestation::{AttestationData, XmssSignature}, primitives::{H256, HashTreeRoot as _}, - signature::{ValidatorSecretKey, ValidatorSignature}, }; use tracing::{info, warn}; diff --git a/crates/blockchain/src/lib.rs b/crates/blockchain/src/lib.rs index b2929ab6..a06d82f9 100644 --- a/crates/blockchain/src/lib.rs +++ b/crates/blockchain/src/lib.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use std::time::{Duration, Instant, SystemTime}; +use ethlambda_crypto::signature::{ValidatorPubkeys, ValidatorPublicKey, ValidatorSignature}; use ethlambda_network_api::{BlockChainToP2PRef, InitP2P}; use ethlambda_state_transition::is_proposer; use ethlambda_storage::{ALL_TABLES, Store}; @@ -10,7 +11,6 @@ use ethlambda_types::{ attestation::{SignedAggregatedAttestation, SignedAttestation}, block::{ByteList512KiB, MultiMessageAggregate, SignedBlock}, primitives::{H256, HashTreeRoot as _}, - signature::{ValidatorPublicKey, ValidatorSignature}, }; use crate::aggregation::{ diff --git a/crates/blockchain/src/reaggregate.rs b/crates/blockchain/src/reaggregate.rs index f47d6c51..aa36143b 100644 --- a/crates/blockchain/src/reaggregate.rs +++ b/crates/blockchain/src/reaggregate.rs @@ -24,6 +24,7 @@ use std::collections::HashSet; +use ethlambda_crypto::signature::{ValidatorPubkeys, ValidatorPublicKey}; use ethlambda_storage::Store; use ethlambda_types::{ attestation::{ @@ -32,7 +33,6 @@ use ethlambda_types::{ }, block::{SignedBlock, SingleMessageAggregate}, primitives::{H256, HashTreeRoot as _}, - signature::ValidatorPublicKey, }; use tracing::{debug, warn}; diff --git a/crates/blockchain/src/store.rs b/crates/blockchain/src/store.rs index 2bdf46b0..c0e3e7ce 100644 --- a/crates/blockchain/src/store.rs +++ b/crates/blockchain/src/store.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; +use ethlambda_crypto::signature::{ValidatorPubkeys, ValidatorPublicKey, ValidatorSignature}; use ethlambda_state_transition::{is_proposer, slot_is_justifiable_after}; use ethlambda_storage::{ForkCheckpoints, Store}; use ethlambda_types::{ @@ -11,7 +12,6 @@ use ethlambda_types::{ block::{Block, BlockHeader, SignedBlock, SingleMessageAggregate}, checkpoint::Checkpoint, primitives::{H256, HashTreeRoot as _}, - signature::{ValidatorPublicKey, ValidatorSignature}, state::{HISTORICAL_ROOTS_LIMIT, State}, }; use tracing::{info, trace, warn}; diff --git a/crates/common/crypto/src/lib.rs b/crates/common/crypto/src/lib.rs index 4e081445..51d7d282 100644 --- a/crates/common/crypto/src/lib.rs +++ b/crates/common/crypto/src/lib.rs @@ -1,10 +1,8 @@ use std::sync::Once; -use ethlambda_types::{ - block::ByteList512KiB, - primitives::H256, - signature::{ValidatorPublicKey, ValidatorSignature}, -}; +use ethlambda_types::{block::ByteList512KiB, primitives::H256}; + +use crate::signature::{ValidatorPublicKey, ValidatorSignature}; use lean_multisig::{ MultiMessageAggregateSignature as LMType2, ProofError, SingleMessageAggregateSignature as LMType1, aggregate_single_message_signatures, @@ -14,6 +12,8 @@ use lean_multisig::{ use leansig_wrapper::{XmssPublicKey as LeanSigPubKey, XmssSignature as LeanSigSignature}; use thiserror::Error; +pub mod signature; + #[cfg(feature = "shadow-integration")] pub mod shadow_cost; @@ -508,7 +508,7 @@ pub fn split_type_2_by_message( #[cfg(test)] mod tests { use super::*; - use ethlambda_types::signature::LeanSignatureScheme; + use crate::signature::LeanSignatureScheme; use leansig::{serialization::Serializable, signature::SignatureScheme}; use rand::{SeedableRng, rngs::StdRng}; diff --git a/crates/common/types/src/signature.rs b/crates/common/crypto/src/signature.rs similarity index 86% rename from crates/common/types/src/signature.rs rename to crates/common/crypto/src/signature.rs index fa9c8da8..7475928f 100644 --- a/crates/common/types/src/signature.rs +++ b/crates/common/crypto/src/signature.rs @@ -1,12 +1,14 @@ +//! Validator XMSS signatures, public/secret keys, and the leansig-backed +//! primitives behind them. + use std::ops::Range; +use ethlambda_types::{primitives::H256, state::Validator}; use leansig::{ serialization::Serializable, signature::{SignatureScheme, SignatureSchemeSecretKey as _, SigningError}, }; -use crate::primitives::H256; - /// The XMSS signature scheme used for validator signatures. /// /// This is a post-quantum secure signature scheme based on hash functions. @@ -25,11 +27,6 @@ pub type LeanSigSecretKey = ::SecretKey; pub type Signature = LeanSigSignature; -/// Size of an XMSS signature in bytes. -/// -/// Computed from: path(32*8*4) + rho(7*4) + hashes(46*8*4) + ssz_offsets(3*4) = 2536 -pub const SIGNATURE_SIZE: usize = 2536; - /// Error returned when parsing signature or key bytes fails. #[derive(Debug, Clone, thiserror::Error)] #[error("signature parse error: {0}")] @@ -125,6 +122,26 @@ impl ValidatorSecretKey { } } +/// Leansig-backed public-key access for [`Validator`]. +/// +/// `Validator` lives in `ethlambda-types`, which stays leansig-free, so these +/// helpers can't be inherent methods there. Import this trait to call +/// `validator.get_attestation_pubkey()` / `get_proposal_pubkey()` as before. +pub trait ValidatorPubkeys { + fn get_attestation_pubkey(&self) -> Result; + fn get_proposal_pubkey(&self) -> Result; +} + +impl ValidatorPubkeys for Validator { + fn get_attestation_pubkey(&self) -> Result { + ValidatorPublicKey::from_bytes(&self.attestation_pubkey) + } + + fn get_proposal_pubkey(&self) -> Result { + ValidatorPublicKey::from_bytes(&self.proposal_pubkey) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/common/test-fixtures/src/common.rs b/crates/common/test-fixtures/src/common.rs index 6293b897..6705292b 100644 --- a/crates/common/test-fixtures/src/common.rs +++ b/crates/common/test-fixtures/src/common.rs @@ -2,12 +2,11 @@ use ethlambda_types::{ attestation::{ AggregatedAttestation as DomainAggregatedAttestation, AggregationBits as DomainAggregationBits, AttestationData as DomainAttestationData, - XmssSignature, + SIGNATURE_SIZE, XmssSignature, }, block::{Block as DomainBlock, BlockBody as DomainBlockBody}, checkpoint::Checkpoint as DomainCheckpoint, primitives::H256, - signature::SIGNATURE_SIZE, state::{ ChainConfig, JustificationValidators, JustifiedSlots, State, Validator as DomainValidator, ValidatorPubkeyBytes, diff --git a/crates/common/types/Cargo.toml b/crates/common/types/Cargo.toml index 1de09a67..383f77a3 100644 --- a/crates/common/types/Cargo.toml +++ b/crates/common/types/Cargo.toml @@ -14,8 +14,6 @@ thiserror.workspace = true serde.workspace = true hex.workspace = true -leansig.workspace = true - libssz.workspace = true libssz-derive.workspace = true libssz-merkle.workspace = true diff --git a/crates/common/types/src/attestation.rs b/crates/common/types/src/attestation.rs index 0d68addb..91d00105 100644 --- a/crates/common/types/src/attestation.rs +++ b/crates/common/types/src/attestation.rs @@ -7,7 +7,6 @@ use crate::{ block::SingleMessageAggregate, checkpoint::Checkpoint, primitives::{H256, HashTreeRoot as _}, - signature::SIGNATURE_SIZE, }; /// Validator specific attestation wrapping shared attestation data. @@ -55,6 +54,13 @@ pub struct SignedAttestation { pub signature: XmssSignature, } +/// Size of an XMSS signature in bytes. +/// +/// Computed from: path(32*8*4) + rho(7*4) + hashes(46*8*4) + ssz_offsets(3*4) = 2536. +/// This is the SSZ wire size, independent of the `leansig` scheme itself, so it +/// lives here (leansig-free) rather than in `ethlambda-crypto`. +pub const SIGNATURE_SIZE: usize = 2536; + /// XMSS signature as a fixed-length byte vector (`SIGNATURE_SIZE` bytes). pub type XmssSignature = SszVector; diff --git a/crates/common/types/src/lib.rs b/crates/common/types/src/lib.rs index 6db9a590..88ba98b9 100644 --- a/crates/common/types/src/lib.rs +++ b/crates/common/types/src/lib.rs @@ -5,7 +5,6 @@ pub mod checkpoint; pub mod constants; pub mod genesis; pub mod primitives; -pub mod signature; pub mod state; /// Display helper for truncated root hashes (8 hex chars) diff --git a/crates/common/types/src/state.rs b/crates/common/types/src/state.rs index 26ff110d..6cc25bb4 100644 --- a/crates/common/types/src/state.rs +++ b/crates/common/types/src/state.rs @@ -6,7 +6,6 @@ use crate::{ block::{Block, BlockBody, BlockHeader}, checkpoint::Checkpoint, primitives::{self, H256}, - signature::{SignatureParseError, ValidatorPublicKey}, }; // Convenience trait for calling hash_tree_root() without a hasher argument @@ -85,16 +84,6 @@ where serializer.serialize_str(&hex::encode(pubkey)) } -impl Validator { - pub fn get_attestation_pubkey(&self) -> Result { - ValidatorPublicKey::from_bytes(&self.attestation_pubkey) - } - - pub fn get_proposal_pubkey(&self) -> Result { - ValidatorPublicKey::from_bytes(&self.proposal_pubkey) - } -} - pub type ValidatorPubkeyBytes = [u8; 52]; impl State { diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 7381a53e..035d802a 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -10,6 +10,7 @@ rust-version.workspace = true version.workspace = true [dependencies] +ethlambda-crypto.workspace = true ethlambda-types.workspace = true tracing.workspace = true diff --git a/crates/storage/src/store.rs b/crates/storage/src/store.rs index 83f1e8fc..d5cac0ed 100644 --- a/crates/storage/src/store.rs +++ b/crates/storage/src/store.rs @@ -7,6 +7,7 @@ use lru::LruCache; use crate::api::{StorageBackend, StorageReadView, StorageWriteBatch, Table}; use crate::error::Error; +use ethlambda_crypto::signature::ValidatorSignature; use ethlambda_types::{ attestation::{AggregationBits, AttestationData, HashedAttestationData, bits_is_subset}, block::{ @@ -14,7 +15,6 @@ use ethlambda_types::{ }, checkpoint::Checkpoint, primitives::{H256, HashTreeRoot as _}, - signature::ValidatorSignature, state::{ChainConfig, State, anchor_pair_is_consistent}, }; use libssz::{SszDecode, SszEncode}; @@ -2695,7 +2695,7 @@ mod tests { // ============ GossipSignatureBuffer Tests ============ fn make_dummy_sig() -> ValidatorSignature { - use ethlambda_types::signature::LeanSignatureScheme; + use ethlambda_crypto::signature::LeanSignatureScheme; use leansig::{serialization::Serializable, signature::SignatureScheme}; use rand::{SeedableRng, rngs::StdRng};