-
Notifications
You must be signed in to change notification settings - Fork 709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core/ecdsa
implementation in runtime?
#3448
Comments
We only required these changes so that key derivation works inside the runtime, which then permits some genesis block check, right? We could build using the faster crate for native, and build using the slower rust crate for this key deriviation call in the runtime. We could even always do this one genesis key derivation using the slower crate.. or hotwire the genesis key derivation somehow. We cannot use the slow wasm build for actual workloads anyways, but this holds for ed25519 and sr25519 too. We've hostcalls for the real verification workloads, but hostcalls could continue invoking the C libsecp256k1 As an aside, there are many "bad feelings" about secp256k1 implementations, but a priori I'd trust the ones by rust crypto and blockstream (probably the C libsecp256k1), but aovid switching back to the old parity one (not even discussed here). |
my two options:
My no-go options:
I paste the benches here for reference: Sign:
Verify:
The gap between k256 and secp256k1 is not super bad (considering that not long ago we were using libsecp256k1) Also depends on the usage of this stuff. Is ecdsa verification in a real hot path to justify a choice based on 50 µs diff? |
At some point may be worth to see what magic secp256k1 is doing wrt k256. |
If we only need this to be part of the runtime for genesis then using a pure-Rust slower one only for that would be an option, and that'd probably be the easiest. I really would like to avoid having non-Rust dependencies for the runtime. We technically could support them (even on RISC-V!), but that'd be extra pain for everyone. Another option would be to help optimize Also, one thing I'd like to note: the benchmarks that @davxy did were done on bare metal, right? In which case they might give us entirely different results when running inside of the runtime. I'll see if I can port them to my PolkaVM benchmark harness and see how they perform under WASM. |
Yes #25 says "the normal production builds should not include the GenesisConfig anymore" so hopefully #1984 makes this code disapear entirely after the genesis WASM, meaning the key derivation stuff could've a feature gate for the rust crypto crate. I do think @michalkucharczyk or someone should check how Afaik.. We're doing some key derivation check required by our domain seperation for AccountIds, but exactly what and why remains unclear. It's nothing related to session keys since we never had secp256k1 session keys before BEEFY. |
@koute yeah the benchmarks were run on bare metal.
Of course, nothing prevents users to call core/ecdsa directly (without passing through the HF), in this case wasm is what matters. But I was mostly referring to our use cases |
We only need support for account derivation. The runtime code may contain numerous instances of polkadot-sdk/polkadot/runtime/rococo/src/genesis_configs.rs Lines 79 to 94 in 7c6bccb
GenesisConfig :
|
This would require some extra code maintenance burden, however acceptable if we don't want to give up on performance. |
It's only doing sr25519 derivations? Would everything work if we made a stub for secp256k1 in which all calls just panic? Or some other conditional compilation on our side? |
Nope. More kinds of keys can be generated: polkadot-sdk/polkadot/runtime/rococo/src/genesis_configs.rs Lines 48 to 77 in 7c6bccb
|
As an aside.. It's problematic if someone does "secret // counter" for a session key. We want session keys to be created on the node or its HSM, and then certified by a controller that lives elsewhere. We'd ideally never have placed this derivation mess into the session key code paths, just computation of keys from entropy. Anyways.. |
All this work done here and in #1984 is for testnets / dev chain specs (used in |
@davxy it depends what specifically you're interested in. For signing we've done all of the easy optimizations, but there is still a lot of opportunity for improving verification/public key speeds where we've encountered various small blockers, e.g. using wNAF, variable-time linear combinations |
If there are no other points, I am planning to start work on:
which either-way is a prerequisite for @davxy 1st option in #3448 (comment) (if we wanted to have it). |
If you do a full migration, then it's good to have benchmarks. If they look bad then maybe we continue using the C one in the host. All that said, ecdsa is only a lower tier scheme for us. It'll never support batch verification anyways, so it'll wind up being way slower eventually, and then we'll have to tell people to use schnorr. |
We only care about signature verification time since we only create ecdsa signatures in beefy. It's likely only the EVM guys who care even about verification, so maybe we could ask them if this change impacts their peformance much? |
Replacing secp256k1 with k256 should not have impact for the runtimes shipping with the pallets contained in this repo. We can't know if a third party runtime contains some code using Currently (if I've not missed something) only Beefy equivocations are using For what concerns bare metal, I think the results of my benchmarks are quite explicit. Signing is ~1.5x slower
Verifying is ~2.5x slower
Said that, beefy for verifying the signature doesn't use the polkadot-sdk/substrate/primitives/io/src/lib.rs Lines 1180 to 1193 in b0741d4
Called from here Have you already replicated this recovery using k256? If yes, I can add it to my benchmarks |
Yes: polkadot-sdk/substrate/primitives/core/src/ecdsa.rs Lines 337 to 342 in 35878b2
note 1: the final |
We risk bricking EVM chains by such a large drop. As observed elsewhere, we've collators who run on older host software, and they hate upgrading, so if we downgrade performance too much, then their collators would think the block runs in 1s or 2s, but it'll run notably slower in backing, and thus get dropped. We filter this through weights of course, which maybe prevents the problem in practice, but we'd hit these risks if the EVM parachain makes its ecdsa weights wrong because their nodes use secp256k1. It's likely safest & easiest if we use some feature here, so k256 in the runtime, and secp256k1 in the host. If that's irksome then you could still see how this fairs in the community testnet, or ask some EVM guys. It's also possible EVM spends way way more time doing keccak, and not much time doing ecdsa. |
I've added two features |
We do not use k256 for much here, and this derivation stuff is as standard as it gets in blockchain, so incompatability risks sound minimal. |
Key recovery from signature is even slower(6x). Let's stick with secp256k1 for bare metal execution
|
This PR replaces the usage of [secp256k](https://crates.io/crates/secp256k1) crate with [k256](https://crates.io/crates/k256) in `core::crypto::ecdsa` for `non-std` environments as outcome of discussion in #3448. `secp256k1` is used in `std`, meaning that we should not affect host performance with this PR. `k256` is enabled in runtimes (`no-std`), and is required to proceed with #2044. If desirable, in future we can switch to `k256` also for `std`. That would require some performance evaluation (e.g. for EVM chains as per #3448 (comment)). Closes #3448 --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi <[email protected]>
This PR replaces the usage of [secp256k](https://crates.io/crates/secp256k1) crate with [k256](https://crates.io/crates/k256) in `core::crypto::ecdsa` for `non-std` environments as outcome of discussion in paritytech#3448. `secp256k1` is used in `std`, meaning that we should not affect host performance with this PR. `k256` is enabled in runtimes (`no-std`), and is required to proceed with paritytech#2044. If desirable, in future we can switch to `k256` also for `std`. That would require some performance evaluation (e.g. for EVM chains as per paritytech#3448 (comment)). Closes paritytech#3448 --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi <[email protected]>
This PR replaces the usage of [secp256k](https://crates.io/crates/secp256k1) crate with [k256](https://crates.io/crates/k256) in `core::crypto::ecdsa` for `non-std` environments as outcome of discussion in paritytech#3448. `secp256k1` is used in `std`, meaning that we should not affect host performance with this PR. `k256` is enabled in runtimes (`no-std`), and is required to proceed with paritytech#2044. If desirable, in future we can switch to `k256` also for `std`. That would require some performance evaluation (e.g. for EVM chains as per paritytech#3448 (comment)). Closes paritytech#3448 --------- Co-authored-by: command-bot <> Co-authored-by: Davide Galassi <[email protected]>
This issue is related to work done in #2044. A goal of this ticket is to gather some opinions on the direction how ECDSA should be implemented in
core/ecdsa
for runtime usage.Problem
Substrate
core/ecdsa
module is usingsecp256k1
crate. This crate is not pure rust, and depends onlibsecp256k1
C
library. It can be compiled to WASM, but unfortunately compilation to RISC target fails.error details
``` running: "clang-15" "-O3" "-ffunction-sections" "-fdata-sections" "--target=riscv32ema-unknown-none-elf" "-I" "depend/secp256k1/" "-I" "depend/secp256k1/include" "-I" "depend/secp256k1/src" "-Wall" "-Wextra" "-DSECP256K1_API=" "-DENABLE_MODULE_ECDH=1" "-DENABLE_MODULE_SCHNORRSIG=1" "-DENABLE_MODULE_EXTRAKEYS=1" "-DENABLE_MODULE_ELLSWIFT=1" "-DECMULT_GEN_PREC_BITS=4" "-DECMULT_WINDOW_SIZE=15" "-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" "-DENABLE_MODULE_RECOVERY=1" "-o" "/builds/parity/mirrors/polkadot-sdk/target/debug/rbuild/minimal-runtime/target/riscv32ema-unknown-none-elf/release/build/secp256k1-sys-a2573b0b926fe764/out/depend/secp256k1/contrib/lax_der_parsing.o" "-c" "depend/secp256k1/contrib/lax_der_parsing.c" cargo:warning=error: unknown target triple 'riscv32ema-unknown-none-elf', please use -triple or -arch ```Support for ecdsa is required in runtime in context of #1984. We want maximum flexibility while defining keys (e.g. beefy) in chain specs.
k256
There was also an idea to migrate from
secp256k1
torust-crypto-k256
which is pure-rust. Some work was already done:Some benchmarking done by @davxy shows that performance is slightly worse:
This probably would be acceptable as ECDSA is not on critical path.
Options
I see two reasonable directions:
core/ecdsa
module,k256
incore/ecdsa
,Any other ideas?
tagging: @davxy @koute @bkchr
The text was updated successfully, but these errors were encountered: