diff --git a/Cargo.lock b/Cargo.lock index 41e77fc7..d9eca970 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -810,6 +810,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +dependencies = [ + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -843,12 +866,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -926,7 +943,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] [[package]] @@ -935,6 +952,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitcoin-internals" version = "0.2.0" @@ -1235,9 +1261,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.38" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "jobserver", @@ -1479,6 +1505,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + [[package]] name = "coarsetime" version = "0.1.36" @@ -2901,6 +2936,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.3", + "libm", + "rand 0.9.2", + "siphasher 1.0.1", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -2997,9 +3044,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixed-hash" @@ -3415,6 +3462,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -3517,7 +3570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.32", + "rustls", "rustls-pki-types", ] @@ -4171,8 +4224,8 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio 1.47.1", "tokio-rustls", @@ -4732,14 +4785,14 @@ version = "0.24.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc4280b709ac3bb5e16cf3bad5056a0ec8df55fa89edfe996361219aadc2c7ea" dependencies = [ - "base64 0.22.1", + "base64", "futures-util", "http 1.3.1", "jsonrpsee-core", "pin-project", - "rustls 0.23.32", + "rustls", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.5.3", "soketto", "thiserror 1.0.69", "tokio 1.47.1", @@ -5225,10 +5278,10 @@ dependencies = [ "libp2p-identity", "libp2p-tls", "parking_lot 0.12.4", - "quinn 0.11.9", + "quinn", "rand 0.8.5", "ring 0.17.14", - "rustls 0.23.32", + "rustls", "socket2 0.5.10", "thiserror 1.0.69", "tokio 1.47.1", @@ -5318,13 +5371,13 @@ dependencies = [ "futures-rustls", "libp2p-core", "libp2p-identity", - "rcgen", + "rcgen 0.11.3", "ring 0.17.14", - "rustls 0.23.32", + "rustls", "rustls-webpki 0.101.7", "thiserror 1.0.69", "x509-parser 0.16.0", - "yasna", + "yasna 0.5.2", ] [[package]] @@ -5410,7 +5463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" dependencies = [ "arrayref", - "base64 0.22.1", + "base64", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -5564,7 +5617,7 @@ dependencies = [ "x25519-dalek", "x509-parser 0.17.0", "yamux 0.13.8", - "yasna", + "yasna 0.5.2", "zeroize", ] @@ -7098,7 +7151,7 @@ version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ - "base64 0.22.1", + "base64", "serde", ] @@ -7949,7 +8002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", - "bit-vec", + "bit-vec 0.8.0", "bitflags 2.9.4", "lazy_static", "num-traits", @@ -8511,10 +8564,12 @@ dependencies = [ "qpow-math", "quantus-miner-api", "quantus-runtime", - "quinn 0.10.2", + "quinn", "rand 0.8.5", - "rcgen", - "rustls 0.21.12", + "rcgen 0.14.8", + "rustls", + "rustls-pki-types", + "rustls-post-quantum", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -8530,6 +8585,7 @@ dependencies = [ "sc-transaction-pool-api", "serde", "serde_json", + "sha2 0.10.9", "sp-api", "sp-block-builder", "sp-blockchain", @@ -8649,23 +8705,6 @@ dependencies = [ "rand 0.10.0", ] -[[package]] -name = "quinn" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" -dependencies = [ - "bytes 1.10.1", - "pin-project-lite 0.2.16", - "quinn-proto 0.10.6", - "quinn-udp 0.4.1", - "rustc-hash 1.1.0", - "rustls 0.21.12", - "thiserror 1.0.69", - "tokio 1.47.1", - "tracing", -] - [[package]] name = "quinn" version = "0.11.9" @@ -8676,10 +8715,10 @@ dependencies = [ "cfg_aliases 0.2.1", "futures-io", "pin-project-lite 0.2.16", - "quinn-proto 0.11.13", - "quinn-udp 0.5.14", + "quinn-proto", + "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.32", + "rustls", "socket2 0.6.0", "thiserror 2.0.18", "tokio 1.47.1", @@ -8687,24 +8726,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "quinn-proto" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" -dependencies = [ - "bytes 1.10.1", - "rand 0.8.5", - "ring 0.16.20", - "rustc-hash 1.1.0", - "rustls 0.21.12", - "rustls-native-certs 0.6.3", - "slab", - "thiserror 1.0.69", - "tinyvec", - "tracing", -] - [[package]] name = "quinn-proto" version = "0.11.13" @@ -8712,13 +8733,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes 1.10.1", + "fastbloom", "getrandom 0.3.3", "lru-slab", "rand 0.9.2", "ring 0.17.14", "rustc-hash 2.1.1", - "rustls 0.23.32", + "rustls", "rustls-pki-types", + "rustls-platform-verifier 0.6.2", "slab", "thiserror 2.0.18", "tinyvec", @@ -8726,19 +8749,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "quinn-udp" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" -dependencies = [ - "bytes 1.10.1", - "libc", - "socket2 0.5.10", - "tracing", - "windows-sys 0.48.0", -] - [[package]] name = "quinn-udp" version = "0.5.14" @@ -8927,7 +8937,20 @@ dependencies = [ "pem", "ring 0.16.20", "time", - "yasna", + "yasna 0.5.2", +] + +[[package]] +name = "rcgen" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" +dependencies = [ + "aws-lc-rs", + "rustls-pki-types", + "time", + "x509-parser 0.18.1", + "yasna 0.6.0", ] [[package]] @@ -9214,23 +9237,13 @@ dependencies = [ "windows-sys 0.61.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring 0.17.14", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ + "aws-lc-rs", "log", "once_cell", "ring 0.17.14", @@ -9240,18 +9253,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework 2.11.1", -] - [[package]] name = "rustls-native-certs" version = "0.8.1" @@ -9261,16 +9262,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", + "security-framework", ] [[package]] @@ -9294,22 +9286,54 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls", + "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki 0.103.6", - "security-framework 3.5.0", + "security-framework", "security-framework-sys", "webpki-root-certs 0.26.11", "windows-sys 0.59.0", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.6", + "security-framework", + "security-framework-sys", + "webpki-root-certs 1.0.2", + "windows-sys 0.61.0", +] + [[package]] name = "rustls-platform-verifier-android" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-post-quantum" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da3cd9229bac4fae1f589c8f875b3c891a058ddaa26eb3bde16b5e43dc174ce" +dependencies = [ + "aws-lc-rs", + "rustls", + "rustls-webpki 0.103.6", +] + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -9326,6 +9350,7 @@ version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ + "aws-lc-rs", "ring 0.17.14", "rustls-pki-types", "untrusted 0.9.0", @@ -10057,7 +10082,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.4", "rand 0.8.5", - "rustls 0.23.32", + "rustls", "sc-client-api", "sc-network", "sc-network-types", @@ -10642,16 +10667,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "sec1" version = "0.7.3" @@ -10741,19 +10756,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.5.0" @@ -10870,7 +10872,7 @@ version = "3.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "serde", @@ -11068,7 +11070,7 @@ dependencies = [ "arrayvec 0.7.6", "async-lock", "atomic-take", - "base64 0.22.1", + "base64", "bip39", "blake2-rfc", "bs58", @@ -11121,7 +11123,7 @@ checksum = "f1bba9e591716567d704a8252feeb2f1261a286e1e2cbdd4e49e9197c34a14e2" dependencies = [ "async-channel 2.5.0", "async-lock", - "base64 0.22.1", + "base64", "blake2-rfc", "bs58", "derive_more 2.0.1", @@ -11193,7 +11195,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ - "base64 0.22.1", + "base64", "bytes 1.10.1", "futures 0.3.31", "http 1.3.1", @@ -12388,7 +12390,7 @@ version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a9bd240ae819f64ac6898d7ec99a88c8b838dba2fb9d83b843feb70e77e34c8" dependencies = [ - "base64 0.22.1", + "base64", "bip32", "bip39", "cfg-if", @@ -12799,7 +12801,7 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" dependencies = [ - "rustls 0.23.32", + "rustls", "tokio 1.47.1", ] @@ -12823,8 +12825,8 @@ checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" dependencies = [ "futures-util", "log", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio 1.47.1", "tokio-rustls", @@ -13124,7 +13126,7 @@ dependencies = [ "httparse", "log", "rand 0.9.2", - "rustls 0.23.32", + "rustls", "rustls-pki-types", "sha1", "thiserror 2.0.18", @@ -13831,7 +13833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e33ad4bd120f3b1c77d6d0dcdce0de8239555495befcda89393a40ba5e324" dependencies = [ "anyhow", - "base64 0.22.1", + "base64", "directories-next", "log", "postcard", @@ -14745,6 +14747,24 @@ dependencies = [ "time", ] +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs 0.7.1", + "aws-lc-rs", + "data-encoding", + "der-parser 10.0.0", + "lazy_static", + "nom 7.1.3", + "oid-registry 0.8.1", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "xcm-procedural" version = "11.0.2" @@ -14818,6 +14838,16 @@ dependencies = [ "time", ] +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec 0.9.1", + "time", +] + [[package]] name = "yoke" version = "0.8.0" diff --git a/miner-api/src/lib.rs b/miner-api/src/lib.rs index 6c15fc34..5e540991 100644 --- a/miner-api/src/lib.rs +++ b/miner-api/src/lib.rs @@ -83,8 +83,8 @@ pub struct MiningRequest { pub job_id: String, /// Hex encoded header hash (32 bytes -> 64 chars, no 0x prefix) pub mining_hash: String, - /// Distance threshold (U512 as decimal string) - pub distance_threshold: String, + /// Difficulty (U512 as decimal string). Must be non-zero. + pub difficulty: String, } /// Response payload for job submission (`/mine`) and cancellation (`/cancel`). diff --git a/node/Cargo.toml b/node/Cargo.toml index 3761d166..a7787a02 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -47,13 +47,15 @@ qp-wormhole.workspace = true qpow-math.workspace = true quantus-miner-api = { workspace = true } quantus-runtime.workspace = true -quinn = "0.10" +quinn = "0.11" rand = { workspace = true, default-features = false, features = [ "alloc", "getrandom", ] } -rcgen = "0.11" -rustls = { version = "0.21", default-features = false, features = ["dangerous_configuration", "quic"] } +rcgen = { version = "0.14", default-features = false, features = ["aws_lc_rs", "aws_lc_rs_unstable"] } +rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs", "logging", "std", "tls12"] } +rustls-pki-types = "1" +rustls-post-quantum = { version = "0.2", features = ["aws-lc-rs-unstable"] } sc-basic-authorship.default-features = true sc-basic-authorship.workspace = true sc-cli.default-features = true @@ -81,6 +83,7 @@ sc-transaction-pool-api.default-features = true sc-transaction-pool-api.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["alloc"] } +sha2 = { workspace = true, default-features = true } sp-api.default-features = true sp-api.workspace = true sp-block-builder.default-features = true diff --git a/node/src/miner_server.rs b/node/src/miner_server.rs index 17951bf9..923e23d9 100644 --- a/node/src/miner_server.rs +++ b/node/src/miner_server.rs @@ -26,6 +26,15 @@ //! - Each miner independently selects a random nonce starting point //! - First miner to find a valid solution sends `MinerMessage::JobResult` //! - When a new job is broadcast, miners implicitly cancel their current work +//! +//! # Certificate Security +//! +//! The server uses post-quantum cryptography for TLS: +//! - Certificate: ML-DSA-87 (NIST FIPS 204 standardized Dilithium) +//! - Key exchange: X25519MLKEM768 (hybrid classical + post-quantum) +//! +//! Note: Due to rcgen 0.14 limitations, the certificate fingerprint changes on +//! each restart. This will be fixed when rcgen adds ML-DSA key persistence support. use std::{ collections::HashMap, @@ -38,6 +47,8 @@ use std::{ use jsonrpsee::tokio; use quantus_miner_api::{read_message, write_message, MinerMessage, MiningRequest, MiningResult}; +use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; +use sha2::{Digest, Sha256}; use tokio::sync::{mpsc, RwLock}; /// A QUIC server that accepts connections from miners. @@ -64,6 +75,13 @@ impl MinerServer { /// Start the QUIC server and listen for miner connections. /// /// This spawns a background task that accepts incoming connections. + /// + /// # Arguments + /// * `port` - The port to listen on for miner connections + /// + /// # Note + /// Due to rcgen 0.14 limitations, the certificate fingerprint changes on each restart. + /// This will be fixed when rcgen adds ML-DSA key persistence support. pub async fn start(port: u16) -> Result, String> { let (result_tx, result_rx) = mpsc::channel::(64); @@ -83,7 +101,7 @@ impl MinerServer { acceptor_task(endpoint, server_clone).await; }); - log::info!("⛏️ Miner server listening on port {}", port); + log::info!("Miner server listening on port {port}"); Ok(server) } @@ -146,31 +164,57 @@ impl MinerServer { } } -/// Create a QUIC server endpoint with self-signed certificate. +/// Create a QUIC server endpoint with self-signed ML-DSA (post-quantum) certificate. +/// +/// Uses post-quantum cryptography: +/// - Certificate: ML-DSA-87 (NIST FIPS 204) +/// - Key exchange: X25519MLKEM768 (hybrid classical + post-quantum) +/// +/// Note: Due to rcgen 0.14 limitations, ML-DSA keys cannot be persisted and reloaded. +/// The certificate fingerprint will change on each restart until this is fixed upstream. async fn create_server_endpoint(port: u16) -> Result { - // Generate self-signed certificate - let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()]) - .map_err(|e| format!("Failed to generate certificate: {}", e))?; - - let cert_der = cert - .serialize_der() - .map_err(|e| format!("Failed to serialize certificate: {}", e))?; - let key_der = cert.serialize_private_key_der(); - - let cert_chain = vec![rustls::Certificate(cert_der)]; - let key = rustls::PrivateKey(key_der); - - // Create server config - let mut server_config = rustls::ServerConfig::builder() - .with_safe_defaults() - .with_no_client_auth() - .with_single_cert(cert_chain, key) - .map_err(|e| format!("Failed to create server config: {}", e))?; - - // Set ALPN protocol + // Generate ML-DSA-87 key pair + // TODO: Implement deterministic key derivation when rcgen adds ML-DSA key persistence support + let key_pair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ML_DSA_87) + .map_err(|e| format!("Failed to generate ML-DSA key pair: {e}"))?; + + let cert_params = rcgen::CertificateParams::new(vec!["localhost".to_string()]) + .map_err(|e| format!("Failed to create certificate params: {e}"))?; + + let cert = cert_params + .self_signed(&key_pair) + .map_err(|e| format!("Failed to generate certificate: {e}"))?; + + let cert_der = cert.der().clone(); + let key_der = key_pair.serialize_der(); + + // Log certificate fingerprint for miners to use with --node-cert-fingerprint + let fingerprint = compute_cert_fingerprint(&cert_der); + log::info!("⛏️ Miner server certificate fingerprint: {}", fingerprint); + log::info!("⛏️ Certificate algorithm: ML-DSA-87 (post-quantum)"); + log::info!("⛏️ Key exchange: X25519MLKEM768 (hybrid post-quantum)"); + log::warn!("⛏️ NOTE: Fingerprint changes on restart (rcgen ML-DSA key persistence bug)"); + log::info!("⛏️ Miners should use: --node-cert-fingerprint {}", fingerprint); + + let cert_chain = vec![cert_der]; + let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key_der)); + + // Create server config with post-quantum crypto provider (aws-lc-rs with ML-DSA support) + let mut server_config = + rustls::ServerConfig::builder_with_provider(Arc::new(rustls_post_quantum::provider())) + .with_safe_default_protocol_versions() + .map_err(|e| format!("Failed to set protocol versions: {e}"))? + .with_no_client_auth() + .with_single_cert(cert_chain, key) + .map_err(|e| format!("Failed to create server config: {e}"))?; + + // Set ALPN protocol (required by QUIC RFC 9001) server_config.alpn_protocols = vec![b"quantus-miner".to_vec()]; - let mut quinn_config = quinn::ServerConfig::with_crypto(Arc::new(server_config)); + let mut quinn_config = quinn::ServerConfig::with_crypto(Arc::new( + quinn::crypto::rustls::QuicServerConfig::try_from(server_config) + .map_err(|e| format!("Failed to create QUIC server config: {e}"))?, + )); // Set transport config let mut transport_config = quinn::TransportConfig::default(); @@ -179,13 +223,21 @@ async fn create_server_endpoint(port: u16) -> Result { quinn_config.transport_config(Arc::new(transport_config)); // Create endpoint - let addr = format!("0.0.0.0:{}", port).parse().unwrap(); + let addr = format!("0.0.0.0:{port}").parse().unwrap(); let endpoint = quinn::Endpoint::server(quinn_config, addr) - .map_err(|e| format!("Failed to create server endpoint: {}", e))?; + .map_err(|e| format!("Failed to create server endpoint: {e}"))?; Ok(endpoint) } +/// Compute SHA-256 fingerprint of a certificate in the format `sha256:`. +fn compute_cert_fingerprint(cert_der: &CertificateDer) -> String { + let mut hasher = Sha256::new(); + hasher.update(cert_der.as_ref()); + let hash = hasher.finalize(); + format!("sha256:{}", hex::encode(hash)) +} + /// Background task that accepts incoming miner connections. async fn acceptor_task(endpoint: quinn::Endpoint, server: Arc) { log::debug!("Acceptor task started"); diff --git a/node/src/service.rs b/node/src/service.rs index 3867262a..32d88e8e 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -6,6 +6,8 @@ //! - Mining infrastructure (local and external miner support) //! - RPC endpoint configuration +use std::path::PathBuf; + use futures::FutureExt; #[cfg(feature = "tx-logging")] use futures::StreamExt; @@ -175,11 +177,8 @@ async fn handle_external_mining( mining_hash, difficulty ); - let job = MiningRequest { - job_id: job_id.clone(), - mining_hash, - distance_threshold: difficulty.to_string(), - }; + let job = + MiningRequest { job_id: job_id.clone(), mining_hash, difficulty: difficulty.to_string() }; server.broadcast_job(job).await; @@ -526,12 +525,12 @@ fn spawn_authority_tasks( match MinerServer::start(port).await { Ok(server) => Some(server), Err(e) => { - log::error!("⛏️ Failed to start miner server on port {}: {}", port, e); + log::error!("Failed to start miner server on port {port}: {e}"); None }, } } else { - log::warn!("⚠️ No --miner-listen-port specified. Using LOCAL mining only."); + log::warn!("No --miner-listen-port specified. Using LOCAL mining only."); None }; diff --git a/primitives/consensus/qpow/src/lib.rs b/primitives/consensus/qpow/src/lib.rs index 6e38f6b8..28080664 100644 --- a/primitives/consensus/qpow/src/lib.rs +++ b/primitives/consensus/qpow/src/lib.rs @@ -16,7 +16,7 @@ sp_api::decl_runtime_apis! { /// Get the max possible difficulty for work calculation fn get_max_difficulty() -> U512; - /// Get the current difficulty (max_distance / distance_threshold) + /// Get the current mining difficulty fn get_difficulty() -> U512; /// Get last block timestamp