Embed trusted setup in network config (#3851)
* Load trusted setup in network config * Fix trusted setup serialize and deserialize * Load trusted setup from hardcoded preset instead of a file * Truncate after deserialising trusted setup * Fix beacon node script * Remove hardcoded setup file * Add length checks
This commit is contained in:
parent
33ff84743d
commit
ba410c3012
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -472,6 +472,7 @@ dependencies = [
|
|||||||
"node_test_rig",
|
"node_test_rig",
|
||||||
"sensitive_url",
|
"sensitive_url",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"slasher",
|
"slasher",
|
||||||
"slog",
|
"slog",
|
||||||
"store",
|
"store",
|
||||||
@ -787,7 +788,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "c-kzg"
|
name = "c-kzg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pawanjay176/c-kzg-4844?rev=69bde8f4e0bbf0da30d92601b7db138bdd7e6a04#69bde8f4e0bbf0da30d92601b7db138bdd7e6a04"
|
source = "git+https://github.com/pawanjay176/c-kzg-4844?rev=c9e4fa0dabdd000738b7fcdf85a72880a5da8748#c9e4fa0dabdd000738b7fcdf85a72880a5da8748"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1902,6 +1903,8 @@ dependencies = [
|
|||||||
"enr",
|
"enr",
|
||||||
"eth2_config",
|
"eth2_config",
|
||||||
"eth2_ssz",
|
"eth2_ssz",
|
||||||
|
"kzg",
|
||||||
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"types",
|
"types",
|
||||||
|
@ -39,6 +39,7 @@ eth2_network_config = { path = "../common/eth2_network_config" }
|
|||||||
execution_layer = { path = "execution_layer" }
|
execution_layer = { path = "execution_layer" }
|
||||||
lighthouse_network = { path = "./lighthouse_network" }
|
lighthouse_network = { path = "./lighthouse_network" }
|
||||||
serde = "1.0.116"
|
serde = "1.0.116"
|
||||||
|
serde_json = "1.0.58"
|
||||||
clap_utils = { path = "../common/clap_utils" }
|
clap_utils = { path = "../common/clap_utils" }
|
||||||
hyper = "0.14.4"
|
hyper = "0.14.4"
|
||||||
lighthouse_version = { path = "../common/lighthouse_version" }
|
lighthouse_version = { path = "../common/lighthouse_version" }
|
||||||
|
@ -21,7 +21,7 @@ use eth1::Config as Eth1Config;
|
|||||||
use execution_layer::ExecutionLayer;
|
use execution_layer::ExecutionLayer;
|
||||||
use fork_choice::{ForkChoice, ResetPayloadStatuses};
|
use fork_choice::{ForkChoice, ResetPayloadStatuses};
|
||||||
use futures::channel::mpsc::Sender;
|
use futures::channel::mpsc::Sender;
|
||||||
use kzg::Kzg;
|
use kzg::{Kzg, TrustedSetup};
|
||||||
use operation_pool::{OperationPool, PersistedOperationPool};
|
use operation_pool::{OperationPool, PersistedOperationPool};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use proto_array::ReOrgThreshold;
|
use proto_array::ReOrgThreshold;
|
||||||
@ -29,7 +29,6 @@ use slasher::Slasher;
|
|||||||
use slog::{crit, error, info, Logger};
|
use slog::{crit, error, info, Logger};
|
||||||
use slot_clock::{SlotClock, TestingSlotClock};
|
use slot_clock::{SlotClock, TestingSlotClock};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use store::{Error as StoreError, HotColdDB, ItemStore, KeyValueStoreOp};
|
use store::{Error as StoreError, HotColdDB, ItemStore, KeyValueStoreOp};
|
||||||
@ -97,7 +96,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
|
|||||||
// Pending I/O batch that is constructed during building and should be executed atomically
|
// Pending I/O batch that is constructed during building and should be executed atomically
|
||||||
// alongside `PersistedBeaconChain` storage when `BeaconChainBuilder::build` is called.
|
// alongside `PersistedBeaconChain` storage when `BeaconChainBuilder::build` is called.
|
||||||
pending_io_batch: Vec<KeyValueStoreOp>,
|
pending_io_batch: Vec<KeyValueStoreOp>,
|
||||||
trusted_setup_path: Option<PathBuf>,
|
trusted_setup: Option<TrustedSetup>,
|
||||||
task_executor: Option<TaskExecutor>,
|
task_executor: Option<TaskExecutor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +136,7 @@ where
|
|||||||
slasher: None,
|
slasher: None,
|
||||||
validator_monitor: None,
|
validator_monitor: None,
|
||||||
pending_io_batch: vec![],
|
pending_io_batch: vec![],
|
||||||
trusted_setup_path: None,
|
trusted_setup: None,
|
||||||
task_executor: None,
|
task_executor: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,8 +593,8 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trusted_setup(mut self, trusted_setup_file_path: PathBuf) -> Self {
|
pub fn trusted_setup(mut self, trusted_setup: TrustedSetup) -> Self {
|
||||||
self.trusted_setup_path = Some(trusted_setup_file_path);
|
self.trusted_setup = Some(trusted_setup);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,8 +639,8 @@ where
|
|||||||
slot_clock.now().ok_or("Unable to read slot")?
|
slot_clock.now().ok_or("Unable to read slot")?
|
||||||
};
|
};
|
||||||
|
|
||||||
let kzg = if let Some(trusted_setup_file) = self.trusted_setup_path {
|
let kzg = if let Some(trusted_setup) = self.trusted_setup {
|
||||||
let kzg = Kzg::new_from_file(trusted_setup_file)
|
let kzg = Kzg::new_from_trusted_setup(trusted_setup)
|
||||||
.map_err(|e| format!("Failed to load trusted setup: {:?}", e))?;
|
.map_err(|e| format!("Failed to load trusted setup: {:?}", e))?;
|
||||||
Some(Arc::new(kzg))
|
Some(Arc::new(kzg))
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,6 +70,7 @@ pub use events::ServerSentEventHandler;
|
|||||||
pub use execution_layer::EngineState;
|
pub use execution_layer::EngineState;
|
||||||
pub use execution_payload::NotifyExecutionLayer;
|
pub use execution_payload::NotifyExecutionLayer;
|
||||||
pub use fork_choice::{ExecutionStatus, ForkchoiceUpdateParameters};
|
pub use fork_choice::{ExecutionStatus, ForkchoiceUpdateParameters};
|
||||||
|
pub use kzg::TrustedSetup;
|
||||||
pub use metrics::scrape_for_metrics;
|
pub use metrics::scrape_for_metrics;
|
||||||
pub use parking_lot;
|
pub use parking_lot;
|
||||||
pub use slot_clock;
|
pub use slot_clock;
|
||||||
|
@ -185,8 +185,8 @@ where
|
|||||||
builder
|
builder
|
||||||
};
|
};
|
||||||
|
|
||||||
let builder = if let Some(trusted_setup_file) = config.trusted_setup_file {
|
let builder = if let Some(trusted_setup) = config.trusted_setup {
|
||||||
builder.trusted_setup(trusted_setup_file)
|
builder.trusted_setup(trusted_setup)
|
||||||
} else {
|
} else {
|
||||||
builder
|
builder
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use beacon_chain::TrustedSetup;
|
||||||
use directory::DEFAULT_ROOT_DIR;
|
use directory::DEFAULT_ROOT_DIR;
|
||||||
use environment::LoggerConfig;
|
use environment::LoggerConfig;
|
||||||
use network::NetworkConfig;
|
use network::NetworkConfig;
|
||||||
@ -68,7 +69,7 @@ pub struct Config {
|
|||||||
pub chain: beacon_chain::ChainConfig,
|
pub chain: beacon_chain::ChainConfig,
|
||||||
pub eth1: eth1::Config,
|
pub eth1: eth1::Config,
|
||||||
pub execution_layer: Option<execution_layer::Config>,
|
pub execution_layer: Option<execution_layer::Config>,
|
||||||
pub trusted_setup_file: Option<PathBuf>,
|
pub trusted_setup: Option<TrustedSetup>,
|
||||||
pub http_api: http_api::Config,
|
pub http_api: http_api::Config,
|
||||||
pub http_metrics: http_metrics::Config,
|
pub http_metrics: http_metrics::Config,
|
||||||
pub monitoring_api: Option<monitoring_api::Config>,
|
pub monitoring_api: Option<monitoring_api::Config>,
|
||||||
@ -91,7 +92,7 @@ impl Default for Config {
|
|||||||
sync_eth1_chain: false,
|
sync_eth1_chain: false,
|
||||||
eth1: <_>::default(),
|
eth1: <_>::default(),
|
||||||
execution_layer: None,
|
execution_layer: None,
|
||||||
trusted_setup_file: None,
|
trusted_setup: None,
|
||||||
graffiti: Graffiti::default(),
|
graffiti: Graffiti::default(),
|
||||||
http_api: <_>::default(),
|
http_api: <_>::default(),
|
||||||
http_metrics: <_>::default(),
|
http_metrics: <_>::default(),
|
||||||
|
@ -513,13 +513,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
)
|
)
|
||||||
/* 4844 settings */
|
/* 4844 settings */
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("trusted-setup-file")
|
Arg::with_name("trusted-setup-file-override")
|
||||||
.long("trusted-setup-file")
|
.long("trusted-setup-file-override")
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("File containing the trusted setup parameters. \
|
.help("Path to a json file containing the trusted setup params. \
|
||||||
NOTE: This is only for the devnet, the trusted setup params \
|
NOTE: This will override the trusted setup that is generated \
|
||||||
must be embedded into the ethspec once parameter loading \
|
from the mainnet kzg ceremony. Use with caution")
|
||||||
is supported in the ckzg library")
|
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
/*
|
/*
|
||||||
|
@ -2,6 +2,7 @@ use beacon_chain::chain_config::{
|
|||||||
ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
|
ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
|
||||||
DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_RE_ORG_THRESHOLD,
|
DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_RE_ORG_THRESHOLD,
|
||||||
};
|
};
|
||||||
|
use beacon_chain::TrustedSetup;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG;
|
use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG;
|
||||||
use client::{ClientConfig, ClientGenesis};
|
use client::{ClientConfig, ClientGenesis};
|
||||||
@ -371,8 +372,19 @@ pub fn get_config<E: EthSpec>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4844 params
|
// 4844 params
|
||||||
if let Some(trusted_setup_file) = cli_args.value_of("trusted-setup-file") {
|
client_config.trusted_setup = context
|
||||||
client_config.trusted_setup_file = Some(PathBuf::from(trusted_setup_file));
|
.eth2_network_config
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|config| config.kzg_trusted_setup.clone());
|
||||||
|
|
||||||
|
// Override default trusted setup file if required
|
||||||
|
// TODO: consider removing this when we get closer to launch
|
||||||
|
if let Some(trusted_setup_file_path) = cli_args.value_of("trusted-setup-file-override") {
|
||||||
|
let file = std::fs::File::open(trusted_setup_file_path)
|
||||||
|
.map_err(|e| format!("Failed to open trusted setup file: {}", e))?;
|
||||||
|
let trusted_setup: TrustedSetup = serde_json::from_reader(file)
|
||||||
|
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?;
|
||||||
|
client_config.trusted_setup = Some(trusted_setup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(freezer_dir) = cli_args.value_of("freezer-dir") {
|
if let Some(freezer_dir) = cli_args.value_of("freezer-dir") {
|
||||||
|
@ -15,7 +15,9 @@ tempfile = "3.1.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
|
serde_json = "1.0.58"
|
||||||
types = { path = "../../consensus/types"}
|
types = { path = "../../consensus/types"}
|
||||||
|
kzg = { path = "../../crypto/kzg" }
|
||||||
eth2_ssz = "0.4.1"
|
eth2_ssz = "0.4.1"
|
||||||
eth2_config = { path = "../eth2_config"}
|
eth2_config = { path = "../eth2_config"}
|
||||||
enr = { version = "0.6.2", features = ["ed25519", "k256"] }
|
enr = { version = "0.6.2", features = ["ed25519", "k256"] }
|
||||||
|
File diff suppressed because one or more lines are too long
@ -13,10 +13,11 @@
|
|||||||
|
|
||||||
use enr::{CombinedKey, Enr};
|
use enr::{CombinedKey, Enr};
|
||||||
use eth2_config::{instantiate_hardcoded_nets, HardcodedNet};
|
use eth2_config::{instantiate_hardcoded_nets, HardcodedNet};
|
||||||
|
use kzg::TrustedSetup;
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{create_dir_all, File};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use types::{BeaconState, ChainSpec, Config, EthSpec, EthSpecId};
|
use types::{BeaconState, ChainSpec, Config, Epoch, EthSpec, EthSpecId};
|
||||||
|
|
||||||
pub const DEPLOY_BLOCK_FILE: &str = "deploy_block.txt";
|
pub const DEPLOY_BLOCK_FILE: &str = "deploy_block.txt";
|
||||||
pub const BOOT_ENR_FILE: &str = "boot_enr.yaml";
|
pub const BOOT_ENR_FILE: &str = "boot_enr.yaml";
|
||||||
@ -32,6 +33,14 @@ instantiate_hardcoded_nets!(eth2_config);
|
|||||||
|
|
||||||
pub const DEFAULT_HARDCODED_NETWORK: &str = "mainnet";
|
pub const DEFAULT_HARDCODED_NETWORK: &str = "mainnet";
|
||||||
|
|
||||||
|
/// Contains the bytes from the trusted setup json.
|
||||||
|
/// The mainnet trusted setup is also reused in testnets.
|
||||||
|
///
|
||||||
|
/// This is done to ensure that testnets also inherit the high security and
|
||||||
|
/// randomness of the mainnet kzg trusted setup ceremony.
|
||||||
|
pub const TRUSTED_SETUP: &[u8] =
|
||||||
|
include_bytes!("../built_in_network_configs/testing_trusted_setups.json");
|
||||||
|
|
||||||
/// Specifies an Eth2 network.
|
/// Specifies an Eth2 network.
|
||||||
///
|
///
|
||||||
/// See the crate-level documentation for more details.
|
/// See the crate-level documentation for more details.
|
||||||
@ -43,6 +52,7 @@ pub struct Eth2NetworkConfig {
|
|||||||
pub boot_enr: Option<Vec<Enr<CombinedKey>>>,
|
pub boot_enr: Option<Vec<Enr<CombinedKey>>>,
|
||||||
pub genesis_state_bytes: Option<Vec<u8>>,
|
pub genesis_state_bytes: Option<Vec<u8>>,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
pub kzg_trusted_setup: Option<TrustedSetup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eth2NetworkConfig {
|
impl Eth2NetworkConfig {
|
||||||
@ -58,6 +68,20 @@ impl Eth2NetworkConfig {
|
|||||||
|
|
||||||
/// Instantiates `Self` from a `HardcodedNet`.
|
/// Instantiates `Self` from a `HardcodedNet`.
|
||||||
fn from_hardcoded_net(net: &HardcodedNet) -> Result<Self, String> {
|
fn from_hardcoded_net(net: &HardcodedNet) -> Result<Self, String> {
|
||||||
|
let config: Config = serde_yaml::from_reader(net.config)
|
||||||
|
.map_err(|e| format!("Unable to parse yaml config: {:?}", e))?;
|
||||||
|
let kzg_trusted_setup = if let Some(epoch) = config.eip4844_fork_epoch {
|
||||||
|
// Only load the trusted setup if the eip4844 fork epoch is set
|
||||||
|
if epoch.value != Epoch::max_value() {
|
||||||
|
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP)
|
||||||
|
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?;
|
||||||
|
Some(trusted_setup)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
deposit_contract_deploy_block: serde_yaml::from_reader(net.deploy_block)
|
deposit_contract_deploy_block: serde_yaml::from_reader(net.deploy_block)
|
||||||
.map_err(|e| format!("Unable to parse deploy block: {:?}", e))?,
|
.map_err(|e| format!("Unable to parse deploy block: {:?}", e))?,
|
||||||
@ -67,8 +91,8 @@ impl Eth2NetworkConfig {
|
|||||||
),
|
),
|
||||||
genesis_state_bytes: Some(net.genesis_state_bytes.to_vec())
|
genesis_state_bytes: Some(net.genesis_state_bytes.to_vec())
|
||||||
.filter(|bytes| !bytes.is_empty()),
|
.filter(|bytes| !bytes.is_empty()),
|
||||||
config: serde_yaml::from_reader(net.config)
|
config,
|
||||||
.map_err(|e| format!("Unable to parse yaml config: {:?}", e))?,
|
kzg_trusted_setup,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +218,7 @@ impl Eth2NetworkConfig {
|
|||||||
|
|
||||||
let deposit_contract_deploy_block = load_from_file!(DEPLOY_BLOCK_FILE);
|
let deposit_contract_deploy_block = load_from_file!(DEPLOY_BLOCK_FILE);
|
||||||
let boot_enr = optional_load_from_file!(BOOT_ENR_FILE);
|
let boot_enr = optional_load_from_file!(BOOT_ENR_FILE);
|
||||||
let config = load_from_file!(BASE_CONFIG_FILE);
|
let config: Config = load_from_file!(BASE_CONFIG_FILE);
|
||||||
|
|
||||||
// The genesis state is a special case because it uses SSZ, not YAML.
|
// The genesis state is a special case because it uses SSZ, not YAML.
|
||||||
let genesis_file_path = base_dir.join(GENESIS_STATE_FILE);
|
let genesis_file_path = base_dir.join(GENESIS_STATE_FILE);
|
||||||
@ -212,11 +236,25 @@ impl Eth2NetworkConfig {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let kzg_trusted_setup = if let Some(epoch) = config.eip4844_fork_epoch {
|
||||||
|
// Only load the trusted setup if the eip4844 fork epoch is set
|
||||||
|
if epoch.value != Epoch::max_value() {
|
||||||
|
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP)
|
||||||
|
.map_err(|e| format!("Unable to read trusted setup file: {}", e))?;
|
||||||
|
Some(trusted_setup)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
deposit_contract_deploy_block,
|
deposit_contract_deploy_block,
|
||||||
boot_enr,
|
boot_enr,
|
||||||
genesis_state_bytes,
|
genesis_state_bytes,
|
||||||
config,
|
config,
|
||||||
|
kzg_trusted_setup,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ eth2_serde_utils = "0.1.1"
|
|||||||
hex = "0.4.2"
|
hex = "0.4.2"
|
||||||
eth2_hashing = "0.3.0"
|
eth2_hashing = "0.3.0"
|
||||||
ethereum-types = "0.12.1"
|
ethereum-types = "0.12.1"
|
||||||
c-kzg = {git = "https://github.com/pawanjay176/c-kzg-4844", rev = "69bde8f4e0bbf0da30d92601b7db138bdd7e6a04" }
|
c-kzg = {git = "https://github.com/pawanjay176/c-kzg-4844", rev = "c9e4fa0dabdd000738b7fcdf85a72880a5da8748" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["mainnet-spec"]
|
default = ["mainnet-spec"]
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
mod kzg_commitment;
|
mod kzg_commitment;
|
||||||
mod kzg_proof;
|
mod kzg_proof;
|
||||||
|
mod trusted_setup;
|
||||||
|
|
||||||
pub use crate::{kzg_commitment::KzgCommitment, kzg_proof::KzgProof};
|
pub use crate::{kzg_commitment::KzgCommitment, kzg_proof::KzgProof, trusted_setup::TrustedSetup};
|
||||||
pub use c_kzg::bytes_to_g1;
|
pub use c_kzg::bytes_to_g1;
|
||||||
pub use c_kzg::{
|
pub use c_kzg::{
|
||||||
Error as CKzgError, KZGSettings, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT,
|
Blob, Error as CKzgError, KzgSettings, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT,
|
||||||
FIELD_ELEMENTS_PER_BLOB,
|
FIELD_ELEMENTS_PER_BLOB,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// The consensus type `Blob` is generic over EthSpec, so it cannot be imported
|
|
||||||
/// in this crate without creating a cyclic dependency between the kzg and consensus/types crates.
|
|
||||||
/// So need to use a Vec here unless we think of a smarter way of doing this
|
|
||||||
type Blob = [u8; BYTES_PER_BLOB];
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
/// TODO(pawan): add docs after the c_kzg interface changes to bytes only.
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
InvalidTrustedSetup(CKzgError),
|
InvalidTrustedSetup(CKzgError),
|
||||||
InvalidKzgCommitment(CKzgError),
|
InvalidKzgCommitment(CKzgError),
|
||||||
@ -27,23 +24,46 @@ pub enum Error {
|
|||||||
|
|
||||||
/// A wrapper over a kzg library that holds the trusted setup parameters.
|
/// A wrapper over a kzg library that holds the trusted setup parameters.
|
||||||
pub struct Kzg {
|
pub struct Kzg {
|
||||||
trusted_setup: KZGSettings,
|
trusted_setup: KzgSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kzg {
|
impl Kzg {
|
||||||
pub fn new_from_file(file_path: PathBuf) -> Result<Self, Error> {
|
/// Load the kzg trusted setup parameters from a vec of G1 and G2 points.
|
||||||
|
///
|
||||||
|
/// The number of G1 points should be equal to FIELD_ELEMENTS_PER_BLOB
|
||||||
|
/// Note: this number changes based on the preset values.
|
||||||
|
/// The number of G2 points should be equal to 65.
|
||||||
|
pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result<Self, Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
trusted_setup: KZGSettings::load_trusted_setup_file(file_path)
|
trusted_setup: KzgSettings::load_trusted_setup(
|
||||||
|
trusted_setup.g1_points(),
|
||||||
|
trusted_setup.g2_points(),
|
||||||
|
)
|
||||||
.map_err(Error::InvalidTrustedSetup)?,
|
.map_err(Error::InvalidTrustedSetup)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads a trusted setup given the path to the file containing the trusted setup values.
|
||||||
|
/// The format is specified in `c_kzg::KzgSettings::load_trusted_setup_file`.
|
||||||
|
///
|
||||||
|
/// Note: This function will likely be deprecated. Use `Kzg::new_from_trusted_setup` instead.
|
||||||
|
#[deprecated]
|
||||||
|
pub fn new_from_file(file_path: PathBuf) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
trusted_setup: KzgSettings::load_trusted_setup_file(file_path)
|
||||||
|
.map_err(Error::InvalidTrustedSetup)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the aggregated kzg proof given an array of blobs.
|
||||||
pub fn compute_aggregate_kzg_proof(&self, blobs: &[Blob]) -> Result<KzgProof, Error> {
|
pub fn compute_aggregate_kzg_proof(&self, blobs: &[Blob]) -> Result<KzgProof, Error> {
|
||||||
c_kzg::KZGProof::compute_aggregate_kzg_proof(blobs, &self.trusted_setup)
|
c_kzg::KzgProof::compute_aggregate_kzg_proof(blobs, &self.trusted_setup)
|
||||||
.map_err(Error::KzgProofComputationFailed)
|
.map_err(Error::KzgProofComputationFailed)
|
||||||
.map(|proof| KzgProof(proof.to_bytes()))
|
.map(|proof| KzgProof(proof.to_bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify an aggregate kzg proof given the blobs that generated the proof, the kzg commitments
|
||||||
|
/// and the kzg proof.
|
||||||
pub fn verify_aggregate_kzg_proof(
|
pub fn verify_aggregate_kzg_proof(
|
||||||
&self,
|
&self,
|
||||||
blobs: &[Blob],
|
blobs: &[Blob],
|
||||||
@ -58,19 +78,20 @@ impl Kzg {
|
|||||||
let commitments = expected_kzg_commitments
|
let commitments = expected_kzg_commitments
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|comm| {
|
.map(|comm| {
|
||||||
c_kzg::KZGCommitment::from_bytes(&comm.0).map_err(Error::InvalidKzgCommitment)
|
c_kzg::KzgCommitment::from_bytes(&comm.0).map_err(Error::InvalidKzgCommitment)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<c_kzg::KZGCommitment>, Error>>()?;
|
.collect::<Result<Vec<c_kzg::KzgCommitment>, Error>>()?;
|
||||||
let proof =
|
let proof =
|
||||||
c_kzg::KZGProof::from_bytes(&kzg_aggregated_proof.0).map_err(Error::InvalidKzgProof)?;
|
c_kzg::KzgProof::from_bytes(&kzg_aggregated_proof.0).map_err(Error::InvalidKzgProof)?;
|
||||||
proof
|
proof
|
||||||
.verify_aggregate_kzg_proof(blobs, &commitments, &self.trusted_setup)
|
.verify_aggregate_kzg_proof(blobs, &commitments, &self.trusted_setup)
|
||||||
.map_err(Error::InvalidKzgProof)
|
.map_err(Error::InvalidKzgProof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a blob to a kzg commitment.
|
||||||
pub fn blob_to_kzg_commitment(&self, blob: Blob) -> KzgCommitment {
|
pub fn blob_to_kzg_commitment(&self, blob: Blob) -> KzgCommitment {
|
||||||
KzgCommitment(
|
KzgCommitment(
|
||||||
c_kzg::KZGCommitment::blob_to_kzg_commitment(blob, &self.trusted_setup).to_bytes(),
|
c_kzg::KzgCommitment::blob_to_kzg_commitment(blob, &self.trusted_setup).to_bytes(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
crypto/kzg/src/trusted_setup.rs
Normal file
160
crypto/kzg/src/trusted_setup.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use c_kzg::{BYTES_PER_G1_POINT, BYTES_PER_G2_POINT, FIELD_ELEMENTS_PER_BLOB};
|
||||||
|
use serde::{
|
||||||
|
de::{self, Deserializer, Visitor},
|
||||||
|
Deserialize, Serialize,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Wrapper over a BLS G1 point's byte representation.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
struct G1Point([u8; BYTES_PER_G1_POINT]);
|
||||||
|
|
||||||
|
/// Wrapper over a BLS G2 point's byte representation.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
struct G2Point([u8; BYTES_PER_G2_POINT]);
|
||||||
|
|
||||||
|
/// Contains the trusted setup parameters that are required to instantiate a
|
||||||
|
/// `c_kzg::KzgSettings` object.
|
||||||
|
///
|
||||||
|
/// The serialize/deserialize implementations are written according to
|
||||||
|
/// the format specified in the the ethereum consensus specs trusted setup files.
|
||||||
|
///
|
||||||
|
/// See https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/trusted_setups/testing_trusted_setups.json
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TrustedSetup {
|
||||||
|
#[serde(rename = "setup_G1")]
|
||||||
|
#[serde(deserialize_with = "deserialize_g1_points")]
|
||||||
|
g1_points: Vec<G1Point>,
|
||||||
|
#[serde(rename = "setup_G2")]
|
||||||
|
g2_points: Vec<G2Point>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrustedSetup {
|
||||||
|
pub fn g1_points(&self) -> Vec<[u8; BYTES_PER_G1_POINT]> {
|
||||||
|
self.g1_points.iter().map(|p| p.0).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn g2_points(&self) -> Vec<[u8; BYTES_PER_G2_POINT]> {
|
||||||
|
self.g2_points.iter().map(|p| p.0).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn g1_len(&self) -> usize {
|
||||||
|
self.g1_points.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for G1Point {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let point = hex::encode(self.0);
|
||||||
|
serializer.serialize_str(&point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for G2Point {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let point = hex::encode(self.0);
|
||||||
|
serializer.serialize_str(&point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for G1Point {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct G1PointVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for G1PointVisitor {
|
||||||
|
type Value = G1Point;
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("A 48 byte hex encoded string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let point = hex::decode(strip_prefix(v))
|
||||||
|
.map_err(|e| de::Error::custom(format!("Failed to decode G1 point: {}", e)))?;
|
||||||
|
if point.len() != BYTES_PER_G1_POINT {
|
||||||
|
return Err(de::Error::custom(format!(
|
||||||
|
"G1 point has invalid length. Expected {} got {}",
|
||||||
|
BYTES_PER_G1_POINT,
|
||||||
|
point.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let mut res = [0; BYTES_PER_G1_POINT];
|
||||||
|
res.copy_from_slice(&point);
|
||||||
|
Ok(G1Point(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(G1PointVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for G2Point {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct G2PointVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for G2PointVisitor {
|
||||||
|
type Value = G2Point;
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("A 96 byte hex encoded string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let point = hex::decode(strip_prefix(v))
|
||||||
|
.map_err(|e| de::Error::custom(format!("Failed to decode G2 point: {}", e)))?;
|
||||||
|
if point.len() != BYTES_PER_G2_POINT {
|
||||||
|
return Err(de::Error::custom(format!(
|
||||||
|
"G2 point has invalid length. Expected {} got {}",
|
||||||
|
BYTES_PER_G2_POINT,
|
||||||
|
point.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let mut res = [0; BYTES_PER_G2_POINT];
|
||||||
|
res.copy_from_slice(&point);
|
||||||
|
Ok(G2Point(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(G2PointVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_g1_points<'de, D>(deserializer: D) -> Result<Vec<G1Point>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let mut decoded: Vec<G1Point> = serde::de::Deserialize::deserialize(deserializer)?;
|
||||||
|
// FIELD_ELEMENTS_PER_BLOB is a compile time parameter that
|
||||||
|
// depends on whether lighthouse is compiled with minimal or mainnet features.
|
||||||
|
// Minimal and mainnet trusted setup parameters differ only by the
|
||||||
|
// number of G1 points they contain.
|
||||||
|
//
|
||||||
|
// Hence, we truncate the number of G1 points after deserialisation
|
||||||
|
// to ensure that we have the right number of g1 points in the
|
||||||
|
// trusted setup.
|
||||||
|
decoded.truncate(FIELD_ELEMENTS_PER_BLOB);
|
||||||
|
Ok(decoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strip_prefix(s: &str) -> &str {
|
||||||
|
if let Some(stripped) = s.strip_prefix("0x") {
|
||||||
|
stripped
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
@ -62,5 +62,4 @@ exec $lighthouse_binary \
|
|||||||
--disable-packet-filter \
|
--disable-packet-filter \
|
||||||
--target-peers $((BN_COUNT - 1)) \
|
--target-peers $((BN_COUNT - 1)) \
|
||||||
--execution-endpoint $execution_endpoint \
|
--execution-endpoint $execution_endpoint \
|
||||||
--trusted-setup-file ./trusted_setup.txt \
|
|
||||||
--execution-jwt $execution_jwt
|
--execution-jwt $execution_jwt
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user