Repository navigation
feat(runtime)!: ed25519 accounts sign the transaction text (0x03/0x04) and raw 0x00 never verifies; refuse small-order ed25519 keys, the sr25519 identity key and non-canonical ECDSA (spec 20) - #174
Merged
Conversation
…) and raw 0x00 never verifies; refuse small-order ed25519 keys, the sr25519 identity key and non-canonical ECDSA (spec 20)
git commit -m "fix(deps): bump wasmtime 36.0.19, rustls-webpki 0.103.16 and webpki-root-certs 1.0.10 for RUSTSEC-2026-0379/0380/0382/0383; ignore RUSTSEC-2026-0381 (webpki-roots 0.25, pinned by libp2p-websocket)"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ed25519 accounts now sign a text that names the transaction instead of the raw signing payload, so Solana wallets (Phantom, MetaMask, Backpack, Solflare, Trust, Talisman) can sign Orbinum extrinsics and a signature obtained as a "login nonce" can no longer authorise one.
OrbinumSignatureis also hardened against keys and encodings the host primitives accept as forgeries or aliases, and split into a module per responsibility. Ships in runtime spec 20 ([Unreleased]).Why
solana:signMessageand MetaMask rewrites it, so neither could produce a0x00signature. All six wallets tested sign UTF-8 text deterministically.0x00verified ed25519 over raw bytes, and Backpack, Solflare, Trust and Talisman sign arbitrary bytes throughsignMessage. A site that had a user sign a payload's blake2_256 as a "nonce" could submit it as that user's transaction. The attacker picks the variant, so an account cannot opt out.ed25519_verifyfollows ZIP-215: for a small-order key,R = identity, s = 0verifies any message. Account0x0100…00(EVM address0x01followed by zeros) is such a key. Confirmed on testnet (spec 19) withvalidate_transaction; it has no funds. The sr25519 identity key acceptsR = 0, s = 0. ECDSA recovery accepts(r, n−s)andv + 27, so one signed extrinsic had up to four valid encodings.Changes
OrbinumSignature, with explicit#[codec(index)]:0x00Ed25519Ed25519,Sr25519andEcdsa)0x01Sr255190x02Ecdsas ≤ n/2andv < 40x03Ed25519Text(new)"Orbinum transaction\nchain: 0x{genesis}\npayload: 0x{blake2_256(msg)}"0x04Ed25519WrappedText(new)<Bytes>…</Bytes>, as a Substrate extension'ssignRawsigns itmsgis whatVerify::verifyreceives (payload, or its blake2_256 above 256 bytes). It is always hashed again, sinceverifycannot tell which. The genesis comes fromblock_hash(0), whichCheckGenesisalready reads, so there is no extra read or PoV.orbinum_signature.rs→orbinum_signature/{mod, signer, ed25519, sr25519, ecdsa, text}.rs.transaction_versionis unchanged: no call encoding moved, and every existing index keeps its bytes.RUNTIME_VERSIONS.md: spec 20 entries.Client action required (before the upgrade)
s,v ∈ {0,1}(sp_core, polkadot-js and noble already do)signRaw→ tag0x04, orsignMessage→ tag0x03. PlainsignPayloadgives0x00→BadProofDependency security fixes
The daily
cargo denyjob started failing on new RustSec advisories, none caused by this change. Lockfile-only bumps, all within semver:wasmtime36.0.18rustls-webpki0.103.15webpki-root-certs1.0.9webpki-roots0.25.4deny.tomlwebpki-roots0.25.4 comes only throughlibp2p-websocket0.44, pinned bysc-network'slibp2p0.54, and the fix exists only in 1.0.10, so it waits for the next polkadot-sdk bump. Those roots validate TLS onwssp2p dials; peers are still authenticated by Noise and peer id.Testing
cargo test -p orbinum-runtime --lib: 85 passed. New suitesruntime_tests::ed25519_textandruntime_tests::signature_hardening, using real Phantom and MetaMask signatures, fullcheck()with short and long payloads, cross-variant refusal, small-order and identity forgeries (asserting first that the host accepts them), ECDSA aliases, and the metadata shape polkadot-api requires.cargo clippy -p orbinum-runtime -p orbinum-node --all-targets: clean.rustfmt: clean. Release build (wasm): OK.validate_transactionand real inclusion:0x03and0x04accepted and included withExtrinsicSuccess; tampered, blind, cross-framing and small-order signatures refused; raw0x00refused.0x04and bare-text0x03transfers included, fee estimation for each,0x00→BadProof.cargo deny check: advisories, bans, licenses and sources ok. Release build withwasmtime36.0.19 and a--devsmoke run: blocks produced, no errors.