diff --git a/Cargo.lock b/Cargo.lock index 152ed22de..5c3817c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7663,6 +7663,15 @@ dependencies = [ [[package]] name = "serai-orchestrator" version = "0.0.1" +dependencies = [ + "ciphersuite", + "flexible-transcript", + "hex", + "rand_chacha", + "rand_core", + "zalloc", + "zeroize", +] [[package]] name = "serai-primitives" diff --git a/orchestration/Cargo.toml b/orchestration/Cargo.toml index 9588be262..fffd248af 100644 --- a/orchestration/Cargo.toml +++ b/orchestration/Cargo.toml @@ -16,3 +16,13 @@ rustdoc-args = ["--cfg", "docsrs"] workspace = true [dependencies] +hex = { version = "0.4", default-features = false, features = ["std"] } + +zeroize = { version = "1", default-features = false, features = ["std"] } +rand_core = { version = "0.6", default-features = false, features = ["std", "getrandom"] } +rand_chacha = { version = "0.3", default-features = false, features = ["std"] } + +transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std", "recommended"] } +ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std", "ristretto"] } + +zalloc = { path = "../common/zalloc" } diff --git a/orchestration/src/coins/bitcoin.rs b/orchestration/src/coins/bitcoin.rs index 1ae0438df..a5c8b21c0 100644 --- a/orchestration/src/coins/bitcoin.rs +++ b/orchestration/src/coins/bitcoin.rs @@ -40,7 +40,7 @@ EXPOSE 8332 8333 ADD /orchestration/{}/coins/bitcoin/run.sh / CMD ["/run.sh"] "#, - network.folder() + network.label() ); let run = os(Os::Debian, "", "bitcoin") + &run_bitcoin; diff --git a/orchestration/src/coins/monero.rs b/orchestration/src/coins/monero.rs index d6129306d..dcdc58b1d 100644 --- a/orchestration/src/coins/monero.rs +++ b/orchestration/src/coins/monero.rs @@ -38,7 +38,7 @@ RUN gpg --keyserver hkp://keyserver.ubuntu.com:80 --keyserver-options no-self-si # Extract it RUN tar -xvjf monero-linux-{arch}-v{MONERO_VERSION}.tar.bz2 --strip-components=1 "#, - network.folder(), + network.label(), ); let setup = mimalloc(os).to_string() + &download_monero; @@ -52,7 +52,7 @@ EXPOSE {ports} ADD /orchestration/{}/coins/{folder}/run.sh / CMD ["/run.sh"] "#, - network.folder(), + network.label(), ); let run = diff --git a/orchestration/src/coordinator.rs b/orchestration/src/coordinator.rs index 62b5c543b..c537434ae 100644 --- a/orchestration/src/coordinator.rs +++ b/orchestration/src/coordinator.rs @@ -1,8 +1,17 @@ use std::{path::Path}; +use zeroize::Zeroizing; + +use ciphersuite::{group::ff::PrimeField, Ciphersuite, Ristretto}; + use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile}; -pub fn coordinator(orchestration_path: &Path, network: Network) { +#[allow(clippy::needless_pass_by_value)] +pub fn coordinator( + orchestration_path: &Path, + network: Network, + coordinator_key: Zeroizing<::F>, +) { let db = network.db(); let longer_reattempts = if network == Network::Dev { "longer-reattempts" } else { "" }; let setup = mimalloc(Os::Debian).to_string() + @@ -18,10 +27,11 @@ RUN apt install -y ca-certificates "#; let env_vars = [ - ("MESSAGE_QUEUE_KEY", ""), - ("DB_PATH", "./coordinator-db"), - ("SERAI_KEY", ""), - ("RUST_LOG", "serai_coordinator=debug,tributary_chain=debug,tendermint=debug"), + ("MESSAGE_QUEUE_KEY", hex::encode(coordinator_key.to_repr())), + ("DB_PATH", "./coordinator-db".to_string()), + ("SERAI_KEY", String::new()), // TODO + ("SERAI_HOSTNAME", format!("serai-{}", network.label())), + ("RUST_LOG", "serai_coordinator=debug,tributary_chain=debug,tendermint=debug".to_string()), ]; let mut env_vars_str = String::new(); for (env_var, value) in env_vars { diff --git a/orchestration/src/main.rs b/orchestration/src/main.rs index 53b105775..2c08fa1b3 100644 --- a/orchestration/src/main.rs +++ b/orchestration/src/main.rs @@ -1,8 +1,18 @@ // TODO: Generate randomized RPC credentials for all services // TODO: Generate keys for a validator and the infra +use core::ops::Deref; use std::{env, path::PathBuf, io::Write, fs}; +use zeroize::Zeroizing; + +use rand_core::{RngCore, SeedableRng, OsRng}; +use rand_chacha::ChaCha20Rng; + +use transcript::{Transcript, RecommendedTranscript}; + +use ciphersuite::{group::ff::Field, Ciphersuite, Ristretto}; + mod mimalloc; use mimalloc::mimalloc; @@ -21,6 +31,10 @@ use coordinator::coordinator; mod serai; use serai::serai; +#[global_allocator] +static ALLOCATOR: zalloc::ZeroizingAlloc = + zalloc::ZeroizingAlloc(std::alloc::System); + #[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] pub enum Network { Dev, @@ -42,7 +56,7 @@ impl Network { } } - pub fn folder(&self) -> &'static str { + pub fn label(&self) -> &'static str { match self { Network::Dev => "dev", Network::Testnet => "testnet", @@ -170,7 +184,7 @@ fn dockerfiles(network: Network) { let mut orchestration_path = repo_path.clone(); orchestration_path.push("orchestration"); - orchestration_path.push(network.folder()); + orchestration_path.push(network.label()); orchestration_path }; @@ -181,13 +195,58 @@ fn dockerfiles(network: Network) { monero_wallet_rpc(&orchestration_path); } - message_queue(&orchestration_path, network); - - processor(&orchestration_path, network, "bitcoin"); - processor(&orchestration_path, network, "ethereum"); - processor(&orchestration_path, network, "monero"); - - coordinator(&orchestration_path, network); + // Generate entropy for the infrastructure keys + let mut entropy = [0; 32]; + OsRng.fill_bytes(&mut entropy); + let mut transcript = RecommendedTranscript::new(b"Serai Orchestrator Transcript"); + transcript.append_message(b"entropy", entropy); + let mut new_rng = |label| ChaCha20Rng::from_seed(transcript.rng_seed(label)); + + let mut message_queue_keys_rng = new_rng(b"message_queue_keys"); + let mut key_pair = || { + let key = Zeroizing::new(::F::random(&mut message_queue_keys_rng)); + let public = Ristretto::generator() * key.deref(); + (key, public) + }; + let coordinator_key = key_pair(); + let bitcoin_key = key_pair(); + let ethereum_key = key_pair(); + let monero_key = key_pair(); + + message_queue( + &orchestration_path, + network, + coordinator_key.1, + bitcoin_key.1, + ethereum_key.1, + monero_key.1, + ); + + let mut processor_entropy_rng = new_rng(b"processor_entropy"); + let mut new_entropy = || { + let mut res = Zeroizing::new([0; 32]); + processor_entropy_rng.fill_bytes(res.as_mut()); + res + }; + processor( + &orchestration_path, + network, + "bitcoin", + coordinator_key.1, + bitcoin_key.0, + new_entropy(), + ); + processor( + &orchestration_path, + network, + "ethereum", + coordinator_key.1, + ethereum_key.0, + new_entropy(), + ); + processor(&orchestration_path, network, "monero", coordinator_key.1, monero_key.0, new_entropy()); + + coordinator(&orchestration_path, network, coordinator_key.0); serai(&orchestration_path, network); } diff --git a/orchestration/src/message_queue.rs b/orchestration/src/message_queue.rs index a36fca71f..fb1a94213 100644 --- a/orchestration/src/message_queue.rs +++ b/orchestration/src/message_queue.rs @@ -1,18 +1,27 @@ use std::{path::Path}; +use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; + use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile}; -pub fn message_queue(orchestration_path: &Path, network: Network) { +pub fn message_queue( + orchestration_path: &Path, + network: Network, + coordinator_key: ::G, + bitcoin_key: ::G, + ethereum_key: ::G, + monero_key: ::G, +) { let setup = mimalloc(Os::Debian).to_string() + &build_serai_service(network.release(), network.db(), "serai-message-queue"); let env_vars = [ - ("COORDINATOR_KEY", ""), - ("BITCOIN_KEY", ""), - ("ETHEREUM_KEY", ""), - ("MONERO_KEY", ""), - ("DB_PATH", "./message-queue-db"), - ("RUST_LOG", "serai_message_queue=trace"), + ("COORDINATOR_KEY", hex::encode(coordinator_key.to_bytes())), + ("BITCOIN_KEY", hex::encode(bitcoin_key.to_bytes())), + ("ETHEREUM_KEY", hex::encode(ethereum_key.to_bytes())), + ("MONERO_KEY", hex::encode(monero_key.to_bytes())), + ("DB_PATH", "./message-queue-db".to_string()), + ("RUST_LOG", "serai_message_queue=trace".to_string()), ]; let mut env_vars_str = String::new(); for (env_var, value) in env_vars { diff --git a/orchestration/src/processor.rs b/orchestration/src/processor.rs index 5b22ecb6e..4c37eb451 100644 --- a/orchestration/src/processor.rs +++ b/orchestration/src/processor.rs @@ -1,8 +1,20 @@ use std::{path::Path}; +use zeroize::Zeroizing; + +use ciphersuite::{group::ff::PrimeField, Ciphersuite, Ristretto}; + use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile}; -pub fn processor(orchestration_path: &Path, network: Network, coin: &'static str) { +#[allow(clippy::needless_pass_by_value)] +pub fn processor( + orchestration_path: &Path, + network: Network, + coin: &'static str, + _coordinator_key: ::G, + coin_key: Zeroizing<::F>, + entropy: Zeroizing<[u8; 32]>, +) { let setup = mimalloc(Os::Debian).to_string() + &build_serai_service( network.release(), @@ -15,14 +27,27 @@ pub fn processor(orchestration_path: &Path, network: Network, coin: &'static str RUN apt install -y ca-certificates "#; + // TODO: Randomly generate these + const RPC_USER: &str = "serai"; + const RPC_PASS: &str = "seraidex"; + // TODO: Isolate networks + let hostname = format!("{coin}-{}", network.label()); + let port = match coin { + "bitcoin" => 8332, + "ethereum" => return, // TODO + "monero" => 18081, + _ => panic!("unrecognized external network"), + }; + let env_vars = [ - ("MESSAGE_QUEUE_KEY", ""), - ("ENTROPY", ""), - ("NETWORK", ""), - ("NETWORK_RPC_LOGIN", ""), - ("NETWORK_RPC_PORT", ""), - ("DB_PATH", "./processor-db"), - ("RUST_LOG", "serai_processor=debug"), + ("MESSAGE_QUEUE_KEY", hex::encode(coin_key.to_repr())), + ("ENTROPY", hex::encode(entropy.as_ref())), + ("NETWORK", coin.to_string()), + ("NETWORK_RPC_LOGIN", format!("{RPC_USER}:{RPC_PASS}")), + ("NETWORK_RPC_HOSTNAME", hostname), + ("NETWORK_RPC_PORT", format!("{port}")), + ("DB_PATH", "./processor-db".to_string()), + ("RUST_LOG", "serai_processor=debug".to_string()), ]; let mut env_vars_str = String::new(); for (env_var, value) in env_vars { diff --git a/orchestration/src/serai.rs b/orchestration/src/serai.rs index e12397f23..ac677dd58 100644 --- a/orchestration/src/serai.rs +++ b/orchestration/src/serai.rs @@ -19,7 +19,7 @@ EXPOSE 30333 9615 9933 9944 ADD /orchestration/{}/serai/run.sh / CMD ["/run.sh"] "#, - network.folder() + network.label() ); let run = os(Os::Debian, "", "serai") + &run_serai; diff --git a/orchestration/testnet/coins/monero/run.sh b/orchestration/testnet/coins/monero/run.sh index d1ce89fa3..a4ef851a5 100755 --- a/orchestration/testnet/coins/monero/run.sh +++ b/orchestration/testnet/coins/monero/run.sh @@ -4,7 +4,7 @@ RPC_USER="${RPC_USER:=serai}" RPC_PASS="${RPC_PASS:=seraidex}" # Run Monero -monerod --non-interactive --testnet \ +monerod --non-interactive --stagenet \ --no-zmq --rpc-bind-ip=0.0.0.0 --rpc-bind-port=18081 --confirm-external-bind \ --rpc-access-control-origins "*" --disable-rpc-ban \ --rpc-login=$RPC_USER:$RPC_PASS