From d506db48850266489459559d776b4f9ded5f1cf7 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Mon, 23 Jun 2025 18:59:23 +0200 Subject: [PATCH 1/3] Add openpgp support --- Cargo.lock | 417 +++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 2 + src/config.rs | 8 + src/main.rs | 105 +++++++++++-- 4 files changed, 516 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3dd3f7..ed26520 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,6 +220,18 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -355,6 +367,15 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "asn1-rs" version = "0.5.2" @@ -503,6 +524,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + [[package]] name = "bincode" version = "1.3.3" @@ -512,6 +539,39 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.101", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitcoin-io" version = "0.1.3" @@ -543,6 +603,15 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "blake3" version = "1.8.2" @@ -729,6 +798,17 @@ dependencies = [ "serde", ] +[[package]] +name = "buffered-reader" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f" +dependencies = [ + "bzip2", + "flate2", + "libc", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -777,6 +857,25 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "caps" version = "0.5.5" @@ -804,6 +903,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -852,6 +960,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.39" @@ -1239,6 +1358,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1326,6 +1466,15 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + [[package]] name = "encode_unicode" version = "1.0.0" @@ -1462,6 +1611,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.1.1" @@ -1663,6 +1818,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + [[package]] name = "governor" version = "0.6.3" @@ -2225,6 +2386,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -2306,6 +2476,36 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.8.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata 0.4.9", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2318,6 +2518,26 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.0", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.1", + "libc", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -2433,6 +2653,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memsec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" + [[package]] name = "merlin" version = "3.0.0" @@ -2504,6 +2730,39 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nettle" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" +dependencies = [ + "getrandom 0.2.16", + "libc", + "nettle-sys", + "thiserror 1.0.69", + "typenum", +] + +[[package]] +name = "nettle-sys" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a3f5406064d310d59b1a219d3c5c9a49caf4047b6496032e3f930876488c34" +dependencies = [ + "bindgen", + "cc", + "libc", + "pkg-config", + "tempfile", + "vcpkg", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.29.0" @@ -2814,6 +3073,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -2853,6 +3123,25 @@ dependencies = [ "num", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2913,6 +3202,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -2940,6 +3235,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "pythnet-watcher" version = "0.1.0" @@ -2949,8 +3267,10 @@ dependencies = [ "borsh 0.9.3", "clap", "hex", + "prost", "reqwest 0.12.19", "secp256k1", + "sequoia-openpgp", "serde", "serde_json", "serde_wormhole", @@ -3000,7 +3320,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.1", "rustls 0.23.27", "socket2", "thiserror 2.0.12", @@ -3021,7 +3341,7 @@ dependencies = [ "lru-slab", "rand 0.9.1", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls 0.23.27", "rustls-pki-types", "rustls-platform-verifier", @@ -3199,6 +3519,17 @@ dependencies = [ "bitflags 2.9.1", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "regex" version = "1.11.1" @@ -3364,6 +3695,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -3647,6 +3984,34 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +[[package]] +name = "sequoia-openpgp" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015e5fc3d023418b9db98ca9a7f3e90b305872eeafe5ca45c5c32b5eb335c1e8" +dependencies = [ + "anyhow", + "argon2", + "base64 0.22.1", + "buffered-reader", + "bzip2", + "chrono", + "dyn-clone", + "flate2", + "getrandom 0.2.16", + "idna", + "lalrpop", + "lalrpop-util", + "libc", + "memsec", + "nettle", + "regex", + "regex-syntax 0.8.5", + "sha1collisiondetection", + "thiserror 2.0.12", + "xxhash-rust", +] + [[package]] name = "serde" version = "1.0.219" @@ -3767,6 +4132,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1collisiondetection" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" +dependencies = [ + "digest 0.10.7", + "generic-array", +] + [[package]] name = "sha2" version = "0.9.9" @@ -6350,6 +6725,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + [[package]] name = "strsim" version = "0.11.1" @@ -6486,6 +6873,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -6575,6 +6973,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -7629,6 +8036,12 @@ dependencies = [ "time", ] +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 179b748..c484f18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,10 @@ anyhow = "1.0.98" borsh = "0.9.3" clap = { version = "4.5.39", features = ["derive", "env"] } hex = { version = "0.4.3", features = ["serde"] } +prost = "0.14.1" reqwest = { version = "0.12.19", features = ["json"] } secp256k1 = { version = "0.30.0", features = ["recovery", "rand"] } +sequoia-openpgp = "2.0.0" serde = "1.0.219" serde_wormhole = "0.1.0" sha3 = "0.10.8" diff --git a/src/config.rs b/src/config.rs index 3c6fcf5..de0785c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,11 @@ use clap::Parser; +#[derive(clap::ValueEnum, Clone, Debug)] +pub enum Mode { + Production, + Development, +} + #[derive(Parser, Clone, Debug)] pub struct RunOptions { /// The API key to use for auction server authentication. @@ -17,6 +23,8 @@ pub struct RunOptions { pub wormhole_pid: String, #[arg(long = "server-url", env = "SERVER_URL")] pub server_url: String, + #[arg(long = "mode", env = "MODE", default_value = "production")] + pub mode: Mode, } #[derive(Parser, Clone, Debug)] diff --git a/src/main.rs b/src/main.rs index 4892b82..0d8140c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,9 @@ use { borsh::BorshDeserialize, clap::Parser, posted_message::PostedMessageUnreliableData, + prost::Message, secp256k1::{rand::rngs::OsRng, PublicKey, Secp256k1, SecretKey}, + sequoia_openpgp::armor::{Kind, Reader, ReaderMode, Writer}, serde_wormhole::RawMessage, sha3::{Digest, Keccak256}, solana_account_decoder::UiAccountEncoding, @@ -16,7 +18,12 @@ use { rpc_response::{Response, RpcKeyedAccount}, }, solana_sdk::pubkey::Pubkey, - std::{fs, io::IsTerminal, str::FromStr, time::Duration}, + std::{ + fs, + io::{Cursor, IsTerminal, Read, Write}, + str::FromStr, + time::Duration, + }, tokio::time::sleep, tokio_stream::StreamExt, wormhole_sdk::{vaa::Body, Address, Chain}, @@ -160,18 +167,43 @@ async fn run_listener(input: RunListenerInput) -> Result<(), PubsubClientError> )) } -fn load_secret_key(path: String) -> SecretKey { - let bytes = fs::read(path.clone()).expect("Invalid secret key file"); - if bytes.len() == 32 { - let byte_array: [u8; 32] = bytes.try_into().expect("Invalid secret key length"); - return SecretKey::from_byte_array(&byte_array).expect("Invalid secret key length"); +#[derive(Clone, PartialEq, Message)] +pub struct GuardianKey { + #[prost(bytes = "vec", tag = "1")] + pub data: Vec, + #[prost(bool, tag = "2")] + pub unsafe_deterministic_key: bool, +} + +const GUARDIAN_KEY_ARMORED_BLOCK: &str = "WORMHOLE GUARDIAN PRIVATE KEY"; +const STANDARD_ARMOR_LINE_HEADER: &str = "PGP PRIVATE KEY BLOCK"; + +fn parse_and_verify_proto_guardian_key(content: String, mode: crate::config::Mode) -> GuardianKey { + let content = content.replace(GUARDIAN_KEY_ARMORED_BLOCK, STANDARD_ARMOR_LINE_HEADER); + let cursor = Cursor::new(content); + let mut armor_reader = Reader::from_reader(cursor, ReaderMode::Tolerant(Some(Kind::SecretKey))); + + let mut buf = Vec::new(); + armor_reader + .read_to_end(&mut buf) + .expect("Failed to read armored content"); + + let guardian_key = + GuardianKey::decode(&mut buf.as_slice()).expect("Failed to decode GuardianKey"); + + if let crate::config::Mode::Production = mode { + if guardian_key.unsafe_deterministic_key { + panic!("Unsafe deterministic key is not allowed in production mode"); + } } - let content = fs::read_to_string(path) - .expect("Invalid secret key file") - .trim() - .to_string(); - SecretKey::from_str(&content).expect("Invalid secret key") + guardian_key +} + +fn load_secret_key(run_options: config::RunOptions) -> SecretKey { + let content = fs::read_to_string(run_options.secret_key_path).expect("Failed to read file"); + let guardian_key = parse_and_verify_proto_guardian_key(content, run_options.mode); + SecretKey::from_slice(&guardian_key.data).expect("Failed to create SecretKey from bytes") } fn get_public_key(secret_key: &SecretKey) -> (PublicKey, [u8; 20]) { @@ -188,7 +220,7 @@ fn get_public_key(secret_key: &SecretKey) -> (PublicKey, [u8; 20]) { } async fn run(run_options: config::RunOptions) { - let secret_key = load_secret_key(run_options.secret_key_path); + let secret_key = load_secret_key(run_options.clone()); let client = PubsubClient::new(&run_options.pythnet_url) .await .expect("Invalid WebSocket URL"); @@ -253,9 +285,30 @@ async fn main() { // Generate keypair (secret + public key) let (secret_key, _) = secp.generate_keypair(&mut rng); - fs::write(opts.output_path.clone(), secret_key.secret_bytes()) - .expect("Failed to write secret key to file"); let (pubkey, pubkey_evm) = get_public_key(&secret_key); + + let guardian_key = GuardianKey { + data: secret_key.secret_bytes().to_vec(), + unsafe_deterministic_key: false, + }; + let mut writer = Writer::with_headers( + Vec::new(), + Kind::SecretKey, + vec![("PublicKey", format!("0x{}", hex::encode(pubkey_evm)))], + ) + .expect("Failed to create writer"); + writer + .write_all(guardian_key.encode_to_vec().as_slice()) + .expect("Failed to write GuardianKey to writer"); + let buffer = writer.finalize().expect("Failed to finalize writer"); + let armored_string = + String::from_utf8(buffer).expect("Failed to convert buffer to string"); + let armored_string = + armored_string.replace(STANDARD_ARMOR_LINE_HEADER, GUARDIAN_KEY_ARMORED_BLOCK); + + fs::write(&opts.output_path, armored_string) + .expect("Failed to write GuardianKey to file"); + tracing::info!("Generated secret key at: {}", opts.output_path); tracing::info!("Public key: {}", pubkey); tracing::info!("EVM encoded public key: 0x{}", hex::encode(pubkey_evm)); @@ -450,4 +503,28 @@ mod tests { ); assert_eq!(result.unwrap_err().to_string(), INVALID_ACCUMULATOR_ADDRESS); } + + #[test] + fn test_parse_and_verify_proto_guardian_key() { + let content = "-----BEGIN WORMHOLE GUARDIAN PRIVATE KEY----- + PublicKey: 0x30e41be3f10d3ac813f91e49e189bbb948d030be + + CiDy8xJ7/1QMhEH5l2P1hoWO80DJlirWK2GBzXcgPoGAjw== + =FQTN + -----END WORMHOLE GUARDIAN PRIVATE KEY----- + " + .to_string(); + let guardian_key = parse_and_verify_proto_guardian_key(content, config::Mode::Production); + assert!(!guardian_key.unsafe_deterministic_key); + let secret_key = SecretKey::from_slice(&guardian_key.data) + .expect("Failed to create SecretKey from bytes"); + assert_eq!( + hex::encode(secret_key.secret_bytes()), + "f2f3127bff540c8441f99763f586858ef340c9962ad62b6181cd77203e81808f", + ); + assert_eq!( + hex::encode(get_public_key(&secret_key).1), + "30e41be3f10d3ac813f91e49e189bbb948d030be", + ); + } } From cc2b7c4c9a25bf883d98a085ee3714238e3e010f Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Mon, 23 Jun 2025 19:17:01 +0200 Subject: [PATCH 2/3] Fix ci --- .github/workflows/ci-pre-commit.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-pre-commit.yml b/.github/workflows/ci-pre-commit.yml index 21c8ace..790ccea 100644 --- a/.github/workflows/ci-pre-commit.yml +++ b/.github/workflows/ci-pre-commit.yml @@ -15,6 +15,9 @@ jobs: # Need to grab the history of the PR fetch-depth: 0 + - name: Install system dependencies + run: sudo apt update && sudo apt install -y pkg-config nettle-dev + - name: Set up Python (for pre-commit) uses: actions/setup-python@v5 with: From c3d9122dad4c25f40084a1d5d7664cb0b65bca22 Mon Sep 17 00:00:00 2001 From: Danial Mehrjerdi Date: Tue, 24 Jun 2025 13:59:05 +0200 Subject: [PATCH 3/3] Address comments --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index 0d8140c..45eacff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -506,6 +506,8 @@ mod tests { #[test] fn test_parse_and_verify_proto_guardian_key() { + // The content below is generated by keygen script at: + // https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/guardiand/keygen.go let content = "-----BEGIN WORMHOLE GUARDIAN PRIVATE KEY----- PublicKey: 0x30e41be3f10d3ac813f91e49e189bbb948d030be