rob thijssen 506b77351c fix(keyring): make account backup and restore work for ML-DSA pairs
Before this, an exported Quantus account could not be imported by anything.
decodePair located its divider by trying the two secret lengths every curve
scheme uses, 64 then 32; an ML-DSA secret is 4032 or 4896 bytes, so neither
matched and restore threw "Invalid encoding divider found in body". That is a
data-durability bug rather than a convenience one, which is why it lands before
any build lets a user create an account.

decodePair now takes an optional secretLength. The caller passes it rather than
this function searching for the divider: searching would work almost always and
fail catastrophically when it did not, since PAIR_DIV is five bytes and a
4032-byte secret contains a false match about once in 270 million keys — and the
result would be a silently wrong key rather than an error. The public key is read
as the remainder, because its length also varies and the body ends there.

The harder half is ordering. createFromJson returns a *locked* pair and callers
read pair.address off it long before any password appears. Every other scheme
manages because the address is the public key; an ML-DSA account id is a one-way
Poseidon2 hash and the public key is inside the encrypted blob. So PairInfo gains
an optional accountId, carried as data and used for the address while locked,
which decodePkcs8 clears once the real key arrives.

It also checks them against each other, and that check is not paranoia. For the
curve schemes a JSON file with an edited `address` field cannot decode at all.
Here it decodes perfectly and yields a pair reporting an address its key does not
control — a user would see someone else's address in their own wallet and believe
they held it. Pinned by a test that tampers exactly that field.

One more silent-wrong-key path closed: decodePkcs8 decided "secret key or seed?"
by length, so a 4032-byte ML-DSA secret took the seed branch and was fed to keygen
as entropy, producing a valid and entirely wrong key. The type knows the answer,
so it is asked.

Refs quantus/common#3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 08:50:56 +03:00
2025-01-17 19:39:05 +02:00
2025-05-19 18:17:15 +03:00
2020-10-23 10:03:23 +02:00
2022-01-13 10:05:40 +02:00
2021-06-08 17:04:13 +02:00
2026-03-12 18:53:56 +02:00
2025-05-19 18:17:15 +03:00
2026-03-23 14:48:13 +02:00
2019-02-28 16:32:31 +01:00
2026-03-23 12:53:26 +00:00
2026-03-12 18:53:56 +02:00
2022-08-12 09:53:00 +03:00
2018-11-21 12:26:38 +01:00
2022-12-08 08:24:41 +02:00
2026-03-12 18:53:56 +02:00
2022-01-11 08:49:59 +02:00

@polkadot/common

Various useful utility functions that are used across all projects in the @polkadot namespace. It provides utility functions with additional safety checks, allowing not only for consistent coding, but also reducing the general boilerplate.

overview

This repository is split up into a number of internal packages, namely utilities -

development

Contributions are welcome!

To start off, this repo (along with others in the @polkadot family) uses yarn workspaces to organise the code. As such, after cloning, its dependencies should be installed via yarn, not via npm; the latter will result in broken dependencies.

To get started -

  1. Clone the repo locally, via git clone https://github.com/polkadot-js/common <optional local path>
  2. Ensure that you have a recent version of Node.js, for development purposes Node 10 is recommended.
  3. Ensure that you have a recent version of Yarn, for development purposes Yarn >=1.10.1 is required.
  4. Install the dependencies by running yarn
  5. Build the everything via yarn run build
  6. You can also launch the API Docs, via yarn vuepress dev docs
  7. Access the docs via http://localhost:8080

tutorials

Looking for tutorials to get started? Look at examples for guides on how to use the base utilities.

Description
Fork of polkadot-js/common. Carries the ML-DSA (Dilithium) keypair types in @polkadot/keyring and @polkadot/util-crypto: Quantus account ids are Poseidon2 hashes of 1952/2592-byte public keys, which upstream's 32-byte assumptions cannot express. Not upstreamable — see quantus/extension#1.
Readme Apache-2.0 54 MiB
Languages
TypeScript 99.7%
JavaScript 0.2%
HTML 0.1%