Compare commits

..
855 Commits
Author SHA1 Message Date
grenade dc295dc3f5 Merge branch 'quantus-crypto' into quantus-codec
Lock Threads / lock (push) Has been cancelled
2026-09-16 18:14:06 +03:00
grenadeandClaude Opus 5 4e5b479db4 feat(quantus-crypto): wormhole nullifiers
A deposit to a wormhole address is spent when its nullifier,
poseidon2(poseidon2(salt || secret || transfer_count)), is in
Wormhole::UsedNullifiers. Working out a wormhole balance means computing one
for each deposit. That needs the address's secret, which never leaves WASM.

wormholeNullifiers(mnemonic, password, account, branch, start, addresses,
first, count) returns them for a run of addresses and a run of transfer
counts. The BIP39 seed is stretched once per call; 40 addresses x 256 counts
takes 194 ms in node. A call is capped at 100,000 nullifiers.

This is ported onto qp-poseidon-core, not qp-wormhole-circuit, which would
bring plonky2 into the WASM. The circuit crate is a dev-dependency only, as
the reference: a known-answer test compares the port with
Nullifier::from_preimage across secrets at and above the Goldilocks-prime
limb edge and transfer counts across both 32-bit limbs, and asserts that
enough cases were actually compared rather than skipped.

The doc comments say to check nullifiers against a local copy of the spent
set, never by key: exits publish nullifiers, so a lookup names the exit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-16 18:13:57 +03:00
grenade d61e886359 Merge branch 'quantus-crypto' into quantus-codec 2026-09-16 15:58:30 +03:00
grenadeandClaude Opus 5 0b1cfe35b3 feat(quantus-crypto): derive wormhole addresses
A wormhole address is not a key. A path under coin type 189189189 yields a
32-byte secret, and the address is poseidon(poseidon(salt || secret)). Funds
leave only through a ZK proof of that secret. The extension needs the
addresses to show a wallet's wormhole account; it has no use for the secrets.

wormholeAddresses(mnemonic, password, account, branch, start, count) returns
32-byte account ids for m/44'/189189189'/<account>'/<branch>'/<index>', the
mobile wallet's paths. The secrets and first hashes are derived and wiped
inside WASM.

The BIP39 seed is stretched once per call rather than once per address, since
a gap-limit window is dozens of addresses and each stretch is 2048 PBKDF2
rounds. A call is capped at 1000 addresses, and indices must stay below 2^31.

Pinned to the chain node's own vector
(node/src/tests/data/quantus_key_test_data.rs): TEST_MNEMONIC at
m/44'/189189189'/0'/0'/0' is TEST_WORMHOLE_ADDRESS, the same pair the mobile
wallet's SDK tests. Checked in Rust and through the packed package's consumer
test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-16 15:58:13 +03:00
grenadeandClaude Opus 5 09a96b64bf feat: render account ids as SS58 when a prefix is set
A decoded call named its recipient as 32 bytes of hex. That is a correct
description of the value and the one form nobody reads — and the only moment in
a wallet where reading the recipient matters is the screen asking somebody to
approve sending them money.

`set_ss58_format` turns it on. Off by default, and deliberately: the prefix is a
property of the chain a caller is talking to rather than of the metadata, so
inferring one would put a plausible, wrong address in front of that same person.

Account types are found by their **registry path**, not by length. A block hash
is also 32 bytes, and rendering one as an address would be a lie a reader cannot
catch — there is a test that `System::BlockHash` stays hex with a prefix set.
`scale_value` carries each value's type id as its context, so the check is on
what the runtime declared.

The vector is crystal_bob on Heisenberg, taken from the chain rather than
computed here, which also pins the two-byte prefix form — 189 needs it, and
getting it wrong yields an address that looks right and belongs to nobody.

Refs #3, quantus/extension#6

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 15:26:11 +03:00
grenadeandClaude Opus 5 e6ff57a334 feat: storage addressing, nested calls, and a stated integer convention
Three things the tier-1 case matrix needed (quantus/extension#7).

**Storage keys and values (#4).** `storage_target` resolves a pallet and item to
`twox128(prefix) ‖ twox128(item)` plus each map key hashed by the hasher the
entry declares, and reports the value type and the entry's default.
`decode_storage_value` reads the result. Nothing here knows that `System::Account`
is a `Blake2_128Concat` map over an `AccountId32`; the hashers, both types and
the default all come out of the metadata.

The `Default` versus `Optional` distinction is carried deliberately. A `Default`
entry that the node returns nothing for means the declared default — an account
nobody has funded reads as a zero balance — where an `Optional` one means
nothing. A wallet that conflated them would report a failure for an account that
simply has no money in it.

**A call nests inside a call.** A multi-field variant with named fields only
accepted a positional array, so `Utility.batch_all` — whose `Vec<RuntimeCall>`
holds calls spelled exactly like top-level ones — could not be encoded at all. It
now takes the same object form at any depth.

**Every integer renders as a decimal string**, whatever its width, and that is
now stated rather than incidental. A u128 balance does not survive a JSON number
(12 decimal places puts ordinary amounts past 2^53) and `scale_value` widens
every unsigned integer to u128, so the width is not available to switch on.
Emitting a number when it happens to fit and a string when it does not would make
a consumer handle both shapes for the same field depending on the value.

All of it proven against Heisenberg: an ML-DSA-65 account funded by a `batch_all`
whose payload crossed the 256-byte BLAKE2b threshold, then signing and being
included itself.

Closes #4. Refs #3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 15:15:35 +03:00
grenadeandClaude Opus 5 f1c51661df feat: accept pre-encoded extension values, validated by round trip
A dapp hands a wallet an `era` it encoded itself, as opaque bytes. There is no
way to render those as a variant without knowing the era algorithm, which is
exactly the kind of knowledge this crate refuses to hold — so they are accepted
as `Supplied::Raw`.

Not on trust, though. Raw bytes are decoded against the type the runtime
declares and re-encoded, and anything that does not come back identical is
refused: a short read, trailing bytes, a non-canonical compact. Appending them
unchecked would mean signing a payload whose shape nobody verified, and the only
report of that is `BadProof` from a node — which is also what a wrong key looks
like.

Also makes a single-field struct transparent whether or not its field is named,
so `CheckMetadataHash { mode }` takes `"Disabled"` the way `AccountId32([u8;32])`
takes its hex. Both wrappers are the runtime's choice, and the registry is what
says they are there.

Refs #3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 14:45:25 +03:00
grenadeandClaude Opus 5 3a1611a92e feat: add @quantus/codec, driving encode and decode from runtime metadata
The extension has to build a signing payload, assemble an extrinsic and decode
a call well enough to show a user what they are approving. The obvious route was
@polkadot/api's codec. That is closed, and quantus/api#1 carries the tested
evidence:

  - @polkadot/types caps fixed arrays at 2048 bytes, and ML-DSA signatures are
    [u8;5261] and [u8;7219], so every Quantus extrinsic trips it
  - api.rpc.chain.getBlock throws on every block of this chain, at the timestamp
    inherent, because it reads the extrinsic preamble byte as a version when the
    top two bits are a type tag
  - it *guesses* that signed extensions it does not recognise contribute nothing
    to the signed payload

The third is why this is a package rather than a patch. The guess is right
today — the registry says ReversibleTransactionExtension and
WormholeProofRecorderExtension are empty on both halves — and it is right only
by luck. This chain's encoding has changed between runtimes, transactionVersion
has gone 2 -> 3 -> 6 across four upgrades, and when the guess stops holding the
wallet keeps signing: valid signatures over a payload missing bytes the runtime
put there, reported by the chain as BadProof, which is also what it reports for
a wrong key.

So nothing here names a pallet, a call, an extension or a signature scheme.
Every type id is read from metadata the node produced by running
Metadata_metadata against the runtime WASM in a given block's state, the same
oracle blackbeard.observer has been decoding against across four upgrade
boundaries. encode_extensions walks the declared extensions in order and refuses
to build a payload when one that encodes to something has no value supplied —
a wallet that cannot sign is a bug report, one that signs the wrong bytes is a
support case nobody diagnoses.

Proven end to end on Heisenberg at spec 148: a balances.transfer_keep_alive
built entirely here, signed by @quantus/crypto under QUANTUS_EXTRINSIC, included
at block 1050475 and read back from that block — inherent at index 0 included,
which is the block @polkadot/api cannot decode at all.

Two notes carried over from @quantus/crypto, both load-bearing: decode_checked
walks with scale_decode's IgnoreVisitor before scale_value touches the bytes,
because scale_value sizes a Vec from the length prefix before decoding an item
and an aborted allocation leaves no Err to catch; and the build needs binaryen
123, since 105 silently corrupts the output.

Closes #3

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 14:14:34 +03:00
rob thijssenandClaude Opus 5 e8bf9e20c7 fix(quantus-crypto): strip wasm-bindgen's fetch-based init from the shipped glue
The package could not be bundled. Every webpack consumer failed with:

  Module not found: Error: Can't resolve 'quantus_crypto_bg.wasm'
    in node_modules/@quantus/crypto/generated

wasm-bindgen's async `__wbg_init` contains

  module_or_path = new URL('quantus_crypto_bg.wasm', import.meta.url);

and webpack resolves `new URL(..., import.meta.url)` statically, at build time,
whether or not the branch can run. The file is not in the package — the wasm
ships base64'd in bytes.js, which is the entire point of this package — so the
build failed on a code path we never call.

node never sees it, which is why ten Rust tests, twelve consumer assertions and a
browser probe all passed while the package was unusable in a bundler. It took a
real extension build to surface, and that is the useful lesson: this package's
consumers bundle, and nothing in its own test suite does.

So the dead init is removed after bindgen runs. Shipping a second copy of the
wasm to satisfy a path we do not use would be the wide fix; deleting generated
code we never call is the narrow one.

The stripper asserts the shape it expects and throws if wasm-bindgen changes it,
rather than silently no-opping — a build that quietly stopped stripping would
ship the broken package again. It also re-checks that no reference to the .wasm
filename survives.

Published as 0.1.1.

Refs quantus/wasm#1, quantus/extension#2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-15 11:53:18 +03:00
rob thijssenandClaude Opus 5 a6d3685c59 refactor(quantus-crypto): drop the @polkadot/wasm-util dependency
It cost more than it saved. Two problems, the second only visible once
quantus/common tried to consume this package:

Its index re-exports packageDetect, whose only job is a side effect registering
with @polkadot/util — a peer dependency inherited for nothing. Deep imports
(/base64, /fflate) avoided that.

But it is a workspace package, so a symlinked consumer resolves its dependencies
through *this* repo's node_modules, where @polkadot/wasm-util points at the
package source rather than its build and carries no exports map. Node follows
symlinks to their realpath, so `@polkadot/wasm-util/base64` failed to resolve
from quantus/common no matter which yarn protocol was used — portal: and link:
behave the same once the realpath is taken.

So: fflate directly for zlib inflate, and fifteen lines for base64 rather than a
dependency at all. Deliberately not atob or Buffer.from — the first is
browser-only, the second node-only, and this runs in an MV3 service worker, a
Worker, node tests and a bundled extension page.

The package is now self-contained apart from fflate, which resolves normally from
any checkout. Size is unchanged at 234,292 raw / 109,649 zlib / 146,200 base64.

Refs quantus/wasm#1, quantus/common#2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 18:39:54 +03:00
rob thijssenandClaude Opus 5 8323e442d9 test(quantus-crypto): browser probes for the constraints node cannot test
cargo test and the consumer test both run in node, which is neither a browser nor
a service worker. Two probes cover the rest.

The automated one is a module Worker served under the exact extension_pages CSP
from both manifests. A module Worker has no window and no document, which is the
property that matters — an MV3 service worker has neither either. On Firefox:

  hasDOM:   false   hasWindow: false
  initWasm: ok  (9.0 ms cold)
  keygen:   1.0 ms
  account:  matches quantus-cli
  sign:     3.0 ms (4627 bytes)
  verify:   1.0 ms  ok
  ctx sep:  ok (rejected under spec-147 ctx)

9 ms to base64-decode 146 KB, inflate it to 234 KB and instantiate. That is the
number the MV3 lifetime question turns on — a worker killed between messages pays
it on every wake — and it settles the cold-start concern raised in quantus/wasm#1.
Those are ML-DSA-87 timings, the larger parameter set, so 65 is cheaper still.

The CSP is enforced, not merely declared: an earlier version of the page used an
inline script and Firefox blocked it, which is why main.js is a separate file.

The manual one is a real MV3 extension whose service worker imports the package
at module scope. Loading an unpacked extension needs an OS file dialog, so it
cannot be driven from here and is documented for a human to load. It covers
chrome.runtime messaging and the real kill-and-restart lifecycle rather than a
stand-in for it.

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 14:20:47 +03:00
rob thijssenandClaude Opus 5 b882f914e7 build(quantus-crypto): buildable, installable and tested as a package
The JS build now runs end to end and the built package has been consumed the way
quantus/common will consume it. Four things had to be worked out.

polkadot-dev-build-ts will not build this package. It returns early for any name
not starting with @polkadot/, in both buildJs and when collecting locals for
import rewriting. Renaming into someone else's scope to satisfy a string check
would be worse than not using the tool, and nothing is lost: this package needs
no deno variant, no rollup bundle, no cross-package import rewriting. A plain tsc
build lives in scripts/build-quantus-js.sh, which also keeps `yarn build:js`
byte-identical to upstream's behaviour.

binaryen 105 silently breaks the wasm. Upstream pins version_105 (2021), which
predates the externref tables wasm-bindgen 0.2.128 emits; wasm-opt "optimises"
the table into something that fails at instantiation with `WebAssembly.Table.
grow(): failed to grow table by 4`. The wasm is valid before wasm-opt and broken
after, every cargo test still passes, and it only surfaces when a consumer tries
to init. install-build-deps.sh now fetches binaryen 123 alongside, exactly as it
does a second wasm-bindgen.

The wasm-util dependency is imported deeply. Its package index re-exports
packageDetect, whose only job is a side effect registering with @polkadot/util —
a peer dependency we would inherit for nothing. base64 and fflate are pure
functions with no dependencies, so the deep paths are both lighter and honest.

ESM only, and the CJS scaffolding is removed. The consumers are ESM and the
wasm-bindgen glue is ESM-only, so a CJS variant would mean a second generated
glue or hand-written marshalling. Revisit if quantus/common's CJS build needs it.

Also: the pack step must run after tsc, which clears build/; the checked-in
bindings are refreshed by the build so they cannot drift; and both test suites
are wired into the repo's test script, which previously ran wasm-crypto's only.

The consumer test stages a real node_modules layout rather than testing in place,
because in this repo node_modules/@polkadot/wasm-util symlinks to the package
source, which carries no exports map — so a deep import resolves for a real
consumer and fails here for reasons that have nothing to do with our package.
Staging tests module resolution too, which is half of what can break in a
published package. It is also what caught the binaryen fault.

Post-wasm-opt: 234,292 raw / 109,649 zlib / 146,200 base64 — smaller than
upstream's entire wasm-crypto blob (335,277 / 168,782 / 225,044).

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 14:17:15 +03:00
rob thijssenandClaude Opus 5 02a3f004d7 chore: ignore the second bindgen download
install-build-deps.sh fetches wasm-bindgen 0.2.128 into bindgen-quantus/ for
packages/quantus-crypto, which the existing bindgen/ rule does not match.

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 13:58:35 +03:00
rob thijssenandClaude Opus 5 1f1f5729ab feat(quantus-crypto): JS surface, build scripts and CSP-safe sync init
Wraps the crate for JS consumers and adds the build that produces it.

Init deliberately avoids fetch and avoids @polkadot/wasm-bridge. The consumer is
an MV3 service worker under `script-src 'self' 'wasm-unsafe-eval'`, which can
compile WASM but not usefully fetch it, and which can be cold-started between any
two messages; callers like pair.sign() are synchronous and have no await to give.
So the WASM is zlib-compressed and base64'd into bytes.js at build time and
instantiated with wasm-bindgen's initSync. Bridge is not usable here regardless:
it implements the 0.2.79 JS-heap ABI and this crate builds with 0.2.128, which
uses externref tables.

build-quantus.sh is separate from build-wasm.sh rather than folded into it,
because that script drives the nightly-2022-06-24 + xargo build wasm-crypto
needs. install-build-deps.sh gains a second wasm-bindgen for the same reason —
the two ABIs cannot share a binary. No asm.js step: wasm2js over ML-DSA would be
enormous and slow, and every context we ship into permits wasm.

bytes.js is emitted in both module systems, with the CJS copy under a directory
carrying its own {"type":"commonjs"} — the package is "type": "module" and node
otherwise refuses to load an exports.-style file from it.

Proven end to end against the real build output: base64 -> inflate -> initSync
with no fetch, crystal_alice's account id matching the CLI through the JS path,
sig||pk matching the runtime's fixed-array size, and JsError surfacing as a JS
exception across the boundary.

Sizes are read from the crate rather than exposed as constants to copy. They are
consensus-critical and a drifted JS constant would re-frame every byte after the
signature while looking entirely healthy.

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 13:58:25 +03:00
rob thijssenandClaude Opus 5 6eb04f63ac feat(quantus-crypto): ML-DSA, Poseidon2 and HD derivation as a separate crate
Wraps the chain's own crypto crates for the browser: qp-rusty-crystals-dilithium
(ML-DSA-65 and ML-DSA-87), qp-poseidon-core for the account-id hash, and
qp-rusty-crystals-hdwallet for BIP44 derivation. Nothing is reimplemented — a
browser wallet that disagreed with the chain about a key or a signature would
emit well-formed output the chain rejects, with nothing on this side able to
tell.

A separate crate rather than more files in wasm-crypto, because the two cannot
share a Cargo graph. wasm-crypto builds with nightly-2022-06-24 against a
2019-era dependency set; the ML-DSA crates use inline `const {}` blocks that
need Rust >= 1.79. Bumping the older one would mean rewriting upstream's
sr25519/ed25519 build, which is the thing most worth leaving alone so rebases
stay boring. wasm-crypto is untouched here.

The scheme selector is the chain's own signature-enum variant index (0 for
ML-DSA-87, 1 for ML-DSA-65), so the number threaded through this API is the
byte that ends up on the wire and there is no mapping to get backwards. Key and
signature sizes are exported rather than left for JS to hardcode: they are
consensus-critical and a drifted constant would mis-frame every byte after the
signature while looking healthy.

Logic is split from the #[wasm_bindgen] wrappers because JsError cannot be
constructed off-wasm, which made every error path untestable by cargo test —
and the error paths are what most needs testing.

Verified against the `quantus` CLI 2.2.2 as an independent oracle, not against
our own output: the three dev-genesis account ids, and HD derivation at both
schemes' default paths from the public Substrate dev phrase. Context separation
is pinned too — a signature made under QUANTUS_EXTRINSIC must not verify under
the empty context, which is what makes the spec-148 boundary detectable rather
than a silent chain rejection.

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 13:54:25 +03:00
Tarik Gul 65286fb3ec Set headers to 2026 (#609)
Lock Threads / lock (push) Has been cancelled
2026-03-13 01:32:10 +02:00
github-actions[bot] f55a3e75a2 [CI Skip] release/stable 7.5.4
skip-checks: true
2025-12-09 10:03:06 +00:00
rajk93 6c8b0afd8d 7.5.4 (#606) 2025-12-09 15:27:27 +05:30
github-actions[bot] 9c6611087c [CI Skip] bump/beta 7.5.4-0-x
skip-checks: true
2025-12-09 09:23:51 +00:00
rajk93 dc34df3b54 chore: bump polkadot dependencies (#605) 2025-12-09 14:48:23 +05:30
github-actions[bot] 8bf7e88458 [CI Skip] release/stable 7.5.3
skip-checks: true
2025-11-24 08:24:07 +00:00
rajk93 e8f1fb3aed 7.5.3 (#604) 2025-11-24 13:50:24 +05:30
github-actions[bot] ba6155880e [CI Skip] bump/beta 7.5.3-0-x
skip-checks: true
2025-11-24 07:25:14 +00:00
rajk93 1e696a5520 chore: bump polkadot dependencies (#603) 2025-11-24 12:51:27 +05:30
github-actions[bot] b6c704eca8 [CI Skip] release/stable 7.5.2
skip-checks: true
2025-11-11 03:02:29 +00:00
rajk93 c7053fa112 7.5.2 (#602) 2025-11-11 08:24:34 +05:30
github-actions[bot] d76ab093a8 [CI Skip] bump/beta 7.5.2-1-x
skip-checks: true
2025-11-10 13:40:53 +00:00
rajk93 4a54a37ae1 chore: bump polkadot dependencies (#601) 2025-11-10 19:03:00 +05:30
github-actions[bot] 0eb433f3c2 [CI Skip] bump/beta 7.5.2-0-x
skip-checks: true
2025-11-10 13:09:40 +00:00
rajk93andFrancisco Valentim Castilho 278ecc7210 Fix/Revert asm build (#599)
* chore: revert asm build

* chore: revert info in build-wasm.sh

* chore: revert install-build-deps.sh

* chore: lock libc version

* chore: lock libc version in xargo

* chore: use --locked while building

* Fix: Switch `RUST_VER` to 1.63.0-nightly

* chore(CI): revert continue-on-error to false

* Revert "chore(CI): revert continue-on-error to false"

This reverts commit 425a93ea4d6c18e94ca04a0142818dd440442182.

---------

Co-authored-by: Francisco Valentim Castilho <franciscoannyon@gmail.com>
2025-11-10 18:31:44 +05:30
github-actions[bot] 03fe7dcb1d [CI Skip] release/stable 7.5.1
skip-checks: true
2025-08-25 14:05:16 +00:00
Valentin Fernandezandgithub-actions[bot] d99abde915 7.5.1 (#596)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-25 17:03:27 +03:00
github-actions[bot] 06502e8fe8 [CI Skip] bump/beta 7.4.2-4-x
skip-checks: true
2025-08-25 13:48:20 +00:00
Valentin Fernandezandgithub-actions[bot] f3004fdb31 bump deps (#595)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-25 16:46:30 +03:00
github-actions[bot] f5834e684f [CI Skip] bump/beta 7.4.2-3-x
skip-checks: true
2025-08-13 17:01:23 +00:00
Valentin Fernandezandgithub-actions[bot] d7a1060824 Remove ASM build (#594)
* Remove ASM build

* remove CI build blag

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-13 13:59:40 -03:00
c6f8748878 Tweak install-build-deps.sh script (#593)
* add additional flag

* downgrade bindgen

* Fix rust build

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: José Molina <jose@blockdeep.io>
2025-08-13 13:34:01 -03:00
Valentin Fernandezandgithub-actions[bot] 24a46c7262 Setup nightly as default (#592)
* run CI

* run CI

* setup nightly as default

* install  nightly-2024-11-22

* rustup show

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-13 17:01:17 +03:00
Valentin Fernandezandgithub-actions[bot] 78a282bda3 Readd lock file (#591)
* get rust versions

* modify build-wasm

* switch to nightly on build-wasm

* prevent script from using stable

* extra log

* new log

* run CI on current branch

* run CI on current branch

* Minor fixes

* Remove rust installation

* nightly on build.sh

* add log

* logs

* small change

* rust version is nightly

* auto-approve

* re add lock file

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 12:02:48 -03:00
Valentin Fernandezandgithub-actions[bot] 1713dccba3 Ci Fix (#590)
* get rust versions

* modify build-wasm

* switch to nightly on build-wasm

* prevent script from using stable

* extra log

* new log

* run CI on current branch

* run CI on current branch

* Minor fixes

* Remove rust installation

* nightly on build.sh

* add log

* logs

* small change

* rust version is nightly

* auto-approve

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 11:40:51 -03:00
Valentin Fernandezandgithub-actions[bot] 0a22251212 default to nightly build (#589)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 09:56:45 -03:00
Valentin Fernandezandgithub-actions[bot] 540d46717b default to installed rust version (#588)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-11 13:33:46 -03:00
Valentin Fernandezandgithub-actions[bot] e5112e690d fix rust version to 1.84 (#587)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-11 12:01:58 -03:00
Valentin Fernandezandgithub-actions[bot] 2f8c91fc15 rollback bindgen version change (#586)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-11 11:41:17 -03:00
rajk93 6d552f1ced Added validation checks in PBKDF2 and Scrypt hashing functions (#584)
* chore: added validation checks in PBKDF2 and Scrypt functions

* chore(eslint): ignore linting for mod.ts

* chore(ci): bump RUST_VER

* chore(ci): bump RUST_VER

* chore(CI): downgrade RUST_VER and update xargo build script

* chore(CI): revert last change and use RUST_VER as stable

* chore(CI): bump BINDGEN_VER

* chore(CI): bump BINDGEN_VER

* chore(CI): bump BINARYEN_VER

* chore(CI): downgrade BINARYEN_VER

* chore(CI): recomended fix for wasm-bindgen

* chore(test): point wasm to package

* Revert "chore(test): point wasm to package"

This reverts commit 66104540fdff0e760ca0a6a666d4e09d162c5769.

* chore(test): temporary test

* Revert "chore(test): temporary test"

This reverts commit af10b8d8b9bb597e02ea9c8d6cc3bf62676a6609.

* chore(test): added more logs to build-wasm.sh script

* Revert "chore(test): added more logs to build-wasm.sh script"

This reverts commit c5073005ae9daa84308296736a41636da8f3d21b.

* chore(test): added more logs to test all

* Revert "chore(test): added more logs to test all"

This reverts commit 9b0ac43c2c053ac408164bbf9b31b46d0844af1b.

* chore: add references for RFCs
2025-07-23 12:10:03 +05:30
rajk93 afa992b40b Revert CI improvements and wasm-bindgen version (#583)
* chore: revert wasm-bindgen

* chore: revert pull_request in github action workflow

* chore: revert CI improvements

* chore: revert CI improvements
2025-07-16 13:01:04 +05:30
Valentin Fernandez 401c6e5763 chore: Improve CI (#580)
* Prevent false possitive result

* Use stable cargo version

* Remove 2nd continue-on-error
2025-06-26 09:53:32 -03:00
rajk93andValentin Fernandez 76d051b16e chore: added check in ext_secp_recover for signature normalization (#579)
* chore: added check in ext_secp_recover for signature normalization

* update wasm-bindgen

* Add test for non-normalized signature

---------

Co-authored-by: Valentin Fernandez <tinchofernandez8@gmail.com>
2025-06-24 12:01:13 -03:00
github-actions[bot] 5b69d5aadc [CI Skip] bump/beta 7.4.2-2-x
skip-checks: true
2025-01-17 22:18:32 +00:00
Tarik Gul 780323538a Bump dev to 0.83.2 (#578) 2025-01-18 00:14:18 +02:00
github-actions[bot] 042d653852 [CI Skip] bump/beta 7.4.2-1-x
skip-checks: true
2025-01-02 19:57:35 +00:00
Tarik Gul da47390fa4 Set permissions on all scripts (#577)
* Set permissions on all scripts

* cleanup
2025-01-02 21:53:46 +02:00
Tarik Gul 488abd68bb Set execute for build script in CI (#576) 2025-01-02 21:40:37 +02:00
Tarik Gul d926ee63f4 Bump yarn to 4.6.0 (#575) 2025-01-02 21:26:31 +02:00
Tarik Gul 6777f8ef5e 2025 (#574)
* 2025

* include more files
2025-01-02 17:31:20 +02:00
github-actions[bot] 1001083009 [CI Skip] bump/beta 7.4.2-0-x
skip-checks: true
2024-10-22 14:24:12 +00:00
Tarik Gul 898b067081 Bump yarn to 4.5.1 (#573) 2024-10-22 17:20:13 +03:00
github-actions[bot] acc07b9345 [CI Skip] release/stable 7.4.1
skip-checks: true
2024-10-21 02:30:29 +00:00
Tarik Gul bc572b16d5 7.4.1 (#572)
* 7.4.1

* spacing
2024-10-21 05:27:10 +03:00
github-actions[bot] 91d2530ea8 [CI Skip] bump/beta 7.3.3-16-x
skip-checks: true
2024-10-21 00:59:52 +00:00
Tarik Gul e679298d8d Bump dev to 0.81.2 (#571) 2024-10-21 03:56:31 +03:00
Tarik Gul 949ad77dab Bump dev to 0.81.1 (#570) 2024-10-21 02:51:21 +03:00
github-actions[bot] 24ce35ae43 [CI Skip] bump/beta 7.3.3-15-x
skip-checks: true
2024-10-20 20:43:34 +00:00
Tarik Gul 9e22f34720 Set CI deno version to 1.42.x (#569) 2024-10-20 23:40:08 +03:00
github-actions[bot] 2b867b2e91 [CI Skip] bump/beta 7.3.3-14-x
skip-checks: true
2024-08-29 15:07:39 +00:00
Tarik Gul 230593ee17 Bump yarn to 4.4.1 (#568) 2024-08-29 18:02:48 +03:00
github-actions[bot] 60a3b8916c [CI Skip] bump/beta 7.3.3-13-x
skip-checks: true
2024-08-29 14:23:31 +00:00
Tarik Gul 1f20fdf377 Bump dev, and typescript (#567) 2024-08-29 17:18:39 +03:00
github-actions[bot] 64dcd40bee [CI Skip] bump/beta 7.3.3-12-x
skip-checks: true
2024-08-20 17:43:05 +00:00
Tarik Gul f3948b90f7 Upgrade deps (#566) 2024-08-20 20:37:19 +03:00
github-actions[bot] 83da578b60 [CI Skip] bump/beta 7.3.3-11-x
skip-checks: true
2024-05-14 00:43:00 +00:00
Tarik Gul 407ec8e1a1 Bump yarn to 4.2.2 (#565) 2024-05-14 03:38:02 +03:00
github-actions[bot] aa30920183 [CI Skip] bump/beta 7.3.3-10-x
skip-checks: true
2024-05-13 23:41:56 +00:00
Tarik Gul 35d56606bd Bump @polkadot/dev to 0.79.1 for topo sort (#564) 2024-05-14 02:37:40 +03:00
github-actions[bot] 4083abb1dd [CI Skip] bump/beta 7.3.3-9-x
skip-checks: true
2024-04-08 17:47:21 +00:00
Tarik Gul c6cb3a9226 Update ci checkout and setup_node v4 (#563) 2024-04-08 20:43:29 +03:00
github-actions[bot] 04d46701b1 [CI Skip] bump/beta 7.3.3-8-x
skip-checks: true
2024-03-26 01:14:57 +00:00
Tarik Gul 61f4c5eb7d Bump yarn to 4.1.1 (#562) 2024-03-26 03:11:57 +02:00
github-actions[bot] d0e99aebef [CI Skip] bump/beta 7.3.3-7-x
skip-checks: true
2024-02-17 13:49:09 +00:00
Tarik Gul dc752685d7 chore(yarn): update yarn to 4.1.0 (#560) 2024-02-17 15:43:24 +02:00
github-actions[bot] 9bf3c1be07 [CI Skip] bump/beta 7.3.3-6-x
skip-checks: true
2024-02-17 02:01:40 +00:00
Tarik Gul 32bd2172aa ci: add user (TarikGul) to auto-approve (#561) 2024-02-17 03:55:58 +02:00
github-actions[bot] 1f58821cd4 [CI Skip] bump/beta 7.3.3-5-x
skip-checks: true
2024-01-08 13:10:59 +00:00
Jaco 8352373fdd 2024 (#559) 2024-01-08 15:07:04 +02:00
github-actions[bot] 610fcee9cd [CI Skip] bump/beta 7.3.3-4-x
skip-checks: true
2023-12-19 15:09:13 +00:00
Jaco b086928d01 Add missing sideEffect declarations (#558) 2023-12-19 17:05:22 +02:00
github-actions[bot] 8b3bd58e79 [CI Skip] bump/beta 7.3.3-3-x
skip-checks: true
2023-12-19 08:46:15 +00:00
Jaco e6fd1e20a5 Bump dev w/ packageDetect adjustments (#557)
* Bump dev w/ packageDetect adjustments

* sideEffects
2023-12-19 10:42:52 +02:00
github-actions[bot] 22075f8262 [CI Skip] bump/beta 7.3.3-2-x
skip-checks: true
2023-12-18 12:05:07 +00:00
Jaco c8805a09dd Bump util (#556) 2023-12-18 14:01:44 +02:00
github-actions[bot] 758066b4ea [CI Skip] bump/beta 7.3.3-1-x
skip-checks: true
2023-12-18 08:29:42 +00:00
Jaco da7c71c32f Bump yarn berry, bump deps (#555) 2023-12-18 10:26:25 +02:00
github-actions[bot] cb38c6f1c5 [CI Skip] bump/beta 7.3.3-0-x
skip-checks: true
2023-12-12 05:34:17 +00:00
Jaco 39d5b3bcce Bump dev deps (w/ TS 5.3.3.) (#554) 2023-12-12 07:30:56 +02:00
github-actions[bot] 41c7af32c9 [CI Skip] release/stable 7.3.2
skip-checks: true
2023-12-06 09:28:24 +00:00
Jaco 68d698502d 7.3.2 (#553) 2023-12-06 11:23:54 +02:00
github-actions[bot] 3d4a87af6a [CI Skip] bump/beta 7.3.2-2-x
skip-checks: true
2023-12-06 08:57:15 +00:00
Jaco 77b1e338cf Sync fflate huffman tree with upstream (#552) 2023-12-06 10:52:27 +02:00
github-actions[bot] 3af17400ba [CI Skip] bump/beta 7.3.2-1-x
skip-checks: true
2023-12-06 08:48:37 +00:00
Jaco e16029776f Fix base64 last decoding offset (#551) 2023-12-06 10:44:07 +02:00
github-actions[bot] 61624a627b [CI Skip] bump/beta 7.3.2-0-x
skip-checks: true
2023-11-18 08:41:17 +00:00
Jaco c964570806 Bump common (#549) 2023-11-18 10:34:43 +02:00
github-actions[bot] f32846d41b [CI Skip] release/stable 7.3.1
skip-checks: true
2023-11-17 09:20:13 +00:00
Jaco 705b08765b 7.3.1 (#548) 2023-11-17 11:13:36 +02:00
github-actions[bot] 4f6771e758 [CI Skip] bump/beta 7.2.3-9-x
skip-checks: true
2023-11-17 08:15:49 +00:00
Jaco 731dee91e4 Update dev, drop Node 16 (#547) 2023-11-17 10:09:14 +02:00
github-actions[bot] b82e28ad4e [CI Skip] bump/beta 7.2.3-8-x
skip-checks: true
2023-10-15 10:55:03 +00:00
Jaco 6d5b3f5404 Bump TS (#546) 2023-10-15 13:46:13 +03:00
github-actions[bot] 1f643dd705 [CI Skip] bump/beta 7.2.3-7-x
skip-checks: true
2023-10-11 08:57:16 +00:00
Jaco af9491f7fd Bump deps (#545) 2023-10-11 11:49:18 +03:00
github-actions[bot] 7377da8e7e [CI Skip] bump/beta 7.2.3-6-x
skip-checks: true
2023-09-15 07:00:35 +00:00
Jaco 32fa12c3fa Bump deps (w/ util) (#543) 2023-09-15 09:53:57 +03:00
github-actions[bot] 6aabb2f869 [CI Skip] bump/beta 7.2.3-5-x
skip-checks: true
2023-09-14 05:23:44 +00:00
Jaco 0edb0289a9 Bump dev deps (#542) 2023-09-14 08:16:59 +03:00
github-actions[bot] 004996d772 [CI Skip] bump/beta 7.2.3-4-x
skip-checks: true
2023-08-31 12:51:49 +00:00
Jaco 7611fd1788 Collapse build:mac command into build (w/ detect) (#541) 2023-08-31 15:44:26 +03:00
github-actions[bot] e4f85e2358 [CI Skip] bump/beta 7.2.3-3-x
skip-checks: true
2023-08-30 06:37:28 +00:00
Jaco 6c5e7deaa5 Bump dev deps (#540) 2023-08-30 09:31:36 +03:00
github-actions[bot] 1f024c1da0 [CI Skip] bump/beta 7.2.3-2-x
skip-checks: true
2023-08-23 10:42:00 +00:00
Jaco 26b6cf843a Bump deps (#539) 2023-08-23 13:35:59 +03:00
github-actions[bot] 8e54efe4a5 [CI Skip] bump/beta 7.2.3-1-x
skip-checks: true
2023-08-20 06:57:44 +00:00
Jaco daecf47197 Bump deps (#537) 2023-08-20 09:51:51 +03:00
github-actions[bot] 6f5ed67aad [CI Skip] bump/beta 7.2.3-0-x
skip-checks: true
2023-08-18 06:44:50 +00:00
Jaco 8556566c1d Bump common (#536) 2023-08-18 09:38:25 +03:00
github-actions[bot] e28a5ffd4b [CI Skip] release/stable 7.2.2
skip-checks: true
2023-08-17 07:42:59 +00:00
Jaco 7f3ca3159d 7.2.2 (#535)
* 7.2.2

* CHANGELOG typo

* Adjust root dependencies
2023-08-17 10:37:26 +03:00
github-actions[bot] 3a3214e602 [CI Skip] bump/beta 7.2.2-12-x
skip-checks: true
2023-08-16 08:21:33 +00:00
Jaco 319f33bec1 Bump dev (#534)
* Bump dev

* Adjust linting
2023-08-16 11:14:44 +03:00
github-actions[bot] a8f5189252 [CI Skip] bump/beta 7.2.2-11-x
skip-checks: true
2023-08-16 06:22:41 +00:00
Jaco ee26a6ef98 Bump deps (w/ eslint updates) (#533) 2023-08-16 09:17:00 +03:00
github-actions[bot] 71291442bb [CI Skip] bump/beta 7.2.2-10-x
skip-checks: true
2023-07-06 07:27:43 +00:00
Jaco f26f855942 Bump deps (#532) 2023-07-06 10:22:27 +03:00
github-actions[bot] 3a06871f82 [CI Skip] bump/beta 7.2.2-9-x
skip-checks: true
2023-06-12 06:04:02 +00:00
Jaco 279da24ca1 Bump util (#531) 2023-06-12 08:57:00 +03:00
github-actions[bot] af81a69ba6 [CI Skip] bump/beta 7.2.2-8-x
skip-checks: true
2023-06-11 07:08:14 +00:00
Jaco 0b39c9d2f1 Bump common (#530) 2023-06-11 10:02:36 +03:00
github-actions[bot] 7d2de26fdb [CI Skip] bump/beta 7.2.2-7-x
skip-checks: true
2023-06-04 14:48:02 +00:00
Jaco fc370eedb2 Bump common (#529) 2023-06-04 17:42:36 +03:00
github-actions[bot] 792baf352c [CI Skip] bump/beta 7.2.2-6-x
skip-checks: true
2023-06-02 10:29:57 +00:00
Jaco a79d6ded77 Bump deps (w/ TS 5.1) (#528) 2023-06-02 13:24:22 +03:00
github-actions[bot] 51b45133d9 [CI Skip] bump/beta 7.2.2-5-x
skip-checks: true
2023-05-25 07:32:56 +00:00
Jaco b3c934d602 Bump dev deps (#527) 2023-05-25 10:27:24 +03:00
github-actions[bot] 25cd084f30 [CI Skip] bump/beta 7.2.2-4-x
skip-checks: true
2023-05-21 09:48:55 +00:00
Jaco 9df575ad7b Bump dev (w/ eslint config adj) (#526) 2023-05-21 12:43:14 +03:00
github-actions[bot] 0175ac56a7 [CI Skip] bump/beta 7.2.2-3-x
skip-checks: true
2023-05-18 09:04:24 +00:00
Jaco e589fba3b1 Adjust tsconfig usage (w/ latest dev) (#525) 2023-05-18 11:59:20 +03:00
github-actions[bot] 570c46e889 [CI Skip] bump/beta 7.2.2-2-x
skip-checks: true
2023-05-18 05:28:27 +00:00
Jaco 4d002c7563 Bump dev deps (#524) 2023-05-18 08:22:56 +03:00
github-actions[bot] 6aeaa69a8b [CI Skip] bump/beta 7.2.2-1-x
skip-checks: true
2023-05-16 06:36:58 +00:00
Jaco 4565f85077 CJS export cleanups (#523) 2023-05-16 09:31:41 +03:00
github-actions[bot] 0d0dcbf005 [CI Skip] bump/beta 7.2.2-0-x
skip-checks: true
2023-05-13 08:49:41 +00:00
Jaco 7e38ff8faf Bump util (#522) 2023-05-13 11:43:56 +03:00
github-actions[bot] 5640651945 [CI Skip] release/stable 7.2.1
skip-checks: true
2023-05-13 08:07:05 +00:00
Jaco 657ac95ad9 7.2.1 (#521) 2023-05-13 11:00:42 +03:00
github-actions[bot] 23441ec34d [CI Skip] bump/beta 7.1.3-3-x
skip-checks: true
2023-05-08 13:40:53 +00:00
Jaco b7768c369c cjs/bytes.js generation adjustment (#520) 2023-05-08 16:36:00 +03:00
github-actions[bot] 646eabf516 [CI Skip] bump/beta 7.1.3-2-x
skip-checks: true
2023-05-06 08:54:15 +00:00
Jaco ac36b68a5e Bump dev (#519) 2023-05-06 11:49:24 +03:00
github-actions[bot] 390edd8b6d [CI Skip] bump/beta 7.1.3-1-x
skip-checks: true
2023-05-05 08:25:04 +00:00
Jaco 083eba1d8f Bump dev (w/ dev loader order fix) (#518) 2023-05-05 11:19:59 +03:00
Jaco 0a70cc7cfb Bump common (#517) 2023-05-01 20:12:38 +03:00
github-actions[bot] 034f625118 [CI Skip] bump/beta 7.1.3-0-x
skip-checks: true
2023-04-29 06:10:29 +00:00
Jaco 919c4aa7d4 Bump common (#516) 2023-04-29 09:04:19 +03:00
github-actions[bot] 85350b15d2 [CI Skip] release/stable 7.1.2
skip-checks: true
2023-04-28 05:44:41 +00:00
Jaco fcc48bf20a 7.1.2 (#515) 2023-04-28 08:40:05 +03:00
github-actions[bot] c408836bc6 [CI Skip] bump/beta 7.1.2-0-x
skip-checks: true
2023-04-22 08:06:12 +00:00
Jaco 194d1a6cd4 Bump common (#514) 2023-04-22 11:01:26 +03:00
github-actions[bot] fbb7d77f06 [CI Skip] release/stable 7.1.1
skip-checks: true
2023-04-22 07:06:48 +00:00
Jaco 1536cd9b48 7.1.1 (#513) 2023-04-22 10:01:26 +03:00
github-actions[bot] 695ccae218 [CI Skip] bump/beta 7.0.4-15-x
skip-checks: true
2023-04-13 11:32:52 +00:00
Jaco bd8d729765 Add util tests for (small) base64 decoder (#512) 2023-04-13 14:28:08 +03:00
github-actions[bot] 2453c8728b [CI Skip] bump/beta 7.0.4-14-x
skip-checks: true
2023-04-08 07:09:53 +00:00
Jaco f39f0d72f2 Bump TypeScript (#511) 2023-04-08 10:04:03 +03:00
github-actions[bot] 89739683f5 [CI Skip] bump/beta 7.0.4-13-x
skip-checks: true
2023-04-04 05:33:47 +00:00
Jaco 7f0c60b4f0 Update lock wf (#510) 2023-04-04 08:27:30 +03:00
github-actions[bot] 6ee5b6da86 [CI Skip] bump/beta 7.0.4-12-x
skip-checks: true
2023-04-01 07:31:39 +00:00
Jaco 68575449f1 Bump deps (#509) 2023-04-01 10:25:56 +03:00
github-actions[bot] ea7035a484 [CI Skip] bump/beta 7.0.4-11-x
skip-checks: true
2023-03-25 15:52:26 +00:00
Jaco cbb7cd94f7 Add repo dev req. for Node.js (#508) 2023-03-25 17:46:17 +02:00
github-actions[bot] d0af71031f [CI Skip] bump/beta 7.0.4-10-x
skip-checks: true
2023-03-25 10:58:53 +00:00
Jaco 929401b8b6 Bump dev (w/ some node:test adjustments) (#507) 2023-03-25 12:51:41 +02:00
github-actions[bot] 778879b1c1 [CI Skip] bump/beta 7.0.4-9-x
skip-checks: true
2023-03-25 07:35:59 +00:00
Jaco cadb0d9123 Bump util (#506) 2023-03-25 09:29:43 +02:00
github-actions[bot] 4e505bbe29 [CI Skip] bump/beta 7.0.4-8-x
skip-checks: true
2023-03-19 08:10:28 +00:00
Jaco 72cbdf6eaa Bump common deps (#505) 2023-03-19 10:05:23 +02:00
github-actions[bot] a032cbce6e [CI Skip] bump/beta 7.0.4-7-x
skip-checks: true
2023-03-18 10:02:53 +00:00
Jaco 12a5b0da0f Bump deps (& remove unused overrides) (#504) 2023-03-18 11:57:41 +02:00
github-actions[bot] f1129ddcbb [CI Skip] bump/beta 7.0.4-6-x
skip-checks: true
2023-03-17 06:05:27 +00:00
Jaco 7d2a29d231 Bump to TS 5.0 (#503) 2023-03-17 07:59:57 +02:00
github-actions[bot] c5550ad559 [CI Skip] bump/beta 7.0.4-5-x
skip-checks: true
2023-03-17 05:25:08 +00:00
Jaco d1fd2a74a4 Bump dev deps (#502) 2023-03-17 07:18:36 +02:00
github-actions[bot] f1d678132a [CI Skip] bump/beta 7.0.4-4-x
skip-checks: true
2023-03-15 16:39:54 +00:00
Jaco 784422a129 Bump dev (w/ /src/ caching only) (#501) 2023-03-15 18:34:19 +02:00
Jaco 0a6b25fbdd Bump dev (#500) 2023-03-15 17:42:17 +02:00
github-actions[bot] 6bc249181b [CI Skip] bump/beta 7.0.4-3-x
skip-checks: true
2023-03-15 14:55:48 +00:00
Jaco a47fb3bff9 Bump dev (#499) 2023-03-15 16:50:05 +02:00
github-actions[bot] d21c3fc639 [CI Skip] bump/beta 7.0.4-2-x
skip-checks: true
2023-03-14 11:01:52 +00:00
Jaco 7da2f705dc Remove stale workflow (#498) 2023-03-14 12:56:26 +02:00
github-actions[bot] 69278851bc [CI Skip] bump/beta 7.0.4-1-x
skip-checks: true
2023-03-12 09:44:54 +00:00
Jaco 41dbf12257 Bump dev (#497) 2023-03-12 11:39:33 +02:00
github-actions[bot] 7a8ce5ea3a [CI Skip] bump/beta 7.0.4-0-x
skip-checks: true
2023-03-11 07:22:45 +00:00
Jaco 7d24e46947 Bump util (#496) 2023-03-11 09:16:35 +02:00
github-actions[bot] 2bd507af55 [CI Skip] release/stable 7.0.3
skip-checks: true
2023-03-11 06:25:47 +00:00
Jaco 7232fd88b5 7.0.3 (#495) 2023-03-11 08:20:24 +02:00
github-actions[bot] dbfd08942a [CI Skip] bump/beta 7.0.3-5-x
skip-checks: true
2023-03-10 06:29:35 +00:00
Jaco 5d7a167d19 Update GH actions (#494) 2023-03-10 08:24:17 +02:00
github-actions[bot] b5478b52b4 [CI Skip] bump/beta 7.0.3-4-x
skip-checks: true
2023-03-09 11:27:31 +00:00
Jaco 66f4af6dda Align tsconfig to allow moduleResolution: nodenext (#493) 2023-03-09 13:21:53 +02:00
github-actions[bot] 74344c862c [CI Skip] bump/beta 7.0.3-3-x
skip-checks: true
2023-03-09 08:44:52 +00:00
Jaco 783476fd8d Use .js imports in src (#492)
* Use .js imports in src

* Bump dev
2023-03-09 10:39:39 +02:00
github-actions[bot] 0a7af910e1 [CI Skip] bump/beta 7.0.3-2-x
skip-checks: true
2023-03-06 12:18:06 +00:00
Jaco 478cd6ffcf Bump dev deps (#491) 2023-03-06 14:11:50 +02:00
github-actions[bot] df61ff95ca [CI Skip] bump/beta 7.0.3-1-x
skip-checks: true
2023-03-05 11:49:20 +00:00
Jaco 9137bd9848 jg-rm-babel-config (#490) 2023-03-05 13:44:14 +02:00
github-actions[bot] 3479d7f63b [CI Skip] bump/beta 7.0.3-0-x
skip-checks: true
2023-03-04 15:50:45 +00:00
Jaco a718bcbb0c Bump common deps (#489) 2023-03-04 17:45:40 +02:00
github-actions[bot] ec1958dfde [CI Skip] release/stable 7.0.2
skip-checks: true
2023-03-04 13:42:57 +00:00
Jaco a1f6452a7d 7.0.2 (#488) 2023-03-04 15:37:42 +02:00
github-actions[bot] 13e8c6af1d [CI Skip] release/stable 7.0.1
skip-checks: true
2023-03-04 12:39:32 +00:00
Jaco 56f98e67a1 7.0.1 (#487) 2023-03-04 14:33:31 +02:00
github-actions[bot] 5023c02a73 [CI Skip] bump/beta 6.4.2-36-x
skip-checks: true
2023-03-04 12:03:32 +00:00
Jaco 3b286e6034 Use tsc compiler (#486) 2023-03-04 13:57:24 +02:00
github-actions[bot] bccb16f691 [CI Skip] bump/beta 6.4.2-35-x
skip-checks: true
2023-03-03 12:07:29 +00:00
Jaco aeae6c137e Swap TS -> JS compiler to use swc (#485) 2023-03-03 14:02:01 +02:00
github-actions[bot] 2a2bd06284 [CI Skip] bump/beta 6.4.2-34-x
skip-checks: true
2023-03-03 09:31:06 +00:00
Jaco 1310dca729 Bump dev & update gh workflows (#484) 2023-03-03 11:25:46 +02:00
github-actions[bot] 34f2b544f0 [CI Skip] bump/beta 6.4.2-33-x
skip-checks: true
2023-03-01 12:11:29 +00:00
Jaco dde2f92445 Add wf continue-on-error: true (#483) 2023-03-01 14:06:04 +02:00
github-actions[bot] b9ad508d27 [CI Skip] bump/beta 6.4.2-32-x
skip-checks: true
2023-03-01 08:16:32 +00:00
Jaco ca7e44c25a Align gh workflows (#482) 2023-03-01 10:09:28 +02:00
github-actions[bot] a0de0ac427 [CI Skip] bump/beta 6.4.2-31-x
skip-checks: true
2023-02-28 10:51:06 +00:00
Jaco 2893343bf2 Bump dev (#481)
* Bump dev

* typo
2023-02-28 12:45:45 +02:00
github-actions[bot] 8b70740a18 [CI Skip] bump/beta 6.4.2-30-x
skip-checks: true
2023-02-27 09:46:41 +00:00
Jaco 5e54136fff Bump deps (#480) 2023-02-27 11:41:21 +02:00
github-actions[bot] 35b4c38be4 [CI Skip] bump/beta 6.4.2-29-x
skip-checks: true
2023-02-27 09:17:59 +00:00
Jaco e1b24a61c6 Bump dev deps (#479) 2023-02-27 11:12:34 +02:00
github-actions[bot] a71d353fff [CI Skip] bump/beta 6.4.2-28-x
skip-checks: true
2023-02-25 08:23:48 +00:00
Jaco 218d2b9217 Remove usage of describe.each (#478) 2023-02-25 10:18:40 +02:00
github-actions[bot] 0429de0429 [CI Skip] bump/beta 6.4.2-27-x
skip-checks: true
2023-02-22 07:20:17 +00:00
Jaco 5f18253ba8 Bump deps (#477)
* Bump deps

* Bump dev
2023-02-22 09:14:54 +02:00
github-actions[bot] b17de3422a [CI Skip] bump/beta 6.4.2-26-x
skip-checks: true
2023-02-20 10:38:08 +00:00
Jaco 935f92dd5b Swap jest test environment (#476)
* Swap jest test environment

* Remove jest config
2023-02-20 12:32:42 +02:00
github-actions[bot] ea79adf45d [CI Skip] bump/beta 6.4.2-25-x
skip-checks: true
2023-02-19 09:39:53 +00:00
Jaco e71807c2a3 Bump deps (#475) 2023-02-19 11:34:35 +02:00
github-actions[bot] 04365b87a5 [CI Skip] bump/beta 6.4.2-24-x
skip-checks: true
2023-02-19 07:49:49 +00:00
Jaco f5856d091b Bump dev (#474)
* Bump dev

* measure overall runUnaasisted duration
2023-02-19 09:44:27 +02:00
github-actions[bot] 45554b753f [CI Skip] bump/beta 6.4.2-23-x
skip-checks: true
2023-02-18 13:12:54 +00:00
Jaco 5967b48515 Convert all tests to ESM (#473)
* Convert all tests to ESM

* Add nodeWithBuildLoader
2023-02-18 15:07:37 +02:00
github-actions[bot] 2d85a62bb7 [CI Skip] bump/beta 6.4.2-23-x
skip-checks: true
2023-02-18 11:47:32 +00:00
Jaco 39ca57f059 Bump deps (#472) 2023-02-18 13:42:24 +02:00
github-actions[bot] 5a08739f24 [CI Skip] bump/beta 6.4.2-22-x
skip-checks: true
2023-02-15 10:02:22 +00:00
Jaco fe09bc21ed Bump deps (#471) 2023-02-15 11:56:43 +02:00
github-actions[bot] 8706cdb9c2 [CI Skip] bump/beta 6.4.2-21-x
skip-checks: true
2023-02-15 07:24:10 +00:00
Jaco 498a58d95a Fix CI release workflow (#470) 2023-02-15 09:17:39 +02:00
Jaco 2501f771a7 Use latest LTS for CI scripts (#469) 2023-02-14 10:49:30 +02:00
github-actions[bot] 55aef41eee [CI Skip] bump/beta 6.4.2-20-x
skip-checks: true
2023-02-12 11:57:25 +00:00
Jaco e14c249ae2 Bump common (#468) 2023-02-12 13:52:14 +02:00
github-actions[bot] 561abdbf0d [CI Skip] bump/beta 6.4.2-19-x
skip-checks: true
2023-02-05 12:12:41 +00:00
Jaco 964432c184 Bump dev (#467) 2023-02-05 14:07:17 +02:00
github-actions[bot] 4944d228cd [CI Skip] bump/beta 6.4.2-18-x
skip-checks: true
2023-02-05 07:57:54 +00:00
Jaco de4a6c69fe Bump dev (#466) 2023-02-05 09:53:11 +02:00
github-actions[bot] f3ffb229ff [CI Skip] bump/beta 6.4.2-17-x
skip-checks: true
2023-02-03 08:53:16 +00:00
Jaco 3910ad5241 Bump deps (incl. TS) (#465) 2023-02-03 10:48:30 +02:00
github-actions[bot] e8cc388f3a [CI Skip] bump/beta 6.4.2-16-x
skip-checks: true
2023-01-28 07:52:24 +00:00
Jaco 888a5d00ed Bump util (#464) 2023-01-28 09:47:48 +02:00
github-actions[bot] dcd5533149 [CI Skip] bump/beta 6.4.2-15-x
skip-checks: true
2023-01-27 08:31:11 +00:00
Jaco f3a5b7e373 Convert pack wasm to ESM (#463)
* Convert pack wasm to ESM

* Cleanup clean scripts

* Adjust
2023-01-27 10:26:14 +02:00
Jaco 6f06fe6b2a Bump dev (#462) 2023-01-27 10:00:18 +02:00
github-actions[bot] ac96179904 [CI Skip] bump/beta 6.4.2-14-x
skip-checks: true
2023-01-25 07:35:27 +00:00
Jaco c37f707b15 Bump actions (#461)
* Bump actions

* Bump dev
2023-01-25 09:29:12 +02:00
github-actions[bot] 80f40a500c [CI Skip] bump/beta 6.4.2-13-x
skip-checks: true
2023-01-22 07:01:14 +00:00
Jaco 445863a940 Bump dev (#460) 2023-01-22 08:56:01 +02:00
github-actions[bot] 30a8ab0d8c [CI Skip] bump/beta 6.4.2-12-x
skip-checks: true
2023-01-15 08:50:16 +00:00
Jaco 4a239f5ed5 Bump dev (#459) 2023-01-15 10:45:51 +02:00
github-actions[bot] 3db8d49d11 [CI Skip] bump/beta 6.4.2-11-x
skip-checks: true
2023-01-15 08:23:38 +00:00
Jaco 9885b65cf0 Bump deps (#458) 2023-01-15 10:18:59 +02:00
github-actions[bot] 5c867e0cd4 [CI Skip] bump/beta 6.4.2-10-x
skip-checks: true
2023-01-13 08:03:58 +00:00
Jaco 00b79f4f9f Bump common (#457) 2023-01-13 09:58:48 +02:00
github-actions[bot] 0f82e9c5d8 [CI Skip] bump/beta 6.4.2-9-x
skip-checks: true
2023-01-08 08:35:35 +00:00
Jaco 007fc9923a Bump deps (#456) 2023-01-08 10:30:40 +02:00
github-actions[bot] ccfe31d9b5 [CI Skip] bump/beta 6.4.2-8-x
skip-checks: true
2023-01-06 10:50:39 +00:00
Jaco f921359f64 Bump deps (#455) 2023-01-06 12:45:58 +02:00
github-actions[bot] 4463395dfe [CI Skip] bump/beta 6.4.2-7-x
skip-checks: true
2023-01-01 08:27:44 +00:00
Jaco f4080e5754 Update headers for 2023 (#454) 2023-01-01 10:23:06 +02:00
github-actions[bot] c6bb302f9c [CI Skip] bump/beta 6.4.2-6-x
skip-checks: true
2022-12-26 07:57:35 +00:00
Jaco 6d7ace4291 Bump dev (#453) 2022-12-26 09:52:45 +02:00
github-actions[bot] 53a62bec02 [CI Skip] bump/beta 6.4.2-5-x
skip-checks: true
2022-12-14 06:15:33 +00:00
Jaco 263caf3238 Bump dev (w/ deprecation warnings) (#451) 2022-12-14 08:09:34 +02:00
github-actions[bot] 6e0d56e955 [CI Skip] bump/beta 6.4.2-4-x
skip-checks: true
2022-12-13 07:09:19 +00:00
Jaco cf9d894556 Adjust TS target (#450) 2022-12-13 09:03:24 +02:00
github-actions[bot] 1c1a10f14b [CI Skip] bump/beta 6.4.2-3-x
skip-checks: true
2022-12-08 07:07:54 +00:00
Jaco 7d3ce85684 Remove CC (#449) 2022-12-08 09:00:31 +02:00
github-actions[bot] 5fd16cda08 [CI Skip] bump/beta 6.4.2-2-x
skip-checks: true
2022-12-08 06:27:23 +00:00
Jaco 87fc9d9ee1 Bump TS (#448) 2022-12-08 08:21:37 +02:00
github-actions[bot] bf1a4b7b7f [CI Skip] bump/beta 6.4.2-1-x
skip-checks: true
2022-12-07 13:56:19 +00:00
Jaco 4c10357c41 Update token retrieval (#447) 2022-12-07 15:49:23 +02:00
github-actions[bot] 4ceb620462 [CI Skip] bump/beta 6.4.2-0-x
skip-checks: true
2022-12-04 10:52:32 +00:00
Jaco 97ef0b0dd6 Bump util (#446) 2022-12-04 12:46:42 +02:00
github-actions[bot] a27a5ccf3c [CI Skip] release/stable 6.4.1
skip-checks: true
2022-12-03 07:54:59 +00:00
Jaco 8e47fb20a1 6.4.1 (#445) 2022-12-03 09:47:40 +02:00
github-actions[bot] a014aea1b4 [CI Skip] bump/beta 6.3.2-37-x
skip-checks: true
2022-12-02 11:51:59 +00:00
Jaco 18cb000218 Apply /*#__PURE__*/ annotations (#444) 2022-12-02 13:46:17 +02:00
github-actions[bot] 0cb6566bab [CI Skip] bump/beta 6.3.2-36-x
skip-checks: true
2022-11-27 14:41:05 +00:00
Jaco 9ae9de4ac9 Bump util (#443) 2022-11-27 16:34:07 +02:00
github-actions[bot] 04ac7dd00d [CI Skip] bump/beta 6.3.2-35-x
skip-checks: true
2022-11-20 09:38:34 +00:00
Jaco 5a4a2fde71 Bump TS (#442) 2022-11-20 11:33:02 +02:00
github-actions[bot] 71237d7df7 [CI Skip] bump/beta 6.3.2-34-x
skip-checks: true
2022-11-13 09:39:03 +00:00
Jaco 424b3fe653 Bump util (#441) 2022-11-13 11:33:24 +02:00
github-actions[bot] 7b56956fdd [CI Skip] bump/beta 6.3.2-33-x
skip-checks: true
2022-11-05 15:42:58 +00:00
Jaco a991236fa3 Bump dev deps (#440) 2022-11-05 17:36:20 +02:00
github-actions[bot] 168e862e3a [CI Skip] bump/beta 6.3.2-32-x
skip-checks: true
2022-10-30 08:16:55 +00:00
Jaco 1dfc6660ba Bump dev (#439) 2022-10-30 10:11:24 +02:00
github-actions[bot] 21b47e7924 [CI Skip] bump/beta 6.3.2-31-x
skip-checks: true
2022-10-22 07:26:39 +00:00
Jaco d6ce0d1bf8 Bump dev (#438) 2022-10-22 10:21:29 +03:00
github-actions[bot] c5cd242033 [CI Skip] bump/beta 6.3.2-30-x
skip-checks: true
2022-10-19 05:16:34 +00:00
Jaco 73d21079a4 Bump deps (#437) 2022-10-19 08:11:15 +03:00
github-actions[bot] e0edfa3cec [CI Skip] bump/beta 6.3.2-29-x
skip-checks: true
2022-10-15 10:22:55 +00:00
Jaco 674b3c7c12 Bump util (#436) 2022-10-15 13:16:36 +03:00
github-actions[bot] 16ecd2b8c2 [CI Skip] bump/beta 6.3.2-28-x
skip-checks: true
2022-10-14 07:25:35 +00:00
Jaco ee575c2589 Bump dev (#435) 2022-10-14 10:19:10 +03:00
github-actions[bot] 57c6b454f6 [CI Skip] bump/beta 6.3.2-27-x
skip-checks: true
2022-10-07 05:08:03 +00:00
Jaco e66f1830b0 Bump util (#434) 2022-10-07 08:01:50 +03:00
github-actions[bot] ea93565e11 [CI Skip] bump/beta 6.3.2-26-x
skip-checks: true
2022-10-06 07:38:57 +00:00
Jaco 8eabfef781 Bump deps (#433) 2022-10-06 10:32:39 +03:00
github-actions[bot] 9bb9e8d241 [CI Skip] bump/beta 6.3.2-25-x
skip-checks: true
2022-09-30 06:08:42 +00:00
Jaco 6da8edae2c Bump deps (#432) 2022-09-30 09:04:02 +03:00
github-actions[bot] eae8054c0e [CI Skip] bump/beta 6.3.2-24-x
skip-checks: true
2022-09-28 10:50:38 +00:00
Jaco fd7f9caca9 Bump TS (#431) 2022-09-28 13:45:00 +03:00
github-actions[bot] e12cffa958 [CI Skip] bump/beta 6.3.2-23-x
skip-checks: true
2022-09-24 06:11:40 +00:00
Jaco 7519e48482 Bump deps (#430) 2022-09-24 09:07:11 +03:00
github-actions[bot] 24780d5723 [CI Skip] bump/beta 6.3.2-22-x
skip-checks: true
2022-09-22 07:16:24 +00:00
Jaco 06d74925ec Bump deps (#429) 2022-09-22 10:11:29 +03:00
github-actions[bot] 6144148bc3 [CI Skip] bump/beta 6.3.2-21-x
skip-checks: true
2022-09-17 07:21:23 +00:00
Jaco 39d8fd81e0 Bump common (#428)
* Bump common

* Bump deps
2022-09-17 10:15:51 +03:00
github-actions[bot] a90ccb9718 [CI Skip] bump/beta 6.3.2-20-x
skip-checks: true
2022-09-12 08:39:09 +00:00
Jaco 2a28c02965 Bump deps (#427) 2022-09-12 11:34:25 +03:00
github-actions[bot] b032b2baf0 [CI Skip] bump/beta 6.3.2-19-x
skip-checks: true
2022-09-09 06:11:02 +00:00
Jaco e111622377 Bump deps (#426) 2022-09-09 09:05:29 +03:00
github-actions[bot] 21a5e14552 [CI Skip] bump/beta 6.3.2-18-x
skip-checks: true
2022-09-02 08:55:26 +00:00
Jaco 71d23d0d34 Bump common (#425) 2022-09-02 11:50:10 +03:00
github-actions[bot] 650320a18b [CI Skip] bump/beta 6.3.2-17-x
skip-checks: true
2022-08-31 05:51:09 +00:00
Jaco e0172f3a7d Adjust test execution (#424) 2022-08-31 08:45:32 +03:00
github-actions[bot] 8db05486c0 [CI Skip] bump/beta 6.3.2-16-x
skip-checks: true
2022-08-26 15:02:57 +00:00
Jaco 22328a1368 Pin Github actions (#422) 2022-08-26 17:57:59 +03:00
github-actions[bot] 7dd2cf97e6 [CI Skip] bump/beta 6.3.2-15-x
skip-checks: true
2022-08-26 12:58:45 +00:00
Jaco 2191a78e19 Bump TS (#421) 2022-08-26 15:52:55 +03:00
github-actions[bot] 856d97740e [CI Skip] bump/beta 6.3.2-14-x
skip-checks: true
2022-08-24 08:59:26 +00:00
Jaco b80f22abae Bump deps (#420) 2022-08-24 11:54:16 +03:00
github-actions[bot] 9dfc893309 [CI Skip] bump/beta 6.3.2-13-x
skip-checks: true
2022-08-21 05:50:29 +00:00
Jaco 1087c5b1cf Bump common (#419) 2022-08-21 08:45:51 +03:00
github-actions[bot] 781632d134 [CI Skip] bump/beta 6.3.2-12-x
skip-checks: true
2022-08-19 08:46:11 +00:00
Jaco 1e149c5844 Bump pjs/dev (#418) 2022-08-19 11:41:21 +03:00
github-actions[bot] 8ba4a5afb3 [CI Skip] bump/beta 6.3.2-11-x
skip-checks: true
2022-08-16 12:10:05 +00:00
Jaco 5ec9f9f52e Bump deps (#417) 2022-08-16 15:04:17 +03:00
github-actions[bot] 1a343bc065 [CI Skip] bump/beta 6.3.2-10-x
skip-checks: true
2022-08-12 09:09:07 +00:00
Jaco 3eff5e7a18 Bump deps (#416) 2022-08-12 12:03:12 +03:00
github-actions[bot] ed5f749d38 [CI Skip] bump/beta 6.3.2-9-x
skip-checks: true
2022-08-12 05:48:39 +00:00
Jaco ab02a865b0 Bump dev (#415) 2022-08-12 08:42:44 +03:00
github-actions[bot] 16fb3fe24c [CI Skip] bump/beta 6.3.2-8-x
skip-checks: true
2022-08-07 08:59:11 +00:00
Jaco 0378fba23c Bump dev (#414) 2022-08-07 11:53:14 +03:00
github-actions[bot] 429eff7c2e [CI Skip] bump/beta 6.3.2-7-x
skip-checks: true
2022-08-05 13:55:44 +00:00
Jaco 068343a2cb Bump dev deps (#413) 2022-08-05 16:50:43 +03:00
github-actions[bot] 5f91e4da6e [CI Skip] bump/beta 6.3.2-6-x
skip-checks: true
2022-08-05 06:04:47 +00:00
Jaco d73f3598e4 Bump dev (#412) 2022-08-05 09:00:16 +03:00
github-actions[bot] a8e512a3d3 [CI Skip] bump/beta 6.3.2-5-x
skip-checks: true
2022-08-02 04:38:56 +00:00
Jaco e35ceda7db Bump deps (#411) 2022-08-02 07:33:25 +03:00
github-actions[bot] 2fc192f2d4 [CI Skip] bump/beta 6.3.2-4-x
skip-checks: true
2022-07-30 05:18:06 +00:00
Jaco 7c1c54a413 Adjust CC ignores (#410) 2022-07-30 08:12:44 +03:00
github-actions[bot] b2bf04e475 [CI Skip] bump/beta 6.3.2-3-x
skip-checks: true
2022-07-30 04:51:42 +00:00
Jaco f0d95d63ad Allow errors on GH actions (#409) 2022-07-30 07:47:10 +03:00
github-actions[bot] c2aba270ff [CI Skip] bump/beta 6.3.2-2-x
skip-checks: true
2022-07-29 10:28:04 +00:00
Jaco 59a2ba5135 Bump common (#408) 2022-07-29 13:23:06 +03:00
github-actions[bot] 77b3674d01 [CI Skip] bump/beta 6.3.2-1-x
skip-checks: true
2022-07-26 11:57:21 +00:00
Jaco 34779964ce Bump deps (#407) 2022-07-26 14:51:40 +03:00
github-actions[bot] a9aa786332 [CI Skip] bump/beta 6.3.2-0-x
skip-checks: true
2022-07-21 07:37:39 +00:00
Jaco cd86d0bf35 Bump common (#406) 2022-07-21 10:32:55 +03:00
github-actions[bot] 6ce3e3d67c [CI Skip] release/stable 6.3.1
skip-checks: true
2022-07-21 05:20:47 +00:00
Jaco af4ed8a1db 6.3.1 (#405) 2022-07-21 08:15:29 +03:00
github-actions[bot] 57248e7ce4 [CI Skip] bump/beta 6.2.4-10-x
skip-checks: true
2022-07-19 06:50:16 +00:00
Jaco fe91118385 Optimize packed WASM base64 decoding loop (#404) 2022-07-19 09:45:11 +03:00
github-actions[bot] b36cd04348 [CI Skip] bump/beta 6.2.4-9-x
skip-checks: true
2022-07-19 05:50:20 +00:00
Jaco 8ae4176af6 Bump dev deps (#403) 2022-07-19 08:45:50 +03:00
github-actions[bot] 775b64f1bd [CI Skip] bump/beta 6.2.4-8-x
skip-checks: true
2022-07-15 10:02:49 +00:00
Jaco 66ebae8c62 Slight adjustment to tests (#402)
* Slight adjustment to tests

* beforeAll adjustment

* Adjust test forEach

* Test import map removal

* Adjust

* Remove input import_map template
2022-07-15 12:57:59 +03:00
github-actions[bot] c925bcf8d9 [CI Skip] bump/beta 6.2.4-7-x
skip-checks: true
2022-07-11 13:43:28 +00:00
Jaco beb995d507 Adjust import_map.in.json (#401) 2022-07-11 16:36:57 +03:00
github-actions[bot] 1523a53e10 [CI Skip] bump/beta 6.2.4-6-x
skip-checks: true
2022-07-11 06:08:08 +00:00
Jaco 188f7d3edc Bump common (#400) 2022-07-11 09:02:04 +03:00
github-actions[bot] 6da14ce25b [CI Skip] bump/beta 6.2.4-5-x
skip-checks: true
2022-07-11 05:25:44 +00:00
Jaco 9cacf07fe3 Bump dev (#399) 2022-07-11 08:20:04 +03:00
github-actions[bot] d0258cb3f3 [CI Skip] bump/beta 6.2.4-4-x
skip-checks: true
2022-07-09 08:01:12 +00:00
Jaco b5ae0089d1 Single deno step (aligning with other repos) (#396)
* Single deno step (aligning with other repos)

* skip root mod.ts
2022-07-09 10:56:18 +03:00
github-actions[bot] e07bd1eb00 [CI Skip] bump/beta 6.2.4-3-x
skip-checks: true
2022-07-08 21:41:19 +00:00
Jaco 6d79a71d93 Bump dev deps (#395) 2022-07-09 00:36:12 +03:00
github-actions[bot] c3289ca919 [CI Skip] bump/beta 6.2.4-2-x
skip-checks: true
2022-07-08 13:37:31 +00:00
Jaco b7648e5883 Adjust eslint config (#394) 2022-07-08 16:32:39 +03:00
github-actions[bot] 03b487ae81 [CI Skip] bump/beta 6.2.4-1-x
skip-checks: true
2022-07-08 07:46:21 +00:00
Jaco b1350bd8b4 Adjust size stats output on build (#393) 2022-07-08 10:41:42 +03:00
github-actions[bot] 1516d23ea4 [CI Skip] bump/beta 6.2.4-0-x
skip-checks: true
2022-07-08 04:50:05 +00:00
Jaco 9abaae980f Bump dev (#392)
* Bump dev

* Rebump
2022-07-08 07:44:57 +03:00
github-actions[bot] 370a529668 [CI Skip] release/stable 6.2.3
skip-checks: true
2022-07-07 06:42:17 +00:00
Jaco b7486f4f3b 6.2.3 (w/ dev publish fix) (#391) 2022-07-07 09:37:32 +03:00
Jaco ff4a877ef9 6.2.3 (#390)
* 6.2.3

* Skip extra installs on linting (non-build)
2022-07-07 09:19:49 +03:00
github-actions[bot] e0f741db37 [CI Skip] bump/beta 6.2.3-4-x
skip-checks: true
2022-07-06 11:09:51 +00:00
Jaco 3107861322 Adjust issue template (#389) 2022-07-06 14:04:54 +03:00
github-actions[bot] 7eff345003 [CI Skip] bump/beta 6.2.3-3-x
skip-checks: true
2022-07-06 10:24:19 +00:00
Jaco 00f7da2136 Bump depv deps (#388) 2022-07-06 13:19:14 +03:00
github-actions[bot] 150a143163 [CI Skip] bump/beta 6.2.3-2-x
skip-checks: true
2022-07-06 09:51:51 +00:00
Jaco f31ec881ef Additional platform-specific tests (#387)
* Additional platform-specific tests

* align casing

* Step rename

* lenIn/lenOut for deno

* Remove install ls

* Run deno tests on full suite

* trigger
2022-07-06 12:46:38 +03:00
github-actions[bot] 0b838d2055 [CI Skip] bump/beta 6.2.3-1-x
skip-checks: true
2022-07-05 21:27:10 +00:00
Jaco b68aefe64d Additional CI actions (#386) 2022-07-06 00:21:24 +03:00
github-actions[bot] 9340c296ee [CI Skip] bump/beta 6.2.3-0-x
skip-checks: true
2022-07-04 06:40:44 +00:00
Jaco 132ed20d18 Bump common (#385) 2022-07-04 09:33:42 +03:00
github-actions[bot] 2927c37776 [CI Skip] release/stable 6.2.2
skip-checks: true
2022-07-04 05:57:19 +00:00
Jaco ac63788ecd 6.2.2 (#384) 2022-07-04 08:51:08 +03:00
github-actions[bot] 0a64c9d329 [CI Skip] bump/beta 6.2.2-2-x
skip-checks: true
2022-07-04 05:01:04 +00:00
Jaco 81c9f3aa33 Bump deps (#383) 2022-07-04 07:55:37 +03:00
github-actions[bot] 6fae33074a [CI Skip] bump/beta 6.2.2-1-x
skip-checks: true
2022-07-03 18:45:43 +00:00
Jaco 679b282061 Remove extra serialize/deseralize on ed pair creation (#382) 2022-07-03 21:40:11 +03:00
github-actions[bot] 396b4cb598 [CI Skip] bump/beta 6.2.2-0-x
skip-checks: true
2022-07-03 18:26:17 +00:00
Jaco 8b67b82047 ed25519 signing leaks (#381) 2022-07-03 21:20:41 +03:00
github-actions[bot] da7d771898 [CI Skip] release/stable 6.2.1
skip-checks: true
2022-07-01 14:26:19 +00:00
Jaco 42b5942886 6.2.1 (#380) 2022-07-01 17:20:16 +03:00
github-actions[bot] d848c42bd3 [CI Skip] bump/beta 6.1.6-5-x
skip-checks: true
2022-07-01 14:07:29 +00:00
Jaco e9d034928f Adjust WebAssembly.{Memory, ModuleImports} usage to cater for non-dom TS (#379)
* Adjust `WebAssembly.{Memory, ModuleImports}` usage to cater for non-dom TS

* Remove wbg getter (only internal access required)

* Additional peerDeps for wasm-crypto-init

* Bump @polkadot/dev

* Remove never cast & comment, imports are functions
2022-07-01 17:01:56 +03:00
github-actions[bot] 2f042819ac [CI Skip] bump/beta 6.1.6-4-x
skip-checks: true
2022-06-30 11:41:53 +00:00
Jaco 2177d2f2cc Bump dev deps (#378) 2022-06-30 14:36:28 +03:00
github-actions[bot] 4d974e4d7f [CI Skip] bump/beta 6.1.6-3-x
skip-checks: true
2022-06-25 06:14:51 +00:00
Jaco cb05a1782a Bump common (dev deps) (#377)
* Bump common (dev deps)

* Add missing peerDependencies

* CHANGELOG
2022-06-25 09:09:15 +03:00
github-actions[bot] 5f7cb7641a [CI Skip] bump/beta 6.1.6-2-x
skip-checks: true
2022-06-23 17:10:26 +00:00
Jaco ff62f24cd4 Bump dev (w/ deno build fix) (#376) 2022-06-23 20:04:42 +03:00
github-actions[bot] d45dfb7dd2 [CI Skip] bump/beta 6.1.6-1-x
skip-checks: true
2022-06-23 11:22:09 +00:00
Jaco 1d4de873cb Bump dev 2022-06-23 14:15:28 +03:00
github-actions[bot] edfc1f0610 [CI Skip] release/beta 6.1.6-0
skip-checks: true
2022-06-23 08:37:41 +00:00
Jaco a662a23d19 README updates (#375)
* README updates

* Bump polkadot deps
2022-06-23 11:31:01 +03:00
github-actions[bot] 7cff1c8736 [CI Skip] release/stable 6.1.5
skip-checks: true
2022-06-23 07:36:43 +00:00
Jaco 6bfdebcff5 6.1.5 (#374) 2022-06-23 10:31:14 +03:00
github-actions[bot] 5b3158cb15 [CI Skip] release/stable 6.1.4
skip-checks: true
2022-06-22 05:59:18 +00:00
Jaco baa3439646 6.1.4 (#373) 2022-06-22 08:54:08 +03:00
github-actions[bot] ac040bd62b [CI Skip] release/beta 6.1.4-0
skip-checks: true
2022-06-21 17:39:22 +00:00
Jaco e0a9e33623 Adjust cjs -> deno path rewrites (#372) 2022-06-21 20:33:07 +03:00
github-actions[bot] b29f959dda [CI Skip] release/stable 6.1.3
skip-checks: true
2022-06-21 16:09:09 +00:00
Jaco 7a5ec9d347 6.1.3 (#371) 2022-06-21 19:03:53 +03:00
github-actions[bot] 28ddad0549 [CI Skip] release/stable 6.1.2
skip-checks: true
2022-06-21 15:42:22 +00:00
Jaco 615746a323 6.1.2 (#370) 2022-06-21 18:36:19 +03:00
Jaco e49d5a3219 6.1.2 (#369) 2022-06-21 18:22:51 +03:00
github-actions[bot] a31f7cac0d [CI Skip] release/beta 6.1.2-15
skip-checks: true
2022-06-21 13:41:20 +00:00
Jaco 9b65fe6c86 CHANGELOG & additional comments (#368) 2022-06-21 16:35:45 +03:00
github-actions[bot] 3b5dcd41d9 [CI Skip] release/beta 6.1.2-14
skip-checks: true
2022-06-21 12:49:22 +00:00
Jaco f4db1385fc Bump dev (w/ stable deno publish) (#367) 2022-06-21 15:43:49 +03:00
github-actions[bot] 1b844254fe [CI Skip] release/beta 6.1.2-13
skip-checks: true
2022-06-21 05:26:46 +00:00
Jaco bf924e5da0 Adjust WebAssembly init (#365)
* Adjust WebAssembly init

* Adjust

* Re-add length check
2022-06-21 08:21:29 +03:00
github-actions[bot] da37be391e [CI Skip] release/beta 6.1.2-12
skip-checks: true
2022-06-21 04:54:13 +00:00
Jaco 2a44054387 Bump TS to 4.7.4 (#364) 2022-06-21 07:47:51 +03:00
github-actions[bot] 4c85c4d336 [CI Skip] release/beta 6.1.2-11
skip-checks: true
2022-06-18 10:33:32 +00:00
Jaco 03030ae93f Adjust assert inside withWasm (#363) 2022-06-18 13:26:50 +03:00
github-actions[bot] ed438e8877 [CI Skip] release/beta 6.1.2-10
skip-checks: true
2022-06-13 19:27:43 +00:00
Jaco e7700787b2 Bump dev (#362) 2022-06-13 22:22:41 +03:00
github-actions[bot] 6cccb7b9b0 [CI Skip] release/beta 6.1.2-9
skip-checks: true
2022-06-13 05:23:33 +00:00
Jaco f8678ed024 Bump dev deps (#361) 2022-06-13 08:18:37 +03:00
github-actions[bot] 9b48e3dd36 [CI Skip] release/beta 6.1.2-8
skip-checks: true
2022-06-12 08:20:04 +00:00
Jaco f5db698705 Update issue template (#360) 2022-06-12 11:15:01 +03:00
github-actions[bot] 2a24642220 [CI Skip] release/beta 6.1.2-7
skip-checks: true
2022-06-11 07:20:21 +00:00
Jaco 5cd8ea6926 Sprinkle in comments on the actual code (#359) 2022-06-11 10:15:03 +03:00
github-actions[bot] 633b33430a [CI Skip] release/beta 6.1.2-6
skip-checks: true
2022-06-11 05:27:28 +00:00
Jaco 341e57eeb5 Bump deps (w/ issue template) (#358)
* Bump deps (w/ issue template)

* Adjust

* Adjust
2022-06-11 08:22:18 +03:00
github-actions[bot] 2a9b79f086 [CI Skip] release/beta 6.1.2-5
skip-checks: true
2022-06-04 05:22:54 +00:00
Jaco fc5a7bf9ce Bump @polkadot/util (#357) 2022-06-04 08:17:13 +03:00
github-actions[bot] fbb57dc9ca [CI Skip] release/beta 6.1.2-4
skip-checks: true
2022-06-04 04:51:04 +00:00
Jaco 2358984605 Bump deps (#356) 2022-06-04 07:45:46 +03:00
github-actions[bot] 28ae0b8963 [CI Skip] release/beta 6.1.2-3
skip-checks: true
2022-05-30 07:32:00 +00:00
Jaco 4e316440b9 Bump TS (#355) 2022-05-30 10:26:43 +03:00
github-actions[bot] f9c65c8fb2 [CI Skip] release/beta 6.1.2-2
skip-checks: true
2022-05-29 08:57:09 +00:00
Jaco d3c5d1a617 Adjust eslint ignore (#354)
* Adjust eslint ignore

* Update .eslintrc.js
2022-05-29 11:50:17 +03:00
github-actions[bot] b57cdaef14 [CI Skip] release/beta 6.1.2-1
skip-checks: true
2022-05-29 08:37:22 +00:00
Jaco 1f2ad4ea36 Bump deps (#353) 2022-05-29 11:32:02 +03:00
github-actions[bot] 4c3537d869 [CI Skip] release/beta 6.1.2-0
skip-checks: true
2022-05-13 19:38:44 +00:00
Jaco 6f1ff9f276 Bump base common (#351) 2022-05-13 22:32:01 +03:00
github-actions[bot] 34ab9d3354 [CI Skip] release/stable 6.1.1
skip-checks: true
2022-05-13 19:06:27 +00:00
Jaco 635aeb1465 6.1.1 (#350)
* 6.1.1

* 13 May
2022-05-13 22:01:20 +03:00
github-actions[bot] adf9b57dd6 [CI Skip] release/beta 6.0.2-15
skip-checks: true
2022-05-13 05:32:41 +00:00
Jaco 669aa9f53b Explicit empty catch (#349) 2022-05-13 08:27:24 +03:00
github-actions[bot] 399d439aa7 [CI Skip] release/beta 6.0.2-14
skip-checks: true
2022-05-12 06:39:34 +00:00
Jaco 29ecaa46c2 Tidy up with some renames (#347)
* Tidy up with some renames

* Adjust
2022-05-12 09:33:42 +03:00
github-actions[bot] 614c88e6c3 [CI Skip] release/beta 6.0.2-13
skip-checks: true
2022-05-12 05:34:30 +00:00
Jaco 49ab036894 Split into common wasm-bridge package (#346)
* Split into common wasm-bridge package

* README

* Adjust rollup bundling

* Adjust

* Adjust

* Adjust, full re-usable

* Cleanup deps

* Restore initWasm exports from init*

* Split base64 & fflate into wasm-util

* sideEffects for wasm-util

* Dedupe types

* Additional

* Adjust

* Expose error on InitResult

* Bump deps

* CHANGELOG

* Re-usable rollup config
2022-05-12 08:29:21 +03:00
github-actions[bot] c552006b38 [CI Skip] release/beta 6.0.2-12
skip-checks: true
2022-05-11 10:17:58 +00:00
Jaco b01f35cde5 Add environment type check to tests (#344) 2022-05-11 13:10:44 +03:00
github-actions[bot] a85615f12b [CI Skip] release/beta 6.0.2-11
skip-checks: true
2022-05-11 09:59:55 +00:00
Jaco 04285faf55 Adjust wasm build process w/ wasm-crypto naming (#343) 2022-05-11 12:54:36 +03:00
github-actions[bot] 962b880fa6 [CI Skip] release/beta 6.0.2-10
skip-checks: true
2022-05-11 06:07:05 +00:00
Jaco e75ebd07a0 Restore older package names (#342)
* Restore older package names

* Fix headers

* Adjust imports & tupe exports
2022-05-11 09:01:12 +03:00
github-actions[bot] a601a8d034 [CI Skip] release/beta 6.0.2-9
skip-checks: true
2022-05-10 07:30:01 +00:00
Jaco 13826c371e Bump deps & adjust test output (#341) 2022-05-10 10:23:47 +03:00
github-actions[bot] 0355bb4769 [CI Skip] release/beta 6.0.2-8
skip-checks: true
2022-05-09 14:54:17 +00:00
Jaco 2e14af5693 Adjust WASM init process (w/ RN aliases) (#340)
* Adjust WASM init process (w/ RN aliases)

* Remove stray log

* Cleanup

* CHANGELOG

* yarn.lock
2022-05-09 17:48:45 +03:00
github-actions[bot] 135b99ee63 [CI Skip] release/beta 6.0.2-7
skip-checks: true
2022-04-30 05:49:12 +00:00
Jaco f4851dc4d8 Bump dev deps (#338) 2022-04-30 08:43:43 +03:00
github-actions[bot] 8f31b00608 [CI Skip] release/beta 6.0.2-6
skip-checks: true
2022-04-29 11:29:57 +00:00
Jaco 0ac2977788 Bump TS (#337) 2022-04-29 14:23:51 +03:00
github-actions[bot] ef30070360 [CI Skip] release/beta 6.0.2-5
skip-checks: true
2022-04-27 18:46:15 +00:00
Jaco 3b9ac03b70 Explicit versions for wasm-crypto-* (#336) 2022-04-27 21:41:03 +03:00
github-actions[bot] 84f2e0da77 [CI Skip] release/beta 6.0.2-4
skip-checks: true
2022-04-27 07:00:16 +00:00
Jaco b0a5eaf20e Bump @polkadot/dev (#335) 2022-04-27 09:53:40 +03:00
github-actions[bot] 1fec165bac [CI Skip] release/beta 6.0.2-3
skip-checks: true
2022-04-24 09:26:00 +00:00
Jaco 5838ac1e69 Bump @polkadot/dev (#334) 2022-04-24 12:20:11 +03:00
github-actions[bot] dfd83c2463 [CI Skip] release/beta 6.0.2-2
skip-checks: true
2022-04-19 14:04:50 +00:00
Jaco b25d8dfd4b Bump deps (#333) 2022-04-19 16:59:39 +03:00
github-actions[bot] 21ee330e9b [CI Skip] release/beta 6.0.2-1
skip-checks: true
2022-04-12 05:05:39 +00:00
Jaco 599f6300c0 Bump deps (#332) 2022-04-12 07:59:21 +03:00
github-actions[bot] 1916a4e10c [CI Skip] release/beta 6.0.2-0
skip-checks: true
2022-04-09 09:18:49 +00:00
Jaco 0fd619c4f7 Bump common (#331) 2022-04-09 12:13:11 +03:00
github-actions[bot] 54c600a676 [CI Skip] release/stable 6.0.1
skip-checks: true
2022-04-09 07:27:33 +00:00
Jaco 763cd473b4 6.0.1 (#330)
* 5.2.1

* 6.0.1

* CHANGELOG

* Bump dev
2022-04-09 10:22:29 +03:00
github-actions[bot] e435c1e7b8 [CI Skip] release/beta 5.1.2-4
skip-checks: true
2022-04-05 05:08:16 +00:00
Jaco 59bf7495b4 Bump dev deps (#328) 2022-04-05 08:03:29 +03:00
github-actions[bot] ec36f55ed8 [CI Skip] release/beta 5.1.2-3
skip-checks: true
2022-04-05 04:34:07 +00:00
Jaco 03f38cb07b Adjust test for updated dev (#327)
* Adjust test for updated dev

* Bump dev
2022-04-05 07:29:17 +03:00
github-actions[bot] 36719449c2 [CI Skip] release/beta 5.1.2-2
skip-checks: true
2022-04-04 08:44:43 +00:00
Jaco efb0c51648 Allow for CJS file locations under cjs/** root (#326) 2022-04-04 11:39:55 +03:00
github-actions[bot] 2faf907296 [CI Skip] release/beta 5.1.2-1
skip-checks: true
2022-04-04 06:31:16 +00:00
Jaco 33b77fed37 Update ed25519 secret key format return description (#325) 2022-04-04 09:25:39 +03:00
github-actions[bot] 8cc2a167e1 [CI Skip] release/beta 5.1.2-0
skip-checks: true
2022-03-28 05:45:28 +00:00
Jaco 09f33968b9 Bump dev deps (@polkadot/util) (#323) 2022-03-28 08:40:40 +03:00
github-actions[bot] 346720f384 [CI Skip] release/stable 5.1.1
skip-checks: true
2022-03-27 07:06:01 +00:00
Jaco aeade5636a 5.1.1 (#322) 2022-03-27 10:01:06 +03:00
github-actions[bot] 9f3c8f1f74 [CI Skip] release/beta 5.0.2-7
skip-checks: true
2022-03-27 06:29:19 +00:00
Jaco 3d1e48ec4b Bump TypeScript (#321) 2022-03-27 09:23:31 +03:00
github-actions[bot] cbffca3984 [CI Skip] release/beta 5.0.2-6
skip-checks: true
2022-03-26 20:05:39 +00:00
Jaco 9d6427d9da Bump dev deps (#320) 2022-03-26 18:10:18 +02:00
github-actions[bot] 368cb6806f [CI Skip] release/beta 5.0.2-5
skip-checks: true
2022-03-26 15:44:48 +00:00
Jaco 9795eaf31c Don't run auto-init, but set input (#319)
* Don't run auto-init, but set input

* Adjust
2022-03-26 17:39:57 +02:00
github-actions[bot] b4f7b0b177 [CI Skip] release/beta 5.0.2-4
skip-checks: true
2022-03-24 11:38:15 +00:00
Jaco 44048626cd Update secp256k1 library (#318)
* Update secp256k1 library

* Adjust

* compress/uncompress

* All of them?

* Test removal of lazy section hack

* Run tests sequentially

* build:mac target

* s/sepc256k1/secp256k1/

* CHANGELOG
2022-03-24 13:31:57 +02:00
github-actions[bot] 7fb8a1cb93 [CI Skip] release/beta 5.0.2-3
skip-checks: true
2022-03-23 13:26:55 +00:00
Jaco 2d544e7bc3 Check instantiate as function (#317)
* Check instantiate as function

* Rename wbg
2022-03-23 15:20:10 +02:00
github-actions[bot] 0f0a8131c5 [CI Skip] release/beta 5.0.2-2
skip-checks: true
2022-03-23 12:00:49 +00:00
Jaco f7e6acbf9c Add initNone (#316)
* Add initNone

* Add force to explicit call
2022-03-23 13:54:11 +02:00
github-actions[bot] eb445e79e2 [CI Skip] release/beta 5.0.2-1
skip-checks: true
2022-03-23 05:21:23 +00:00
Jaco ddee3dfd25 Bump dev (#314) 2022-03-23 07:15:15 +02:00
github-actions[bot] 8b7e6b90a1 [CI Skip] release/beta 5.0.2-0
skip-checks: true
2022-03-19 08:57:25 +00:00
Jaco dd571dd35f Update dev deps to latest util (#313) 2022-03-19 10:52:05 +02:00
Jaco c4e4414bbf FAQ link 2022-03-19 10:43:05 +02:00
github-actions[bot] 221b50e905 [CI Skip] release/stable 5.0.1
skip-checks: true
2022-03-19 07:42:08 +00:00
Jaco 42598dc36b 5.0.1 (#312) 2022-03-19 09:37:11 +02:00
github-actions[bot] ea9d986a48 [CI Skip] release/beta 4.6.2-6
skip-checks: true
2022-03-19 07:25:36 +00:00
Jaco 64b10dd4ad Deps & CHANGELOG (#311) 2022-03-19 09:20:33 +02:00
github-actions[bot] 729b46ee5f [CI Skip] release/beta 4.6.2-5
skip-checks: true
2022-03-19 07:08:10 +00:00
Jaco 0dfb491e9d Reproduction for secp256k1 asm.js failure (#310)
* Reproduction for secp256k1 asm.js failure

* Make test output more readable

* Additional test cleanups

* Bump build deps

* Adjust output sizing flags

* Bump wasm-bindgen

* secp256k1 HACK

* Update packages/wasm-crypto/src/bundle.ts

* Update packages/wasm-crypto/src/bundle.ts

* Update packages/wasm-crypto/test/all/index.cjs
2022-03-19 09:02:52 +02:00
github-actions[bot] 63585ff3a7 [CI Skip] release/beta 4.6.2-4
skip-checks: true
2022-03-18 12:46:20 +00:00
Jaco 698e62d70a Adjust init to allow for asm/wasm or combo (#309)
* Additional known secp256k1 test

* Fix test

* typo

* ... one more typo

* Adjust init to allow for asm/wasm or combo

* Cleanup export, no internal cjs

* Adjust sideEffects

* CHANGELOG
2022-03-18 14:40:59 +02:00
github-actions[bot] ab9ca9f49d [CI Skip] release/beta 4.6.2-3
skip-checks: true
2022-03-18 12:00:14 +00:00
Jaco 257080e1f9 Additional known secp256k1 test (#308)
* Additional known secp256k1 test

* Fix test

* typo

* ... one more typo
2022-03-18 13:54:52 +02:00
github-actions[bot] 068c83b9fb [CI Skip] release/beta 4.6.2-2
skip-checks: true
2022-03-17 05:42:55 +00:00
Jaco cb86c48bc4 Bump @polkadot/dev (#306)
* Bump @polkadot/dev

* trigger
2022-03-17 07:36:16 +02:00
github-actions[bot] f0ceed5454 [CI Skip] release/beta 4.6.2-1
skip-checks: true
2022-03-16 08:04:19 +00:00
Jaco f0e4b29d73 Bump dev deps (#305) 2022-03-16 09:58:59 +02:00
github-actions[bot] 4d23c75fa4 [CI Skip] release/beta 4.6.2-0
skip-checks: true
2022-03-12 10:12:21 +00:00
Jaco 0ae73cbad3 Bump common (#303) 2022-03-12 12:07:27 +02:00
github-actions[bot] 44b70b745a [CI Skip] release/stable 4.6.1
skip-checks: true
2022-03-12 07:52:01 +00:00
Jaco 3bf0e29d94 4.6.1 (#302) 2022-03-12 09:46:59 +02:00
github-actions[bot] 60759e7a1a [CI Skip] release/beta 4.5.2-52
skip-checks: true
2022-03-10 07:42:35 +00:00
Jaco 28f4457e0a Bump deps (& yarn 3.2.0) (#301) 2022-03-10 09:36:44 +02:00
github-actions[bot] aca9e2655b [CI Skip] release/beta 4.5.2-51
skip-checks: true
2022-03-07 08:12:11 +00:00
Jaco 567ebe69d0 Support bundlers where import.meta.url is undefined (#300) 2022-03-07 10:06:55 +02:00
github-actions[bot] 6c3b30fe53 [CI Skip] release/beta 4.5.2-50
skip-checks: true
2022-03-03 13:31:11 +00:00
Jaco e9b2ba93c4 Rename auto step (#299) 2022-03-03 15:25:52 +02:00
github-actions[bot] a9fa4ce1a5 [CI Skip] release/beta 4.5.2-49
skip-checks: true
2022-03-03 09:32:31 +00:00
Jaco 18e2ab6389 Remove checkout from auto-{approve, merge} actions (#298) 2022-03-03 11:27:28 +02:00
github-actions[bot] 917b654c63 [CI Skip] release/beta 4.5.2-48
skip-checks: true
2022-03-02 05:19:27 +00:00
Jaco c7a202525c Replace mergify with action (#297) 2022-03-02 05:14:25 +00:00
github-actions[bot] 4c80c9bd0f [CI Skip] release/beta 4.5.2-47
skip-checks: true
2022-03-01 10:23:23 +00:00
Jaco 480d8e2dc8 Bump TS (#296) 2022-03-01 10:18:28 +00:00
github-actions[bot] 73a4c5d37f [CI Skip] release/beta 4.5.2-46
skip-checks: true
2022-02-27 17:47:34 +00:00
Jaco b003749832 Approve action adjust (#295)
* Approve action adjust

* Only labelled
2022-02-27 17:41:20 +00:00
github-actions[bot] 0ef6797ce9 [CI Skip] release/beta 4.5.2-45
skip-checks: true
2022-02-23 10:40:29 +00:00
Jaco 0013bbc14d Skip job on non-local repo 2022-02-23 12:33:31 +02:00
github-actions[bot] 93c4f62b3d [CI Skip] release/beta 4.5.2-44
skip-checks: true
2022-02-23 10:07:10 +00:00
Jaco 0008428ae0 Use jacogr/action-approve (#292) 2022-02-23 12:00:24 +02:00
github-actions[bot] 49818a5aef [CI Skip] release/beta 4.5.2-43
skip-checks: true
2022-02-21 10:33:38 +00:00
Jaco 9acb068f26 Bump dev (#291) 2022-02-21 10:27:24 +00:00
github-actions[bot] 2e35918650 [CI Skip] release/beta 4.5.2-42
skip-checks: true
2022-02-15 18:25:23 +00:00
Jaco c6877b7207 Bump deps (#290) 2022-02-15 18:18:17 +00:00
github-actions[bot] af598af917 [CI Skip] release/beta 4.5.2-41
skip-checks: true
2022-02-15 07:51:47 +00:00
Jaco fd98695a1c Add mergify (#289) 2022-02-15 09:45:41 +02:00
github-actions[bot] 737c373706 [CI Skip] release/beta 4.5.2-40
skip-checks: true
2022-02-14 05:49:16 +00:00
Jaco 2fe9d88068 Bump common (#288) 2022-02-14 07:43:21 +02:00
github-actions[bot] 81f6e8b214 [CI Skip] release/beta 4.5.2-39
skip-checks: true
2022-02-13 08:36:51 +00:00
Jaco b484c66f9c Disable yarn scripts on CI (#287) 2022-02-13 10:31:21 +02:00
github-actions[bot] a30354dd22 [CI Skip] release/beta 4.5.2-38
skip-checks: true
2022-02-10 04:57:15 +00:00
Jaco 98ba005cbc Bump dev deps (#286) 2022-02-10 06:51:45 +02:00
github-actions[bot] 5ef4c0c3e3 [CI Skip] release/beta 4.5.2-37
skip-checks: true
2022-02-07 09:20:18 +00:00
Jaco 748cf146c2 Bump deps (#285) 2022-02-07 11:14:33 +02:00
github-actions[bot] 9d86641a09 [CI Skip] release/beta 4.5.2-36
skip-checks: true
2022-02-04 07:43:15 +00:00
Jaco 4940a58942 Bump dev & util (#284) 2022-02-04 09:37:50 +02:00
github-actions[bot] 56560d767b [CI Skip] release/beta 4.5.2-35
skip-checks: true
2022-01-22 12:03:33 +00:00
Jaco c024262479 Bump deps (#283) 2022-01-22 13:58:03 +02:00
github-actions[bot] 91616be8c1 [CI Skip] release/beta 4.5.2-34
skip-checks: true
2022-01-17 07:49:35 +00:00
Jaco 14bf2209c1 Remove unused *.json type definition (#282) 2022-01-17 09:43:01 +02:00
github-actions[bot] 26352dfb2c [CI Skip] release/beta 4.5.2-33
skip-checks: true
2022-01-17 06:30:44 +00:00
Jaco 56a5bc7f4e Bump common (util deps) (#281) 2022-01-17 08:24:40 +02:00
github-actions[bot] c5cca3da2d [CI Skip] release/beta 4.5.2-32
skip-checks: true
2022-01-14 10:24:27 +00:00
Jaco b8b72adc38 Manual format of tsconfig.build.json (#280) 2022-01-14 12:18:07 +02:00
github-actions[bot] e69571d469 [CI Skip] release/beta 4.5.2-31
skip-checks: true
2022-01-14 05:43:26 +00:00
Jaco 859bef5d24 Bump dependencies (#279) 2022-01-14 07:38:15 +02:00
github-actions[bot] 1b6ffdd728 [CI Skip] release/beta 4.5.2-30
skip-checks: true
2022-01-13 08:11:25 +00:00
Jaco cedfc3ddc2 Update .mailmap 2022-01-13 10:05:36 +02:00
github-actions[bot] 317d837c26 [CI Skip] release/beta 4.5.2-29
skip-checks: true
2022-01-12 13:49:01 +00:00
Jaco 10e42c4a5f Adjust .mailmap (#278) 2022-01-12 15:42:18 +02:00
github-actions[bot] ccd71cc6fe [CI Skip] release/beta 4.5.2-28
skip-checks: true
2022-01-12 08:22:57 +00:00
Jaco 4981ca3f50 Adjust with tsconfig.build.json inside packages (#277) 2022-01-12 10:17:26 +02:00
github-actions[bot] 20f9969b90 [CI Skip] release/beta 4.5.2-27
skip-checks: true
2022-01-11 10:26:22 +00:00
Jaco f34deb94be Bump dev (w/ babel updates) (#276)
* Bump dev (w/ babel updates)

* codeclimate.yml
2022-01-11 12:20:57 +02:00
github-actions[bot] b98d787dd9 [CI Skip] release/beta 4.5.2-26
skip-checks: true
2022-01-11 06:49:58 +00:00
Jaco fa8ab999d3 Add tsconfig.build.json (#275) 2022-01-11 08:43:55 +02:00
github-actions[bot] b9e7d5a2c1 [CI Skip] release/beta 4.5.2-25
skip-checks: true
2022-01-09 07:13:25 +00:00
Jaco 6b8634462d Bump dev & common (#273)
* Bump dev & common

* Adjust alias
2022-01-09 09:07:40 +02:00
github-actions[bot] f3706b4975 [CI Skip] release/beta 4.5.2-24
skip-checks: true
2022-01-05 09:29:15 +00:00
Jaco 66c70aba9a Adjust for new packageInfo (#272) 2022-01-05 11:23:46 +02:00
github-actions[bot] 2ee13d5063 [CI Skip] release/beta 4.5.2-23
skip-checks: true
2022-01-05 06:46:05 +00:00
Jaco b81eb9037d Bump dev (#270) 2022-01-05 08:40:00 +02:00
github-actions[bot] 2a261ab180 [CI Skip] release/beta 4.5.2-22
skip-checks: true
2022-01-04 17:13:37 +00:00
Jaco b3facfeafe Add git .mailmap (#269) 2022-01-04 19:07:16 +02:00
github-actions[bot] edbd81d6a6 [CI Skip] release/beta 4.5.2-21
skip-checks: true
2022-01-04 10:24:20 +00:00
Jaco c22c861534 fetch-depth 0 (#268) 2022-01-04 12:18:55 +02:00
github-actions[bot] b256423ee7 [CI Skip] release/beta 4.5.2-20
skip-checks: true
2022-01-04 09:58:45 +00:00
Jaco cda39039ea Bump dev (w/ CONTRIBUTORS & umd) (#267) 2022-01-04 11:52:12 +02:00
github-actions[bot] 64242926e2 [CI Skip] release/beta 4.5.2-19
skip-checks: true
2022-01-02 05:58:56 +00:00
Jaco a6357d8b23 Bump deps (#266) 2022-01-02 07:52:08 +02:00
github-actions[bot] 84387bc56d [CI Skip] release/beta 4.5.2-18
skip-checks: true
2022-01-01 16:39:41 +00:00
Jaco 3d1dee1164 2022 (#265)
* 2022

* Update scripts/rust-version.sh
2022-01-01 18:33:38 +02:00
github-actions[bot] b9c627d4c3 [CI Skip] release/beta 4.5.2-17
skip-checks: true
2022-01-01 08:10:22 +00:00
Jaco c588a37cc3 Bump dev (#264) 2022-01-01 10:03:47 +02:00
github-actions[bot] 372bfccb68 [CI Skip] release/beta 4.5.2-16
skip-checks: true
2022-01-01 07:36:23 +00:00
Jaco be4f3ce82c 2022 (#263)
* 2022

* Update scripts/rust-version.sh
2022-01-01 09:30:22 +02:00
github-actions[bot] d7ced7c0e4 [CI Skip] release/beta 4.5.2-15
skip-checks: true
2021-12-31 15:29:22 +00:00
Jaco 3454f0685c Introduce detectOther (#262) 2021-12-31 17:23:05 +02:00
github-actions[bot] 3810eff007 [CI Skip] release/beta 4.5.2-14
skip-checks: true
2021-12-31 09:49:19 +00:00
Jaco a03283fe32 Mock for __dirname (#261)
* Mock for __dirname

* undefined

* CHANGELOG
2021-12-31 11:43:30 +02:00
github-actions[bot] 96d016f0a4 [CI Skip] release/beta 4.5.2-13
skip-checks: true
2021-12-31 08:01:02 +00:00
Jaco 622e60990a Bump babel (#260) 2021-12-31 09:54:41 +02:00
github-actions[bot] 112fbaa97d [CI Skip] release/beta 4.5.2-12
skip-checks: true
2021-12-29 17:25:48 +00:00
Jaco 516cf8347c Additional ed25519 cleanups (#259)
* Adjust ed25519 internals (speed & size)

* Additional ed25519 cleanups
2021-12-29 19:19:41 +02:00
github-actions[bot] 9f0fff863f [CI Skip] release/beta 4.5.2-11
skip-checks: true
2021-12-29 16:15:16 +00:00
Jaco 44c77e5bf3 Adjust ed25519 internals (speed & size) (#258) 2021-12-29 18:08:56 +02:00
github-actions[bot] 1fa4de4276 [CI Skip] release/beta 4.5.2-10
skip-checks: true
2021-12-29 15:29:09 +00:00
Jaco 9f6aa8dd33 Wrapped verification test (#257)
* Wrapped verification test

* tabs
2021-12-29 17:22:34 +02:00
github-actions[bot] f5563c9ed3 [CI Skip] release/beta 4.5.2-9
skip-checks: true
2021-12-25 10:17:50 +00:00
Jaco 32245f5b61 Bump berry (#255) 2021-12-25 12:12:23 +02:00
github-actions[bot] edcd6ee44b [CI Skip] release/beta 4.5.2-8
skip-checks: true
2021-12-24 14:28:20 +00:00
Jaco 93fae330ae Bump deps (#254) 2021-12-24 16:22:00 +02:00
github-actions[bot] 2f13511810 [CI Skip] release/beta 4.5.2-7
skip-checks: true
2021-12-23 07:01:39 +00:00
Jaco 9d1b58917b Dev bump (w/ types key in export map) (#253) 2021-12-23 08:55:27 +02:00
github-actions[bot] 0eb06843f7 [CI Skip] release/beta 4.5.2-6
skip-checks: true
2021-12-22 06:39:49 +00:00
Jaco a977c8fc9f Bump deps (#252) 2021-12-22 08:33:43 +02:00
github-actions[bot] c33ccd1cf9 [CI Skip] release/beta 4.5.2-5
skip-checks: true
2021-12-20 09:55:54 +00:00
Jaco 55c3107e91 Bump dev (w/ output linting adjustments) (#251) 2021-12-20 11:48:59 +02:00
github-actions[bot] 387334854e [CI Skip] release/beta 4.5.2-4
skip-checks: true
2021-12-19 07:26:05 +00:00
Jaco 19a852bee3 Bump common deps (#250) 2021-12-19 09:19:52 +02:00
github-actions[bot] 4c06f8c69b [CI Skip] release/beta 4.5.2-3
skip-checks: true
2021-12-14 06:01:00 +00:00
Jaco 39deef5b8b tsconfig project references (#249)
* Use tsconfig references

* Working :)

* Ignore bytes outputs

* spacing

* Adjust

* tsconfig.eslint.json

* Upgrade

* Include scripts in linting
2021-12-14 07:54:31 +02:00
github-actions[bot] bc605481d2 [CI Skip] release/beta 4.5.2-2
skip-checks: true
2021-12-13 06:19:07 +00:00
Jaco 60dc2ce9c5 Add tsconfig.base (#248) 2021-12-13 08:13:04 +02:00
github-actions[bot] 7ba258f750 [CI Skip] release/beta 4.5.2-1
skip-checks: true
2021-12-12 09:32:17 +00:00
Jaco 4ec72cac9e Bump tsc (#247) 2021-12-12 11:26:31 +02:00
github-actions[bot] cd4ec3ece5 [CI Skip] release/beta 4.5.2-0
skip-checks: true
2021-12-09 11:12:31 +00:00
Jaco 30385b85e4 Align codeclimate.yml (#246) 2021-12-09 13:06:16 +02:00
github-actions[bot] 27bef46818 [CI Skip] release/stable 4.5.1
skip-checks: true
2021-12-03 11:48:36 +00:00
Jaco 2b4ed56dcb 4.5.1 (#245)
* 4.5.1

* Bump deps
2021-12-03 13:43:15 +02:00
github-actions[bot] e167eba7d8 [CI Skip] release/beta 4.4.2-9
skip-checks: true
2021-12-03 09:54:40 +00:00
Jaco 272050938f Local variable cleanups (#244)
* Local variable cleanups

* Fixup

* Revert res moves
2021-12-03 11:49:41 +02:00
github-actions[bot] 3ee381512b [CI Skip] release/beta 4.4.2-8
skip-checks: true
2021-12-03 07:11:06 +00:00
Jaco a2d5affb88 Adjust formatting (#243)
* Adjust formatting

* Remove all unwrap

* Err(_) => _
2021-12-03 09:05:43 +02:00
github-actions[bot] 2b759aab12 [CI Skip] release/beta 4.4.2-7
skip-checks: true
2021-12-03 04:54:44 +00:00
Jaco 223d7bf514 publicKey from slice in secp256k1 compress/expand (#242) 2021-12-03 06:48:02 +02:00
github-actions[bot] fa2eb4e214 [CI Skip] release/beta 4.4.2-6
skip-checks: true
2021-12-02 12:24:51 +00:00
Jaco 7689afb616 Add secp256k1 interfaces (#241)
* Add secp256k1 functions

* features for rand

* JS tests

* signing

* CHANGELOG

* Add secp256k1 seed
2021-12-02 14:19:33 +02:00
github-actions[bot] 10002e9ec5 [CI Skip] release/beta 4.4.2-5
skip-checks: true
2021-12-01 08:12:11 +00:00
Jaco b2a0af0df4 Adjust stale cron (#240) 2021-12-01 10:07:03 +02:00
github-actions[bot] 4966fd2837 [CI Skip] release/beta 4.4.2-4
skip-checks: true
2021-11-30 11:24:34 +00:00
Jaco 421d36d159 Simplify base64 bytes decoding (#239) 2021-11-30 13:19:24 +02:00
github-actions[bot] 74270adba7 [CI Skip] release/beta 4.4.2-3
skip-checks: true
2021-11-30 09:23:58 +00:00
Jaco 2b97759fa7 WASM function JS interface construction (#238) 2021-11-30 11:17:08 +02:00
github-actions[bot] b8b9784763 [CI Skip] release/beta 4.4.2-2
skip-checks: true
2021-11-28 07:17:05 +00:00
Jaco 8439d5c668 Bump common (#237) 2021-11-28 09:12:15 +02:00
Github Actions cb3a0f667a [CI Skip] release/beta 4.4.2-1
skip-checks: true
2021-11-24 14:57:49 +00:00
Jaco adf21a5fc2 Adjust stale schedule (#236) 2021-11-24 16:52:47 +02:00
Github Actions 4c28fadc07 [CI Skip] release/beta 4.4.2-0
skip-checks: true
2021-11-22 06:27:27 +00:00
Jaco 2849a05507 Bump dev & common (#235) 2021-11-22 08:22:24 +02:00
Github Actions 801ed235cf [CI Skip] release/stable 4.4.1
skip-checks: true
2021-11-22 05:03:50 +00:00
Jaco 98433c7399 4.4.1 (#234) 2021-11-22 06:58:30 +02:00
Github Actions b537dcf3f4 [CI Skip] release/beta 4.3.2-0
skip-checks: true
2021-11-21 05:54:49 +00:00
Jaco eaf8ecf2c1 Add hmacSha{256, 512} functions (#233)
* Add hmacSha{256, 512} functions

* type

* Adjust

* Apply suggestions from code review

* Update packages/wasm-crypto/src/rs/hashing.rs

* Update packages/wasm-crypto/src/rs/hashing.rs

* Update packages/wasm-crypto/src/rs/hashing.rs

* Fix Rust side

* naming for wasm interfaces

* Remove type

* Bump common
2021-11-21 07:49:53 +02:00
Github Actions 9f232459d9 [CI Skip] release/stable 4.3.1
skip-checks: true
2021-11-19 13:14:30 +00:00
Jaco b92661cfe0 4.3.1 (#232) 2021-11-19 15:08:46 +02:00
Github Actions 6ca4470752 [CI Skip] release/beta 4.2.2-17
skip-checks: true
2021-11-19 12:34:40 +00:00
Jaco 6cecb67edd keccak512 & sha256 (#231)
* keccak512 & sha256

* Update interface

* Correct test
2021-11-19 14:28:44 +02:00
Github Actions 91388ca10d [CI Skip] release/beta 4.2.2-16
skip-checks: true
2021-11-18 08:28:57 +00:00
Jaco 11e2acbdb5 Bump deps (#230) 2021-11-18 10:24:03 +02:00
Github Actions 4e3d1b631c [CI Skip] release/beta 4.2.2-15
skip-checks: true
2021-11-12 07:39:59 +00:00
Jaco 4f06de4844 Bump deps (#229) 2021-11-12 09:34:30 +02:00
Github Actions affb3c57e3 [CI Skip] release/beta 4.2.2-14
skip-checks: true
2021-11-07 10:44:51 +00:00
Jaco 39e762a419 Bump @polkadot deps (#227) 2021-11-07 12:38:53 +02:00
Github Actions fe966c8576 [CI Skip] release/beta 4.2.2-13
skip-checks: true
2021-11-06 11:42:08 +00:00
Jaco 12c90dfb53 Bump deps (#226) 2021-11-06 13:37:22 +02:00
Github Actions 03aabfd6d1 [CI Skip] release/beta 4.2.2-12
skip-checks: true
2021-11-03 12:50:00 +00:00
Jaco 49b3cf552b Bump dev (#225) 2021-11-03 14:45:06 +02:00
Github Actions 6300012c32 [CI Skip] release/beta 4.2.2-11
skip-checks: true
2021-10-26 07:25:50 +00:00
Jaco 9d0773c185 Bump dev (#224) 2021-10-26 10:20:33 +03:00
Github Actions 96bd2f466e [CI Skip] release/beta 4.2.2-10
skip-checks: true
2021-10-25 13:28:49 +00:00
Jaco c6151e1a7d Bump dev deps (#223) 2021-10-25 16:22:19 +03:00
Github Actions c0c6671bd0 [CI Skip] release/beta 4.2.2-9
skip-checks: true
2021-10-25 11:38:15 +00:00
Jaco 2b9d90ff49 Bump dev (#222) 2021-10-25 14:32:37 +03:00
Github Actions 2caa6fb41a [CI Skip] release/beta 4.2.2-8
skip-checks: true
2021-10-25 09:13:13 +00:00
Jaco df00473ae2 Adjust package.json consistency (#221)
* Adjust package.json consistency

* Bump deps
2021-10-25 12:08:38 +03:00
Github Actions 2acce9283f [CI Skip] release/beta 4.2.2-7
skip-checks: true
2021-10-25 08:52:12 +00:00
Zhongpeng Zhouandmsftenanceprovenance 7971624cf9 Update package.json to include the repository (#220)
* Update package.json to include the repository

Hi there!
This change adds the repository property to your package.json file(s). Having this available provides a number of benefits to security tooling. For example, it allows for greater trust by checking for signed commits, contributors to a release and validating history with the project. It also allows for comparison between the source code and the published artifact in order to detect attacks on authors during the publication process.
We validate that we're making a PR against the correct repository by comparing the metadata for the published artifact on [npmjs.com](www.npmjs.com) against the metadata in the package.json file in the repository.
This change is provided by a team at Microsoft -- we're happy to answer any questions you may have. (Members of this team include [@s-tuli](https://github.com/s-tuli), [@iarna](https://github.com/iarna), [@v-rr](https://github.com/v-rr), [@v-jiepeng](https://github.com/v-jiepeng), [@v-zhzhou](https://github.com/v-zhzhou) and [@v-gjy](https://github.com/v-gjy)). If you would prefer that we not make these sorts of PRs to projects you maintain, please just say. If you'd like to learn more about what we're doing here, we've prepared a document talking about both this project and some of our other activities around supply chain security here: [microsoft/Secure-Supply-Chain](https://github.com/microsoft/Secure-Supply-Chain)
This PR provides repository metadata for the following packages:
* @polkadot/wasm-crypto
* @polkadot/wasm-crypto-asmjs
* @polkadot/wasm-crypto-wasm

* update

* update

Co-authored-by: msftenanceprovenance <msftenanceprovenance@microsoft.com>
2021-10-25 11:45:36 +03:00
Github Actions e353fe7f2c [CI Skip] release/beta 4.2.2-6
skip-checks: true
2021-10-17 09:37:46 +00:00
Jaco e797e7a7e4 Bump dev (#219)
* Bump dev

* Bump
2021-10-17 12:32:50 +03:00
Github Actions cb91f766c7 [CI Skip] release/beta 4.2.2-5
skip-checks: true
2021-10-16 06:46:50 +00:00
Jaco c983de54f6 Bump deps (#218) 2021-10-16 09:40:31 +03:00
Github Actions 9d9b983694 [CI Skip] release/beta 4.2.2-4
skip-checks: true
2021-09-27 05:45:44 +00:00
Jaco 6db930d03d Bump deps (#217) 2021-09-27 07:39:52 +02:00
Github Actions 0233a868ab [CI Skip] release/beta 4.2.2-3
skip-checks: true
2021-09-20 08:39:48 +00:00
Jaco ed98d4820e Bump util (#216) 2021-09-20 10:33:18 +02:00
Github Actions 971d40ba18 [CI Skip] release/beta 4.2.2-2
skip-checks: true
2021-09-14 11:29:28 +00:00
Jaco f3e1e30838 Bump deps (#215) 2021-09-14 13:24:17 +02:00
Github Actions bff8604c8a [CI Skip] release/beta 4.2.2-1
skip-checks: true
2021-09-05 08:28:45 +00:00
Jaco 6cf4fc0989 Bump deps (#214) 2021-09-05 10:22:39 +02:00
Github Actions 308374c7da [CI Skip] release/beta 4.2.2-0
skip-checks: true
2021-09-01 16:49:58 +00:00
Jaco 06bb7ae090 Jest config cleanup (#213)
* Jest config cleanup

* Bump
2021-09-01 18:43:16 +02:00
Github Actions b236d50c3c [CI Skip] release/stable 4.2.1
skip-checks: true
2021-08-28 05:30:23 +00:00
Jaco e2ac301993 4.2.1 (#212) 2021-08-28 07:24:12 +02:00
Github Actions d6bdcaccd7 [CI Skip] release/beta 4.1.3-7
skip-checks: true
2021-08-26 07:36:51 +00:00
Jaco Greeff a7f0e68443 Bump deps 2021-08-26 10:31:04 +03:00
Github Actions dc24ab5804 [CI Skip] release/beta 4.1.3-6
skip-checks: true
2021-08-25 10:01:34 +00:00
Jaco d5512418d2 Use stable as nightly compiler (#192)
* Use stable as nightly compiler

* detect stable

* Apply suggestions from code review

* CHANGELOG

* De-dupe Rust version

* Adjust script location

* Script cleanups

* trigger

* Script location
2021-08-25 11:55:17 +02:00
Github Actions 7a8e570dfa [CI Skip] release/beta 4.1.3-5
skip-checks: true
2021-08-25 08:58:11 +00:00
Jaco 3794a30b4b Adjust JS tests (#211) 2021-08-25 10:53:04 +02:00
Github Actions 700acfe764 [CI Skip] release/beta 4.1.3-4
skip-checks: true
2021-08-24 11:07:21 +00:00
Shunfan ZhouandJaco 9b8d6e0b64 Support sr25519 agreement (#209)
* Support sr25519 ecdh agreement

* Align version of curve25519-dalek

Co-authored-by: Jaco <jacogr@gmail.com>

* Reduce code size

Co-authored-by: Jaco <jacogr@gmail.com>

* Add explicit tests on sr25519 key agreement

* Fix linting issues

* Fix sr25519 key_agreement test

Co-authored-by: Jaco <jacogr@gmail.com>
2021-08-24 13:00:54 +02:00
Github Actions 3575f57a2a [CI Skip] release/beta 4.1.3-3
skip-checks: true
2021-08-24 07:05:13 +00:00
Jaco 8838651405 Bump deps (#210) 2021-08-24 08:59:29 +02:00
Github Actions 6cb8f2254a [CI Skip] release/beta 4.1.3-2
skip-checks: true
2021-08-16 06:04:41 +00:00
Jaco 72c2a70a32 Bump deps (#208) 2021-08-16 07:58:49 +02:00
Github Actions 51b1d12aab [CI Skip] release/beta 4.1.3-1
skip-checks: true
2021-08-13 11:52:29 +00:00
Jaco Greeff 93159192bb berry 3.0.1 2021-08-13 14:46:26 +03:00
Github Actions d208694d05 [CI Skip] release/beta 4.1.3-0
skip-checks: true
2021-08-13 11:40:39 +00:00
Jaco e7cb8a4907 Bump deps (#207) 2021-08-13 13:35:19 +02:00
Github Actions 01dfe6e35c [CI Skip] release/stable 4.1.2
skip-checks: true
2021-07-09 05:54:46 +00:00
Jaco a5d4c4b43c 4.1.2 (#206) 2021-07-09 07:49:27 +02:00
Github Actions 9a5107534d [CI Skip] release/stable 4.1.1
skip-checks: true
2021-07-07 16:04:14 +00:00
Jaco d50d04318e 4.1 (#205) 2021-07-07 17:59:17 +02:00
Github Actions a0afa3cef6 [CI Skip] release/beta 4.0.3-35
skip-checks: true
2021-07-07 15:40:39 +00:00
Jaco cf20e027af Single module bundle via rollup (#203)
* Single module bundle via rollup

* Adjust naming

* Allow multiple bundles (consistency)

* Remove unused rollup plugins

* Update rollup.config.js

* preferConst

* Rollup with dev build

* Use createBundle

* Update rollup.config.mjs

* Add bundle entrypoint

* Bump dev

* Bump dev

* Remove x-* overrides
2021-07-07 17:34:32 +02:00
Github Actions b68ab94939 [CI Skip] release/beta 4.0.3-34
skip-checks: true
2021-07-06 11:16:52 +00:00
Jaco Greeff af94bc472d Bump dev 2021-07-06 14:11:15 +03:00
Github Actions 289b102b38 [CI Skip] release/beta 4.0.3-33
skip-checks: true
2021-07-06 07:13:57 +00:00
Jaco Greeff ba6cbc2247 Bump deps 2021-07-06 10:08:04 +03:00
Jaco Greeff 379b574b84 Bump dev 2021-07-06 09:56:08 +03:00
Github Actions f1c44a65b1 [CI Skip] release/beta 4.0.3-32
skip-checks: true
2021-07-06 05:52:17 +00:00
Jaco Greeff 7ddb5ebbe5 Bump dev 2021-07-06 08:46:29 +03:00
Github Actions afd2fe3228 [CI Skip] release/beta 4.0.3-31
skip-checks: true
2021-07-05 15:00:16 +00:00
Jaco 292197a3a2 Bump dev (#204) 2021-07-05 16:54:53 +02:00
Github Actions 8fac7feabd [CI Skip] release/beta 4.0.3-30
skip-checks: true
2021-07-02 07:12:59 +00:00
Jaco ca69955332 Bump TS (#202) 2021-07-02 09:08:21 +02:00
Github Actions eacb24a133 [CI Skip] release/beta 4.0.3-29
skip-checks: true
2021-06-27 08:19:12 +00:00
Jaco 21b3dbbb94 Bump deps (#201) 2021-06-27 10:14:23 +02:00
Github Actions 57ff683121 [CI Skip] release/beta 4.0.3-28
skip-checks: true
2021-06-22 13:51:08 +00:00
Jaco 8b7e35ad0b Bump deps (#200) 2021-06-22 15:45:31 +02:00
Github Actions 0732f053b8 [CI Skip] release/beta 4.0.3-27
skip-checks: true
2021-06-08 15:09:51 +00:00
Jaco 831a72b519 Prettier ignore all (#199)
* Prettier ignore all

* Add scripts
2021-06-08 17:04:07 +02:00
Github Actions a5dad40521 [CI Skip] release/beta 4.0.3-26
skip-checks: true
2021-06-07 14:05:43 +00:00
Jaco Greeff e8263b2597 Adjust cron locks 2021-06-07 16:59:58 +03:00
Github Actions 9d6c0afc8e [CI Skip] release/beta 4.0.3-25
skip-checks: true
2021-06-06 19:30:29 +00:00
Jaco Greeff 6393d078e8 Adjust semgrep check 2021-06-06 22:25:08 +03:00
Github Actions c62f6493d9 [CI Skip] release/beta 4.0.3-24
skip-checks: true
2021-06-05 11:13:51 +00:00
Jaco Greeff e8737c403e No semgrep.yml on forks 2021-06-05 14:07:33 +03:00
Github Actions f279a89dc7 [CI Skip] release/beta 4.0.3-23
skip-checks: true
2021-06-05 06:43:12 +00:00
Jaco Greeff 30463cfe75 push-master.yml adjust skip 2021-06-05 09:38:11 +03:00
Github Actions c1405bbe2e [CI Skip] release/beta 4.0.3-22
skip-checks: true
2021-06-05 06:28:05 +00:00
Jaco 7d9dafd9e1 semgrep.yml on PR (#198)
* semgrep.yml on PR

* if

* if adjust

* if test

* Check
2021-06-05 08:22:35 +02:00
Github Actions e0e3634714 [CI Skip] release/beta 4.0.3-21
skip-checks: true
2021-06-04 14:38:13 +00:00
Jaco Greeff a5818af5fe Update semgrep.yml 2021-06-04 17:32:21 +03:00
Github Actions 6ebec52ffc [CI Skip] release/beta 4.0.3-20
skip-checks: true
2021-06-04 10:50:23 +00:00
Jaco Greeff ebd96dea49 semgrep skip 2021-06-04 13:44:52 +03:00
Github Actions d692383d80 [CI Skip] release/beta 4.0.3-19
skip-checks: true
2021-06-04 08:44:52 +00:00
Jaco Greeff cefc8c97ec semgrep on master only 2021-06-04 11:38:32 +03:00
Github Actions 8ce18ff065 [CI Skip] release/beta 4.0.3-18
skip-checks: true
2021-06-04 05:41:43 +00:00
Jaco Greeff 40a97d2206 semgrep only for non-forked 2021-06-04 08:35:56 +03:00
Github Actions e111d9e91d [CI Skip] release/beta 4.0.3-17
skip-checks: true
2021-06-02 16:09:06 +00:00
Jaco Greeff faf407d62d fix stale.yml 2021-06-02 19:03:33 +03:00
Github Actions cf5759a324 [CI Skip] release/beta 4.0.3-16
skip-checks: true
2021-06-02 07:11:39 +00:00
Jaco Greeff d220a69ab1 cron workflows 2021-06-02 10:05:48 +03:00
Github Actions 4d8dde58dc [CI Skip] release/beta 4.0.3-15
skip-checks: true
2021-06-01 10:04:28 +00:00
Jaco Greeff c5b98fcd5b semgrep.yml 2021-06-01 12:58:33 +03:00
Github Actions 482576be81 [CI Skip] release/beta 4.0.3-14
skip-checks: true
2021-06-01 06:08:44 +00:00
Jaco Greeff fdea2aa4dc cron daily only 2021-06-01 09:03:50 +03:00
Github Actions e4dbdc570d [CI Skip] release/beta 4.0.3-13
skip-checks: true
2021-05-31 20:21:54 +00:00
Jaco Greeff 7f3146ce64 cron locks 2021-05-31 23:15:39 +03:00
Github Actions 1bf001b2f3 [CI Skip] release/beta 4.0.3-12
skip-checks: true
2021-05-31 07:55:52 +00:00
Jaco 2a99496e9a Update .123trigger 2021-05-31 09:49:34 +02:00
Github Actions 59ba89a032 [CI Skip] release/beta 4.0.3-11
skip-checks: true
2021-05-31 07:48:52 +00:00
Jaco Greeff be9786fc4c Bump dev 2021-05-31 10:42:50 +03:00
Jaco 629140e6c3 Bump dev (#197) 2021-05-31 09:15:12 +02:00
Jaco Greeff 5f46f9e698 lock.yml 2021-05-30 22:22:16 +03:00
Github Actions d4daf14c77 [CI Skip] release/beta 4.0.3-11
skip-checks: true
2021-05-30 09:38:55 +00:00
Jaco cfdaab8f86 Bump berry (#196)
* Bump berry

* Bumps
2021-05-30 11:33:41 +02:00
Github Actions 70ca570a66 [CI Skip] release/beta 4.0.3-10
skip-checks: true
2021-05-29 08:24:22 +00:00
Jaco Greeff ab7e12a30d Update stale.yml 2021-05-29 11:18:37 +03:00
Github Actions 87a95b9ab2 [CI Skip] release/beta 4.0.3-9
skip-checks: true
2021-05-28 08:45:18 +00:00
Jaco Greeff 9aff03c5b6 Update stale.yml 2021-05-28 11:39:36 +03:00
Github Actions adfa4fb099 [CI Skip] release/beta 4.0.3-8
skip-checks: true
2021-05-28 08:11:42 +00:00
Jaco 5e8b3c1c24 Add stale.yml (#195) 2021-05-28 10:06:59 +02:00
Github Actions 714b9ebf48 [CI Skip] release/beta 4.0.3-7
skip-checks: true
2021-05-28 06:45:01 +00:00
Jaco c93dbd2d2e Apply lgtm alert fixes (#194) 2021-05-28 08:40:18 +02:00
Github Actions 7139f1fe42 [CI Skip] release/beta 4.0.3-6
skip-checks: true
2021-05-26 20:20:07 +00:00
Jaco 7e490f1f96 Bump deps (#193) 2021-05-26 22:15:16 +02:00
Github Actions b6aa432b26 [CI Skip] release/beta 4.0.3-5
skip-checks: true
2021-05-07 05:26:26 +00:00
Jaco 547e31ffef Bump dev (#191) 2021-05-07 07:20:53 +02:00
Github Actions 092ee15603 [CI Skip] release/beta 4.0.3-4
skip-checks: true
2021-04-30 05:55:01 +00:00
Jaco dd52d5158e Bump deps (#190) 2021-04-30 07:47:21 +02:00
Github Actions 88d8f79e3c [CI Skip] release/beta 4.0.3-3
skip-checks: true
2021-04-24 07:39:11 +00:00
Jaco 3a1a75f99f Add engines field to package.json (#189) 2021-04-24 09:32:52 +02:00
Github Actions 422c23dbbd [CI Skip] release/beta 4.0.3-2
skip-checks: true
2021-04-21 07:20:11 +00:00
Jaco 13fd02d455 Bump deps (#188) 2021-04-21 09:13:36 +02:00
Github Actions b75e2e4778 [CI Skip] release/beta 4.0.3-1
skip-checks: true
2021-04-08 08:22:23 +00:00
Jaco Greeff 43222700be Bump deps (#187) 2021-04-08 10:16:07 +02:00
Github Actions 05abb02b64 [CI Skip] release/beta 4.0.3-0
skip-checks: true
2021-03-08 15:27:35 +00:00
Jaco Greeff bf1590ab70 Bump TS (#186) 2021-03-08 16:21:16 +01:00
Github Actions f9b5b9f55f [CI Skip] release/stable 4.0.2
skip-checks: true
2021-03-05 22:01:17 +00:00
Jaco Greeff 25d9e21b38 Adjust esm -> cjs imports (4.0.2) (#185)
* Adjust esm -> cjs impors

* cleanups

* CHANGELOG

* Apply suggestions from code review

* Apply suggestions from code review

* Apply suggestions from code review

* Update packages/wasm-crypto-wasm/src/empty.ts

* Apply suggestions from code review

* Update packages/wasm-crypto-wasm/src/cjs/bytes.d.ts
2021-03-05 22:55:19 +01:00
Github Actions 77641fc43d [CI Skip] release/stable 4.0.1
skip-checks: true
2021-03-04 18:04:12 +00:00
Jaco Greeff 90865fe9c1 4.0 (#184) 2021-03-04 18:56:54 +01:00
Github Actions 15fbfc3c51 [CI Skip] release/beta 4.0.1-7
skip-checks: true
2021-03-04 17:27:21 +00:00
Jaco Greeff 340b6a0cd6 packageInfo exports (#183) 2021-03-04 18:21:00 +01:00
Github Actions 064e13268a [CI Skip] release/beta 4.0.1-6
skip-checks: true
2021-03-04 17:06:29 +00:00
Jaco Greeff 641ea0f9d8 Small cleanups (#182)
* Small cleanups

* Detect wasm-crypt-* alongside detectPackage

* Adjust alias imports

* Adjust

* Adjust
2021-03-04 17:59:38 +01:00
Github Actions 98bc7147e3 [CI Skip] release/beta 4.0.1-5
skip-checks: true
2021-03-03 07:55:20 +00:00
Jaco Greeff 3d9e5d49b8 Bump TS 2021-03-03 08:48:38 +01:00
Github Actions 8bdcfbb049 [CI Skip] release/beta 4.0.1-4
skip-checks: true
2021-03-03 07:39:46 +00:00
Jaco Greeff 13dcd606ea Bump deps (& berry) (#181) 2021-03-03 08:33:29 +01:00
Github Actions 6576688f92 [CI Skip] release/beta 4.0.1-3
skip-checks: true
2021-03-02 17:03:46 +00:00
Jaco Greeff 33e63df4ad reset 2021-03-02 17:40:53 +01:00
Jaco Greeff e910e9fc77 Revert "[CI Skip] release/stable 4.0.0"
This reverts commit a00b36d50d.
2021-03-02 17:39:54 +01:00
Github Actions a00b36d50d [CI Skip] release/stable 4.0.0
skip-checks: true
2021-03-02 16:34:29 +00:00
Jaco Greeff 0f6e143a6f Default build to type: module (#180)
* Defaul build to type: module

* Add packageInfo

* 4.0

* pre

* Adjust tests

* jest js, rest cjs

* Bump dev
2021-03-02 17:27:41 +01:00
Github Actions 854d209be8 [CI Skip] release/beta 3.2.5-0
skip-checks: true
2021-03-01 20:33:12 +00:00
Jaco Greeff 3f50efb951 Bump deps (#179) 2021-03-01 21:27:10 +01:00
Github Actions aceaa90466 [CI Skip] release/stable 3.2.4
skip-checks: true
2021-02-24 16:14:52 +00:00
Jaco Greeff 63622edcf4 Cleanup implicit dependencies, perform base64 decoding using base64-js (#178)
* Cleanup implicit dependencies, perform base64 decoding using base64-js

* base64 decoding

* lint

* remove extra call

* adjust
2021-02-24 17:09:06 +01:00
Github Actions 4a1c0563cb [CI Skip] release/stable 3.2.3
skip-checks: true
2021-02-16 10:55:04 +00:00
Jaco Greeff b34181f104 3.2.3 (#176) 2021-02-16 11:48:28 +01:00
Github Actions 141a067b85 [CI Skip] release/stable 3.2.2
skip-checks: true
2021-01-24 11:00:54 +00:00
Jaco Greeff 4c48d91f8e 3.2.2 (#175) 2021-01-24 11:55:09 +01:00
216 changed files with 17872 additions and 8561 deletions
-1
View File
@@ -1 +0,0 @@
4
-5
View File
@@ -1,5 +0,0 @@
exclude_patterns:
- "**/*.spec.js"
- "**/*.spec.ts"
- "docs/**/*.js"
- "**/test/**/*.js"
-26
View File
@@ -1,26 +0,0 @@
// Copyright 2019-2021 @polkadot/wasm-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
const base = require('@polkadot/dev/config/eslint.cjs');
module.exports = {
...base,
ignorePatterns: [
'.eslintrc.js',
'.github/**',
'.vscode/**',
'.yarn/**',
'**/binaryen/*',
'**/build/*',
'**/coverage/*',
'**/node_modules/*',
'**/pkg/*',
'**/target/*'
],
parserOptions: {
...base.parserOptions,
project: [
'./tsconfig.json'
]
}
};
+86
View File
@@ -0,0 +1,86 @@
<!--
For general support, howto, coding and bundling questions, please
use the Substrate & Polkadot StackExchange at
https://substrate.stackexchange.com/
and get other ecosystem developers involved. This issues in this
repository are meant for the tracking of feature requests and bug
reports.
While all issues are looked at non-bug and non-features would take
quite a bit longer to get to and may yield less than satisfactory
responses in this format.
Additionally, please ensure you have done a search on the existing
and closed issues before logging a new request. This saves time on
all sides.
-->
* **I'm submitting a ...**
<!---
REQUIRED:
Classify the type of report your are submitting
-->
- [ ] Bug report
- [ ] Feature request
- [ ] Support request
- [ ] Other
* **What is the current behavior and expected behavior?**
<!---
REQUIRED:
If you're describing a bug, tell us what should happen. If you're
suggesting a change/improvement, tell us how it should work.
-->
* **What is the motivation for changing the behavior?**
<!---
OPTIONAL:
Suggest a motivation for the request or ideas how to implement the
addition or change
-->
* **Please tell us about your environment:**
<!---
REQUIRED:
Include as many relevant details about the environment in which you
experienced the issue. Also ensure that you have tested against the
latest stable releases if you believe this to be a bug
-->
- Version:
- Environment:
- [ ] Node.js
- [ ] Browser
- [ ] Other (limited support for other environments)
- Language:
- [ ] JavaScript
- [ ] TypeScript (include tsc --version)
- [ ] Other
+16
View File
@@ -0,0 +1,16 @@
name: bot
on:
pull_request:
types: [labeled]
jobs:
approve:
if: "! startsWith(github.event.head_commit.message, '[CI Skip]') && (!github.event.pull_request || github.event.pull_request.head.repo.full_name == github.repository)"
runs-on: ubuntu-latest
steps:
- uses: jacogr/action-approve@795afd1dd096a2071d7ec98740661af4e853b7da
with:
authors: jacogr, TarikGul, valentinfernandez1
labels: -auto
token: ${{ secrets.GH_PAT_BOT }}
+16
View File
@@ -0,0 +1,16 @@
name: bot
on:
pull_request:
types: [labeled]
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: jacogr/action-merge@d2d64b4545acd93b0a9575177d3d215ae3f92029
with:
checks: pr (build),pr (lint),pr (test)
labels: -auto
strategy: squash
token: ${{ secrets.GH_PAT_BOT }}
+25
View File
@@ -0,0 +1,25 @@
name: 'Lock Threads'
on:
schedule:
- cron: '20 1/3 * * *'
jobs:
lock:
runs-on: ubuntu-latest
env:
YARN_ENABLE_SCRIPTS: false
steps:
- uses: dessant/lock-threads@c1b35aecc5cdb1a34539d14196df55838bb2f836
with:
github-token: ${{ secrets.GH_PAT_BOT }}
issue-inactive-days: '7'
issue-comment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue
if you think you have a related problem or query.
pr-inactive-days: '2'
pr-comment: >
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
+18 -5
View File
@@ -3,15 +3,28 @@ on: [pull_request]
jobs:
pr:
continue-on-error: true
strategy:
matrix:
step: ['lint', 'test', 'build']
name: ${{ matrix.step }}
step: ['lint', 'test', 'build', 'deno']
runs-on: ubuntu-latest
env:
YARN_ENABLE_SCRIPTS: false
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- uses: denoland/setup-deno@v1
with:
deno-version: v1.42.x
- name: ${{ matrix.step }}
if: always()
continue-on-error: true
run: |
yarn install --immutable | grep -v 'YN0013'
./scripts/install-build-deps.sh
yarn install --immutable
if [ "${{ matrix.step }}" != "lint" ]; then
./scripts/install-build-deps.sh
fi
yarn polkadot-dev-deno-map
yarn ${{ matrix.step }}
+19 -18
View File
@@ -6,30 +6,31 @@ on:
jobs:
master:
if: "! startsWith(github.event.head_commit.message, '[CI Skip]')"
strategy:
matrix:
step: ['build:release']
name: ${{ matrix.step }}
if: "! startsWith(github.event.head_commit.message, '[CI Skip]') && github.repository == 'polkadot-js/wasm'"
runs-on: ubuntu-latest
env:
YARN_ENABLE_SCRIPTS: false
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
GH_PAT: ${{ secrets.GH_PAT_BOT }}
GH_RELEASE_GITHUB_API_TOKEN: ${{ secrets.GH_PAT_BOT }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
fetch-depth: 0
token: ${{ secrets.GH_PAT_BOT }}
ref: ${{ github.ref }}
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Set Execute Permissions
run: chmod +x ./scripts/*
- name: Run Install Build Deps
run: bash ./scripts/install-build-deps.sh
- name: build
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
GH_PAT: ${{ secrets.GH_PAT }}
GH_RELEASE_GITHUB_API_TOKEN: ${{ secrets.GH_PAT }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
yarn install --immutable | grep -v 'YN0013'
./scripts/install-build-deps.sh
yarn install --immutable
yarn ${{ matrix.step }}
dummy:
runs-on: ubuntu-latest
steps:
- name: dummy
run: |
echo "Dummy skip step"
+7 -2
View File
@@ -1,15 +1,19 @@
binaryen/
binaryen-quantus/
bindgen/
bindgen-quantus/
build/
build-docs/
build-*/
build-test/
bytes/
coverage/
docs/.vuepress/dist/
node_modules/
pkg/
target/
tmp/
wabt/
/import_map.json
/mod.ts
.DS_Store
.env.local
.env.development.local
@@ -26,5 +30,6 @@ lerna-debug.log*
npm-debug.log*
package-lock.json
report.*.json
tsconfig.*buildinfo
yarn-debug.log*
yarn-error.log*
+3
View File
@@ -0,0 +1,3 @@
Jaco <jacogr@gmail.com>
github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> <action@github.com>
github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Github Actions <action@github.com>
-1
View File
@@ -1 +0,0 @@
12
+4
View File
@@ -0,0 +1,4 @@
build
coverage
packages
scripts
+4
View File
@@ -0,0 +1,4 @@
// Copyright 2017-2026 @polkadot/wasm-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
module.exports = require('@polkadot/dev/config/prettier.cjs');
+4
View File
@@ -0,0 +1,4 @@
{
"eslint.enable": true,
"eslint.experimental.useFlatConfig": true
}
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-55
View File
File diff suppressed because one or more lines are too long
+934
View File
File diff suppressed because one or more lines are too long
+9 -7
View File
@@ -1,13 +1,15 @@
compressionLevel: mixed
enableGlobalCache: false
enableImmutableInstalls: false
enableProgressBars: false
logFilters:
- code: YN0013
level: discard
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
yarnPath: .yarn/releases/yarn-2.4.0.cjs
yarnPath: .yarn/releases/yarn-4.6.0.cjs
+340
View File
@@ -1,5 +1,345 @@
# CHANGELOG
## 7.5.4 Dec 9, 2025
Changes:
- Bump polkadot-js dependencies ([#605](https://github.com/polkadot-js/wasm/pull/605))
## 7.5.3 Nov 24, 2025
Changes:
- Bump @polkadot dependencies ([#603](https://github.com/polkadot-js/wasm/pull/603))
## 7.5.2 Nov 10, 2025
Changes:
- Fix/Revert asm build ([#599](https://github.com/polkadot-js/wasm/pull/599))
- Bump @polkadot dependencies ([#601](https://github.com/polkadot-js/wasm/pull/601))
## 7.5.1 aug 25, 2025
Changes:
- Bump yarn to 4.5.1 ([#573](https://github.com/polkadot-js/wasm/pull/573))
- Update comments and labels from 2024 to 2025 ([#574](https://github.com/polkadot-js/wasm/pull/574))
- Bump yarn to 4.6.0 ([#575](https://github.com/polkadot-js/wasm/pull/575))
- Set execute for build script in CI ([#576](https://github.com/polkadot-js/wasm/pull/576))
- Set permissions on all scripts ([#577](https://github.com/polkadot-js/wasm/pull/577))
- Bump dev to 0.83.2 ([#578](https://github.com/polkadot-js/wasm/pull/578))
- chore: added check in ext_secp_recover for signature normalization ([#579](https://github.com/polkadot-js/wasm/pull/579))
- chore: Improve CI ([#580](https://github.com/polkadot-js/wasm/pull/580))
- Revert CI improvements and wasm-bindgen version ([#583](https://github.com/polkadot-js/wasm/pull/583))
- Added validation checks in PBKDF2 and Scrypt hashing functions ([#584](https://github.com/polkadot-js/wasm/pull/584))
- Rollback wasm-bindgen version change ([#586](https://github.com/polkadot-js/wasm/pull/586))
- Fix rust version to 1.84 ([#587](https://github.com/polkadot-js/wasm/pull/587))
- Default to installed rust version ([#588](https://github.com/polkadot-js/wasm/pull/588))
- Default to nightly rust version ([#589](https://github.com/polkadot-js/wasm/pull/589))
- Ci Fix ([#590](https://github.com/polkadot-js/wasm/pull/590))
- Read lock file ([#591](https://github.com/polkadot-js/wasm/pull/591))
- Setup nightly as default ([#592](https://github.com/polkadot-js/wasm/pull/592))
- Tweak install-build-deps.sh script ([#593](https://github.com/polkadot-js/wasm/pull/593))
- Remove ASM build ([#594](https://github.com/polkadot-js/wasm/pull/594))
- Bump @polkadot deps ([#595](https://github.com/polkadot-js/wasm/pull/595))
## 7.4.1 Oct 20, 2024
- Bump dev deps to 0.81.2
- Bump TS
- Ensure CJS is exported correctly
- Bump yarn
- Add missing sideEffect declarations
- Set Deno build in CI to 1.42.x
## 7.3.2 Dec 6, 2023
Changes:
- Apply fixes for OOB array access
## 7.3.1 Nov 17, 2023
Changes:
- Drop support for Node 16 (EOL 11 Sep 2023)
## 7.2.2 Aug 17, 2023
Changes:
- Adjust cjs exports for consistency
- Adjust usage of `?.` as per (latest) linting rules
## 7.2.1 May 13, 2023
Changes:
- Adjust `cjs/bytes.js` generation to follow `export.<var> = ...` form
- Add `module` to `package.json` export map (ESM-only)
## 7.1.2 Apr 28, 2023
Changes:
- Apply `readonly` specifiers to private class fields where applicable
- Adjust compilation output for `__internal__` class fields
## 7.1.1 Apr 22, 2023
Changes:
- Add `wasm-util` as dependency where `x-randomvalues` is a peer
- Drop support for Node 14 (EOL 30 Apr 2023)
## 7.0.3 Mar 11, 2023
Changes:
- Use consistent `.js` imports in source files (TS moduleResolution)
## 7.0.2 Mar 4, 2023
Changes:
- Update to latest `@polkadot/dev` (w/ tsc jsx detection output changes)
## 7.0.1 Mar 4, 2023
Changes:
- Swap TS -> JS compiler to use tsc (from babel)
- Adjust all tests to use `node:test` runner (ESM & CJS variants)
## 6.4.1 Dec 3, 2022
Changes:
- Add `/*#__PURE__*/` annotations for specific `export const something = someFunction(...)`
## 6.3.1 Jul 21, 2022
Changes:
- Optimize packed WASM base64 decoding loop
- Adjust test environment (no duplication)
- Adjust CI check steps, align with other org repos
- Remove unneeded `import_map.in.json` for Deno tests
## 6.2.3 Jul 7, 2022
Changes:
- Optimize WASM init with pre-allocated buffers
- Additional platform-specific tests
## 6.2.2 Jul 4, 2022
Changes:
- Protect against potential low-level double-sign leak in dalek-ed25519 (Don't use provided input pubKey, see https://github.com/MystenLabs/ed25519-unsafe-libs)
## 6.2.1 Jul 1, 2022
Changes:
- Add missing `peerDependencies` to `wasm-crypto` (`bridge` requirement)
- Adjust `WebAssembly.{Memory, ModuleImports}` usage to cater for non-dom TS
## 6.1.5 Jun 23, 2022
Changes:
- Adjust build outputs for Deno targets
## 6.1.4 Jun 22, 2022
Changes:
- Adjust build outputs for Deno targets
## 6.1.3 Jun 21, 2022
Changes:
- Fix bundle publish (from dev bump)
## 6.1.2 Jun 21, 2022
Changes:
- Adjust assert usage in all internal non-test code
- Additional comments where missing
## 6.1.1 May 13, 2022
Changes:
- Adjust init, allow RN with default ASM.js-only fallback
- Split `wasm-{bridge, util}` packages for internal re-use
## 6.0.1 Apr 9, 2022
- **Breaking change** In this major version the commonjs outputs are moved to a sub-folder. Since the `export` map and `main` field in `package.json` does reflect this change, there should be no usage changes. However the packages here will all need to be on the same version for internal linkage.
Changes:
- Update ed25519 secret key format return description
- Output commonjs files under the `cjs/**` root
## 5.1.1 Mar 27, 2022
Changes:
- Swap from `libsecp256k1` to `secp256k1` (this aligns with the Substrate use)
- Adjust `wasm-crypto/init*` to also export `initWasm(): Promise<void>` (optional manual init)
- Allow for `wasm-crypto/initNone` with no defined Wasm or Asm interfaces
- Fix initialization on React Native with only ASM
## 5.0.1 Mar 19, 2022
- **Breaking change** For users of React Native, you are now required to add `import '@polkadot/wasm-crypto/initOnlyAsm'` at your project top-level to ensure that asm.js is initialized. (Or alternatively `import '@polkadot/wasm-crypto/initWasmAsm'` to future-proof when WASM does become available)
- **Breaking change** For users who used to map the `data` and `empty` of the internal `wasm-crypto-{wasm, asmjs}` packages in their bundlers, swap to one of the `@polkadot/wasm-crypto/init*` top-level imports to set the type of interfaces you would prefer. A full writeup of the rationale and other options can be found [in the FAQ](https://polkadot.js.org/docs/util-crypto/FAQ#i-dont-have-wasm-available-in-my-environment)
Changes:
- Add (optional) `@polkadot/wasm-crypto/init{OnlyAsm, OnlyWasm, WasmAsm}` to allow specific interface types
- Add work-around for lazy secp256k1 init in asm.js environments
- Optimize asm.js output size
- Use latest `wasm-bindgen`, `binaryen` & `wabt` packages in build
- Additional workaround for Vite bundling
## 4.6.1 Mar 12, 2022
Changes:
- Adjust ed25519 internals, consistency in code
- Ensure package path is available under ESM & CJS
- JS wrapped bytes interoperability test
- Adjust for bundlers where `import.meta.url` is undefined
## 4.5.1 Dec 3, 2021
Changes:
- Add `secp256k1{Compress, Expand, Recover, Sign}` functions
- Remove all occurences of `.unwrap()` (match everywhere)
- Adjust and optimize WASM function JS interface construction
- Simplify base64 bytes decoding on construction
## 4.4.1 Nov 22, 2021
Changes:
- Add `hmacSha256` & `hmacSha512` functions
## 4.3.1 Nov 19, 2021
Contributed:
- Updated package.json to include repo (Thanks to https://github.com/v-zhzhou)
Changes:
- Add `keccak512` function
- Add `sha256` function
## 4.2.1 Aug 28, 2021
Contributed:
- Add sr25519 agreement external (Thanks to https://github.com/shelvenzhou)
Changes:
- Adjust tests to align with JS coding standards
- Allow for optional build with Rust stable bootstrap
## 4.1.2 Jul 9, 2021
Changes:
- Bump `@polkadot/dev` to allow for bundles with new-format
## 4.1.1 Jul 7, 2021
Changes:
- Add an explicit `engines` field to `package.json`
- Allow building as a completely stand-alone browser bundle (experimental)
## 4.0.2 Mar 5, 2021
Changes:
- Add import indirection for both CJS & ESM (where generated source file is commonjs)
## 4.0.1 Mar 4, 2021
**Important** In the 4.0 version the default package type has been changed to ESM modules by default. This should not affect usage, however since the output formats changed, a new major version is required.
Changes:
- Build to ESM by default (with cjs versions via export map)
## 3.2.4 Feb 24, 2021
Changes:
- Cleanup implicit dependencies, perform base64 decoding using base64-js
## 3.2.3 Feb 16, 2021
Changes:
- Change package detect import to use `.js` source, not `.json`
## 3.2.2 Jan 24, 2021
Changes:
- Remove `module` field in `package.json`
## 3.2.1 Jan 22, 2021
Contributed:
+8
View File
@@ -0,0 +1,8 @@
618 Jaco 2024 (#559)
19 Tarik Gul Bump dev to 0.83.2 (#578)
12 Valentin Fernandez 7.5.1 (#596)
10 rajk93 7.5.4 (#606)
1 Evgeny Fixed type (#121)
1 Shunfan Zhou Support sr25519 agreement (#209)
1 Steve Degosserie Expose Schnorrkel's VRF capabilities (#170)
1 Zhongpeng Zhou Update package.json to include the repository (#220)
-6
View File
@@ -1,9 +1,3 @@
[![polkadotjs](https://img.shields.io/badge/polkadot-js-orange?style=flat-square)](https://polkadot.js.org)
![license](https://img.shields.io/badge/License-Apache%202.0-blue?logo=apache&style=flat-square)
[![npm](https://img.shields.io/npm/v/@polkadot/wasm-crypto?logo=npm&style=flat-square)](https://www.npmjs.com/package/@polkadot/wasm-crypto)
[![beta](https://img.shields.io/npm/v/@polkadot/wasm-crypto/beta?label=beta&logo=npm&&style=flat-square)](https://www.npmjs.com/package/@polkadot/wasm-crypto)
[![maintainability](https://img.shields.io/codeclimate/maintainability-percentage/polkadot-js/wasm?logo=code-climate&style=flat-square)](https://codeclimate.com/github/polkadot-js/wasm/maintainability)
# @polkadot/wasm
Various WASM wrappers around Rust crates
-4
View File
@@ -1,4 +0,0 @@
// Copyright 2019-2021 @polkadot/wasm-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
module.exports = require('@polkadot/dev/config/babel-config-cjs.cjs');
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2017-2026 @polkadot/wasm-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import baseConfig from '@polkadot/dev/config/eslint';
export default [
...baseConfig,
{
ignores: [
'mod.ts'
]
}
];
+5
View File
@@ -0,0 +1,5 @@
{
"imports": {
"https://esm.sh/v90/@types/bn.js@~5.2/index.d.ts": "https://esm.sh/v90/@types/bn.js@5.1.0/index.d.ts"
}
}
-19
View File
@@ -1,19 +0,0 @@
// Copyright 2019-2021 @polkadot/wasm-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
const config = require('@polkadot/dev/config/jest.cjs');
module.exports = Object.assign({}, config, {
moduleNameMapper: {
'@polkadot/wasm-crypto-asmjs(.*)$': '<rootDir>/packages/wasm-crypto-asmjs/build/$1',
'@polkadot/wasm-crypto-wasm(.*)$': '<rootDir>/packages/wasm-crypto-wasm/build/$1',
// eslint-disable-next-line sort-keys
'@polkadot/wasm-crypto(.*)$': '<rootDir>/packages/wasm-crypto/src/$1'
},
modulePathIgnorePatterns: [
'<rootDir>/packages/wasm-crypto-asmjs/build',
'<rootDir>/packages/wasm-crypto-wasm/build',
'<rootDir>/packages/wasm-crypto/build'
],
resolver: '@polkadot/dev/config/jest-resolver.cjs'
});
+42 -16
View File
@@ -1,32 +1,58 @@
{
"repository": "https://github.com/polkadot-js/wasm",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "Apache-2",
"bugs": "https://github.com/polkadot-js/wasm/issues",
"engines": {
"node": ">=18.14"
},
"homepage": "https://github.com/polkadot-js/wasm#readme",
"license": "Apache-2.0",
"packageManager": "yarn@4.6.0",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/polkadot-js/wasm.git"
},
"sideEffects": false,
"type": "module",
"version": "7.5.4",
"versions": {
"git": "7.5.4",
"npm": "7.5.4"
},
"workspaces": [
"packages/*"
],
"resolutions": {
"typescript": "^4.1.3"
},
"scripts": {
"build": "yarn build:wasm",
"build:js": "./scripts/build-js.sh",
"build:quantus": "./scripts/build-quantus.sh",
"build:quantus:js": "./scripts/build-quantus-js.sh",
"build:release": "polkadot-ci-ghact-build",
"build:rollup": "polkadot-exec-rollup --config",
"build:wasm": "./scripts/build.sh",
"lint": "polkadot-dev-run-lint",
"clean": "./scripts/clean.sh",
"deno": "yarn deno:build && yarn deno:check",
"deno:build": "WITH_DENO=1 yarn build",
"deno:check": "deno check --import-map=import_map.json mod.ts",
"lint": "polkadot-dev-run-lint",
"postinstall": "polkadot-dev-yarn-only",
"test": "yarn test:wasm:rust",
"test:wasm:js": "yarn test:wasm:js:jest && yarn test:wasm:js:node",
"test:wasm:js:jest": "polkadot-dev-run-test ./test/jest.spec.js",
"test:wasm:js:node": "cd packages/wasm-crypto && node ./test/wasm.js && node ./test/asm.js",
"test:wasm:rust": "cd packages/wasm-crypto && RUST_BACKTRACE=full cargo test --release -- --nocapture"
"test": "yarn test:wasm-crypto:rust && yarn test:quantus-crypto:rust",
"test:js": "yarn test:wasm-crypto:js",
"test:quantus-crypto:js": "./scripts/test-quantus-js.sh",
"test:quantus-crypto:rust": "cd packages/quantus-crypto && RUST_BACKTRACE=full cargo test --release",
"test:wasm-crypto:deno": "deno test --allow-read --import-map=import_map.json packages/wasm-crypto/test/deno.ts",
"test:wasm-crypto:js": "yarn test:wasm-crypto:js:jest && yarn test:wasm-crypto:js:node",
"test:wasm-crypto:js:jest": "polkadot-dev-run-test --env node --loader ./packages/wasm-crypto/test/loader-build.js",
"test:wasm-crypto:js:node": "node --no-warnings --loader ./packages/wasm-crypto/test/loader-build.js ./packages/wasm-crypto/test/wasm.js && node --no-warnings --loader ./packages/wasm-crypto/test/loader-build.js ./packages/wasm-crypto/test/asm.js",
"test:wasm-crypto:rust": "cd packages/wasm-crypto && RUST_BACKTRACE=full cargo test --release -- --test-threads=1 --nocapture"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@polkadot/dev": "^0.61.24",
"fflate": "^0.6.0",
"override-require": "^1.1.1"
"@polkadot/dev": "^0.83.3",
"@polkadot/util": "^14.0.1",
"@types/node": "^20.16.1",
"fflate": "^0.8.2"
},
"version": "3.2.1"
"resolutions": {
"typescript": "^5.5.4"
}
}
+602
View File
@@ -0,0 +1,602 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "arrayvec"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "byte-slice-cast"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "const_format"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e"
dependencies = [
"const_format_proc_macros",
"konst",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "either"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "frame-metadata"
version = "23.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba5be0edbdb824843a0f9c6f0906ecfc66c5316218d74457003218b24909ed0"
dependencies = [
"cfg-if",
"parity-scale-codec",
"scale-info",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "indexmap"
version = "2.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "konst"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb"
dependencies = [
"konst_macro_rules",
]
[[package]]
name = "konst_macro_rules"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "parity-scale-codec"
version = "3.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa"
dependencies = [
"arrayvec",
"byte-slice-cast",
"const_format",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"rustversion",
]
[[package]]
name = "parity-scale-codec-derive"
version = "3.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "proc-macro-crate"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quantus_codec"
version = "0.0.0"
dependencies = [
"blake2",
"bs58",
"frame-metadata",
"parity-scale-codec",
"scale-decode",
"scale-info",
"scale-value",
"serde_json",
"twox-hash",
"wasm-bindgen",
]
[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "scale-bits"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27243ab0d2d6235072b017839c5f0cd1a3b1ce45c0f7a715363b0c7d36c76c94"
dependencies = [
"parity-scale-codec",
"scale-info",
"scale-type-resolver",
"serde",
]
[[package]]
name = "scale-decode"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d6ed61699ad4d54101ab5a817169259b5b0efc08152f8632e61482d8a27ca3d"
dependencies = [
"parity-scale-codec",
"scale-bits",
"scale-type-resolver",
"smallvec",
"thiserror",
]
[[package]]
name = "scale-encode"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2a976d73564a59e482b74fd5d95f7518b79ca8c8ca5865398a4d629dd15ee50"
dependencies = [
"parity-scale-codec",
"scale-bits",
"scale-type-resolver",
"smallvec",
"thiserror",
]
[[package]]
name = "scale-info"
version = "2.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b"
dependencies = [
"cfg-if",
"derive_more",
"parity-scale-codec",
"scale-info-derive",
]
[[package]]
name = "scale-info-derive"
version = "2.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "scale-type-resolver"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb"
dependencies = [
"scale-info",
"smallvec",
]
[[package]]
name = "scale-value"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3b64809a541e8d5a59f7a9d67cc700cdf5d7f907932a83a0afdedc90db07ccb"
dependencies = [
"either",
"parity-scale-codec",
"scale-bits",
"scale-decode",
"scale-encode",
"scale-type-resolver",
"thiserror",
]
[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.5",
]
[[package]]
name = "serde_json"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "smallvec"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.5",
]
[[package]]
name = "tinyvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.25.13+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b"
dependencies = [
"indexmap",
"toml_datetime",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_parser"
version = "1.1.3+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
dependencies = [
"winnow",
]
[[package]]
name = "twox-hash"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5283634e518fe9e82c7b20520bb4bc209009fd16c82077c802f8111ecbb0117a"
[[package]]
name = "typenum"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasm-bindgen"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 3.0.5",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "winnow"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
dependencies = [
"memchr",
]
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+63
View File
@@ -0,0 +1,63 @@
# Metadata-driven SCALE encode/decode for the Quantus chain, compiled to WASM.
#
# A separate crate from `quantus-crypto` for the same reason that one is separate
# from `wasm-crypto`: different dependency graphs, built independently. They ship
# as sibling packages and the extension uses both — this one decides *what bytes*
# get signed, that one signs them.
#
# Why this exists at all rather than `@polkadot/api`: quantus/api#1. In short,
# polkadot-js cannot decode a Quantus block (it reads the extrinsic preamble byte
# as a version when the top two bits are a type tag), it refuses fixed arrays
# longer than 2048 (ML-DSA signatures are 5261 and 7219 bytes), and — the part
# that matters after those are patched — it *guesses* that signed extensions it
# does not recognise contribute nothing to the signed payload. On a chain whose
# encoding has already changed between runtimes, a guess like that produces a
# valid signature over the wrong bytes, which arrives as `BadProof` and looks
# exactly like a wrong key. See quantus/wasm#3.
[package]
authors = ["Quantus Network Developers <hello@quantus.com>"]
description = "Metadata-driven SCALE codec for the Quantus chain, as WASM bindings."
edition = "2021"
license = "Apache-2.0"
name = "quantus_codec"
publish = false
repository = "https://git.lair.cafe/quantus/wasm"
resolver = "2"
version = "0.0.0"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
# Versions match blackbeard.observer's, which is the other consumer decoding this
# chain against its own metadata and the reference implementation for this crate.
frame-metadata = { version = "23", default-features = false, features = ["current", "decode"] }
parity-scale-codec = { version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false }
scale-value = { version = "0.18", default-features = false }
# Only for `IgnoreVisitor`. `scale_value` sizes a sequence's Vec from the length
# prefix *before* decoding an item, so a blob that disagrees with the registry can
# ask for an allocation of any size and abort the process — there is no Err to
# catch. Pinned to the version `scale-value` itself resolves so both see one
# registry. blackbeard.observer took a 76 GiB allocation to find this.
scale-decode = { version = "0.16", default-features = false }
serde_json = "1"
wasm-bindgen = "0.2"
# Storage keys. Substrate hashes a pallet prefix and an item name with twox128
# and each map key with whatever hasher the metadata declares for it.
blake2 = { version = "0.10", default-features = false }
twox-hash = { version = "2", default-features = false, features = ["xxhash64"] }
# SS58. An account id rendered as 32 bytes of hex is a correct description of the
# value and unreadable to the person being asked to approve it.
bs58 = { version = "0.5", default-features = false, features = ["alloc"] }
[profile.release]
codegen-units = 1
debug = false
debug-assertions = false
incremental = false
lto = true
opt-level = "z"
panic = "abort"
rpath = false
+88
View File
@@ -0,0 +1,88 @@
# @quantus/codec
Metadata-driven SCALE encode and decode for the [Quantus](https://quantus.com)
chain, compiled to WASM.
Nothing in this package names a pallet, a call, a signed extension or a signature
scheme. Everything is read from the metadata the node produced by running
`Metadata_metadata` against the runtime WASM in a given block's state, which
makes the runtime the oracle rather than this package's author.
## Why not `@polkadot/api`
Three reasons, in increasing order of importance — the evidence is on
[quantus/api#1](https://git.lair.cafe/quantus/api/issues/1).
1. `@polkadot/types` refuses fixed arrays longer than 2048 bytes. ML-DSA
signatures are `[u8;5261]` and `[u8;7219]`, so every Quantus extrinsic trips
it.
2. `api.rpc.chain.getBlock` throws on **every block of this chain**, at the
timestamp inherent. The extrinsic preamble byte's top two bits are a type tag
(`0b00` bare, `0b10` signed, `0b01` general) and the low six are the version;
Quantus emits `0x84` — signed, v4 — and `0x05` — bare, v5 — in the same block
while the metadata declares version 4. polkadot-js reads that byte as a
version.
3. It **guesses** that signed extensions it does not recognise contribute nothing
to the signed payload, logging `Unknown signed extensions … treating them as
no-effect`.
The third is why this package exists rather than a patch. The guess is correct
only while every unrecognised extension happens to be zero-sized. This chain's
encoding has already changed between runtimes — `transactionVersion` has gone
2 → 3 → 6 across four upgrades, each an extrinsic-format change — and when the
guess stops being correct the wallet keeps signing. Those signatures are
cryptographically valid, over a payload missing bytes the runtime put there, and
the chain reports them as `BadProof`, which is also what it reports for a wrong
key. Silent, remote, and indistinguishable from the one thing it is not.
Here the registry decides. An extension whose declared type encodes to nothing
contributes nothing; anything else must be supplied by the caller or no payload
is produced at all.
## Use
```ts
import { Runtime } from '@quantus/codec';
const runtime = Runtime.fromMetadata(await fetchMetadata()); // state_getMetadata
const call = runtime.encodeCall('Balances', 'transfer_keep_alive', {
dest: { Id: '0x…' },
value: '1000000000'
});
const values = runtime.standardExtensions({
blockHash: genesisHash, // immortal era
genesisHash,
nonce,
specVersion,
transactionVersion
});
const payload = runtime.signerPayload(call, values);
// sign `payload` with @quantus/crypto under the QUANTUS_EXTRINSIC context,
// hashing it first with BLAKE2b-256 if it is longer than 256 bytes
const extrinsic = runtime.encodeExtrinsic(
{ Id: accountId },
signature,
runtime.encodeExtra(values),
call
);
```
`standardExtensions` fills in the extensions Substrate itself defines. Anything
else this runtime declares as non-empty is refused by name — see above for why
that is the desired behaviour rather than a limitation.
## Build
```
./scripts/build-quantus.sh quantus-codec
```
Same constraints as `@quantus/crypto`: a modern toolchain (separate from
`wasm-crypto`'s 2022 nightly), `initSync` over base64+zlib for the MV3 CSP,
wasm-bindgen's own glue rather than `@polkadot/wasm-bridge`, and **binaryen 123**
— version 105 silently corrupts the output. See
[quantus/wasm#1](https://git.lair.cafe/quantus/wasm/issues/1) and
[#3](https://git.lair.cafe/quantus/wasm/issues/3).
+24
View File
@@ -0,0 +1,24 @@
{
"author": "Quantus Network Developers <hello@quantus.com>",
"bugs": "https://git.lair.cafe/quantus/wasm/issues",
"description": "Metadata-driven SCALE encode/decode for the Quantus chain",
"engines": {
"node": ">=18"
},
"homepage": "https://git.lair.cafe/quantus/wasm/src/branch/main/packages/quantus-codec#readme",
"license": "Apache-2.0",
"name": "@quantus/codec",
"repository": {
"directory": "packages/quantus-codec",
"type": "git",
"url": "https://git.lair.cafe/quantus/wasm.git"
},
"sideEffects": false,
"type": "module",
"version": "0.5.0",
"main": "index.js",
"dependencies": {
"fflate": "^0.8.2",
"tslib": "^2.7.0"
}
}
@@ -0,0 +1,8 @@
# Matches the chain's toolchain (chain/rust-toolchain), so this crate is built by
# the same compiler that builds the runtime it has to agree with. Upstream's
# `wasm-crypto` keeps its own nightly-2022-06-24 pin; the two builds are separate
# on purpose. See quantus/wasm#1.
[toolchain]
channel = "1.93.0"
targets = ["wasm32-unknown-unknown"]
profile = "minimal"
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// An array indexer rather than a Map: the input is ASCII by construction, so it
// cannot overflow, and array access is measurably faster on the hot loop.
const MAP = new Array<number>(256);
for (let i = 0; i < CHARS.length; i++) {
MAP[CHARS.charCodeAt(i)] = i;
}
/**
* Decode base64 into a caller-supplied buffer.
*
* Deliberately not `atob` or `Buffer.from`: the first is browser-only, the second
* node-only, and this runs in an MV3 service worker, a Worker, node tests and a
* bundled extension page. The output length is known at build time, so the
* caller provides the buffer and there is no growth or reallocation.
*
* This is a reimplementation of `@polkadot/wasm-util`'s base64Decode, which was
* the dependency it replaced. That package's index re-exports `packageDetect`,
* dragging in a `@polkadot/util` peer dependency for a side effect we do not
* want, and being a workspace package it resolved through its own repo's
* node_modules when consumed by symlink from another checkout. Fifteen lines is
* cheaper than either problem.
*/
export function base64Decode (data: string, out: Uint8Array): Uint8Array {
let byte = 0;
let bits = 0;
let pos = 0;
for (let i = 0; i < data.length && pos < out.length; i++) {
const value = MAP[data.charCodeAt(i)];
if (value === undefined) {
continue;
}
byte = (byte << 6) | value;
bits += 6;
if (bits >= 8) {
bits -= 8;
out[pos++] = (byte >>> bits) & 0xff;
}
}
return out;
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
export declare const lenIn: number;
export declare const lenOut: number;
export declare const bytes: string;
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Generated as part of the build, do not edit
export const lenIn = 0;
export const lenOut = 0;
export const bytes = '';
+242
View File
@@ -0,0 +1,242 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { initWasm } from './init.js';
import { QuantusRuntime } from './generated/quantus_codec.js';
/** What one signed extension needs from the caller, as the runtime declares it. */
export interface ExtensionNeed {
identifier: string;
/** Whether its `ty` encodes to anything — i.e. whether it goes on the wire. */
needsExtra: boolean;
/** Whether its `additional_signed` encodes to anything. */
needsAdditional: boolean;
}
/**
* A value for one signed extension. Omit a half the runtime declares as empty.
*
* Each half is either interpreted against the type the runtime declares
* (`extra`, `additional`) or supplied already SCALE-encoded (`extraHex`,
* `additionalHex`). Pre-encoded bytes are **validated by round trip**, not
* trusted: they are decoded against the declared type and re-encoded, and
* anything that does not come back identical is refused rather than signed.
* Setting both halves of a pair is a contradiction and is also refused.
*/
export interface ExtensionValue {
extra?: unknown;
extraHex?: string;
additional?: unknown;
additionalHex?: string;
}
export type ExtensionValues = Record<string, ExtensionValue>;
export interface StorageTarget {
/** The full key, ready for `state_getStorage`. */
key: string;
/** The registry type its value decodes as — pass to `decodeStorage`. */
valueTy: number;
/**
* What the chain means when `state_getStorage` returns nothing.
*
* Hex for a `Default` entry — an unfunded account reads as a zero balance —
* and `null` for an `Optional` one, where nothing means nothing. A wallet that
* conflated the two would report a failure for an account that simply has no
* money in it.
*/
default: string | null;
}
export interface DecodedExtrinsic {
/** The preamble byte's low six bits — **not** the byte. See `decodeExtrinsic`. */
version: number;
signed: boolean;
address: unknown;
signature: unknown;
extra: unknown;
call: unknown;
}
/** Everything needed to fill in the signed extensions Substrate itself defines. */
export interface PayloadOptions {
specVersion: number;
transactionVersion: number;
genesisHash: string;
/** The era's birth block. For an immortal era this is the genesis hash. */
blockHash: string;
nonce: number;
tip?: bigint | string;
/** `'Immortal'`, or `{ MortalN: phase }` as the registry spells it. */
era?: unknown;
/**
* The era already SCALE-encoded — what a dapp hands a wallet, since it did the
* encoding itself and the wallet has no way to render those two bytes as a
* variant without knowing the era algorithm. Takes precedence over `era`, and
* is round-tripped against the runtime's own `Era` type before it is used.
*/
eraHex?: string;
/** `CheckMetadataHash`: `null` disables it, which is what a wallet wants. */
metadataHash?: string | null;
}
/**
* A runtime, loaded from the metadata it produced about itself.
*
* Construct one per spec version and keep it: parsing metadata is the expensive
* part, and the blob does not change until the chain upgrades.
*/
export class Runtime {
readonly #inner: QuantusRuntime;
private constructor (inner: QuantusRuntime) {
this.#inner = inner;
}
/**
* Parse metadata exactly as `state_getMetadata` returns it.
*
* That RPC takes a block hash and makes the node run `Metadata_metadata`
* against the runtime code in *that block's* state — so this is the runtime
* describing itself, and it is the only description that cannot go stale.
*/
static fromMetadata (metadata: Uint8Array): Runtime {
const failed = initWasm();
if (failed) {
throw new Error(`@quantus/codec: WASM unavailable: ${failed}`);
}
return new Runtime(new QuantusRuntime(metadata));
}
/**
* Render account ids as SS58 at this prefix when decoding.
*
* Off until set. The prefix belongs to the chain a caller is talking to, not
* to the metadata, so this is not something the package can infer — and a
* guessed one would put a plausible, wrong address in front of somebody about
* to approve a transfer. Account ids are found by their **registry path**, so
* a block hash, which is also 32 bytes, still renders as hex.
*/
setSs58Format (prefix: number): void {
this.#inner.setSs58Format(prefix);
}
/** The extrinsic format version the metadata declares. */
get extrinsicVersion (): number {
return this.#inner.extrinsicVersion();
}
/**
* Every signed extension, in the order the runtime applies them — which is the
* order their bytes appear in the payload.
*/
signedExtensions (): ExtensionNeed[] {
return JSON.parse(this.#inner.signedExtensions()) as ExtensionNeed[];
}
/** Encode a call by name. `args` is keyed by the runtime's own argument names. */
encodeCall (pallet: string, call: string, args: Record<string, unknown>): Uint8Array {
return this.#inner.encodeCall(pallet, call, JSON.stringify(args));
}
/** The `extra`: what the extensions contribute to the extrinsic itself. */
encodeExtra (values: ExtensionValues): Uint8Array {
return this.#inner.encodeExtra(JSON.stringify(values));
}
/**
* The bytes to sign: `call ‖ extra ‖ additional`.
*
* Substrate's rule that a payload over 256 bytes is signed as its BLAKE2b-256
* hash is **not** applied here — that belongs with the signing code, which also
* chooses the FIPS 204 context. Splitting one rule across two packages is how
* the halves drift apart.
*/
signerPayload (call: Uint8Array, values: ExtensionValues): Uint8Array {
return this.#inner.signerPayload(call, JSON.stringify(values));
}
/**
* Assemble a signed extrinsic, ready for `author_submitAndWatchExtrinsic`.
*
* `signature` is the encoded `Signature` type with its variant byte already in
* place: the signer knows which ML-DSA scheme its key is, and re-deriving that
* here from the byte length would be a second source of truth.
*/
encodeExtrinsic (address: unknown, signature: Uint8Array, extra: Uint8Array, call: Uint8Array): Uint8Array {
return this.#inner.encodeExtrinsic(JSON.stringify(address), signature, extra, call);
}
/**
* Decode one extrinsic, length prefix and all.
*
* The returned `version` is the preamble byte's low six bits. The top two are a
* type tag — `0b00` bare, `0b10` signed, `0b01` general — so Quantus emits
* `0x84` (signed, v4) and `0x05` (bare, v5) in the same block while the
* metadata declares version 4. Three numbers, all correct. Reading that byte as
* a version is why `@polkadot/api` cannot decode a single block of this chain.
*/
decodeExtrinsic (blob: Uint8Array): DecodedExtrinsic {
return JSON.parse(this.#inner.decodeExtrinsic(blob)) as DecodedExtrinsic;
}
/** Decode a bare call — what an approval screen shows the user. */
decodeCall (bytes: Uint8Array): unknown {
return JSON.parse(this.#inner.decodeCall(bytes)) as unknown;
}
/**
* Where a storage value lives, and what it decodes as.
*
* `keys` are interpreted against the key types the runtime declares, so an
* `AccountId32` is the hex string its inner array accepts. The hashers come
* from the metadata too — nothing here knows that `System::Account` is
* `Blake2_128Concat`.
*/
storageTarget (pallet: string, item: string, keys: unknown[] = []): StorageTarget {
return JSON.parse(this.#inner.storageTarget(pallet, item, JSON.stringify(keys))) as StorageTarget;
}
/** Decode a storage value against the `valueTy` that `storageTarget` reported. */
decodeStorage (valueTy: number, bytes: Uint8Array): unknown {
return JSON.parse(this.#inner.decodeStorage(valueTy, bytes)) as unknown;
}
/**
* Fill in the signed extensions that Substrate itself defines, from one
* options object.
*
* This covers the extensions whose meaning is fixed by Substrate. It
* deliberately does **not** try to cover every extension a runtime might
* declare: anything else that needs a value will be refused by
* `signerPayload` with the extension's name, which is the correct outcome —
* a wallet that cannot sign is a bug report, and one that signs a payload
* missing bytes the runtime put there is a `BadProof` nobody can diagnose.
*
* Pass the result, extended with whatever else this runtime asks for, to
* `signerPayload` and `encodeExtra`.
*/
standardExtensions (options: PayloadOptions): ExtensionValues {
const values: ExtensionValues = {
ChargeTransactionPayment: { extra: (options.tip ?? 0n).toString() },
CheckGenesis: { additional: options.genesisHash },
CheckMetadataHash: {
// `Mode::Disabled`, and `None`. Enabling it would mean shipping a
// metadata hash this package has no way to compute.
additional: options.metadataHash ? { Some: options.metadataHash } : 'None',
extra: 'Disabled'
},
CheckMortality: options.eraHex
? { additional: options.blockHash, extraHex: options.eraHex }
: { additional: options.blockHash, extra: options.era ?? 'Immortal' },
CheckNonce: { extra: options.nonce },
CheckSpecVersion: { additional: options.specVersion },
CheckTxVersion: { additional: options.transactionVersion }
};
return values;
}
}
+125
View File
@@ -0,0 +1,125 @@
/* tslint:disable */
/* eslint-disable */
/**
* A loaded runtime description, held across calls so the metadata is parsed
* once per spec version rather than once per signature.
*/
export class QuantusRuntime {
free(): void;
[Symbol.dispose](): void;
/**
* Decode a bare call — what an approval screen shows the user.
*/
decodeCall(bytes: Uint8Array): string;
/**
* Decode one extrinsic as this runtime describes it, as JSON.
*/
decodeExtrinsic(blob: Uint8Array): string;
/**
* Decode a storage value against the type id `storageTarget` reported.
*/
decodeStorage(value_ty: number, bytes: Uint8Array): string;
/**
* Encode a call by name. `args` is a JSON object keyed by argument name.
*/
encodeCall(pallet: string, call: string, args: string): Uint8Array;
/**
* The `extra` alone, which the extrinsic carries and the payload repeats.
*/
encodeExtra(extensions: string): Uint8Array;
/**
* Assemble a signed extrinsic, ready for `author_submitAndWatchExtrinsic`.
*/
encodeExtrinsic(address: string, signature: Uint8Array, extra: Uint8Array, call: Uint8Array): Uint8Array;
/**
* The extrinsic format version this runtime declares.
*/
extrinsicVersion(): number;
/**
* Parse metadata as `state_getMetadata` returns it.
*/
constructor(metadata: Uint8Array);
/**
* Render account ids as SS58 at this prefix when decoding.
*
* Off until set. The prefix is a property of the chain a caller is talking
* to rather than of the metadata, and a guessed one would put a plausible,
* wrong address in front of somebody about to approve a transfer.
*/
setSs58Format(prefix: number): void;
/**
* Every signed extension, in order, as
* `[{ identifier, needsExtra, needsAdditional }]`.
*
* The two booleans are what a caller has to satisfy, read from the
* registry. A caller that ignores them gets an error rather than a short
* payload.
*/
signedExtensions(): string;
/**
* The bytes to sign, given an encoded call and the extension values.
*
* `extensions` is a JSON object keyed by extension identifier, each value
* `{ extra?, additional? }`. Omitting one the runtime declares as non-empty
* is an error — see [`Runtime::encode_extensions`].
*/
signerPayload(call: Uint8Array, extensions: string): Uint8Array;
/**
* Where a storage value lives, and what it decodes as.
*
* Returns `{ key, valueTy, default }` — `key` ready for `state_getStorage`,
* and `default` the bytes the chain means when it returns nothing, or null
* for an entry where nothing means nothing. An unfunded account reads as a
* zero balance through the first and as an error through the second, so the
* distinction is not a detail.
*/
storageTarget(pallet: string, item: string, keys: string): string;
}
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly __wbg_quantusruntime_free: (a: number, b: number) => void;
readonly quantusruntime_decodeCall: (a: number, b: number, c: number) => [number, number, number, number];
readonly quantusruntime_decodeExtrinsic: (a: number, b: number, c: number) => [number, number, number, number];
readonly quantusruntime_decodeStorage: (a: number, b: number, c: number, d: number) => [number, number, number, number];
readonly quantusruntime_encodeCall: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
readonly quantusruntime_encodeExtra: (a: number, b: number, c: number) => [number, number, number, number];
readonly quantusruntime_encodeExtrinsic: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number, number];
readonly quantusruntime_extrinsicVersion: (a: number) => number;
readonly quantusruntime_new: (a: number, b: number) => [number, number, number];
readonly quantusruntime_setSs58Format: (a: number, b: number) => void;
readonly quantusruntime_signedExtensions: (a: number) => [number, number, number, number];
readonly quantusruntime_signerPayload: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
readonly quantusruntime_storageTarget: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
readonly __wbindgen_externrefs: WebAssembly.Table;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __externref_table_dealloc: (a: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_start: () => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;
/**
* Instantiates the given `module`, which can either be bytes or
* a precompiled `WebAssembly.Module`.
*
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
*
* @returns {InitOutput}
*/
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
/**
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
* for everything else, calls `WebAssembly.instantiate` directly.
*
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
*
* @returns {Promise<InitOutput>}
*/
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,475 @@
/* @ts-self-types="./quantus_codec.d.ts" */
/**
* A loaded runtime description, held across calls so the metadata is parsed
* once per spec version rather than once per signature.
*/
export class QuantusRuntime {
__destroy_into_raw() {
const ptr = this.__wbg_ptr;
this.__wbg_ptr = 0;
QuantusRuntimeFinalization.unregister(this);
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_quantusruntime_free(ptr, 0);
}
/**
* Decode a bare call — what an approval screen shows the user.
* @param {Uint8Array} bytes
* @returns {string}
*/
decodeCall(bytes) {
let deferred3_0;
let deferred3_1;
try {
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_decodeCall(this.__wbg_ptr, ptr0, len0);
var ptr2 = ret[0];
var len2 = ret[1];
if (ret[3]) {
ptr2 = 0; len2 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred3_0 = ptr2;
deferred3_1 = len2;
return getStringFromWasm0(ptr2, len2);
} finally {
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
}
}
/**
* Decode one extrinsic as this runtime describes it, as JSON.
* @param {Uint8Array} blob
* @returns {string}
*/
decodeExtrinsic(blob) {
let deferred3_0;
let deferred3_1;
try {
const ptr0 = passArray8ToWasm0(blob, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_decodeExtrinsic(this.__wbg_ptr, ptr0, len0);
var ptr2 = ret[0];
var len2 = ret[1];
if (ret[3]) {
ptr2 = 0; len2 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred3_0 = ptr2;
deferred3_1 = len2;
return getStringFromWasm0(ptr2, len2);
} finally {
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
}
}
/**
* Decode a storage value against the type id `storageTarget` reported.
* @param {number} value_ty
* @param {Uint8Array} bytes
* @returns {string}
*/
decodeStorage(value_ty, bytes) {
let deferred3_0;
let deferred3_1;
try {
const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_decodeStorage(this.__wbg_ptr, value_ty, ptr0, len0);
var ptr2 = ret[0];
var len2 = ret[1];
if (ret[3]) {
ptr2 = 0; len2 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred3_0 = ptr2;
deferred3_1 = len2;
return getStringFromWasm0(ptr2, len2);
} finally {
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
}
}
/**
* Encode a call by name. `args` is a JSON object keyed by argument name.
* @param {string} pallet
* @param {string} call
* @param {string} args
* @returns {Uint8Array}
*/
encodeCall(pallet, call, args) {
const ptr0 = passStringToWasm0(pallet, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(call, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passStringToWasm0(args, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len2 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_encodeCall(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v4 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v4;
}
/**
* The `extra` alone, which the extrinsic carries and the payload repeats.
* @param {string} extensions
* @returns {Uint8Array}
*/
encodeExtra(extensions) {
const ptr0 = passStringToWasm0(extensions, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_encodeExtra(this.__wbg_ptr, ptr0, len0);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v2;
}
/**
* Assemble a signed extrinsic, ready for `author_submitAndWatchExtrinsic`.
* @param {string} address
* @param {Uint8Array} signature
* @param {Uint8Array} extra
* @param {Uint8Array} call
* @returns {Uint8Array}
*/
encodeExtrinsic(address, signature, extra, call) {
const ptr0 = passStringToWasm0(address, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray8ToWasm0(signature, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passArray8ToWasm0(extra, wasm.__wbindgen_malloc);
const len2 = WASM_VECTOR_LEN;
const ptr3 = passArray8ToWasm0(call, wasm.__wbindgen_malloc);
const len3 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_encodeExtrinsic(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v5 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v5;
}
/**
* The extrinsic format version this runtime declares.
* @returns {number}
*/
extrinsicVersion() {
const ret = wasm.quantusruntime_extrinsicVersion(this.__wbg_ptr);
return ret;
}
/**
* Parse metadata as `state_getMetadata` returns it.
* @param {Uint8Array} metadata
*/
constructor(metadata) {
const ptr0 = passArray8ToWasm0(metadata, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_new(ptr0, len0);
if (ret[2]) {
throw takeFromExternrefTable0(ret[1]);
}
this.__wbg_ptr = ret[0];
QuantusRuntimeFinalization.register(this, this.__wbg_ptr, this);
return this;
}
/**
* Render account ids as SS58 at this prefix when decoding.
*
* Off until set. The prefix is a property of the chain a caller is talking
* to rather than of the metadata, and a guessed one would put a plausible,
* wrong address in front of somebody about to approve a transfer.
* @param {number} prefix
*/
setSs58Format(prefix) {
wasm.quantusruntime_setSs58Format(this.__wbg_ptr, prefix);
}
/**
* Every signed extension, in order, as
* `[{ identifier, needsExtra, needsAdditional }]`.
*
* The two booleans are what a caller has to satisfy, read from the
* registry. A caller that ignores them gets an error rather than a short
* payload.
* @returns {string}
*/
signedExtensions() {
let deferred2_0;
let deferred2_1;
try {
const ret = wasm.quantusruntime_signedExtensions(this.__wbg_ptr);
var ptr1 = ret[0];
var len1 = ret[1];
if (ret[3]) {
ptr1 = 0; len1 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred2_0 = ptr1;
deferred2_1 = len1;
return getStringFromWasm0(ptr1, len1);
} finally {
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
}
}
/**
* The bytes to sign, given an encoded call and the extension values.
*
* `extensions` is a JSON object keyed by extension identifier, each value
* `{ extra?, additional? }`. Omitting one the runtime declares as non-empty
* is an error — see [`Runtime::encode_extensions`].
* @param {Uint8Array} call
* @param {string} extensions
* @returns {Uint8Array}
*/
signerPayload(call, extensions) {
const ptr0 = passArray8ToWasm0(call, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(extensions, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_signerPayload(this.__wbg_ptr, ptr0, len0, ptr1, len1);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v3;
}
/**
* Where a storage value lives, and what it decodes as.
*
* Returns `{ key, valueTy, default }` — `key` ready for `state_getStorage`,
* and `default` the bytes the chain means when it returns nothing, or null
* for an entry where nothing means nothing. An unfunded account reads as a
* zero balance through the first and as an error through the second, so the
* distinction is not a detail.
* @param {string} pallet
* @param {string} item
* @param {string} keys
* @returns {string}
*/
storageTarget(pallet, item, keys) {
let deferred5_0;
let deferred5_1;
try {
const ptr0 = passStringToWasm0(pallet, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(item, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passStringToWasm0(keys, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len2 = WASM_VECTOR_LEN;
const ret = wasm.quantusruntime_storageTarget(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
var ptr4 = ret[0];
var len4 = ret[1];
if (ret[3]) {
ptr4 = 0; len4 = 0;
throw takeFromExternrefTable0(ret[2]);
}
deferred5_0 = ptr4;
deferred5_1 = len4;
return getStringFromWasm0(ptr4, len4);
} finally {
wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
}
}
}
if (Symbol.dispose) QuantusRuntime.prototype[Symbol.dispose] = QuantusRuntime.prototype.free;
function __wbg_get_imports() {
const import0 = {
__proto__: null,
__wbg_Error_67e7344beaa85059: function(arg0, arg1) {
const ret = Error(getStringFromWasm0(arg0, arg1));
return ret;
},
__wbg___wbindgen_throw_5d9e815e6fdf150f: function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
},
__wbindgen_init_externref_table: function() {
const table = wasm.__wbindgen_externrefs;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
},
};
return {
__proto__: null,
"./quantus_codec_bg.js": import0,
};
}
const QuantusRuntimeFinalization = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(ptr => wasm.__wbg_quantusruntime_free(ptr, 1));
function getArrayU8FromWasm0(ptr, len) {
ptr = ptr >>> 0;
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
}
function getStringFromWasm0(ptr, len) {
return decodeText(ptr >>> 0, len);
}
let cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1, 1) >>> 0;
getUint8ArrayMemory0().set(arg, ptr / 1);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8ArrayMemory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
const ret = cachedTextEncoder.encodeInto(arg, view);
offset += ret.written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function takeFromExternrefTable0(idx) {
const value = wasm.__wbindgen_externrefs.get(idx);
wasm.__externref_table_dealloc(idx);
return value;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
const MAX_SAFARI_DECODE_BYTES = 2146435072;
let numBytesDecoded = 0;
function decodeText(ptr, len) {
numBytesDecoded += len;
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
numBytesDecoded = len;
}
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
const cachedTextEncoder = new TextEncoder();
if (!('encodeInto' in cachedTextEncoder)) {
cachedTextEncoder.encodeInto = function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
};
}
let WASM_VECTOR_LEN = 0;
let wasmModule, wasmInstance, wasm;
function __wbg_finalize_init(instance, module) {
wasmInstance = instance;
wasm = instance.exports;
wasmModule = module;
cachedUint8ArrayMemory0 = null;
wasm.__wbindgen_start();
return wasm;
}
async function __wbg_load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (!module.ok) {
throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
}
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
const validResponse = expectedResponseType(module.type);
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else { throw e; }
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
function expectedResponseType(type) {
switch (type) {
case 'basic': case 'cors': case 'default': return true;
}
return false;
}
}
function initSync(module) {
if (wasm !== undefined) return wasm;
if (module !== undefined) {
if (Object.getPrototypeOf(module) === Object.prototype) {
({module} = module)
} else {
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
}
}
const imports = __wbg_get_imports();
if (!(module instanceof WebAssembly.Module)) {
module = new WebAssembly.Module(module);
}
const instance = new WebAssembly.Instance(module, imports);
return __wbg_finalize_init(instance, module);
}
export { initSync };
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { Runtime } from './codec.js';
export type { DecodedExtrinsic, ExtensionNeed, ExtensionValue, ExtensionValues, PayloadOptions, StorageTarget } from './codec.js';
export { initWasm, isReady } from './init.js';
+61
View File
@@ -0,0 +1,61 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { unzlibSync } from 'fflate';
import { base64Decode } from './base64.js';
import { bytes, lenOut } from './bytes.js';
import { initSync } from './generated/quantus_codec.js';
/**
* Instantiate the WASM, synchronously, from bytes compiled into this file.
*
* Three constraints shape this, and all three rule out the obvious approach:
*
* - the background context is an **MV3 service worker**, so there is no DOM, no
* reliable `fetch` of extension-relative URLs at arbitrary times, and the
* worker can be killed and cold-started between any two messages
* - the extension CSP is `script-src 'self' 'wasm-unsafe-eval'`, which permits
* compiling WASM but not fetching it from anywhere interesting
* - callers are synchronous — `pair.sign()` in the keyring has no `await` to give
*
* So the WASM is zlib-compressed, base64'd into `bytes.js` at build time, and
* instantiated here with wasm-bindgen's `initSync`. Nothing is fetched, and the
* whole module is ready before the first call returns.
*
* Deliberately *not* using `@polkadot/wasm-bridge`: its `Bridge` implements
* wasm-bindgen 0.2.79's JS-heap ABI, and this crate is built with 0.2.128, which
* uses externref tables. See quantus/wasm#1.
*/
let initialised = false;
let initError: string | null = null;
/**
* Ensure the WASM is instantiated. Idempotent and cheap after the first call.
*
* Returns `null` on success, or the failure reason. It does not throw: a caller
* deciding whether to offer a Quantus account at all wants to ask, and an
* exception thrown from module scope in a service worker is hard to attribute.
*/
export function initWasm (): string | null {
if (initialised) {
return initError;
}
initialised = true;
try {
initSync({ module: unzlibSync(base64Decode(bytes, new Uint8Array(lenOut))) });
} catch (error) {
initError = (error as Error).message;
}
return initError;
}
/** Whether the WASM is available. Callers that can fall back should ask first. */
export function isReady (): boolean {
return initWasm() === null;
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Metadata-driven SCALE encode and decode for the Quantus chain.
//!
//! Nothing here names a pallet, a call, a signed extension or a signature
//! scheme. Everything is read from the metadata the node produced by running
//! `Metadata_metadata` against the runtime WASM in a given block's state, which
//! makes the runtime the oracle rather than this crate's author.
//!
//! That is not fastidiousness. This chain's encoding has changed between
//! runtimes — `transactionVersion` has gone 2 → 3 → 6 across four upgrades, and
//! each of those is an extrinsic-format change. A signer holding a hand-written
//! idea of the format keeps producing signatures after such an upgrade; they are
//! cryptographically valid, over the wrong bytes, and the chain reports them as
//! `BadProof`, which is what it also reports for a wrong key. See quantus/wasm#3.
extern crate alloc;
#[path = "rs/runtime.rs"]
pub mod runtime;
#[path = "rs/decode.rs"]
pub mod decode;
#[path = "rs/encode.rs"]
pub mod encode;
#[path = "rs/storage.rs"]
pub mod storage;
#[path = "rs/ss58.rs"]
pub mod ss58;
#[path = "rs/bindings.rs"]
mod bindings;
#[cfg(test)]
#[path = "rs/tests.rs"]
mod tests;
+251
View File
@@ -0,0 +1,251 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! The `wasm_bindgen` surface.
//!
//! Deliberately thin: every one of these is a parse of the JS argument, a call
//! into a module that knows nothing about JS, and a serialisation back. The
//! logic lives in [`crate::runtime`], [`crate::decode`] and [`crate::encode`]
//! because `JsError` cannot be constructed outside a wasm target, so anything
//! built on it is untestable by `cargo test` — a lesson from quantus/wasm#1,
//! where the error paths were the ones that turned out to be wrong.
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use wasm_bindgen::prelude::*;
use crate::encode::{ExtensionValue, Supplied};
use crate::runtime::Runtime;
/// A loaded runtime description, held across calls so the metadata is parsed
/// once per spec version rather than once per signature.
#[wasm_bindgen]
pub struct QuantusRuntime {
inner: Runtime,
}
#[wasm_bindgen]
impl QuantusRuntime {
/// Parse metadata as `state_getMetadata` returns it.
#[wasm_bindgen(constructor)]
pub fn new(metadata: &[u8]) -> Result<QuantusRuntime, JsError> {
Runtime::from_metadata(metadata)
.map(|inner| QuantusRuntime { inner })
.map_err(|e| JsError::new(&e.to_string()))
}
/// Render account ids as SS58 at this prefix when decoding.
///
/// Off until set. The prefix is a property of the chain a caller is talking
/// to rather than of the metadata, and a guessed one would put a plausible,
/// wrong address in front of somebody about to approve a transfer.
#[wasm_bindgen(js_name = setSs58Format)]
pub fn set_ss58_format(&mut self, prefix: u16) {
self.inner.set_ss58_format(prefix);
}
/// The extrinsic format version this runtime declares.
#[wasm_bindgen(js_name = extrinsicVersion)]
pub fn extrinsic_version(&self) -> u8 {
self.inner.extrinsic_version()
}
/// Every signed extension, in order, as
/// `[{ identifier, needsExtra, needsAdditional }]`.
///
/// The two booleans are what a caller has to satisfy, read from the
/// registry. A caller that ignores them gets an error rather than a short
/// payload.
#[wasm_bindgen(js_name = signedExtensions)]
pub fn signed_extensions(&self) -> Result<String, JsError> {
let described: Vec<serde_json::Value> = self
.inner
.extensions()
.iter()
.map(|e| {
serde_json::json!({
"identifier": e.identifier,
"needsExtra": !self.inner.is_empty_ty_pub(e.ty),
"needsAdditional": !self.inner.is_empty_ty_pub(e.additional)
})
})
.collect();
serde_json::to_string(&described).map_err(|e| JsError::new(&e.to_string()))
}
/// Encode a call by name. `args` is a JSON object keyed by argument name.
#[wasm_bindgen(js_name = encodeCall)]
pub fn encode_call(&self, pallet: &str, call: &str, args: &str) -> Result<Vec<u8>, JsError> {
let args: serde_json::Value =
serde_json::from_str(args).map_err(|e| JsError::new(&e.to_string()))?;
self.inner
.encode_call(pallet, call, &args)
.map_err(|e| JsError::new(&e.to_string()))
}
/// The bytes to sign, given an encoded call and the extension values.
///
/// `extensions` is a JSON object keyed by extension identifier, each value
/// `{ extra?, additional? }`. Omitting one the runtime declares as non-empty
/// is an error — see [`Runtime::encode_extensions`].
#[wasm_bindgen(js_name = signerPayload)]
pub fn signer_payload(&self, call: &[u8], extensions: &str) -> Result<Vec<u8>, JsError> {
let encoded = self.encoded_extensions(extensions)?;
Ok(self.inner.signer_payload(call, &encoded))
}
/// The `extra` alone, which the extrinsic carries and the payload repeats.
#[wasm_bindgen(js_name = encodeExtra)]
pub fn encode_extra(&self, extensions: &str) -> Result<Vec<u8>, JsError> {
Ok(self.encoded_extensions(extensions)?.extra)
}
/// Assemble a signed extrinsic, ready for `author_submitAndWatchExtrinsic`.
#[wasm_bindgen(js_name = encodeExtrinsic)]
pub fn encode_extrinsic(
&self,
address: &str,
signature: &[u8],
extra: &[u8],
call: &[u8],
) -> Result<Vec<u8>, JsError> {
let address: serde_json::Value =
serde_json::from_str(address).map_err(|e| JsError::new(&e.to_string()))?;
self.inner
.encode_extrinsic(&address, signature, extra, call)
.map_err(|e| JsError::new(&e.to_string()))
}
/// Decode one extrinsic as this runtime describes it, as JSON.
#[wasm_bindgen(js_name = decodeExtrinsic)]
pub fn decode_extrinsic(&self, blob: &[u8]) -> Result<String, JsError> {
let xt = self
.inner
.decode_extrinsic(blob)
.map_err(|e| JsError::new(&e.to_string()))?;
serde_json::to_string(&serde_json::json!({
"version": xt.version,
"signed": xt.signed,
"address": xt.address,
"signature": xt.signature,
"extra": xt.extra,
"call": xt.call
}))
.map_err(|e| JsError::new(&e.to_string()))
}
/// Where a storage value lives, and what it decodes as.
///
/// Returns `{ key, valueTy, default }` — `key` ready for `state_getStorage`,
/// and `default` the bytes the chain means when it returns nothing, or null
/// for an entry where nothing means nothing. An unfunded account reads as a
/// zero balance through the first and as an error through the second, so the
/// distinction is not a detail.
#[wasm_bindgen(js_name = storageTarget)]
pub fn storage_target(&self, pallet: &str, item: &str, keys: &str) -> Result<String, JsError> {
let keys: Vec<serde_json::Value> =
serde_json::from_str(keys).map_err(|e| JsError::new(&e.to_string()))?;
let target = self
.inner
.storage_target(pallet, item, &keys)
.map_err(|e| JsError::new(&e.to_string()))?;
serde_json::to_string(&serde_json::json!({
"default": target.default.as_deref().map(crate::storage::hex),
"key": crate::storage::hex(&target.key),
"valueTy": target.value_ty
}))
.map_err(|e| JsError::new(&e.to_string()))
}
/// Decode a storage value against the type id `storageTarget` reported.
#[wasm_bindgen(js_name = decodeStorage)]
pub fn decode_storage(&self, value_ty: u32, bytes: &[u8]) -> Result<String, JsError> {
let value = self
.inner
.decode_storage_value(value_ty, bytes)
.map_err(|e| JsError::new(&e.to_string()))?;
serde_json::to_string(&value).map_err(|e| JsError::new(&e.to_string()))
}
/// Decode a bare call — what an approval screen shows the user.
#[wasm_bindgen(js_name = decodeCall)]
pub fn decode_call(&self, bytes: &[u8]) -> Result<String, JsError> {
let call = self
.inner
.decode_call(bytes)
.map_err(|e| JsError::new(&e.to_string()))?;
serde_json::to_string(&call).map_err(|e| JsError::new(&e.to_string()))
}
fn encoded_extensions(
&self,
extensions: &str,
) -> Result<crate::encode::EncodedExtensions, JsError> {
let parsed: BTreeMap<String, serde_json::Value> =
serde_json::from_str(extensions).map_err(|e| JsError::new(&e.to_string()))?;
let mut values: BTreeMap<String, ExtensionValue> = BTreeMap::new();
for (identifier, v) in parsed {
values.insert(
identifier,
ExtensionValue {
extra: half(&v, "extra")?,
additional: half(&v, "additional")?,
},
);
}
self.inner
.encode_extensions(&values)
.map_err(|e| JsError::new(&e.to_string()))
}
}
/// One half of an extension value, as JSON or as pre-encoded bytes.
///
/// `extra` / `additional` are interpreted against the runtime's declared type;
/// `extraHex` / `additionalHex` are bytes the caller encoded itself, which are
/// validated by round trip rather than taken on trust. Supplying both is a
/// contradiction, not a preference, so it is refused.
fn half(value: &serde_json::Value, name: &str) -> Result<Option<Supplied>, JsError> {
let json = value.get(name);
let hex = value.get(alloc::format!("{name}Hex"));
match (json, hex) {
(Some(_), Some(_)) => Err(JsError::new(&alloc::format!(
"{name} and {name}Hex are both set"
))),
(Some(v), None) => Ok(Some(Supplied::Json(v.clone()))),
(None, Some(v)) => {
let s = v
.as_str()
.ok_or_else(|| JsError::new(&alloc::format!("{name}Hex is not a string")))?;
let s = s.strip_prefix("0x").unwrap_or(s);
if s.len() % 2 != 0 {
return Err(JsError::new(&alloc::format!("{name}Hex is not whole bytes")));
}
let bytes: Result<Vec<u8>, _> = (0..s.len() / 2)
.map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16))
.collect();
Ok(Some(Supplied::Raw(bytes.map_err(|e| {
JsError::new(&alloc::format!("{name}Hex: {e}"))
})?)))
}
(None, None) => Ok(None),
}
}
+321
View File
@@ -0,0 +1,321 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Reading a chain's own data using the chain's own description of it.
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use parity_scale_codec::Decode;
use crate::runtime::{CodecError, Runtime};
/// One decoded extrinsic, named as the runtime names it.
#[derive(Debug, Clone, PartialEq)]
pub struct DecodedExtrinsic {
/// The **version** from the preamble byte — its low six bits, not the byte.
pub version: u8,
/// Whether the preamble's type tag says signed.
pub signed: bool,
/// The address as the runtime's `Address` type decodes, rendered as JSON.
pub address: serde_json::Value,
/// The signature, rendered as JSON. For Quantus this is a
/// `DilithiumSignatureScheme` variant carrying `sig ‖ pk`.
pub signature: serde_json::Value,
/// The signed extensions as submitted — mortality, nonce, tip, and whatever
/// else this runtime declares.
pub extra: serde_json::Value,
/// The `extra` exactly as it appeared on the wire. Kept because it is half
/// of the signed payload, and re-encoding it from `extra` would be a second
/// implementation that could disagree.
pub extra_bytes: Vec<u8>,
/// The call, SCALE-encoded, as it appeared on the wire.
pub call_bytes: Vec<u8>,
/// The call, decoded.
pub call: serde_json::Value,
}
impl Runtime {
/// Decode one extrinsic, exactly as this runtime describes it.
///
/// ## The preamble byte is not the version
///
/// The **top two bits are a type tag** and the low six are the version:
/// `0b00` bare, `0b10` signed, `0b01` general. Quantus emits `0x84` —
/// signed, v4 — and `0x05` — bare, v**5** — in the same block, while the
/// metadata declares extrinsic version 4. Three different numbers, all
/// correct.
///
/// A decoder that reads the byte as a version and checks it against the
/// metadata rejects every timestamp inherent on the chain. `@polkadot/api`
/// does exactly that, which is why it cannot read a single Quantus block
/// (quantus/api#1), and it is the first thing to break when someone
/// "simplifies" this function.
///
/// `blob` is the extrinsic as the node hands it over: its own length prefix
/// first. A partial read is refused — trailing bytes mean the metadata does
/// not match these bytes, and a decoder that shrugs at that is how a block
/// gets silently mis-read after an upgrade.
pub fn decode_extrinsic(&self, blob: &[u8]) -> Result<DecodedExtrinsic, CodecError> {
let mut cursor = blob;
let declared = <parity_scale_codec::Compact<u64>>::decode(&mut cursor)
.map_err(|e| CodecError::Decode(format!("no length prefix: {e}")))?
.0 as usize;
if cursor.len() != declared {
return Err(CodecError::Decode(format!(
"declared {declared} bytes, {} present",
cursor.len()
)));
}
let preamble = *cursor
.first()
.ok_or_else(|| CodecError::Decode("empty extrinsic".to_string()))?;
cursor = &cursor[1..];
let signed = preamble & 0b1100_0000 == 0b1000_0000;
let version = preamble & 0b0011_1111;
let tys = self.extrinsic;
let (address, signature, extra, extra_bytes) = if signed {
let address = self.decode_at(tys.address, &mut cursor, "address")?;
let signature = self.decode_at(tys.signature, &mut cursor, "signature")?;
let before = cursor;
let extra = self.decode_at(tys.extra, &mut cursor, "signed extensions")?;
let extra_bytes = before[..before.len() - cursor.len()].to_vec();
(address, signature, extra, extra_bytes)
} else {
(
serde_json::Value::Null,
serde_json::Value::Null,
serde_json::Value::Null,
Vec::new(),
)
};
let call_bytes = cursor.to_vec();
let call = self.decode_at(tys.call, &mut cursor, "call")?;
if !cursor.is_empty() {
return Err(CodecError::Decode(format!(
"{} trailing bytes; metadata does not match this extrinsic",
cursor.len()
)));
}
Ok(DecodedExtrinsic {
version,
signed,
address,
signature,
extra,
extra_bytes,
call_bytes: call_bytes[..call_bytes.len() - cursor.len()].to_vec(),
call,
})
}
/// Decode a bare call — what an approval screen needs to say what is about
/// to be authorised.
pub fn decode_call(&self, bytes: &[u8]) -> Result<serde_json::Value, CodecError> {
let mut cursor = bytes;
let call = self.decode_at(self.extrinsic.call, &mut cursor, "call")?;
if !cursor.is_empty() {
return Err(CodecError::Decode(format!(
"{} trailing bytes after call",
cursor.len()
)));
}
Ok(call)
}
fn decode_at(
&self,
ty: u32,
cursor: &mut &[u8],
what: &str,
) -> Result<serde_json::Value, CodecError> {
let value = self
.decode_checked(ty, cursor)
.map_err(|e| CodecError::Decode(format!("{what}: {e}")))?;
Ok(self.render(&value))
}
/// Decode one registry type, walking the bytes first without building
/// anything from them.
///
/// **`scale_value` sizes a sequence's `Vec` from the length prefix before it
/// decodes a single item.** A blob that disagrees with the registry can
/// therefore ask for an allocation of any size at all, and Rust aborts on a
/// failed one — so there is no `Err` for a caller to catch, and `.ok()` at
/// the call site cannot help. blackbeard.observer found this in production
/// as a 76 GiB request that took the daemon down every two minutes.
///
/// `scale_decode`'s `IgnoreVisitor` walks the same bytes against the same
/// type and allocates nothing at all, so a length that cannot be satisfied
/// runs out of input on the first item and comes back as an error. The
/// second pass costs one more walk of a few kilobytes.
pub(crate) fn decode_checked(
&self,
ty: u32,
cursor: &mut &[u8],
) -> Result<scale_value::Value<u32>, String> {
let mut probe: &[u8] = cursor;
scale_decode::visitor::decode_with_visitor(
&mut probe,
ty,
self.types(),
scale_decode::visitor::IgnoreVisitor::<scale_info::PortableRegistry>::new(),
)
.map_err(|e| e.to_string())?;
scale_value::scale::decode_as_type(cursor, ty, self.types()).map_err(|e| e.to_string())
}
}
impl Runtime {
/// Render a decoded value as JSON, for the boundary to JavaScript.
///
/// Byte sequences become `0x…` hex rather than arrays of numbers: an account
/// id as 32 JSON integers is technically the same information and useless to
/// every consumer, and a 7219-byte signature as an array is 30 KiB of JSON.
///
/// Account ids become SS58 when a prefix has been set. `scale_value` carries
/// each value's registry type id as its context, so the check is on the type
/// the runtime declared and not on the shape of the bytes — a block hash is
/// also 32 bytes, and rendering one as an address would be a lie.
pub(crate) fn render(&self, value: &scale_value::Value<u32>) -> serde_json::Value {
use scale_value::{Composite, Primitive, ValueDef};
if let Some(prefix) = self.ss58_format {
if self.account_tys.contains(&value.context) {
if let Some(bytes) = account_bytes(value) {
return serde_json::Value::String(crate::ss58::encode(prefix, &bytes));
}
}
}
match &value.value {
ValueDef::Primitive(p) => match p {
Primitive::Bool(b) => serde_json::Value::Bool(*b),
Primitive::Char(c) => serde_json::Value::String(c.to_string()),
Primitive::String(s) => serde_json::Value::String(s.clone()),
// **Every** integer renders as a decimal string, whatever its width.
//
// A u128 balance does not survive a JSON number — this chain has 12
// decimal places, so ordinary amounts pass 2^53 — and `scale_value`
// widens every unsigned integer to u128 anyway, so the width is not
// available here to switch on. Emitting a number when it happens to
// fit and a string when it does not would make a consumer handle both
// shapes for the same field depending on the value, which is worse
// than either. Strings, always, and the caller parses what it knows.
Primitive::U128(n) => serde_json::Value::String(n.to_string()),
Primitive::I128(n) => serde_json::Value::String(n.to_string()),
Primitive::U256(b) | Primitive::I256(b) => serde_json::Value::String(hex(b)),
},
ValueDef::Composite(Composite::Named(fields)) => serde_json::Value::Object(
fields
.iter()
.map(|(k, v)| (k.clone(), self.render(v)))
.collect(),
),
ValueDef::Composite(Composite::Unnamed(values)) => {
if let Some(bytes) = as_bytes(values) {
serde_json::Value::String(hex(&bytes))
} else if values.len() == 1 {
// A newtype wrapper is noise; unwrap it so `Compact<u64>` reads
// as a number rather than a one-element array.
self.render(&values[0])
} else {
serde_json::Value::Array(values.iter().map(|v| self.render(v)).collect())
}
}
ValueDef::Variant(v) => {
let inner = self.render(&scale_value::Value {
value: ValueDef::Composite(v.values.clone()),
context: value.context,
});
// `Era::Immortal` and friends carry nothing; render them as the name
// alone rather than `{"Immortal": []}`.
match &inner {
serde_json::Value::Array(a) if a.is_empty() => {
serde_json::Value::String(v.name.clone())
}
serde_json::Value::Object(o) if o.is_empty() => {
serde_json::Value::String(v.name.clone())
}
_ => {
let mut map = serde_json::Map::new();
map.insert(v.name.clone(), inner);
serde_json::Value::Object(map)
}
}
}
ValueDef::BitSequence(bits) => {
serde_json::Value::Array(bits.iter().map(serde_json::Value::Bool).collect())
}
}
}
}
/// A sequence of `u8` primitives, if that is what this is.
fn as_bytes(values: &[scale_value::Value<u32>]) -> Option<Vec<u8>> {
use scale_value::{Primitive, ValueDef};
if values.is_empty() {
return None;
}
values
.iter()
.map(|v| match &v.value {
ValueDef::Primitive(Primitive::U128(n)) if *n < 256 => Some(*n as u8),
_ => None,
})
.collect()
}
fn hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(2 + bytes.len() * 2);
s.push_str("0x");
for b in bytes {
s.push(char::from_digit((b >> 4) as u32, 16).unwrap());
s.push(char::from_digit((b & 0x0f) as u32, 16).unwrap());
}
s
}
/// The 32 bytes behind an account id, whatever wrapper the registry put round it.
///
/// `AccountId32` is a newtype over `[u8; 32]`, so the decoded value is a
/// composite of a composite of primitives; a registry could also describe it
/// flat. Anything that is not exactly 32 bytes is not an account id and is left
/// to render as itself.
fn account_bytes(value: &scale_value::Value<u32>) -> Option<Vec<u8>> {
use scale_value::{Composite, ValueDef};
match &value.value {
ValueDef::Composite(Composite::Unnamed(values)) => {
if values.len() == 1 {
return account_bytes(&values[0]);
}
as_bytes(values).filter(|b| b.len() == 32)
}
ValueDef::Composite(Composite::Named(fields)) if fields.len() == 1 => {
account_bytes(&fields[0].1)
}
_ => None,
}
}
+578
View File
@@ -0,0 +1,578 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Building the bytes that get signed, and the extrinsic that carries them.
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use parity_scale_codec::Encode;
use scale_value::{Composite, Primitive, Value, ValueDef};
use crate::runtime::{CodecError, Runtime};
/// A value for one half of one signed extension.
#[derive(Debug, Clone)]
pub enum Supplied {
/// Interpreted against the type the runtime declares — see
/// [`Runtime::json_to_value`].
Json(serde_json::Value),
/// Already SCALE-encoded by whoever is asking for the signature.
///
/// A dapp hands the wallet an `era` as opaque bytes, having encoded it
/// itself, and there is no way to render those as JSON without knowing the
/// era algorithm — which is exactly the kind of knowledge this crate refuses
/// to hold. So they are accepted, but **not on trust**: [`Runtime::encode_half`]
/// decodes them against the declared type and re-encodes them, and anything
/// that does not round-trip is rejected rather than signed.
Raw(Vec<u8>),
}
/// What the caller knows about one signed extension.
///
/// Both halves are optional because most extensions need neither: a zero-sized
/// `ty` contributes nothing to the extrinsic, and a zero-sized `additional`
/// contributes nothing to the payload. Supplying a value for a zero-sized type
/// is not an error; *omitting* one for a non-zero-sized type is.
#[derive(Debug, Clone, Default)]
pub struct ExtensionValue {
pub extra: Option<Supplied>,
pub additional: Option<Supplied>,
}
/// The two byte strings a signed extrinsic needs from its extensions.
#[derive(Debug, Clone)]
pub struct EncodedExtensions {
/// Goes into the extrinsic, after the signature.
pub extra: Vec<u8>,
/// Goes into the signed payload only — never on the wire.
pub additional: Vec<u8>,
}
impl Runtime {
/// Encode a call by name, against this runtime's own call type.
pub fn encode_call(
&self,
pallet: &str,
call: &str,
args: &serde_json::Value,
) -> Result<Vec<u8>, CodecError> {
// The outer `Call` enum is a variant per pallet, and each of those
// carries that pallet's own call enum. So a call is two nested variants
// by name, and the indices — which are what actually go on the wire —
// come from the registry rather than from a table in this crate.
let pallet_ty = self.extrinsic.call;
let inner = Value::variant(
call.to_string(),
self.composite_for_call(pallet, call, args)?,
);
let outer = Value::variant(
pallet.to_string(),
Composite::Unnamed(alloc::vec![inner]),
);
let mut out = Vec::new();
scale_value::scale::encode_as_type(&outer, pallet_ty, self.types(), &mut out)
.map_err(|e| CodecError::Encode(format!("{pallet}.{call}: {e}")))?;
Ok(out)
}
/// Build the argument composite for one call, interpreting `args` against
/// the types the runtime declares for it.
fn composite_for_call(
&self,
pallet: &str,
call: &str,
args: &serde_json::Value,
) -> Result<Composite<()>, CodecError> {
let calls_ty = self
.calls
.get(pallet)
.copied()
.ok_or_else(|| CodecError::NoSuchCall(pallet.to_string()))?;
let variant = match self.types().resolve(calls_ty).map(|t| &t.type_def) {
Some(scale_info::TypeDef::Variant(v)) => v
.variants
.iter()
.find(|v| v.name == call)
.ok_or_else(|| CodecError::NoSuchCall(format!("{pallet}.{call}")))?,
_ => return Err(CodecError::NoSuchCall(format!("{pallet}.{call}"))),
};
let mut fields = Vec::new();
for field in &variant.fields {
let name = field.name.clone().unwrap_or_default();
let supplied = args.get(&name).ok_or_else(|| {
CodecError::Encode(format!("{pallet}.{call}: no value for argument {name}"))
})?;
fields.push((name, self.json_to_value(supplied, field.ty.id)?));
}
Ok(Composite::Named(fields))
}
/// Encode every signed extension this runtime declares, in order.
///
/// ## Why an unsupplied extension is fatal
///
/// `@polkadot/api` logs `Unknown signed extensions … treating them as
/// no-effect` and writes zero bytes for anything it does not recognise. That
/// guess is correct only while every unrecognised extension happens to be
/// zero-sized, and when it stops being correct the wallet keeps signing —
/// valid signatures over a payload that is missing bytes the runtime put
/// there. The chain calls that `BadProof`, which is also what it calls a
/// wrong key, so the failure is silent, remote and indistinguishable from
/// the one thing it is not.
///
/// Here the registry decides. An extension whose declared type encodes to
/// nothing contributes nothing and needs no value; anything else must be
/// supplied by the caller or this refuses to build a payload at all. A
/// wallet that cannot sign is a bug report; a wallet that signs the wrong
/// bytes is a support case that never gets diagnosed.
pub fn encode_extensions(
&self,
values: &BTreeMap<String, ExtensionValue>,
) -> Result<EncodedExtensions, CodecError> {
let mut extra = Vec::new();
let mut additional = Vec::new();
for def in &self.extensions {
let supplied = values.get(&def.identifier);
self.encode_half(
def.ty,
supplied.and_then(|v| v.extra.as_ref()),
&def.identifier,
&mut extra,
)?;
self.encode_half(
def.additional,
supplied.and_then(|v| v.additional.as_ref()),
&def.identifier,
&mut additional,
)?;
}
Ok(EncodedExtensions { extra, additional })
}
fn encode_half(
&self,
ty: u32,
supplied: Option<&Supplied>,
identifier: &str,
out: &mut Vec<u8>,
) -> Result<(), CodecError> {
if self.is_empty_ty(ty) {
// Encodes to nothing whether or not a value was supplied. Writing
// nothing here is a reading of the registry, not an assumption.
return Ok(());
}
let converted = match supplied.ok_or_else(|| {
CodecError::MissingExtension(identifier.to_string())
})? {
Supplied::Json(value) => self.json_to_value(value, ty)?,
// Round-tripped rather than appended. Bytes that decode against the
// declared type and re-encode to themselves are the *only* bytes the
// runtime could have meant; anything else — a short read, trailing
// bytes, a non-canonical compact — is a disagreement about the format
// that would otherwise be signed and only surface as `BadProof`.
Supplied::Raw(bytes) => {
let mut cursor = &bytes[..];
let value = self
.decode_checked(ty, &mut cursor)
.map_err(|e| CodecError::Encode(format!("{identifier}: {e}")))?;
if !cursor.is_empty() {
return Err(CodecError::Encode(format!(
"{identifier}: {} trailing bytes",
cursor.len()
)));
}
let mut check = Vec::new();
scale_value::scale::encode_as_type(&value, ty, self.types(), &mut check)
.map_err(|e| CodecError::Encode(format!("{identifier}: {e}")))?;
if check != *bytes {
return Err(CodecError::Encode(format!(
"{identifier}: supplied bytes do not round-trip against the runtime's type"
)));
}
out.extend_from_slice(bytes);
return Ok(());
}
};
scale_value::scale::encode_as_type(&converted, ty, self.types(), out)
.map_err(|e| CodecError::Encode(format!("{identifier}: {e}")))
}
/// The bytes a signer signs: `call ‖ extra ‖ additional`.
///
/// Substrate's own rule from `unchecked_extrinsic.rs` — a payload longer than
/// 256 bytes is signed as its BLAKE2b-256 hash — is **not** applied here.
/// That is the caller's, because the hash belongs with the signing code that
/// also chooses the FIPS 204 context, and splitting one rule across two
/// packages is how the halves drift apart.
pub fn signer_payload(
&self,
call: &[u8],
extensions: &EncodedExtensions,
) -> Vec<u8> {
let mut out = Vec::with_capacity(call.len() + extensions.extra.len() + extensions.additional.len());
out.extend_from_slice(call);
out.extend_from_slice(&extensions.extra);
out.extend_from_slice(&extensions.additional);
out
}
/// Assemble a signed extrinsic.
///
/// The preamble is `0b10 << 6 | version`: the type tag says signed and the
/// low six bits carry the version the metadata declares. Not a hard-coded
/// `0x84` — if this runtime ever declares a different extrinsic version, the
/// byte follows it.
///
/// `signature` is the already-encoded `Signature` type, variant byte
/// included: the signing side knows which ML-DSA scheme the key is, and
/// re-deriving it here from the byte length would be a second source of
/// truth. It is written raw — a fixed-size array takes **no compact length
/// prefix**, which is the detail that a `Vec<u8>`-shaped assumption gets
/// wrong by exactly two bytes.
pub fn encode_extrinsic(
&self,
address: &serde_json::Value,
signature: &[u8],
extra: &[u8],
call: &[u8],
) -> Result<Vec<u8>, CodecError> {
let mut body = Vec::new();
body.push(0b1000_0000 | (self.extrinsic_version() & 0b0011_1111));
let addr = self.json_to_value(address, self.extrinsic.address)?;
scale_value::scale::encode_as_type(&addr, self.extrinsic.address, self.types(), &mut body)
.map_err(|e| CodecError::Encode(format!("address: {e}")))?;
body.extend_from_slice(signature);
body.extend_from_slice(extra);
body.extend_from_slice(call);
// The node expects the extrinsic length-prefixed.
let mut out = parity_scale_codec::Compact(body.len() as u64).encode();
out.extend_from_slice(&body);
Ok(out)
}
/// Interpret a JSON value as a particular registry type.
///
/// Type-directed on purpose. The same JSON string `"0xa5aa…"` is an
/// `AccountId32`, an `H256` or a `Vec<u8>` depending only on what the runtime
/// says goes there, and JSON carries no way to tell them apart. Asking the
/// registry is the only way that stays right across an upgrade.
pub(crate) fn json_to_value(
&self,
json: &serde_json::Value,
ty: u32,
) -> Result<Value<()>, CodecError> {
use scale_info::TypeDef;
let def = self
.types()
.resolve(ty)
.map(|t| &t.type_def)
.ok_or_else(|| CodecError::Encode(format!("no registry type {ty}")))?;
match def {
TypeDef::Compact(c) => self.json_to_value(json, c.type_param.id),
TypeDef::Primitive(p) => primitive(json, p),
TypeDef::Array(a) => {
let inner = a.type_param.id;
let want = a.len as usize;
if let Some(bytes) = hex_bytes(json) {
if bytes.len() != want {
return Err(CodecError::Encode(format!(
"expected {want} bytes, got {}",
bytes.len()
)));
}
return Ok(byte_composite(&bytes));
}
self.unnamed(json, |_| inner)
}
TypeDef::Sequence(s) => {
if let Some(bytes) = hex_bytes(json) {
return Ok(byte_composite(&bytes));
}
self.unnamed(json, |_| s.type_param.id)
}
TypeDef::Tuple(t) => {
// An empty tuple is the unit type; JSON `null` and an empty
// array both mean it, and so does anything else, since it
// encodes to no bytes either way.
if t.fields.is_empty() {
return Ok(Value::unnamed_composite([]));
}
let ids: Vec<u32> = t.fields.iter().map(|f| f.id).collect();
self.unnamed(json, move |i| ids[i.min(ids.len() - 1)])
}
TypeDef::Composite(c) => {
// A single-field struct is transparent, named or not, unless the
// caller actually spelled the field out. `AccountId32(pub [u8;
// 32])` should take the hex string its inner array takes, and
// `CheckMetadataHash { mode }` should take `"Disabled"` — neither
// wrapper is something a caller should have to know about, and
// both are wrappers the *runtime* chose, so the registry is what
// tells us they are there.
if c.fields.len() == 1 {
let name = c.fields[0].name.clone();
let spelled_out = name
.as_ref()
.zip(json.as_object())
.is_some_and(|(n, map)| map.contains_key(n.as_str()));
if !spelled_out {
let inner = self.json_to_value(json, c.fields[0].ty.id)?;
return Ok(match name {
Some(n) => Value {
value: ValueDef::Composite(Composite::Named(alloc::vec![(n, inner)])),
context: (),
},
None => Value::unnamed_composite([inner]),
});
}
}
match json {
serde_json::Value::Object(map) => {
let mut fields = Vec::new();
for f in &c.fields {
let name = f.name.clone().unwrap_or_default();
let v = map.get(&name).ok_or_else(|| {
CodecError::Encode(format!("no value for field {name}"))
})?;
fields.push((name, self.json_to_value(v, f.ty.id)?));
}
Ok(Value {
value: ValueDef::Composite(Composite::Named(fields)),
context: (),
})
}
_ => {
let ids: Vec<u32> = c.fields.iter().map(|f| f.ty.id).collect();
self.unnamed(json, move |i| ids[i.min(ids.len().saturating_sub(1))])
}
}
}
TypeDef::Variant(v) => {
// Two spellings, both unambiguous: `"Immortal"` for a variant
// that carries nothing, `{"Id": "0x…"}` for one that does.
let (name, payload) = match json {
serde_json::Value::String(s) => (s.clone(), None),
serde_json::Value::Null => ("None".to_string(), None),
serde_json::Value::Object(map) if map.len() == 1 => {
let (k, v) = map.iter().next().expect("len == 1");
(k.clone(), Some(v))
}
_ => {
return Err(CodecError::Encode(format!(
"cannot read {json} as a variant"
)))
}
};
let variant = v
.variants
.iter()
.find(|x| x.name == name)
.ok_or_else(|| CodecError::Encode(format!("no variant {name}")))?;
let named = variant.fields.iter().all(|f| f.name.is_some());
let composite = match (payload, variant.fields.len()) {
(_, 0) => Composite::Unnamed(Vec::new()),
// A call's arguments arrive as an object keyed by the names
// the runtime gives them, at any depth — a `Utility.batch_all`
// carries whole calls in a `Vec<RuntimeCall>`, and each of
// those is this same shape again. Before this, only the
// outermost call could be spelled that way and anything
// nested had to be a positional array.
(Some(serde_json::Value::Object(map)), _) if named => {
let mut fields = Vec::new();
for f in &variant.fields {
let field = f.name.clone().unwrap_or_default();
let v = map.get(&field).ok_or_else(|| {
CodecError::Encode(format!("{name}: no value for {field}"))
})?;
fields.push((field, self.json_to_value(v, f.ty.id)?));
}
Composite::Named(fields)
}
(Some(p), 1) => {
Composite::Unnamed(alloc::vec![self.json_to_value(p, variant.fields[0].ty.id)?])
}
(Some(p), _) => {
let ids: Vec<u32> = variant.fields.iter().map(|f| f.ty.id).collect();
match self.unnamed(p, move |i| ids[i.min(ids.len() - 1)])?.value {
ValueDef::Composite(c) => c,
_ => unreachable!("unnamed always returns a composite"),
}
}
(None, _) => {
return Err(CodecError::Encode(format!(
"variant {name} needs a payload"
)))
}
};
Ok(Value::variant(name, composite))
}
TypeDef::BitSequence(_) => Err(CodecError::Encode(
"encoding a bit sequence is not supported".to_string(),
)),
}
}
fn unnamed(
&self,
json: &serde_json::Value,
ty_at: impl Fn(usize) -> u32,
) -> Result<Value<()>, CodecError> {
let items = match json {
serde_json::Value::Array(a) => a,
_ => {
return Err(CodecError::Encode(format!(
"expected an array, got {json}"
)))
}
};
let mut out = Vec::with_capacity(items.len());
for (i, item) in items.iter().enumerate() {
out.push(self.json_to_value(item, ty_at(i))?);
}
Ok(Value::unnamed_composite(out))
}
}
/// Read a JSON value as a SCALE primitive.
///
/// Numbers arrive as JSON numbers when they fit and as **decimal strings** when
/// they do not: a `u128` balance loses precision above 2^53 in JSON, and this
/// chain's balances are 12 decimal places, so that boundary is reached by
/// ordinary amounts rather than exotic ones.
fn primitive(
json: &serde_json::Value,
p: &scale_info::TypeDefPrimitive,
) -> Result<Value<()>, CodecError> {
use scale_info::TypeDefPrimitive as P;
let as_u128 = || -> Result<u128, CodecError> {
match json {
serde_json::Value::Number(n) => n
.as_u64()
.map(u128::from)
.ok_or_else(|| CodecError::Encode(format!("{n} is not a whole number"))),
serde_json::Value::String(s) => {
let s = s.trim();
if let Some(h) = s.strip_prefix("0x") {
u128::from_str_radix(h, 16)
} else {
s.parse::<u128>()
}
.map_err(|e| CodecError::Encode(format!("{s} is not a number: {e}")))
}
_ => Err(CodecError::Encode(format!("{json} is not a number"))),
}
};
Ok(match p {
P::Bool => Value {
value: ValueDef::Primitive(Primitive::Bool(json.as_bool().ok_or_else(|| {
CodecError::Encode(format!("{json} is not a boolean"))
})?)),
context: (),
},
P::Str => Value {
value: ValueDef::Primitive(Primitive::String(
json.as_str()
.ok_or_else(|| CodecError::Encode(format!("{json} is not a string")))?
.to_string(),
)),
context: (),
},
P::U8 | P::U16 | P::U32 | P::U64 | P::U128 | P::U256 => Value {
value: ValueDef::Primitive(Primitive::U128(as_u128()?)),
context: (),
},
P::I8 | P::I16 | P::I32 | P::I64 | P::I128 | P::I256 => Value {
value: ValueDef::Primitive(Primitive::I128(as_u128()? as i128)),
context: (),
},
P::Char => Err(CodecError::Encode("char is not encodable".to_string()))?,
})
}
/// `0x…` as bytes, if this is a hex string.
fn hex_bytes(json: &serde_json::Value) -> Option<Vec<u8>> {
let s = json.as_str()?.strip_prefix("0x")?;
if s.len() % 2 != 0 {
return None;
}
(0..s.len() / 2)
.map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).ok())
.collect()
}
fn byte_composite(bytes: &[u8]) -> Value<()> {
Value::unnamed_composite(bytes.iter().map(|b| Value {
value: ValueDef::Primitive(Primitive::U128(u128::from(*b))),
context: (),
}))
}
+266
View File
@@ -0,0 +1,266 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! The runtime's description of itself, and the handful of things this crate
//! needs to look up in it.
//!
//! Every type id here is *read* from the metadata. Nothing in this file names a
//! pallet, a call, a signed extension or a signature scheme, which is what lets
//! it keep working across a runtime upgrade that changes any of them.
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use frame_metadata::v14::RuntimeMetadataV14;
use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
use parity_scale_codec::Decode;
/// Failures reading a runtime's description, or its data.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CodecError {
/// The blob is not SCALE-encoded prefixed metadata.
Malformed,
/// Metadata this crate does not read. v14 is what every Quantus runtime
/// observed so far emits; a chain that moves to v15/v16 needs this widened
/// deliberately rather than silently mis-read.
UnsupportedVersion(u8),
/// The runtime does not describe its extrinsic in the usual shape.
NoExtrinsicTypes,
/// No such pallet, or no such call in it.
NoSuchCall(String),
/// A value did not match the type the registry said it would.
Decode(String),
/// A value could not be encoded as the type the registry declares.
Encode(String),
/// A signed extension declares a non-empty type and the caller supplied no
/// value for it. Deliberately fatal — see [`crate::encode`].
MissingExtension(String),
/// The runtime declares no such storage entry, or not in that shape.
NoStorageEntry(String),
}
impl core::fmt::Display for CodecError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Malformed => write!(f, "metadata did not decode"),
Self::UnsupportedVersion(v) => write!(f, "unsupported metadata version {v}"),
Self::NoExtrinsicTypes => write!(f, "runtime describes no extrinsic type"),
Self::NoSuchCall(s) => write!(f, "no such call: {s}"),
Self::Decode(s) => write!(f, "decoding against the registry failed: {s}"),
Self::Encode(s) => write!(f, "encoding against the registry failed: {s}"),
Self::NoStorageEntry(s) => write!(f, "no such storage entry: {s}"),
Self::MissingExtension(s) => write!(
f,
"signed extension {s} declares a non-empty type and no value was supplied"
),
}
}
}
/// The four type parameters of the extrinsic envelope.
#[derive(Debug, Clone, Copy)]
pub struct ExtrinsicTypes {
pub address: u32,
pub signature: u32,
pub extra: u32,
pub call: u32,
}
/// One signed extension, as the runtime declares it.
///
/// `ty` is what it contributes to the extrinsic; `additional` is what it
/// contributes to the signed payload but *not* to the extrinsic. Both are read
/// from the metadata, in the order the runtime applies them, because that order
/// is the payload's byte order.
#[derive(Debug, Clone)]
pub struct ExtensionDef {
pub identifier: String,
pub ty: u32,
pub additional: u32,
}
/// A runtime, as described by its own metadata.
pub struct Runtime {
pub(crate) metadata: RuntimeMetadataV14,
pub(crate) extrinsic: ExtrinsicTypes,
pub(crate) extensions: Vec<ExtensionDef>,
/// Call type id per pallet name, so `encode_call` need not walk the pallet
/// list for every argument.
pub(crate) calls: BTreeMap<String, u32>,
/// Registry types that are account ids.
///
/// Found by their **path**, not their length: a block hash is also 32 bytes,
/// and rendering one as an address would be a lie. Held so that decoding can
/// turn them into something a person can check against what they expected to
/// see, rather than 32 bytes of hex nobody reads.
pub(crate) account_tys: BTreeSet<u32>,
/// The SS58 prefix to render account ids at, when one has been set.
pub(crate) ss58_format: Option<u16>,
}
impl Runtime {
/// Parse metadata exactly as `state_getMetadata` returns it.
///
/// That RPC takes a block hash and makes the node run `Metadata_metadata`
/// against the runtime code in *that block's* state, so what arrives here is
/// the runtime WASM describing itself, executed by the node. It is the only
/// oracle on this chain that cannot go stale.
pub fn from_metadata(raw: &[u8]) -> Result<Self, CodecError> {
let prefixed =
RuntimeMetadataPrefixed::decode(&mut &raw[..]).map_err(|_| CodecError::Malformed)?;
let metadata = match prefixed.1 {
RuntimeMetadata::V14(v) => v,
other => return Err(CodecError::UnsupportedVersion(version_of(&other))),
};
// The envelope's four parameters, by the names `UncheckedExtrinsic`
// gives them. Read from the registry rather than assumed, which is the
// whole point: `Signature` here is
// `qp_dilithium_crypto::types::DilithiumSignatureScheme`, and no decoder
// written against vanilla Substrate would guess that.
let extrinsic = metadata
.types
.resolve(metadata.extrinsic.ty.id)
.and_then(|e| {
let param = |name: &str| {
e.type_params
.iter()
.find(|p| p.name == name)
.and_then(|p| p.ty)
.map(|t| t.id)
};
Some(ExtrinsicTypes {
address: param("Address")?,
signature: param("Signature")?,
extra: param("Extra")?,
call: param("Call")?,
})
})
.ok_or(CodecError::NoExtrinsicTypes)?;
let extensions = metadata
.extrinsic
.signed_extensions
.iter()
.map(|e| ExtensionDef {
identifier: e.identifier.to_string(),
ty: e.ty.id,
additional: e.additional_signed.id,
})
.collect();
let calls = metadata
.pallets
.iter()
.filter_map(|p| p.calls.as_ref().map(|c| (p.name.to_string(), c.ty.id)))
.collect();
let account_tys = metadata
.types
.types
.iter()
.filter(|t| {
t.ty.path
.segments
.last()
.is_some_and(|s| s == "AccountId32")
})
.map(|t| t.id)
.collect();
Ok(Self {
account_tys,
calls,
extensions,
extrinsic,
metadata,
ss58_format: None,
})
}
/// Render account ids as SS58 at this prefix when decoding.
///
/// Off until set, because the prefix is a property of the chain a caller is
/// talking to rather than of the metadata, and guessing it would put a
/// plausible, wrong address in front of somebody about to approve a transfer.
pub fn set_ss58_format(&mut self, prefix: u16) {
self.ss58_format = Some(prefix);
}
/// The extrinsic format version the metadata declares.
///
/// Not to be confused with the preamble byte of any particular extrinsic —
/// see [`crate::decode::decode_extrinsic`], which is where that distinction
/// has teeth.
pub fn extrinsic_version(&self) -> u8 {
self.metadata.extrinsic.version
}
/// The signed extensions, in the order the runtime applies them.
pub fn extensions(&self) -> &[ExtensionDef] {
&self.extensions
}
pub fn extrinsic_types(&self) -> ExtrinsicTypes {
self.extrinsic
}
pub(crate) fn types(&self) -> &scale_info::PortableRegistry {
&self.metadata.types
}
/// Whether a registry type encodes to nothing at all.
///
/// The question [`crate::encode`] asks of every signed extension: a
/// zero-sized one contributes no bytes and needs no value from the caller,
/// and anything else does. Answering it from the registry rather than from a
/// list of known extension names is the difference between this crate and
/// the thing it replaces.
pub(crate) fn is_empty_ty(&self, id: u32) -> bool {
match self.metadata.types.resolve(id).map(|t| &t.type_def) {
// The unit type, and a tuple of nothing, are the same thing here.
Some(scale_info::TypeDef::Tuple(t)) => {
t.fields.iter().all(|f| self.is_empty_ty(f.id))
}
Some(scale_info::TypeDef::Composite(c)) => {
c.fields.iter().all(|f| self.is_empty_ty(f.ty.id))
}
Some(scale_info::TypeDef::Array(a)) => {
a.len == 0 || self.is_empty_ty(a.type_param.id)
}
_ => false,
}
}
}
fn version_of(md: &RuntimeMetadata) -> u8 {
match md {
RuntimeMetadata::V14(_) => 14,
RuntimeMetadata::V15(_) => 15,
_ => 0,
}
}
impl Runtime {
/// [`Runtime::is_empty_ty`], for the bindings module.
pub fn is_empty_ty_pub(&self, id: u32) -> bool {
self.is_empty_ty(id)
}
}
impl Runtime {
/// [`Runtime::types`], for tests.
pub fn types_pub(&self) -> &scale_info::PortableRegistry {
self.types()
}
/// [`Runtime::json_to_value`], for tests.
pub fn json_to_value_pub(
&self,
json: &serde_json::Value,
ty: u32,
) -> Result<scale_value::Value<()>, CodecError> {
self.json_to_value(json, ty)
}
}
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! SS58, so a decoded call names an address a person can recognise.
//!
//! An account id is 32 bytes. Printed as hex it is a correct description of the
//! value and useless to somebody being asked to check who they are paying —
//! which is the only moment in a wallet where reading the recipient matters.
use alloc::string::String;
use alloc::vec::Vec;
use blake2::digest::consts::U64;
use blake2::{Blake2b, Digest};
/// The domain separator Substrate hashes into every SS58 checksum.
const PREFIX: &[u8] = b"SS58PRE";
/// Encode an account id at a network prefix.
///
/// Prefixes below 64 are one byte; the rest are two, with the low six bits of
/// the first byte and the high two bits arranged as Substrate specifies. Quantus
/// is 189, so it takes the two-byte form — getting that wrong yields an address
/// that looks right and belongs to nobody.
pub fn encode(prefix: u16, account: &[u8]) -> String {
let mut body = match prefix {
0..=63 => alloc::vec![prefix as u8],
64..=16_383 => {
let low = ((prefix & 0b0000_0000_1111_1100) as u8) >> 2;
let high = (((prefix >> 8) as u8) | ((prefix & 0b0000_0000_0000_0011) as u8) << 6) as u8;
alloc::vec![low | 0b0100_0000, high]
}
// Reserved by the specification; nothing should ask for one.
_ => alloc::vec![0b0100_0000, 0],
};
body.extend_from_slice(account);
let mut hasher = Blake2b::<U64>::new();
hasher.update(PREFIX);
hasher.update(&body);
let checksum = hasher.finalize();
let mut out: Vec<u8> = body;
out.extend_from_slice(&checksum[..2]);
bs58::encode(out).into_string()
}
+225
View File
@@ -0,0 +1,225 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Addressing chain state, using the runtime's own description of where it lives.
//!
//! A storage key is `twox128(pallet) ‖ twox128(item)`, then each map key hashed
//! by the hasher the entry declares. None of those choices are known here:
//! the pallet prefix, the item name, the hashers, the key type and the value
//! type all come out of the metadata, so a runtime upgrade that re-hashes a map
//! or changes a value's shape is followed rather than mis-read.
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use frame_metadata::v14::{StorageEntryType, StorageHasher};
use crate::runtime::{CodecError, Runtime};
/// Where a storage value lives and what it decodes as.
#[derive(Debug, Clone)]
pub struct StorageTarget {
/// The full key, ready for `state_getStorage`.
pub key: Vec<u8>,
/// The registry type its value decodes as.
pub value_ty: u32,
/// What the chain means when it returns nothing.
///
/// `Some(bytes)` for a `Default` entry — an unfunded account reads as a zero
/// balance, not as an error. `None` for an `Optional` entry, where nothing
/// means nothing. Conflating the two is how a wallet reports "failed to load"
/// for an account that simply has no money in it.
pub default: Option<Vec<u8>>,
}
impl Runtime {
/// Resolve a storage entry, hashing any map keys as the runtime declares.
///
/// `keys` are JSON, interpreted against the key types the metadata gives —
/// so an `AccountId32` is the hex string its inner array accepts, and a
/// double map takes two values in the order the entry lists its hashers.
pub fn storage_target(
&self,
pallet: &str,
item: &str,
keys: &[serde_json::Value],
) -> Result<StorageTarget, CodecError> {
let entry = self
.metadata
.pallets
.iter()
.find(|p| p.name == pallet)
.and_then(|p| p.storage.as_ref())
.and_then(|s| s.entries.iter().find(|e| e.name == item))
.ok_or_else(|| CodecError::NoStorageEntry(format!("{pallet}::{item}")))?;
let prefix = self
.metadata
.pallets
.iter()
.find(|p| p.name == pallet)
.and_then(|p| p.storage.as_ref())
.map(|s| s.prefix.clone())
.unwrap_or_else(|| pallet.to_string());
let mut key = twox_128(prefix.as_bytes()).to_vec();
key.extend_from_slice(&twox_128(item.as_bytes()));
let value_ty = match &entry.ty {
StorageEntryType::Plain(ty) => {
if !keys.is_empty() {
return Err(CodecError::NoStorageEntry(format!(
"{pallet}::{item} takes no keys"
)));
}
ty.id
}
StorageEntryType::Map {
hashers,
key: key_ty,
value,
} => {
if hashers.len() != keys.len() {
return Err(CodecError::NoStorageEntry(format!(
"{pallet}::{item} takes {} key(s), {} given",
hashers.len(),
keys.len()
)));
}
// One hasher means the declared key type *is* the key. More than
// one means it is a tuple, one element per hasher, and the
// elements are hashed separately rather than as a unit.
let key_tys: Vec<u32> = if hashers.len() == 1 {
alloc::vec![key_ty.id]
} else {
match self.types().resolve(key_ty.id).map(|t| &t.type_def) {
Some(scale_info::TypeDef::Tuple(t)) => {
t.fields.iter().map(|f| f.id).collect()
}
_ => {
return Err(CodecError::NoStorageEntry(format!(
"{pallet}::{item} has {} hashers and a non-tuple key",
hashers.len()
)))
}
}
};
for ((supplied, ty), hasher) in keys.iter().zip(key_tys).zip(hashers.iter()) {
let value = self.json_to_value(supplied, ty)?;
let mut encoded = Vec::new();
scale_value::scale::encode_as_type(&value, ty, self.types(), &mut encoded)
.map_err(|e| CodecError::Encode(format!("{pallet}::{item} key: {e}")))?;
key.extend_from_slice(&hash_key(hasher, &encoded));
}
value.id
}
};
let default = match &entry.modifier {
frame_metadata::v14::StorageEntryModifier::Default => Some(entry.default.clone()),
frame_metadata::v14::StorageEntryModifier::Optional => None,
};
Ok(StorageTarget {
default,
key,
value_ty,
})
}
/// Decode a storage value against the type its entry declares.
///
/// `bytes` is what `state_getStorage` returned, or the entry's default when
/// it returned nothing.
pub fn decode_storage_value(
&self,
value_ty: u32,
bytes: &[u8],
) -> Result<serde_json::Value, CodecError> {
let mut cursor = bytes;
let value = self
.decode_checked(value_ty, &mut cursor)
.map_err(|e| CodecError::Decode(e))?;
if !cursor.is_empty() {
return Err(CodecError::Decode(format!(
"{} trailing bytes after storage value",
cursor.len()
)));
}
Ok(self.render(&value))
}
}
/// `twox128`, as Substrate uses it for pallet and item prefixes.
fn twox_128(input: &[u8]) -> [u8; 16] {
use twox_hash::XxHash64;
let mut out = [0u8; 16];
out[..8].copy_from_slice(&XxHash64::oneshot(0, input).to_le_bytes());
out[8..].copy_from_slice(&XxHash64::oneshot(1, input).to_le_bytes());
out
}
/// Hash one map key the way its entry declares.
///
/// The `Concat` variants keep the key after its hash, which is what makes a map
/// enumerable. The plain variants do not.
fn hash_key(hasher: &StorageHasher, encoded: &[u8]) -> Vec<u8> {
use blake2::digest::consts::{U16, U32};
use blake2::{Blake2b, Digest};
use twox_hash::XxHash64;
match hasher {
StorageHasher::Blake2_128 => Blake2b::<U16>::digest(encoded).to_vec(),
StorageHasher::Blake2_256 => Blake2b::<U32>::digest(encoded).to_vec(),
StorageHasher::Blake2_128Concat => {
let mut v = Blake2b::<U16>::digest(encoded).to_vec();
v.extend_from_slice(encoded);
v
}
StorageHasher::Twox128 => twox_128(encoded).to_vec(),
StorageHasher::Twox256 => {
let mut v = Vec::with_capacity(32);
for seed in 0..4u64 {
v.extend_from_slice(&XxHash64::oneshot(seed, encoded).to_le_bytes());
}
v
}
StorageHasher::Twox64Concat => {
let mut v = XxHash64::oneshot(0, encoded).to_le_bytes().to_vec();
v.extend_from_slice(encoded);
v
}
StorageHasher::Identity => encoded.to_vec(),
}
}
/// Hex, for the JSON boundary.
pub(crate) fn hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(2 + bytes.len() * 2);
s.push_str("0x");
for b in bytes {
s.push(char::from_digit((b >> 4) as u32, 16).expect("nibble"));
s.push(char::from_digit((b & 0x0f) as u32, 16).expect("nibble"));
}
s
}
+328
View File
@@ -0,0 +1,328 @@
// Copyright 2026 @quantus/codec authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Tested against metadata captured from the chain, not against a fixture this
//! crate wrote. The point of the package is agreeing with a runtime; a test that
//! agrees with itself proves nothing.
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use crate::encode::{ExtensionValue, Supplied};
use crate::runtime::Runtime;
/// Heisenberg at spec 148, `transactionVersion` 6 — the runtime quantus/extension#7
/// tier 1 submits to.
const HEISENBERG_V148: &str = include_str!("../../tests/heisenberg-v148.metadata.hex");
fn unhex(s: &str) -> Vec<u8> {
let s = s.trim();
let s = s.strip_prefix("0x").unwrap_or(s);
(0..s.len() / 2)
.map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).expect("fixture is hex"))
.collect()
}
fn heisenberg() -> Runtime {
Runtime::from_metadata(&unhex(HEISENBERG_V148)).expect("fixture is v14 metadata")
}
#[test]
fn metadata_loads_and_describes_its_extrinsic() {
let rt = heisenberg();
assert_eq!(rt.extrinsic_version(), 4);
}
/// The listing that `@polkadot/api` cannot produce, and the reason this crate
/// exists. Two of these extensions are Quantus-only and polkadot-js writes zero
/// bytes for both halves of them by assumption; here the answer comes from the
/// registry.
#[test]
fn every_signed_extension_is_read_from_the_registry() {
let rt = heisenberg();
let names: Vec<&str> = rt
.extensions()
.iter()
.map(|e| e.identifier.as_str())
.collect();
for e in rt.extensions() {
println!(
"{:<40} extra={:<5} additional={}",
e.identifier,
!rt.is_empty_ty_pub(e.ty),
!rt.is_empty_ty_pub(e.additional)
);
}
// Not an exhaustive list on purpose — asserting the whole tuple would make
// this test a second copy of the runtime, which is the mistake the crate is
// here to avoid. These two are asserted because they are the ones no
// Substrate-shaped decoder knows about.
assert!(names.contains(&"ReversibleTransactionExtension"));
assert!(names.contains(&"WormholeProofRecorderExtension"));
}
/// The guarantee in [`Runtime::encode_extensions`]: a declared, non-empty
/// extension with no supplied value refuses to produce a payload.
#[test]
fn a_missing_extension_value_is_an_error_not_a_short_payload() {
let rt = heisenberg();
let empty: BTreeMap<String, ExtensionValue> = BTreeMap::new();
let err = rt
.encode_extensions(&empty)
.expect_err("CheckSpecVersion declares a u32 additional; nothing supplied it");
assert!(
err.to_string().contains("no value was supplied"),
"unexpected error: {err}"
);
}
/// A `MultiAddress::Id` is a variant carrying a newtype around `[u8; 32]`, and
/// the caller should be able to say so with a hex string and a variant name
/// without knowing about either wrapper.
#[test]
fn an_account_id_encodes_from_its_hex() {
let rt = heisenberg();
let tys = rt.extrinsic_types();
let id = "0x".to_string() + &"11".repeat(32);
let json = serde_json::json!({ "Id": id });
let value = rt
.json_to_value_pub(&json, tys.address)
.expect("MultiAddress::Id from hex");
let mut out = Vec::new();
scale_value::scale::encode_as_type(&value, tys.address, rt.types_pub(), &mut out)
.expect("encodes");
// Variant index 0 for `Id`, then 32 raw bytes with no length prefix.
assert_eq!(out.len(), 33);
assert_eq!(out[0], 0);
assert_eq!(&out[1..], &[0x11u8; 32]);
}
/// Pre-encoded bytes are accepted — a dapp encodes its own `era`, and nothing
/// here knows the era algorithm — but they are round-tripped against the
/// runtime's declared type rather than trusted.
#[test]
fn raw_extension_bytes_are_validated_not_trusted() {
let rt = heisenberg();
let mut values: BTreeMap<String, ExtensionValue> = BTreeMap::new();
let fill = |values: &mut BTreeMap<String, ExtensionValue>, era: Supplied| {
values.insert(
"CheckMortality".to_string(),
ExtensionValue {
additional: Some(Supplied::Json(serde_json::json!(
"0x".to_string() + &"aa".repeat(32)
))),
extra: Some(era),
},
);
values.insert(
"CheckNonce".to_string(),
ExtensionValue {
additional: None,
extra: Some(Supplied::Json(serde_json::json!(1))),
},
);
values.insert(
"ChargeTransactionPayment".to_string(),
ExtensionValue {
additional: None,
extra: Some(Supplied::Json(serde_json::json!(0))),
},
);
values.insert(
"CheckMetadataHash".to_string(),
ExtensionValue {
additional: Some(Supplied::Json(serde_json::json!("None"))),
extra: Some(Supplied::Json(serde_json::json!("Disabled"))),
},
);
for (id, v) in [
("CheckSpecVersion", 148),
("CheckTxVersion", 6),
] {
values.insert(
id.to_string(),
ExtensionValue {
additional: Some(Supplied::Json(serde_json::json!(v))),
extra: None,
},
);
}
values.insert(
"CheckGenesis".to_string(),
ExtensionValue {
additional: Some(Supplied::Json(serde_json::json!(
"0x".to_string() + &"bb".repeat(32)
))),
extra: None,
},
);
};
// `0x00` is Era::Immortal, and it round-trips.
fill(&mut values, Supplied::Raw(alloc::vec![0x00]));
let encoded = rt.encode_extensions(&values).expect("immortal era encodes");
assert_eq!(encoded.extra[0], 0x00);
// Two bytes where the type says one is a disagreement about the format. A
// signer that appended them would produce a signature the chain rejects as
// BadProof, with nothing locally to say why.
fill(&mut values, Supplied::Raw(alloc::vec![0x00, 0x00]));
let err = rt
.encode_extensions(&values)
.expect_err("trailing byte is refused");
assert!(
err.to_string().contains("trailing"),
"unexpected error: {err}"
);
}
/// A call nested inside another call — `Utility.batch_all` carries a
/// `Vec<RuntimeCall>`, so each element is a call spelled exactly as a top-level
/// one. Anything less than that and batching has to be written positionally,
/// which is unreadable and silently order-dependent.
#[test]
fn a_call_nests_inside_another_call() {
let rt = heisenberg();
let dest = "0x".to_string() + &"22".repeat(32);
let one = serde_json::json!({
"Balances": { "transfer_keep_alive": { "dest": { "Id": dest }, "value": "1000000000" } }
});
let encoded = rt
.encode_call(
"Utility",
"batch_all",
&serde_json::json!({ "calls": [one.clone(), one] }),
)
.expect("batch_all of two transfers encodes");
// Over 256 bytes, which is where Substrate's signing rule switches to
// BLAKE2b — the branch quantus/extension#7 wants exercised.
assert!(encoded.len() > 80, "unexpectedly short: {}", encoded.len());
let decoded = rt.decode_call(&encoded).expect("and decodes again");
let calls = decoded["Utility"]["batch_all"]["calls"]
.as_array()
.expect("calls is a list");
assert_eq!(calls.len(), 2);
assert_eq!(
calls[0]["Balances"]["transfer_keep_alive"]["value"],
serde_json::json!("1000000000")
);
}
/// `System::Account` is the entry every wallet needs first, and it is a map with
/// a `Blake2_128Concat` hasher over an `AccountId32`. Nothing here says so — the
/// hasher and both types come out of the metadata.
#[test]
fn a_storage_key_is_built_from_the_declared_hasher() {
let rt = heisenberg();
let who = "0x".to_string() + &"11".repeat(32);
let target = rt
.storage_target("System", "Account", &[serde_json::json!(who)])
.expect("System::Account is a map over AccountId32");
// twox128(prefix) ++ twox128(item) ++ blake2_128(key) ++ key
assert_eq!(target.key.len(), 16 + 16 + 16 + 32);
assert_eq!(&target.key[48..], &[0x11u8; 32]);
// AccountInfo is a `Default` entry: an account nobody has ever funded reads
// as a zero balance, not as a missing value. A wallet that treated the two
// alike would report a failure for an empty account.
let default = target.default.expect("AccountInfo is a Default entry");
let decoded = rt
.decode_storage_value(target.value_ty, &default)
.expect("the declared default decodes as the declared type");
// Every integer renders as a decimal string, whatever its width — see
// `decode::render` for why the width is not available to switch on.
assert_eq!(decoded["nonce"], serde_json::json!("0"));
assert_eq!(decoded["data"]["free"], serde_json::json!("0"));
}
/// The number of keys is the runtime's to state, not the caller's to assume.
#[test]
fn a_storage_entry_refuses_the_wrong_number_of_keys() {
let rt = heisenberg();
assert!(rt.storage_target("System", "Account", &[]).is_err());
assert!(rt.storage_target("System", "Number", &[serde_json::json!(1)]).is_err());
assert!(rt.storage_target("System", "NoSuchThing", &[]).is_err());
}
/// The recipient of a transfer must render as an address somebody can check
/// against what they meant to type. 32 bytes of hex is a correct description of
/// the value and the one thing nobody reads.
///
/// The vector is crystal_bob on Heisenberg, taken from the chain rather than
/// computed here.
#[test]
fn an_account_id_in_a_call_renders_as_ss58() {
let mut rt = heisenberg();
let bob_id = "0x300bb607ba60e89461d2f9005668231ceb30237b33db53a614164b8590965519";
const BOB: &str = "qzkYEQv8tQsmniZYdame3Cku18RL5g9bGK9Pdydq5TMPdpE3y";
let call = rt
.encode_call(
"Balances",
"transfer_keep_alive",
&serde_json::json!({ "dest": { "Id": bob_id }, "value": "1000000000" }),
)
.expect("a transfer to bob");
// Until a prefix is set, hex. The prefix belongs to the chain a caller is
// talking to, not to the metadata, and a guessed one puts a plausible wrong
// address in front of somebody about to approve a transfer.
let raw = rt.decode_call(&call).expect("decodes");
assert_eq!(
raw["Balances"]["transfer_keep_alive"]["dest"]["Id"],
serde_json::json!(bob_id)
);
rt.set_ss58_format(189);
let decoded = rt.decode_call(&call).expect("decodes again");
assert_eq!(
decoded["Balances"]["transfer_keep_alive"]["dest"]["Id"],
serde_json::json!(BOB)
);
}
/// Found by registry path, not by length. A block hash is 32 bytes too, and
/// rendering one as an address would be a lie a reader cannot catch.
#[test]
fn a_32_byte_value_that_is_not_an_account_stays_hex() {
let mut rt = heisenberg();
rt.set_ss58_format(189);
let target = rt
.storage_target("System", "BlockHash", &[serde_json::json!(0)])
.expect("System::BlockHash is a map over block number");
let hash = [0x11u8; 32];
let decoded = rt
.decode_storage_value(target.value_ty, &hash)
.expect("a block hash decodes");
assert_eq!(decoded, serde_json::json!("0x".to_string() + &"11".repeat(32)));
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"composite": false,
"declaration": true,
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false
},
"exclude": [
"**/*.spec.ts"
],
"include": [
"src/**/*.ts"
],
"references": []
}
+955
View File
@@ -0,0 +1,955 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "ahash"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "anyhow"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]]
name = "arrayvec"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bip39"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc"
dependencies = [
"bitcoin_hashes",
"zeroize",
]
[[package]]
name = "bitcoin_hashes"
version = "0.14.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2"
dependencies = [
"hex-conservative",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "either"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
[[package]]
name = "fixed-hash"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
dependencies = [
"static_assertions",
]
[[package]]
name = "futures-core"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
[[package]]
name = "futures-task"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]]
name = "futures-util"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if",
"libc",
"r-efi",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
"serde",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-conservative"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3fef046dca3ca91ee1408a8c1b80ab777e80a4d308d1bf4e7adb3fcb047e08"
dependencies = [
"arrayvec",
]
[[package]]
name = "hex-literal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e"
dependencies = [
"cfg-if",
"futures-util",
"wasm-bindgen",
]
[[package]]
name = "keccak-hash"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce2bd4c29270e724d3eaadf7bdc8700af4221fc0ed771b855eadcd1b98d52851"
dependencies = [
"primitive-types",
"tiny-keccak",
]
[[package]]
name = "libc"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
dependencies = [
"critical-section",
"portable-atomic",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "plonky2_maybe_rayon"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1e554181dc95243b8d9948ae7bae5759c7fb2502fed28f671f95ef38079406"
[[package]]
name = "plonky2_util"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c32c137808ca984ab2458b612b7eb0462d853ee041a3136e83d54b96074c7610"
[[package]]
name = "portable-atomic"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "primitive-types"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373"
dependencies = [
"fixed-hash",
"uint",
]
[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "qp-plonky2"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd331d489a309f88e2d0e35a2b996932c7d92038b91ccc656a0a8e6b11b6977"
dependencies = [
"ahash",
"anyhow",
"critical-section",
"hashbrown",
"itertools",
"keccak-hash",
"log",
"num",
"once_cell",
"plonky2_maybe_rayon",
"plonky2_util",
"qp-plonky2-core",
"qp-plonky2-field",
"qp-plonky2-verifier",
"qp-poseidon-core",
"rand 0.10.1",
"serde",
"static_assertions",
"unroll",
]
[[package]]
name = "qp-plonky2-core"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b81a3a9fce99f7bd45b8578f8d9b6a33507d34c2eb2c47c969b464db1ad601d3"
dependencies = [
"ahash",
"anyhow",
"hashbrown",
"itertools",
"keccak-hash",
"log",
"num",
"plonky2_util",
"qp-plonky2-field",
"serde",
"static_assertions",
"unroll",
]
[[package]]
name = "qp-plonky2-field"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1630d418ddce9feba18d3364596711d07074851757301350de313eef0a31af4f"
dependencies = [
"anyhow",
"itertools",
"num",
"plonky2_util",
"rustc_version",
"serde",
"static_assertions",
"unroll",
]
[[package]]
name = "qp-plonky2-verifier"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "944da5dec21ee476d561f6c38caddf45e829f3cc5fccbc76f6ece03660378dbe"
dependencies = [
"ahash",
"anyhow",
"critical-section",
"hashbrown",
"itertools",
"keccak-hash",
"log",
"num",
"once_cell",
"plonky2_util",
"qp-plonky2-core",
"qp-plonky2-field",
"qp-poseidon-core",
"serde",
"static_assertions",
"unroll",
]
[[package]]
name = "qp-poseidon-core"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5872607e25ea4ee5fb37e64bf1462168e1a36a4e719cdc8a105533c708253918"
[[package]]
name = "qp-rusty-crystals-dilithium"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789877c169226a35d2ea686bbd9d506becc693f7bb0ee91acc03f74491e80c0f"
dependencies = [
"zeroize",
]
[[package]]
name = "qp-rusty-crystals-hdwallet"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51ec6c3db4055c217a503c45d0c101cf3c10d4fc1e562f0588aa55dda4f60a4d"
dependencies = [
"bip39",
"getrandom 0.2.17",
"hex",
"hex-literal",
"qp-poseidon-core",
"qp-rusty-crystals-dilithium",
"serde",
"serde_json",
"sha2",
"thiserror",
"unicode-normalization",
"zeroize",
]
[[package]]
name = "qp-wormhole-circuit"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55167daf965a3616b74184171148b94c64b3a48771d6433a1a43377a6e46c6e8"
dependencies = [
"anyhow",
"hex",
"qp-plonky2",
"qp-wormhole-inputs",
"qp-zk-circuits-common",
"zeroize",
]
[[package]]
name = "qp-wormhole-inputs"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c07863a2211a17b46319289c5ef22e5670a3fb8653386bb366c418193254793"
dependencies = [
"anyhow",
]
[[package]]
name = "qp-zk-circuits-common"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec45510701f160fdb730bdb622d6cdd0a62547e607c9b1ecb19558202797f81"
dependencies = [
"anyhow",
"qp-plonky2",
"qp-poseidon-core",
"qp-wormhole-inputs",
"rand 0.8.6",
"serde",
"serde_json",
]
[[package]]
name = "quantus_crypto"
version = "0.0.0"
dependencies = [
"qp-poseidon-core",
"qp-rusty-crystals-dilithium",
"qp-rusty-crystals-hdwallet",
"qp-wormhole-circuit",
"qp-zk-circuits-common",
"wasm-bindgen",
]
[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [
"libc",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [
"getrandom 0.4.3",
"rand_core 0.10.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "typenum"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "uint"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-normalization"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "unroll"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 3.0.5",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "zerocopy"
version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+47
View File
@@ -0,0 +1,47 @@
# Quantus post-quantum crypto, compiled to WASM for the browser.
#
# Deliberately a separate crate from `wasm-crypto` rather than more files inside
# it: that package is built with `nightly-2022-06-24` (see scripts/rust-version.sh)
# against a 2019-era dependency set, and the ML-DSA crates use inline `const {}`
# blocks that need Rust >= 1.79. The two cannot share a Cargo graph, and bumping
# the older one would mean rewriting upstream's sr25519/ed25519 build — which is
# the thing we most want to leave alone so rebases stay boring. See quantus/wasm#1.
[package]
authors = ["Quantus Network Developers <hello@quantus.com>"]
description = "WASM bindings to the Quantus chain's post-quantum crypto crates."
edition = "2021"
license = "Apache-2.0"
name = "quantus_crypto"
publish = false
repository = "https://git.lair.cafe/quantus/wasm"
resolver = "2"
version = "0.0.0"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
# The crates the runtime itself uses. Versions match quantus-apps/quantus_sdk's
# rust bridge, which is the other non-Rust consumer of exactly this surface.
qp-poseidon-core = "3.1.0"
qp-rusty-crystals-dilithium = { version = "4.1.1", default-features = false, features = ["ml-dsa-65", "ml-dsa-87"] }
qp-rusty-crystals-hdwallet = { version = "4.1.1", default-features = false, features = ["ml-dsa-65", "ml-dsa-87"] }
wasm-bindgen = "0.2"
[dev-dependencies]
# The chain's own nullifier, for known-answer tests only. It pulls in plonky2,
# which has no place in the shipped WASM: the port in rs/hdwallet.rs has to
# agree with it, and these tests are how that is shown rather than asserted.
qp-wormhole-circuit = { version = "=4.3.0", default-features = false, features = ["std"] }
qp-zk-circuits-common = { version = "=4.3.0" }
[profile.release]
codegen-units = 1
debug = false
debug-assertions = false
incremental = false
lto = true
opt-level = "z"
panic = "abort"
rpath = false
+76
View File
@@ -0,0 +1,76 @@
# @quantus/crypto
Quantus post-quantum crypto for the browser: ML-DSA-65 and ML-DSA-87 signatures,
Poseidon2-over-Goldilocks account-id hashing, and hardened BIP44 key derivation.
Every function delegates to the crates the Quantus runtime itself uses —
`qp-rusty-crystals-dilithium`, `qp-poseidon-core`, `qp-rusty-crystals-hdwallet`
rather than reimplementing them. A browser wallet that disagreed with the chain
about a key or a signature would produce perfectly well-formed output that the
chain rejects, and nothing on this side could tell.
## Why a separate package from `@polkadot/wasm-crypto`
They cannot share a Cargo build. `wasm-crypto` is compiled with
`nightly-2022-06-24` against a 2019-era dependency set; the ML-DSA crates use
inline `const {}` blocks that require Rust >= 1.79. Modernising the older build
would mean rewriting upstream's sr25519/ed25519 crypto, which is the thing most
worth leaving untouched so rebases onto upstream stay boring.
What *is* shared is the packaging: the WASM is zlib-compressed and base64'd into
the JS at build time, so nothing is fetched at runtime. That matters because the
consumer is an MV3 service worker under `script-src 'self' 'wasm-unsafe-eval'`,
which can compile WASM but cannot usefully fetch it, and because callers like
`pair.sign()` are synchronous and have no `await` to give.
`@polkadot/wasm-bridge` is deliberately not used: its `Bridge` implements
wasm-bindgen 0.2.79's JS-heap ABI, while this crate builds with 0.2.128, which
uses externref tables. wasm-bindgen's own generated glue plus `initSync` is both
smaller and correct.
The only runtime dependency is `fflate`, for zlib inflate. Base64 decoding is
fifteen lines here rather than a dependency. Both were originally taken from
`@polkadot/wasm-util`, which turned out to cost more than it saved: its index
re-exports `packageDetect`, dragging in a `@polkadot/util` peer dependency for a
side effect we do not want, and being a workspace package it resolved through its
*own* repo's node_modules when this package was consumed by symlink from another
checkout — which is exactly how `quantus/common` consumes it during development.
## Scheme selector
`Scheme.MlDsa87 = 0`, `Scheme.MlDsa65 = 1` — these are the chain's own
`DilithiumSignatureScheme` variant indices, so the number threaded through this
API is the byte that ends up on the wire. New accounts use ML-DSA-65; ML-DSA-87
is legacy and must be supported but never chosen.
## Signing context
ML-DSA hashes a context into the signature. Quantus extrinsics on spec >= 148 are
verified under `QUANTUS_EXTRINSIC`, earlier specs under the empty context. A
signature made under the wrong one is cryptographically valid, rejected by the
chain, and indistinguishable locally — so use `contextForSpec(specVersion)`
rather than picking one by hand. Nothing here guesses on your behalf.
## Sizes come from the crate
`sizes(scheme)` returns the public/secret/signature lengths rather than exposing
constants to copy. They are consensus-critical — the runtime decodes a fixed-size
array with no compact length prefix — and a JS constant that drifted would
re-frame every byte after the signature while looking entirely healthy.
## Building
```sh
yarn install-build-deps # downloads wasm-bindgen 0.2.128 and binaryen
./scripts/build-quantus.sh
```
The Rust toolchain is pinned in `rust-toolchain.toml` to the same channel the
chain builds its runtime with.
## Tests
`cargo test` runs conformance tests whose expected values come from the `quantus`
CLI, not from this crate — the dev-genesis account ids, HD derivation at both
schemes' default paths, and context separation. A test that pinned our own output
would keep passing through exactly the drift they exist to catch.
+24
View File
@@ -0,0 +1,24 @@
{
"author": "Quantus Network Developers <hello@quantus.com>",
"bugs": "https://git.lair.cafe/quantus/wasm/issues",
"description": "Quantus post-quantum crypto (ML-DSA, Poseidon2, HD derivation) for the browser",
"engines": {
"node": ">=18"
},
"homepage": "https://git.lair.cafe/quantus/wasm/src/branch/main/packages/quantus-crypto#readme",
"license": "Apache-2.0",
"name": "@quantus/crypto",
"repository": {
"directory": "packages/quantus-crypto",
"type": "git",
"url": "https://git.lair.cafe/quantus/wasm.git"
},
"sideEffects": false,
"type": "module",
"version": "0.3.0",
"main": "index.js",
"dependencies": {
"fflate": "^0.8.2",
"tslib": "^2.7.0"
}
}
@@ -0,0 +1,8 @@
# Matches the chain's toolchain (chain/rust-toolchain), so this crate is built by
# the same compiler that builds the runtime it has to agree with. Upstream's
# `wasm-crypto` keeps its own nightly-2022-06-24 pin; the two builds are separate
# on purpose. See quantus/wasm#1.
[toolchain]
channel = "1.93.0"
targets = ["wasm32-unknown-unknown"]
profile = "minimal"
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// An array indexer rather than a Map: the input is ASCII by construction, so it
// cannot overflow, and array access is measurably faster on the hot loop.
const MAP = new Array<number>(256);
for (let i = 0; i < CHARS.length; i++) {
MAP[CHARS.charCodeAt(i)] = i;
}
/**
* Decode base64 into a caller-supplied buffer.
*
* Deliberately not `atob` or `Buffer.from`: the first is browser-only, the second
* node-only, and this runs in an MV3 service worker, a Worker, node tests and a
* bundled extension page. The output length is known at build time, so the
* caller provides the buffer and there is no growth or reallocation.
*
* This is a reimplementation of `@polkadot/wasm-util`'s base64Decode, which was
* the dependency it replaced. That package's index re-exports `packageDetect`,
* dragging in a `@polkadot/util` peer dependency for a side effect we do not
* want, and being a workspace package it resolved through its own repo's
* node_modules when consumed by symlink from another checkout. Fifteen lines is
* cheaper than either problem.
*/
export function base64Decode (data: string, out: Uint8Array): Uint8Array {
let byte = 0;
let bits = 0;
let pos = 0;
for (let i = 0; i < data.length && pos < out.length; i++) {
const value = MAP[data.charCodeAt(i)];
if (value === undefined) {
continue;
}
byte = (byte << 6) | value;
bits += 6;
if (bits >= 8) {
bits -= 8;
out[pos++] = (byte >>> bits) & 0xff;
}
}
return out;
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
export declare const lenIn: number;
export declare const lenOut: number;
export declare const bytes: string;
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Generated as part of the build, do not edit
export const lenIn = 0;
export const lenOut = 0;
export const bytes = '';
+210
View File
@@ -0,0 +1,210 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ext_mldsa_derive, ext_mldsa_from_seed, ext_mldsa_is_scheme, ext_mldsa_sign, ext_mldsa_sizes, ext_mldsa_verify, ext_poseidon_hash, ext_wormhole_addresses, ext_wormhole_nullifiers } from './generated/quantus_crypto.js';
import { initWasm } from './init.js';
import { Scheme } from './scheme.js';
export interface Keypair {
publicKey: Uint8Array;
secretKey: Uint8Array;
}
export interface Sizes {
/** Public key length: 1952 for ML-DSA-65, 2592 for ML-DSA-87. */
publicKey: number;
/** Secret key length: 4032 / 4896. */
secretKey: number;
/** Signature length: 3309 / 4627. */
signature: number;
/** `signature ‖ publicKey`, the runtime's wire form: 5261 / 7219. */
signatureWithPublicKey: number;
}
function ready (): void {
const error = initWasm();
if (error) {
throw new Error(`@quantus/crypto: WASM unavailable: ${error}`);
}
}
/**
* Key and signature sizes for a scheme, read from the crate rather than
* hardcoded here.
*
* These are consensus-critical — the runtime decodes a fixed-size array off the
* wire — so a constant that drifted from the crate would re-frame every byte
* after the signature while looking entirely healthy. Ask, don't assume.
*/
export function sizes (scheme: Scheme): Sizes {
ready();
const raw = new DataView(ext_mldsa_sizes(scheme).buffer);
return {
publicKey: raw.getUint32(0, true),
secretKey: raw.getUint32(4, true),
signature: raw.getUint32(8, true),
signatureWithPublicKey: raw.getUint32(12, true)
};
}
/** Whether this build supports `scheme`. */
export function isScheme (scheme: number): scheme is Scheme {
ready();
return ext_mldsa_is_scheme(scheme);
}
/**
* The account id for a public key — Poseidon2 over Goldilocks, 32 bytes out.
*
* This is the step that has no Substrate equivalent. There, an `AccountId32`
* *is* the public key; here it is a one-way hash of it, which is why a Quantus
* signature has to carry its public key inside itself and why nothing can
* recover a key from an address.
*/
export function accountFromPublicKey (publicKey: Uint8Array): Uint8Array {
ready();
return ext_poseidon_hash(publicKey);
}
/** A keypair from 32 bytes of entropy — FIPS 204 `ML-DSA.KeyGen_internal`. */
export function keypairFromSeed (seed: Uint8Array, scheme: Scheme): Keypair {
ready();
return split(ext_mldsa_from_seed(seed, scheme), scheme);
}
/**
* A keypair from a BIP39 mnemonic at a hardened Quantus derivation path.
*
* `path` must be hardened at every level — lattice keys have no public
* derivability, so there is no soft-junction equivalent and one is rejected
* rather than reinterpreted.
*/
export function keypairFromMnemonic (mnemonic: string, password: string, path: string, scheme: Scheme): Keypair {
ready();
return split(ext_mldsa_derive(mnemonic, password, path, scheme), scheme);
}
/** Which wormhole branch: where deposits arrive, or where a send returns its change. */
export enum WormholeBranch {
Receive = 0,
Change = 1
}
/**
* Consecutive wormhole addresses for one account and branch, as 32-byte account
* ids.
*
* Paths are `m/44'/189189189'/<account>'/<branch>'/<index>'`, the mobile
* wallet's. A wormhole address has no key: it is a double Poseidon hash of a
* secret the path yields, and funds leave it only through a ZK proof of that
* secret. Only the addresses cross into JavaScript; the secrets are derived and
* wiped inside WASM.
*
* The recovery phrase is stretched once per call, so ask for a window of
* addresses at once rather than looping over single ones. At most 1000 per call.
*/
export function wormholeAddresses (mnemonic: string, password: string, account: number, branch: WormholeBranch, start: number, count: number): Uint8Array[] {
ready();
const flat = ext_wormhole_addresses(mnemonic, password, account, branch, start, count);
const out: Uint8Array[] = [];
for (let i = 0; i < count; i++) {
out.push(flat.slice(i * 32, (i + 1) * 32));
}
return out;
}
/**
* Nullifiers for a run of wormhole addresses, one per deposit transfer count.
*
* A deposit to a wormhole address is spent when its nullifier is in
* `Wormhole::UsedNullifiers`. For each address `start..start + addresses` on
* `branch` of `account`, this returns the nullifiers for transfer counts
* `first..first + count`: `result[a][c]` belongs to address `start + a` and
* transfer count `first + c`.
*
* Check them locally, against a copy of the whole spent set. Never look one up
* by key or send it to a service: exits publish their nullifiers, so whoever
* sees yours can name your exits. At most 100,000 per call; the recovery phrase
* is stretched once per call.
*/
export function wormholeNullifiers (mnemonic: string, password: string, account: number, branch: WormholeBranch, start: number, addresses: number, first: number, count: number): Uint8Array[][] {
ready();
const flat = ext_wormhole_nullifiers(mnemonic, password, account, branch, start, addresses, BigInt(first), count);
const out: Uint8Array[][] = [];
for (let a = 0; a < addresses; a++) {
const row: Uint8Array[] = [];
for (let c = 0; c < count; c++) {
const at = (a * count + c) * 32;
row.push(flat.slice(at, at + 32));
}
out.push(row);
}
return out;
}
/**
* Sign under a FIPS 204 context.
*
* `context` is not optional in spirit: extrinsics on spec >= 148 verify under
* `QUANTUS_EXTRINSIC` and earlier ones under the empty context, and the wrong
* choice yields a valid signature that the chain rejects with nothing locally
* able to tell. Use `contextForSpec` rather than picking one by hand.
*
* Returns the bare signature. The runtime's wire form is `signature ‖ publicKey`
* — see {@link signatureWithPublicKey} — but only the caller knows which it
* wants.
*/
export function sign (message: Uint8Array, { publicKey, secretKey }: Keypair, context: Uint8Array, scheme: Scheme): Uint8Array {
ready();
return ext_mldsa_sign(secretKey, publicKey, message, context, scheme);
}
/** Verify a bare signature under a context. */
export function verify (message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array, context: Uint8Array, scheme: Scheme): boolean {
ready();
return ext_mldsa_verify(publicKey, message, signature, context, scheme);
}
/**
* `signature ‖ publicKey` — what a signed extrinsic actually carries.
*
* The runtime encodes this as a fixed-size array with **no compact length
* prefix**, preceded by the scheme's enum variant byte. Getting that framing
* wrong re-frames every byte after it into something that still decodes.
*/
export function signatureWithPublicKey (signature: Uint8Array, publicKey: Uint8Array): Uint8Array {
const out = new Uint8Array(signature.length + publicKey.length);
out.set(signature);
out.set(publicKey, signature.length);
return out;
}
/** The crate returns `secretKey ‖ publicKey`, matching `ext_ed_from_seed`. */
function split (pair: Uint8Array, scheme: Scheme): Keypair {
const { secretKey } = sizes(scheme);
return {
publicKey: pair.subarray(secretKey),
secretKey: pair.subarray(0, secretKey)
};
}
@@ -0,0 +1,226 @@
/* tslint:disable */
/* eslint-disable */
/**
* Derive a keypair from a BIP39 mnemonic at a hardened derivation path.
*
* Lattice keys have no public derivability, so there is no soft-junction
* equivalent and the crate rejects any unhardened path outright. The Quantus
* convention is:
*
* ```text
* m/44'/189189'/<account>'/0'/<0 for ML-DSA-87 | 1 for ML-DSA-65>'
* ```
*
* with the account index at the third level and the *scheme* carried in the
* trailing index. That is unusual, and it is what `quantus-cli` and the mobile
* wallet already use — deriving anything else produces addresses no other
* Quantus tool can find.
*
* The seeding matters as much as the path. This goes mnemonic → 64-byte BIP39
* seed → HMAC-SHA512 chain keyed with the literal string `"Dilithium seed"`.
* Substrate's own `mnemonicToMiniSecret` is a *different* derivation and is the
* default reach in the polkadot-js codebase; using it here would yield a
* well-formed key for an account nobody owns.
*
* * mnemonic: BIP39 phrase, 12/15/18/21/24 words
* * password: BIP39 passphrase; empty string for none
* * path: hardened derivation path, e.g. `m/44'/189189'/0'/0'/1'`
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the secret key followed by the public key, as
* `ext_mldsa_from_seed` returns.
*/
export function ext_mldsa_derive(mnemonic: string, password: string, path: string, scheme: number): Uint8Array;
/**
* Generate a keypair from 32 bytes of entropy.
*
* This is FIPS 204 `ML-DSA.KeyGen_internal` with no Quantus-specific step: the
* crate expands the seed as `SHAKE256(seed ‖ k ‖ )`, so the parameter set is
* absorbed into the expansion and the same 32 bytes yield independent keys per
* scheme. That is why the dev accounts (`[0u8; 32]`, `[1u8; 32]`, `[2u8; 32]`)
* and HD-derived accounts can share this one entry point.
*
* * seed: UIntArray with 32 elements
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the secret key followed by the public key, matching the
* ordering `ext_ed_from_seed` uses. Split it at the secret length from
* `ext_mldsa_sizes`.
*/
export function ext_mldsa_from_seed(seed: Uint8Array, scheme: number): Uint8Array;
/**
* Whether `scheme` names a parameter set this build supports.
*
* `dispatch!` falls back to ML-DSA-87 for anything unrecognised, which is the
* right default but a poor way to discover a typo. Callers that accept a scheme
* from storage or from a user should check here first.
*/
export function ext_mldsa_is_scheme(scheme: number): boolean;
/**
* Sign a message under a FIPS 204 context.
*
* Signing is deterministic — no hedging randomness — because that is what the
* runtime does (`hedge: None`), and a wallet that hedged would produce a
* different signature each time for the same input, which makes the
* byte-for-byte agreement tests in quantus/wasm#2 impossible to write.
*
* `ctx` is domain separation and it is **not** optional in practice: extrinsics
* on spec >= 148 are verified under `QUANTUS_EXTRINSIC`, earlier specs under the
* empty context, and a signature made under the wrong one is valid, rejected by
* the chain, and indistinguishable locally. The caller chooses; this function
* does not guess.
*
* * secret: UIntArray, secret-key length for the scheme
* * public: UIntArray, public-key length for the scheme
* * message: arbitrary length UIntArray
* * ctx: UIntArray, at most 255 elements; empty for no context
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the signature alone. The runtime's wire format is
* `signature ‖ public`; concatenating is the caller's job because only the
* caller knows whether it wants the wire form or the bare signature.
*/
export function ext_mldsa_sign(secret: Uint8Array, _public: Uint8Array, message: Uint8Array, ctx: Uint8Array, scheme: number): Uint8Array;
/**
* Key and signature sizes for a parameter set, as
* `[public, secret, signature, signature_with_public]`.
*
* Exported so that nothing on the JS side has to hardcode 1952/4032/3309/5261 or
* 2592/4896/4627/7219. Those numbers are consensus-critical — the runtime reads a
* fixed-size array off the wire — and a JS constant that drifted from the crate
* would mis-frame every byte after the signature while looking entirely healthy.
* Ask the crate instead.
*
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is four u32 lengths, little-endian, 16 bytes total.
*/
export function ext_mldsa_sizes(scheme: number): Uint8Array;
/**
* Verify a signature against a message and public key under a context.
*
* * public: UIntArray, public-key length for the scheme
* * message: arbitrary length UIntArray
* * signature: UIntArray, signature length for the scheme
* * ctx: UIntArray, at most 255 elements; empty for no context
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*/
export function ext_mldsa_verify(_public: Uint8Array, message: Uint8Array, signature: Uint8Array, ctx: Uint8Array, scheme: number): boolean;
/**
* Poseidon2-over-Goldilocks hash of arbitrary bytes.
*
* This is the account-id derivation. On Substrate an `AccountId32` *is* the
* public key; on Quantus it is `hash_bytes(public_key)`, which is why a Quantus
* signature has to carry its public key along — the address cannot give it back.
*
* `qp_poseidon_core::hash_bytes` is `IdentifyAccount for DilithiumSigner` in the
* runtime, so this is the same function the chain uses to decide who signed
* something, reached through the same crate rather than a port of it.
*
* * data: arbitrary length UIntArray
*
* * returned vector is 32 bytes.
*/
export function ext_poseidon_hash(data: Uint8Array): Uint8Array;
/**
* Derive consecutive wormhole addresses for one account and branch.
*
* A wormhole address is not a key. The path yields a 32-byte **secret**, and
* the address is `poseidon(poseidon(salt ‖ secret))`; funds leave it only
* through a ZK proof of knowing that secret. So this returns the addresses and
* nothing else. The secrets and the intermediate `first_hash` stay inside this
* call and are wiped on drop by the crate's sensitive types.
*
* Paths are `m/44'/189189189'/<account>'/<change>'/<index>'`, as the mobile
* wallet derives them: change `0` is the receive branch, `1` the change branch.
*
* The BIP39 seed is stretched once for the whole batch. Stretching per address
* is PBKDF2 with 2048 rounds each time, and a gap-limit window is dozens of
* addresses.
*
* * mnemonic: BIP39 phrase
* * password: BIP39 passphrase; empty string for none
* * account, change, start, count: which addresses; count <= WORMHOLE_MAX_BATCH
*
* * returned vector is `count` 32-byte account ids, concatenated
*/
export function ext_wormhole_addresses(mnemonic: string, password: string, account: number, change: number, start: number, count: number): Uint8Array;
/**
* Nullifiers for a run of wormhole addresses' deposits, by transfer count.
*
* A deposit to a wormhole address is spent when its nullifier is in
* `Wormhole::UsedNullifiers`. The nullifier is
*
* ```text
* poseidon2(poseidon2(salt("~nullif~") ‖ secret ‖ transfer_count))
* ```
*
* where `transfer_count` is the address's counter when the deposit landed. It
* needs the address's secret, which is why this takes the recovery phrase and
* why a nullifier should never be sent anywhere to be checked: exits publish
* nullifiers, so whoever sees yours can name your exits.
*
* For addresses `m/44'/189189189'/<account>'/<change>'/<index>'` with index in
* `start..start + addresses`, and transfer counts `first..first + count` for
* each. The BIP39 seed is stretched once for the whole run.
*
* Ported onto `qp-poseidon-core` rather than calling `qp-wormhole-circuit`,
* which would bring plonky2 into the WASM. The port is pinned to the circuit
* crate's own `Nullifier::from_preimage` by the tests.
*
* * returned vector is `addresses * count` 32-byte nullifiers: address by
* address, and by transfer count within each
*/
export function ext_wormhole_nullifiers(mnemonic: string, password: string, account: number, change: number, start: number, addresses: number, first: bigint, count: number): Uint8Array;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly ext_mldsa_derive: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
readonly ext_mldsa_from_seed: (a: number, b: number, c: number) => [number, number, number, number];
readonly ext_mldsa_is_scheme: (a: number) => number;
readonly ext_mldsa_sign: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number, number];
readonly ext_mldsa_sizes: (a: number) => [number, number];
readonly ext_mldsa_verify: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => number;
readonly ext_poseidon_hash: (a: number, b: number) => [number, number];
readonly ext_wormhole_addresses: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number, number, number];
readonly ext_wormhole_nullifiers: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: bigint, j: number) => [number, number, number, number];
readonly __wbindgen_externrefs: WebAssembly.Table;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __externref_table_dealloc: (a: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_start: () => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;
/**
* Instantiates the given `module`, which can either be bytes or
* a precompiled `WebAssembly.Module`.
*
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
*
* @returns {InitOutput}
*/
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
/**
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
* for everything else, calls `WebAssembly.instantiate` directly.
*
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
*
* @returns {Promise<InitOutput>}
*/
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,503 @@
/* @ts-self-types="./quantus_crypto.d.ts" */
/**
* Derive a keypair from a BIP39 mnemonic at a hardened derivation path.
*
* Lattice keys have no public derivability, so there is no soft-junction
* equivalent and the crate rejects any unhardened path outright. The Quantus
* convention is:
*
* ```text
* m/44'/189189'/<account>'/0'/<0 for ML-DSA-87 | 1 for ML-DSA-65>'
* ```
*
* with the account index at the third level and the *scheme* carried in the
* trailing index. That is unusual, and it is what `quantus-cli` and the mobile
* wallet already use — deriving anything else produces addresses no other
* Quantus tool can find.
*
* The seeding matters as much as the path. This goes mnemonic → 64-byte BIP39
* seed → HMAC-SHA512 chain keyed with the literal string `"Dilithium seed"`.
* Substrate's own `mnemonicToMiniSecret` is a *different* derivation and is the
* default reach in the polkadot-js codebase; using it here would yield a
* well-formed key for an account nobody owns.
*
* * mnemonic: BIP39 phrase, 12/15/18/21/24 words
* * password: BIP39 passphrase; empty string for none
* * path: hardened derivation path, e.g. `m/44'/189189'/0'/0'/1'`
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the secret key followed by the public key, as
* `ext_mldsa_from_seed` returns.
* @param {string} mnemonic
* @param {string} password
* @param {string} path
* @param {number} scheme
* @returns {Uint8Array}
*/
export function ext_mldsa_derive(mnemonic, password, path, scheme) {
const ptr0 = passStringToWasm0(mnemonic, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len2 = WASM_VECTOR_LEN;
const ret = wasm.ext_mldsa_derive(ptr0, len0, ptr1, len1, ptr2, len2, scheme);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v4 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v4;
}
/**
* Generate a keypair from 32 bytes of entropy.
*
* This is FIPS 204 `ML-DSA.KeyGen_internal` with no Quantus-specific step: the
* crate expands the seed as `SHAKE256(seed ‖ k ‖ )`, so the parameter set is
* absorbed into the expansion and the same 32 bytes yield independent keys per
* scheme. That is why the dev accounts (`[0u8; 32]`, `[1u8; 32]`, `[2u8; 32]`)
* and HD-derived accounts can share this one entry point.
*
* * seed: UIntArray with 32 elements
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the secret key followed by the public key, matching the
* ordering `ext_ed_from_seed` uses. Split it at the secret length from
* `ext_mldsa_sizes`.
* @param {Uint8Array} seed
* @param {number} scheme
* @returns {Uint8Array}
*/
export function ext_mldsa_from_seed(seed, scheme) {
const ptr0 = passArray8ToWasm0(seed, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.ext_mldsa_from_seed(ptr0, len0, scheme);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v2;
}
/**
* Whether `scheme` names a parameter set this build supports.
*
* `dispatch!` falls back to ML-DSA-87 for anything unrecognised, which is the
* right default but a poor way to discover a typo. Callers that accept a scheme
* from storage or from a user should check here first.
* @param {number} scheme
* @returns {boolean}
*/
export function ext_mldsa_is_scheme(scheme) {
const ret = wasm.ext_mldsa_is_scheme(scheme);
return ret !== 0;
}
/**
* Sign a message under a FIPS 204 context.
*
* Signing is deterministic — no hedging randomness — because that is what the
* runtime does (`hedge: None`), and a wallet that hedged would produce a
* different signature each time for the same input, which makes the
* byte-for-byte agreement tests in quantus/wasm#2 impossible to write.
*
* `ctx` is domain separation and it is **not** optional in practice: extrinsics
* on spec >= 148 are verified under `QUANTUS_EXTRINSIC`, earlier specs under the
* empty context, and a signature made under the wrong one is valid, rejected by
* the chain, and indistinguishable locally. The caller chooses; this function
* does not guess.
*
* * secret: UIntArray, secret-key length for the scheme
* * public: UIntArray, public-key length for the scheme
* * message: arbitrary length UIntArray
* * ctx: UIntArray, at most 255 elements; empty for no context
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is the signature alone. The runtime's wire format is
* `signature ‖ public`; concatenating is the caller's job because only the
* caller knows whether it wants the wire form or the bare signature.
* @param {Uint8Array} secret
* @param {Uint8Array} _public
* @param {Uint8Array} message
* @param {Uint8Array} ctx
* @param {number} scheme
* @returns {Uint8Array}
*/
export function ext_mldsa_sign(secret, _public, message, ctx, scheme) {
const ptr0 = passArray8ToWasm0(secret, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray8ToWasm0(_public, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passArray8ToWasm0(message, wasm.__wbindgen_malloc);
const len2 = WASM_VECTOR_LEN;
const ptr3 = passArray8ToWasm0(ctx, wasm.__wbindgen_malloc);
const len3 = WASM_VECTOR_LEN;
const ret = wasm.ext_mldsa_sign(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, scheme);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v5 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v5;
}
/**
* Key and signature sizes for a parameter set, as
* `[public, secret, signature, signature_with_public]`.
*
* Exported so that nothing on the JS side has to hardcode 1952/4032/3309/5261 or
* 2592/4896/4627/7219. Those numbers are consensus-critical — the runtime reads a
* fixed-size array off the wire — and a JS constant that drifted from the crate
* would mis-frame every byte after the signature while looking entirely healthy.
* Ask the crate instead.
*
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
*
* * returned vector is four u32 lengths, little-endian, 16 bytes total.
* @param {number} scheme
* @returns {Uint8Array}
*/
export function ext_mldsa_sizes(scheme) {
const ret = wasm.ext_mldsa_sizes(scheme);
var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v1;
}
/**
* Verify a signature against a message and public key under a context.
*
* * public: UIntArray, public-key length for the scheme
* * message: arbitrary length UIntArray
* * signature: UIntArray, signature length for the scheme
* * ctx: UIntArray, at most 255 elements; empty for no context
* * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
* @param {Uint8Array} _public
* @param {Uint8Array} message
* @param {Uint8Array} signature
* @param {Uint8Array} ctx
* @param {number} scheme
* @returns {boolean}
*/
export function ext_mldsa_verify(_public, message, signature, ctx, scheme) {
const ptr0 = passArray8ToWasm0(_public, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passArray8ToWasm0(message, wasm.__wbindgen_malloc);
const len1 = WASM_VECTOR_LEN;
const ptr2 = passArray8ToWasm0(signature, wasm.__wbindgen_malloc);
const len2 = WASM_VECTOR_LEN;
const ptr3 = passArray8ToWasm0(ctx, wasm.__wbindgen_malloc);
const len3 = WASM_VECTOR_LEN;
const ret = wasm.ext_mldsa_verify(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, scheme);
return ret !== 0;
}
/**
* Poseidon2-over-Goldilocks hash of arbitrary bytes.
*
* This is the account-id derivation. On Substrate an `AccountId32` *is* the
* public key; on Quantus it is `hash_bytes(public_key)`, which is why a Quantus
* signature has to carry its public key along — the address cannot give it back.
*
* `qp_poseidon_core::hash_bytes` is `IdentifyAccount for DilithiumSigner` in the
* runtime, so this is the same function the chain uses to decide who signed
* something, reached through the same crate rather than a port of it.
*
* * data: arbitrary length UIntArray
*
* * returned vector is 32 bytes.
* @param {Uint8Array} data
* @returns {Uint8Array}
*/
export function ext_poseidon_hash(data) {
const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.ext_poseidon_hash(ptr0, len0);
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v2;
}
/**
* Derive consecutive wormhole addresses for one account and branch.
*
* A wormhole address is not a key. The path yields a 32-byte **secret**, and
* the address is `poseidon(poseidon(salt ‖ secret))`; funds leave it only
* through a ZK proof of knowing that secret. So this returns the addresses and
* nothing else. The secrets and the intermediate `first_hash` stay inside this
* call and are wiped on drop by the crate's sensitive types.
*
* Paths are `m/44'/189189189'/<account>'/<change>'/<index>'`, as the mobile
* wallet derives them: change `0` is the receive branch, `1` the change branch.
*
* The BIP39 seed is stretched once for the whole batch. Stretching per address
* is PBKDF2 with 2048 rounds each time, and a gap-limit window is dozens of
* addresses.
*
* * mnemonic: BIP39 phrase
* * password: BIP39 passphrase; empty string for none
* * account, change, start, count: which addresses; count <= WORMHOLE_MAX_BATCH
*
* * returned vector is `count` 32-byte account ids, concatenated
* @param {string} mnemonic
* @param {string} password
* @param {number} account
* @param {number} change
* @param {number} start
* @param {number} count
* @returns {Uint8Array}
*/
export function ext_wormhole_addresses(mnemonic, password, account, change, start, count) {
const ptr0 = passStringToWasm0(mnemonic, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.ext_wormhole_addresses(ptr0, len0, ptr1, len1, account, change, start, count);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v3;
}
/**
* Nullifiers for a run of wormhole addresses' deposits, by transfer count.
*
* A deposit to a wormhole address is spent when its nullifier is in
* `Wormhole::UsedNullifiers`. The nullifier is
*
* ```text
* poseidon2(poseidon2(salt("~nullif~") ‖ secret ‖ transfer_count))
* ```
*
* where `transfer_count` is the address's counter when the deposit landed. It
* needs the address's secret, which is why this takes the recovery phrase and
* why a nullifier should never be sent anywhere to be checked: exits publish
* nullifiers, so whoever sees yours can name your exits.
*
* For addresses `m/44'/189189189'/<account>'/<change>'/<index>'` with index in
* `start..start + addresses`, and transfer counts `first..first + count` for
* each. The BIP39 seed is stretched once for the whole run.
*
* Ported onto `qp-poseidon-core` rather than calling `qp-wormhole-circuit`,
* which would bring plonky2 into the WASM. The port is pinned to the circuit
* crate's own `Nullifier::from_preimage` by the tests.
*
* * returned vector is `addresses * count` 32-byte nullifiers: address by
* address, and by transfer count within each
* @param {string} mnemonic
* @param {string} password
* @param {number} account
* @param {number} change
* @param {number} start
* @param {number} addresses
* @param {bigint} first
* @param {number} count
* @returns {Uint8Array}
*/
export function ext_wormhole_nullifiers(mnemonic, password, account, change, start, addresses, first, count) {
const ptr0 = passStringToWasm0(mnemonic, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.ext_wormhole_nullifiers(ptr0, len0, ptr1, len1, account, change, start, addresses, first, count);
if (ret[3]) {
throw takeFromExternrefTable0(ret[2]);
}
var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
return v3;
}
function __wbg_get_imports() {
const import0 = {
__proto__: null,
__wbg_Error_67e7344beaa85059: function(arg0, arg1) {
const ret = Error(getStringFromWasm0(arg0, arg1));
return ret;
},
__wbindgen_init_externref_table: function() {
const table = wasm.__wbindgen_externrefs;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
},
};
return {
__proto__: null,
"./quantus_crypto_bg.js": import0,
};
}
function getArrayU8FromWasm0(ptr, len) {
ptr = ptr >>> 0;
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
}
function getStringFromWasm0(ptr, len) {
return decodeText(ptr >>> 0, len);
}
let cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1, 1) >>> 0;
getUint8ArrayMemory0().set(arg, ptr / 1);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8ArrayMemory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
const ret = cachedTextEncoder.encodeInto(arg, view);
offset += ret.written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function takeFromExternrefTable0(idx) {
const value = wasm.__wbindgen_externrefs.get(idx);
wasm.__externref_table_dealloc(idx);
return value;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
const MAX_SAFARI_DECODE_BYTES = 2146435072;
let numBytesDecoded = 0;
function decodeText(ptr, len) {
numBytesDecoded += len;
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
numBytesDecoded = len;
}
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
const cachedTextEncoder = new TextEncoder();
if (!('encodeInto' in cachedTextEncoder)) {
cachedTextEncoder.encodeInto = function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
};
}
let WASM_VECTOR_LEN = 0;
let wasmModule, wasmInstance, wasm;
function __wbg_finalize_init(instance, module) {
wasmInstance = instance;
wasm = instance.exports;
wasmModule = module;
cachedUint8ArrayMemory0 = null;
wasm.__wbindgen_start();
return wasm;
}
async function __wbg_load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (!module.ok) {
throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
}
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
const validResponse = expectedResponseType(module.type);
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else { throw e; }
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
function expectedResponseType(type) {
switch (type) {
case 'basic': case 'cors': case 'default': return true;
}
return false;
}
}
function initSync(module) {
if (wasm !== undefined) return wasm;
if (module !== undefined) {
if (Object.getPrototypeOf(module) === Object.prototype) {
({module} = module)
} else {
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
}
}
const imports = __wbg_get_imports();
if (!(module instanceof WebAssembly.Module)) {
module = new WebAssembly.Module(module);
}
const instance = new WebAssembly.Instance(module, imports);
return __wbg_finalize_init(instance, module);
}
export { initSync };
+7
View File
@@ -0,0 +1,7 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { accountFromPublicKey, isScheme, keypairFromMnemonic, keypairFromSeed, sign, signatureWithPublicKey, sizes, verify, WormholeBranch, wormholeAddresses, wormholeNullifiers } from './crypto.js';
export type { Keypair, Sizes } from './crypto.js';
export { initWasm, isReady } from './init.js';
export { contextForSpec, EXTRINSIC_CONTEXT, EXTRINSIC_MIN_SPEC, Scheme, SCHEME_NAME } from './scheme.js';
+61
View File
@@ -0,0 +1,61 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { unzlibSync } from 'fflate';
import { base64Decode } from './base64.js';
import { bytes, lenOut } from './bytes.js';
import { initSync } from './generated/quantus_crypto.js';
/**
* Instantiate the WASM, synchronously, from bytes compiled into this file.
*
* Three constraints shape this, and all three rule out the obvious approach:
*
* - the background context is an **MV3 service worker**, so there is no DOM, no
* reliable `fetch` of extension-relative URLs at arbitrary times, and the
* worker can be killed and cold-started between any two messages
* - the extension CSP is `script-src 'self' 'wasm-unsafe-eval'`, which permits
* compiling WASM but not fetching it from anywhere interesting
* - callers are synchronous — `pair.sign()` in the keyring has no `await` to give
*
* So the WASM is zlib-compressed, base64'd into `bytes.js` at build time, and
* instantiated here with wasm-bindgen's `initSync`. Nothing is fetched, and the
* whole module is ready before the first call returns.
*
* Deliberately *not* using `@polkadot/wasm-bridge`: its `Bridge` implements
* wasm-bindgen 0.2.79's JS-heap ABI, and this crate is built with 0.2.128, which
* uses externref tables. See quantus/wasm#1.
*/
let initialised = false;
let initError: string | null = null;
/**
* Ensure the WASM is instantiated. Idempotent and cheap after the first call.
*
* Returns `null` on success, or the failure reason. It does not throw: a caller
* deciding whether to offer a Quantus account at all wants to ask, and an
* exception thrown from module scope in a service worker is hard to attribute.
*/
export function initWasm (): string | null {
if (initialised) {
return initError;
}
initialised = true;
try {
initSync({ module: unzlibSync(base64Decode(bytes, new Uint8Array(lenOut))) });
} catch (error) {
initError = (error as Error).message;
}
return initError;
}
/** Whether the WASM is available. Callers that can fall back should ask first. */
export function isReady (): boolean {
return initWasm() === null;
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Quantus post-quantum crypto for the browser.
//!
//! Every function here delegates to the crates the Quantus runtime itself uses
//! (`qp-rusty-crystals-dilithium`, `qp-poseidon-core`, `qp-rusty-crystals-hdwallet`)
//! rather than reimplementing anything. That is the whole point: a browser wallet
//! that disagreed with the chain about a key or a signature would produce
//! perfectly well-formed output that the chain rejects, and nothing on this side
//! could tell.
#[path = "rs/hdwallet.rs"]
pub mod hdwallet;
#[path = "rs/mldsa.rs"]
pub mod mldsa;
#[path = "rs/poseidon.rs"]
pub mod poseidon;
#[path = "rs/scheme.rs"]
pub mod scheme;
#[cfg(test)]
#[path = "rs/tests.rs"]
mod tests;
+231
View File
@@ -0,0 +1,231 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
use wasm_bindgen::prelude::*;
use crate::scheme::dispatch;
/// Derive a keypair from a BIP39 mnemonic at a hardened derivation path.
///
/// Lattice keys have no public derivability, so there is no soft-junction
/// equivalent and the crate rejects any unhardened path outright. The Quantus
/// convention is:
///
/// ```text
/// m/44'/189189'/<account>'/0'/<0 for ML-DSA-87 | 1 for ML-DSA-65>'
/// ```
///
/// with the account index at the third level and the *scheme* carried in the
/// trailing index. That is unusual, and it is what `quantus-cli` and the mobile
/// wallet already use — deriving anything else produces addresses no other
/// Quantus tool can find.
///
/// The seeding matters as much as the path. This goes mnemonic → 64-byte BIP39
/// seed → HMAC-SHA512 chain keyed with the literal string `"Dilithium seed"`.
/// Substrate's own `mnemonicToMiniSecret` is a *different* derivation and is the
/// default reach in the polkadot-js codebase; using it here would yield a
/// well-formed key for an account nobody owns.
///
/// * mnemonic: BIP39 phrase, 12/15/18/21/24 words
/// * password: BIP39 passphrase; empty string for none
/// * path: hardened derivation path, e.g. `m/44'/189189'/0'/0'/1'`
/// * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
///
/// * returned vector is the secret key followed by the public key, as
/// `ext_mldsa_from_seed` returns.
#[wasm_bindgen]
pub fn ext_mldsa_derive(mnemonic: &str, password: &str, path: &str, scheme: u32) -> Result<Vec<u8>, JsError> {
mldsa_derive(mnemonic, password, path, scheme).map_err(|e| JsError::new(&e))
}
/// The body of [`ext_mldsa_derive`]. See [`crate::mldsa::mldsa_from_seed`] for why
/// this is split from its binding.
pub fn mldsa_derive(mnemonic: &str, password: &str, path: &str, scheme: u32) -> Result<Vec<u8>, String> {
// An empty passphrase and no passphrase are the same thing in BIP39, but the
// crate distinguishes `None` from `Some("")` in its signature, so normalise
// here rather than leaving each caller to pick one.
let password = if password.is_empty() {
None
} else {
Some(password)
};
dispatch!(scheme, _dsa, hd, {
let pair = hd::derive_key_from_mnemonic(mnemonic, password, path)
.map_err(alloc_error)?;
let mut out = pair.secret().to_bytes().to_vec();
out.extend_from_slice(&pair.public().to_bytes());
Ok(out)
})
}
/// Render a derivation failure as a string.
///
/// Kept separate so the error text stays whatever the crate said — a bad
/// mnemonic, an unhardened path and a path that is too deep are different
/// mistakes and a user can only fix the one they made.
fn alloc_error(e: qp_rusty_crystals_hdwallet::HDLatticeError) -> String {
format!("{e}")
}
/// The largest number of wormhole addresses one call derives. Each is a Poseidon
/// hash over an HMAC-SHA512 chain; the bound keeps a caller from asking for a
/// million of them and locking the page.
pub const WORMHOLE_MAX_BATCH: u32 = 1000;
/// Derive consecutive wormhole addresses for one account and branch.
///
/// A wormhole address is not a key. The path yields a 32-byte **secret**, and
/// the address is `poseidon(poseidon(salt ‖ secret))`; funds leave it only
/// through a ZK proof of knowing that secret. So this returns the addresses and
/// nothing else. The secrets and the intermediate `first_hash` stay inside this
/// call and are wiped on drop by the crate's sensitive types.
///
/// Paths are `m/44'/189189189'/<account>'/<change>'/<index>'`, as the mobile
/// wallet derives them: change `0` is the receive branch, `1` the change branch.
///
/// The BIP39 seed is stretched once for the whole batch. Stretching per address
/// is PBKDF2 with 2048 rounds each time, and a gap-limit window is dozens of
/// addresses.
///
/// * mnemonic: BIP39 phrase
/// * password: BIP39 passphrase; empty string for none
/// * account, change, start, count: which addresses; count <= WORMHOLE_MAX_BATCH
///
/// * returned vector is `count` 32-byte account ids, concatenated
#[wasm_bindgen]
pub fn ext_wormhole_addresses(mnemonic: &str, password: &str, account: u32, change: u32, start: u32, count: u32) -> Result<Vec<u8>, JsError> {
wormhole_addresses(mnemonic, password, account, change, start, count).map_err(|e| JsError::new(&e))
}
/// The body of [`ext_wormhole_addresses`], split from its binding for the same
/// reason as [`mldsa_derive`].
pub fn wormhole_addresses(mnemonic: &str, password: &str, account: u32, change: u32, start: u32, count: u32) -> Result<Vec<u8>, String> {
use qp_rusty_crystals_hdwallet::{generate_wormhole_from_seed, mnemonic_to_seed, SensitiveBytes64};
if count > WORMHOLE_MAX_BATCH {
return Err(format!("At most {WORMHOLE_MAX_BATCH} wormhole addresses per call, asked for {count}"));
}
if start.checked_add(count).is_none_or(|end| end > 0x8000_0000) {
return Err(format!("Wormhole address indices must stay below 2^31, asked for {start} + {count}"));
}
let password = if password.is_empty() {
None
} else {
Some(password)
};
let mut seed = SensitiveBytes64::zeroed();
mnemonic_to_seed(mnemonic.to_string(), password, &mut seed).map_err(alloc_error)?;
let mut out = Vec::with_capacity(count as usize * 32);
for index in start..start + count {
let path = format!("m/44'/189189189'/{account}'/{change}'/{index}'");
let pair = generate_wormhole_from_seed(&seed, &path).map_err(alloc_error)?;
out.extend_from_slice(pair.address());
}
Ok(out)
}
/// Salt the chain's nullifier derivation starts from: `NULLIFIER_SALT` in
/// `qp-wormhole-circuit`.
const NULLIFIER_SALT: &str = "~nullif~";
/// The largest number of nullifiers one call computes.
pub const NULLIFIER_MAX_BATCH: u32 = 100_000;
/// Nullifiers for a run of wormhole addresses' deposits, by transfer count.
///
/// A deposit to a wormhole address is spent when its nullifier is in
/// `Wormhole::UsedNullifiers`. The nullifier is
///
/// ```text
/// poseidon2(poseidon2(salt("~nullif~") ‖ secret ‖ transfer_count))
/// ```
///
/// where `transfer_count` is the address's counter when the deposit landed. It
/// needs the address's secret, which is why this takes the recovery phrase and
/// why a nullifier should never be sent anywhere to be checked: exits publish
/// nullifiers, so whoever sees yours can name your exits.
///
/// For addresses `m/44'/189189189'/<account>'/<change>'/<index>'` with index in
/// `start..start + addresses`, and transfer counts `first..first + count` for
/// each. The BIP39 seed is stretched once for the whole run.
///
/// Ported onto `qp-poseidon-core` rather than calling `qp-wormhole-circuit`,
/// which would bring plonky2 into the WASM. The port is pinned to the circuit
/// crate's own `Nullifier::from_preimage` by the tests.
///
/// * returned vector is `addresses * count` 32-byte nullifiers: address by
/// address, and by transfer count within each
#[wasm_bindgen]
#[allow(clippy::too_many_arguments)]
pub fn ext_wormhole_nullifiers(mnemonic: &str, password: &str, account: u32, change: u32, start: u32, addresses: u32, first: u64, count: u32) -> Result<Vec<u8>, JsError> {
wormhole_nullifiers(mnemonic, password, account, change, start, addresses, first, count).map_err(|e| JsError::new(&e))
}
/// The body of [`ext_wormhole_nullifiers`].
#[allow(clippy::too_many_arguments)]
pub fn wormhole_nullifiers(mnemonic: &str, password: &str, account: u32, change: u32, start: u32, addresses: u32, first: u64, count: u32) -> Result<Vec<u8>, String> {
use qp_rusty_crystals_hdwallet::{generate_wormhole_from_seed, mnemonic_to_seed, SensitiveBytes64};
let total = addresses as u64 * count as u64;
if total > NULLIFIER_MAX_BATCH as u64 {
return Err(format!("At most {NULLIFIER_MAX_BATCH} nullifiers per call, asked for {total}"));
}
if start.checked_add(addresses).is_none_or(|end| end > 0x8000_0000) {
return Err(format!("Wormhole address indices must stay below 2^31, asked for {start} + {addresses}"));
}
first.checked_add(count as u64).ok_or("Transfer counts overflow")?;
let password = if password.is_empty() {
None
} else {
Some(password)
};
let mut seed = SensitiveBytes64::zeroed();
mnemonic_to_seed(mnemonic.to_string(), password, &mut seed).map_err(alloc_error)?;
let mut out = Vec::with_capacity(total as usize * 32);
for index in start..start + addresses {
let path = format!("m/44'/189189189'/{account}'/{change}'/{index}'");
let pair = generate_wormhole_from_seed(&seed, &path).map_err(alloc_error)?;
for transfer_count in first..first + count as u64 {
out.extend_from_slice(&nullifier(pair.secret().as_bytes(), transfer_count));
}
}
Ok(out)
}
/// One nullifier from a wormhole secret and a transfer count.
pub fn nullifier(secret: &[u8; 32], transfer_count: u64) -> [u8; 32] {
use qp_poseidon_core::{
hash_twice,
serialization::{bytes_to_digest_lossy, string_to_felts, u64_to_felts},
};
let salt = string_to_felts(NULLIFIER_SALT);
let secret_felts = bytes_to_digest_lossy(secret);
let count_felts = u64_to_felts(transfer_count);
let mut preimage = Vec::with_capacity(salt.len() + secret_felts.len() + count_felts.len());
preimage.extend_from_slice(&salt);
preimage.extend_from_slice(&secret_felts);
preimage.extend_from_slice(&count_felts);
hash_twice(&preimage)
}
+164
View File
@@ -0,0 +1,164 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
use wasm_bindgen::prelude::*;
use crate::scheme::dispatch;
/// Key and signature sizes for a parameter set, as
/// `[public, secret, signature, signature_with_public]`.
///
/// Exported so that nothing on the JS side has to hardcode 1952/4032/3309/5261 or
/// 2592/4896/4627/7219. Those numbers are consensus-critical — the runtime reads a
/// fixed-size array off the wire — and a JS constant that drifted from the crate
/// would mis-frame every byte after the signature while looking entirely healthy.
/// Ask the crate instead.
///
/// * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
///
/// * returned vector is four u32 lengths, little-endian, 16 bytes total.
#[wasm_bindgen]
pub fn ext_mldsa_sizes(scheme: u32) -> Vec<u8> {
dispatch!(scheme, dsa, _hd, {
let sizes: [u32; 4] = [
dsa::PUBLICKEYBYTES as u32,
dsa::SECRETKEYBYTES as u32,
dsa::SIGNBYTES as u32,
(dsa::SIGNBYTES + dsa::PUBLICKEYBYTES) as u32,
];
sizes.iter().flat_map(|n| n.to_le_bytes()).collect()
})
}
/// Whether `scheme` names a parameter set this build supports.
///
/// `dispatch!` falls back to ML-DSA-87 for anything unrecognised, which is the
/// right default but a poor way to discover a typo. Callers that accept a scheme
/// from storage or from a user should check here first.
#[wasm_bindgen]
pub fn ext_mldsa_is_scheme(scheme: u32) -> bool {
scheme == crate::scheme::ML_DSA_87 || scheme == crate::scheme::ML_DSA_65
}
/// Generate a keypair from 32 bytes of entropy.
///
/// This is FIPS 204 `ML-DSA.KeyGen_internal` with no Quantus-specific step: the
/// crate expands the seed as `SHAKE256(seed ‖ k ‖ )`, so the parameter set is
/// absorbed into the expansion and the same 32 bytes yield independent keys per
/// scheme. That is why the dev accounts (`[0u8; 32]`, `[1u8; 32]`, `[2u8; 32]`)
/// and HD-derived accounts can share this one entry point.
///
/// * seed: UIntArray with 32 elements
/// * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
///
/// * returned vector is the secret key followed by the public key, matching the
/// ordering `ext_ed_from_seed` uses. Split it at the secret length from
/// `ext_mldsa_sizes`.
#[wasm_bindgen]
pub fn ext_mldsa_from_seed(seed: &[u8], scheme: u32) -> Result<Vec<u8>, JsError> {
mldsa_from_seed(seed, scheme).map_err(|e| JsError::new(&e))
}
/// The body of [`ext_mldsa_from_seed`], without the binding layer.
///
/// Split out because `JsError` cannot be constructed on a non-wasm target — it
/// panics with "cannot call wasm-bindgen imported functions on non-wasm targets" —
/// so anything that returns one is untestable by `cargo test`. The error paths are
/// exactly what most needs testing, so the logic lives here and the exported
/// wrapper does nothing but translate.
pub fn mldsa_from_seed(seed: &[u8], scheme: u32) -> Result<Vec<u8>, String> {
if seed.len() != 32 {
return Err("expected a 32 byte seed".into());
}
// `SensitiveBytes32::from` takes the buffer mutably and the crate zeroes it
// after use, so the copy we hand it is destroyed rather than left on the
// stack. Do not replace this with a by-value clone of `seed`.
let mut entropy = [0u8; 32];
entropy.copy_from_slice(seed);
let mut entropy = qp_rusty_crystals_dilithium::SensitiveBytes32::from(&mut entropy);
dispatch!(scheme, dsa, _hd, {
let pair = dsa::Keypair::generate(&mut entropy);
let mut out = pair.secret().to_bytes().to_vec();
out.extend_from_slice(&pair.public().to_bytes());
Ok(out)
})
}
/// Sign a message under a FIPS 204 context.
///
/// Signing is deterministic — no hedging randomness — because that is what the
/// runtime does (`hedge: None`), and a wallet that hedged would produce a
/// different signature each time for the same input, which makes the
/// byte-for-byte agreement tests in quantus/wasm#2 impossible to write.
///
/// `ctx` is domain separation and it is **not** optional in practice: extrinsics
/// on spec >= 148 are verified under `QUANTUS_EXTRINSIC`, earlier specs under the
/// empty context, and a signature made under the wrong one is valid, rejected by
/// the chain, and indistinguishable locally. The caller chooses; this function
/// does not guess.
///
/// * secret: UIntArray, secret-key length for the scheme
/// * public: UIntArray, public-key length for the scheme
/// * message: arbitrary length UIntArray
/// * ctx: UIntArray, at most 255 elements; empty for no context
/// * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
///
/// * returned vector is the signature alone. The runtime's wire format is
/// `signature ‖ public`; concatenating is the caller's job because only the
/// caller knows whether it wants the wire form or the bare signature.
#[wasm_bindgen]
pub fn ext_mldsa_sign(secret: &[u8], public: &[u8], message: &[u8], ctx: &[u8], scheme: u32) -> Result<Vec<u8>, JsError> {
mldsa_sign(secret, public, message, ctx, scheme).map_err(|e| JsError::new(&e))
}
/// The body of [`ext_mldsa_sign`]. See [`mldsa_from_seed`] for why this is split.
pub fn mldsa_sign(secret: &[u8], public: &[u8], message: &[u8], ctx: &[u8], scheme: u32) -> Result<Vec<u8>, String> {
if ctx.len() > 255 {
return Err("context must be at most 255 bytes".into());
}
dispatch!(scheme, dsa, _hd, {
// `from_parts` re-derives the public key from the secret and rejects a
// mismatch, so a corrupted or mixed-up pair fails here rather than
// producing a signature that silently will not verify.
let secret = dsa::SecretKey::from_bytes(secret)
.map_err(|_| "invalid secret key".to_string())?;
let public = dsa::PublicKey::from_bytes(public)
.map_err(|_| "invalid public key".to_string())?;
let pair = dsa::Keypair::from_parts(secret, public)
.map_err(|_| "secret and public key do not correspond".to_string())?;
pair
.sign(message, Some(ctx), None)
.map(|sig| sig.to_vec())
.map_err(|_| "signing failed".to_string())
})
}
/// Verify a signature against a message and public key under a context.
///
/// * public: UIntArray, public-key length for the scheme
/// * message: arbitrary length UIntArray
/// * signature: UIntArray, signature length for the scheme
/// * ctx: UIntArray, at most 255 elements; empty for no context
/// * scheme: 0 for ML-DSA-87, 1 for ML-DSA-65
#[wasm_bindgen]
pub fn ext_mldsa_verify(public: &[u8], message: &[u8], signature: &[u8], ctx: &[u8], scheme: u32) -> bool {
if ctx.len() > 255 {
return false;
}
dispatch!(scheme, dsa, _hd, {
match dsa::PublicKey::from_bytes(public) {
Ok(public) => public.verify(message, signature, Some(ctx)),
Err(_) => false
}
})
}
@@ -0,0 +1,22 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
use wasm_bindgen::prelude::*;
/// Poseidon2-over-Goldilocks hash of arbitrary bytes.
///
/// This is the account-id derivation. On Substrate an `AccountId32` *is* the
/// public key; on Quantus it is `hash_bytes(public_key)`, which is why a Quantus
/// signature has to carry its public key along — the address cannot give it back.
///
/// `qp_poseidon_core::hash_bytes` is `IdentifyAccount for DilithiumSigner` in the
/// runtime, so this is the same function the chain uses to decide who signed
/// something, reached through the same crate rather than a port of it.
///
/// * data: arbitrary length UIntArray
///
/// * returned vector is 32 bytes.
#[wasm_bindgen]
pub fn ext_poseidon_hash(data: &[u8]) -> Vec<u8> {
qp_poseidon_core::hash_bytes(data).to_vec()
}
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Which ML-DSA parameter set a call refers to.
//!
//! The selector is the chain's own signature-enum variant index, not a private
//! numbering: `DilithiumSignatureScheme::Dilithium87` is variant 0 and
//! `Dilithium65` is variant 1, and that byte is what a signed extrinsic carries
//! on the wire. Reusing it here means the number threaded through this API is
//! the number that ends up in the extrinsic, so there is no mapping table to get
//! backwards between here and `TYPE_PREFIX` in the keyring.
/// ML-DSA-87 — the legacy scheme, used by accounts created before the scheme was
/// recorded, and by the dev-genesis accounts.
pub const ML_DSA_87: u32 = 0;
/// ML-DSA-65 — what new accounts use.
pub const ML_DSA_65: u32 = 1;
/// Runs `$body` with `$dsa` and `$hd` bound to the parameter-set modules named by
/// `$scheme`.
///
/// An unrecognised selector resolves to ML-DSA-87 rather than panicking: 0 is the
/// legacy scheme and the safest thing an out-of-range value can mean. Callers
/// that care validate first — see `ext_mldsa_is_scheme`.
macro_rules! dispatch {
($scheme:expr, $dsa:ident, $hd:ident, $body:block) => {
match $scheme {
$crate::scheme::ML_DSA_65 => {
#[allow(unused_imports)]
use qp_rusty_crystals_dilithium::ml_dsa_65 as $dsa;
#[allow(unused_imports)]
use qp_rusty_crystals_hdwallet::ml_dsa_65 as $hd;
$body
},
_ => {
#[allow(unused_imports)]
use qp_rusty_crystals_dilithium::ml_dsa_87 as $dsa;
#[allow(unused_imports)]
use qp_rusty_crystals_hdwallet::ml_dsa_87 as $hd;
$body
},
}
};
}
pub(crate) use dispatch;
+303
View File
@@ -0,0 +1,303 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
//! Conformance against the chain, not against ourselves.
//!
//! Every expected value here came from an independent implementation — the
//! `quantus` CLI 2.2.2 — and not from running this crate and writing down what
//! it said. A test that pins our own output would keep passing through exactly
//! the kind of drift these exist to catch.
//!
//! Addresses are pinned as raw account-id bytes rather than SS58 strings so this
//! file needs no base58 dependency; the SS58 rendering at prefix 189 is pinned on
//! the JS side, which is where it is actually used.
use crate::{hdwallet::{mldsa_derive, wormhole_addresses}, mldsa::*, poseidon::*, scheme::*};
/// FIPS 204 context for on-chain extrinsic signatures, spec >= 148.
/// `chain:primitives/dilithium-crypto/src/signing_context.rs`.
const EXTRINSIC: &[u8] = b"QUANTUS_EXTRINSIC";
fn account_of(seed_fill: u8, scheme: u32) -> Vec<u8> {
let pair = mldsa_from_seed(&[seed_fill; 32], scheme).expect("keygen");
let secret_len = secret_len(scheme);
ext_poseidon_hash(&pair[secret_len..])
}
fn secret_len(scheme: u32) -> usize {
let sizes = ext_mldsa_sizes(scheme);
u32::from_le_bytes(sizes[4..8].try_into().unwrap()) as usize
}
#[test]
fn sizes_match_the_parameter_sets() {
// [public, secret, signature, signature_with_public]
let s87: Vec<u32> = ext_mldsa_sizes(ML_DSA_87).chunks(4).map(|c| u32::from_le_bytes(c.try_into().unwrap())).collect();
let s65: Vec<u32> = ext_mldsa_sizes(ML_DSA_65).chunks(4).map(|c| u32::from_le_bytes(c.try_into().unwrap())).collect();
assert_eq!(s87, vec![2592, 4896, 4627, 7219]);
assert_eq!(s65, vec![1952, 4032, 3309, 5261]);
}
/// The dev accounts endowed at genesis, from `chain:primitives/dilithium-crypto/src/pair.rs`.
///
/// Expected values are the account ids behind the SS58 addresses that
/// `quantus developer create-test-wallets` prints:
///
/// ```text
/// crystal_alice qzk1Nxai3dZD9Cn5kwGcgL6mKxsfxwqdis7kDQJ52aJS2vSn7
/// dilithium_bob qzkYEQv8tQsmniZYdame3Cku18RL5g9bGK9Pdydq5TMPdpE3y
/// crystal_charlie qzntBpmqHZF1jxC8KJKpuxcYuHST892jyXBqRctpAxd1WQ9BL
/// ```
///
/// They are ML-DSA-87 and come from the seed directly with no HD derivation, so
/// this pins the legacy scheme and the raw-seed path in one go.
#[test]
fn dev_account_ids_match_the_cli() {
assert_eq!(
hex(&account_of(0, ML_DSA_87)),
"1883df2ae47d1fd428a6b8237ad7b59cf0facccaacac4541ef7758be44b3c333",
"crystal_alice"
);
assert_eq!(
hex(&account_of(1, ML_DSA_87)),
"300bb607ba60e89461d2f9005668231ceb30237b33db53a614164b8590965519",
"dilithium_bob"
);
assert_eq!(
hex(&account_of(2, ML_DSA_87)),
"97bc5f2db1efa23fb71f6737fcb26e41e448aff07447011369df81ce43555465",
"crystal_charlie"
);
}
/// The same 32 bytes must give different keys per parameter set — FIPS 204
/// absorbs `(k, )` into the seed expansion. If these ever collided it would mean
/// the scheme selector was being ignored somewhere.
#[test]
fn schemes_are_independent_for_the_same_seed() {
assert_ne!(account_of(0, ML_DSA_87), account_of(0, ML_DSA_65));
}
#[test]
fn signs_and_verifies_under_the_extrinsic_context() {
for scheme in [ML_DSA_87, ML_DSA_65] {
let pair = mldsa_from_seed(&[7u8; 32], scheme).expect("keygen");
let (secret, public) = pair.split_at(secret_len(scheme));
let message = b"the payload the chain will see";
let signature = mldsa_sign(secret, public, message, EXTRINSIC, scheme).expect("sign");
assert!(ext_mldsa_verify(public, message, &signature, EXTRINSIC, scheme));
// The whole point of the context. A signature made for an extrinsic must
// not verify as anything else, and vice versa — this is what makes the
// spec-148 boundary detectable instead of a silent chain rejection.
assert!(!ext_mldsa_verify(public, message, &signature, b"", scheme));
assert!(!ext_mldsa_verify(public, b"tampered", &signature, EXTRINSIC, scheme));
}
}
/// The runtime signs with `hedge: None`. If this crate ever introduced hedging
/// randomness the golden vectors in quantus/wasm#2 would become unwritable, and
/// nothing else would notice.
#[test]
fn signing_is_deterministic() {
let pair = mldsa_from_seed(&[9u8; 32], ML_DSA_65).expect("keygen");
let (secret, public) = pair.split_at(secret_len(ML_DSA_65));
let once = mldsa_sign(secret, public, b"m", EXTRINSIC, ML_DSA_65).expect("sign");
let twice = mldsa_sign(secret, public, b"m", EXTRINSIC, ML_DSA_65).expect("sign");
assert_eq!(once, twice);
}
#[test]
fn rejects_bad_input() {
assert!(mldsa_from_seed(&[0u8; 16], ML_DSA_65).is_err(), "short seed");
let pair = mldsa_from_seed(&[1u8; 32], ML_DSA_65).expect("keygen");
let (secret, public) = pair.split_at(secret_len(ML_DSA_65));
assert!(mldsa_sign(secret, public, b"m", &[0u8; 256], ML_DSA_65).is_err(), "context > 255");
assert!(mldsa_sign(&secret[1..], public, b"m", EXTRINSIC, ML_DSA_65).is_err(), "truncated secret");
// A pair whose halves do not correspond must fail at import rather than
// produce a signature that silently will not verify.
let other = mldsa_from_seed(&[2u8; 32], ML_DSA_65).expect("keygen");
let other_public = &other[secret_len(ML_DSA_65)..];
assert!(mldsa_sign(secret, other_public, b"m", EXTRINSIC, ML_DSA_65).is_err(), "mismatched pair");
}
/// The well-known Substrate development phrase. Public by design — it is in
/// polkadot-sdk, in polkadot-js, and in every tutorial — so pinning it here
/// commits no secret. Any account it derives is assumed compromised.
const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// HD derivation at the Quantus BIP44 path, cross-checked against
/// `quantus wallet import --mnemonic-file <DEV_PHRASE> --scheme <s>`, which
/// printed:
///
/// ```text
/// ml-dsa-65 m/44'/189189'/0'/0'/1' qzq29m9WvneDAeXbtgueKCREtNe1rVVs6bXSMLmjr6shqvwq6
/// ml-dsa-87 m/44'/189189'/0'/0'/0' qzjrYTUnnE5NduTZKxe9dESCMTZg7nTueKM3bwhnkRdD1iYV4
/// ```
///
/// This pins the whole derivation chain at once: BIP39 to a 64-byte seed (*not*
/// Substrate's `mnemonicToMiniSecret`), the HMAC-SHA512 walk keyed with
/// "Dilithium seed", the trailing hardened index carrying the scheme, and the
/// Poseidon2 account-id hash on the end.
#[test]
fn hd_derivation_matches_the_cli() {
let cases = [
(ML_DSA_65, "m/44'/189189'/0'/0'/1'", "f647dbdefebcfcf726ba078a83481ffc6f4f33004fdfb4cedacf5a5391bc8f00"),
(ML_DSA_87, "m/44'/189189'/0'/0'/0'", "11c6a314e003cdee3dc51cf6569175360141578d054c38d7a70840a65cc0e990")
];
for (scheme, path, expected) in cases {
let pair = mldsa_derive(DEV_PHRASE, "", path, scheme).expect("derive");
let account = ext_poseidon_hash(&pair[secret_len(scheme)..]);
assert_eq!(hex(&account), expected, "{path}");
}
}
/// Lattice keys have no public derivability, so the crate rejects unhardened
/// paths outright rather than inventing a meaning for them. A wallet that
/// silently hardened a soft path would put funds at an address the user did not
/// ask for.
#[test]
fn derivation_rejects_bad_input() {
assert!(mldsa_derive(DEV_PHRASE, "", "m/44'/189189'/0'/0'/1", ML_DSA_65).is_err(), "unhardened");
assert!(mldsa_derive("not a mnemonic at all", "", "m/44'/189189'/0'/0'/1'", ML_DSA_65).is_err(), "bad phrase");
assert!(mldsa_derive(DEV_PHRASE, "", "not a path", ML_DSA_65).is_err(), "bad path");
}
/// A BIP39 passphrase must change the result, and an empty string must mean
/// "no passphrase" rather than "a passphrase that happens to be empty" — the
/// two are the same in BIP39 but the crate's signature distinguishes them, and
/// normalising in the wrong direction would silently fork every address.
#[test]
fn passphrase_is_honoured_and_empty_means_none() {
let path = "m/44'/189189'/0'/0'/1'";
let none = mldsa_derive(DEV_PHRASE, "", path, ML_DSA_65).expect("derive");
let with = mldsa_derive(DEV_PHRASE, "hunter2", path, ML_DSA_65).expect("derive");
assert_ne!(none, with);
}
#[test]
fn scheme_validation() {
assert!(ext_mldsa_is_scheme(ML_DSA_87));
assert!(ext_mldsa_is_scheme(ML_DSA_65));
assert!(!ext_mldsa_is_scheme(2));
}
fn hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{b:02x}")).collect()
}
/// The chain node's own wormhole vector, `node/src/tests/data/quantus_key_test_data.rs`:
/// `TEST_MNEMONIC` at `m/44'/189189189'/0'/0'/0'` is `TEST_WORMHOLE_ADDRESS`,
/// `qzpWh4AEtsgCyEbv4WBgFWnB9bcdF2L2jVDuyjXP9mSTyBaeU`. The mobile wallet's SDK
/// pins the same pair (`generate_keys_test.dart`), so three implementations agree.
#[test]
fn wormhole_address_matches_the_node() {
const MNEMONIC: &str = "orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven";
let batch = wormhole_addresses(MNEMONIC, "", 0, 0, 0, 3).expect("derive");
assert_eq!(batch.len(), 96);
assert_eq!(hex(&batch[..32]), "dfcfd6e59c75d208e84f54a887537bcf7b04265790ec79960bf49de123404d0e");
// A batch is the same as asking for each index on its own: the seed is
// stretched once, but every address still gets its own path.
for i in 0..3u32 {
let one = wormhole_addresses(MNEMONIC, "", 0, 0, i, 1).expect("derive one");
assert_eq!(one, batch[(i as usize * 32)..(i as usize + 1) * 32].to_vec());
}
// Receive and change branches, and account indices, are different addresses.
assert_ne!(wormhole_addresses(MNEMONIC, "", 0, 1, 0, 1).unwrap(), batch[..32].to_vec());
assert_ne!(wormhole_addresses(MNEMONIC, "", 1, 0, 0, 1).unwrap(), batch[..32].to_vec());
}
#[test]
fn wormhole_addresses_refuse_unbounded_requests() {
const MNEMONIC: &str = "orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven";
assert!(wormhole_addresses(MNEMONIC, "", 0, 0, 0, 1001).is_err());
assert!(wormhole_addresses(MNEMONIC, "", 0, 0, 0x7fff_ffff, 2).is_err());
assert!(wormhole_addresses("not a mnemonic", "", 0, 0, 0, 1).is_err());
}
/// The port of the nullifier agrees with the chain's circuit crate.
///
/// `qp_wormhole_circuit::nullifier::Nullifier::from_preimage` is what the proof
/// commits to and what `Wormhole::UsedNullifiers` records, so it is the
/// reference. Secrets span the edge the lossy 8-bytes-per-felt encoding cares
/// about (limbs at and above the Goldilocks prime), and transfer counts span
/// both 32-bit limbs.
#[test]
fn nullifier_matches_the_circuit() {
use crate::hdwallet::nullifier;
use qp_wormhole_circuit::nullifier::Nullifier;
use qp_zk_circuits_common::utils::{digest_to_bytes, BytesDigest};
let secrets: Vec<[u8; 32]> = vec![
[0u8; 32],
[0xff; 32],
core::array::from_fn(|i| i as u8),
core::array::from_fn(|i| (i as u8).wrapping_mul(97).wrapping_add(13)),
// every limb is the Goldilocks prime 2^64 - 2^32 + 1, big-endian
[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01].repeat(4).try_into().unwrap(),
];
let counts = [0u64, 1, 41_683, u32::MAX as u64, 1u64 << 32, u64::MAX];
let mut compared = 0;
for secret in &secrets {
for &count in &counts {
let digest = BytesDigest::try_from(*secret);
// The circuit's BytesDigest refuses a non-canonical limb; where it
// does, the chain can never produce that secret's nullifier either.
let Ok(digest) = digest else { continue };
let expected = digest_to_bytes(Nullifier::from_preimage(digest, count).hash);
assert_eq!(hex(&nullifier(secret, count)), hex(expected.as_ref()), "secret {} count {count}", hex(secret));
compared += 1;
}
}
// Skipping is for the non-canonical edge only; a test that compared
// nothing would pass just as well.
assert!(compared >= 18, "only {compared} cases compared");
}
#[test]
fn wormhole_nullifiers_follow_each_address_secret() {
use crate::hdwallet::{nullifier, wormhole_nullifiers};
use qp_rusty_crystals_hdwallet::derive_wormhole_from_mnemonic;
const MNEMONIC: &str = "orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven";
// addresses 2 and 3 on the change branch, transfer counts 5..8
let batch = wormhole_nullifiers(MNEMONIC, "", 0, 1, 2, 2, 5, 3).unwrap();
assert_eq!(batch.len(), 2 * 3 * 32);
for (a, index) in [2u32, 3].into_iter().enumerate() {
let pair = derive_wormhole_from_mnemonic(MNEMONIC, None, &format!("m/44'/189189189'/0'/1'/{index}'")).unwrap();
for c in 0..3usize {
let at = (a * 3 + c) * 32;
assert_eq!(batch[at..at + 32].to_vec(), nullifier(pair.secret().as_bytes(), 5 + c as u64).to_vec(), "address {index} count {}", 5 + c);
}
}
assert!(wormhole_nullifiers(MNEMONIC, "", 0, 0, 0, 40, 0, 2_501).is_err());
assert!(wormhole_nullifiers(MNEMONIC, "", 0, 0, 0, 1, u64::MAX, 2).is_err());
assert!(wormhole_nullifiers(MNEMONIC, "", 0, 0, 0x7fff_ffff, 2, 0, 1).is_err());
}
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/**
* Which ML-DSA parameter set a call refers to.
*
* These are the chain's own `DilithiumSignatureScheme` variant indices, not a
* private numbering — the value here is the byte a signed extrinsic carries on
* the wire. Keeping them identical means the keyring's `TYPE_PREFIX` is the
* identity function on a scheme, with no table to get backwards.
*/
export enum Scheme {
/** ML-DSA-87. Legacy: accounts created before the scheme was recorded, and the dev-genesis accounts. */
MlDsa87 = 0,
/** ML-DSA-65. What new accounts use. */
MlDsa65 = 1
}
/**
* The name each scheme is stored under, matching `quantus-cli` and the mobile
* wallet so a wallet exported from one tool imports into another.
*/
export const SCHEME_NAME: Record<Scheme, string> = {
[Scheme.MlDsa87]: 'ml-dsa-87',
[Scheme.MlDsa65]: 'ml-dsa-65'
};
/**
* FIPS 204 context for on-chain extrinsic signatures.
*
* Only from spec 148 onward — earlier runtimes verify under the empty context,
* and a signature made under the wrong one is valid, rejected by the chain, and
* indistinguishable locally. Callers pass the spec version and get the right
* answer from {@link contextForSpec}; nothing here guesses.
*/
export const EXTRINSIC_CONTEXT = new TextEncoder().encode('QUANTUS_EXTRINSIC');
/** First spec version that verifies extrinsics under {@link EXTRINSIC_CONTEXT}. */
export const EXTRINSIC_MIN_SPEC = 148;
/** The signing context a runtime at `specVersion` expects. */
export function contextForSpec (specVersion: number): Uint8Array {
return specVersion >= EXTRINSIC_MIN_SPEC
? EXTRINSIC_CONTEXT
: new Uint8Array();
}
+76
View File
@@ -0,0 +1,76 @@
// Copyright 2026 @quantus/crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
//
// Consumes the *built* package exactly as quantus/common will — a plain import of
// build output, nothing reaching into src or poking the wasm by hand. Run after
// ./scripts/build-quantus.sh.
//
// This exists because the unit tests in src/rs/tests.rs cannot catch packaging
// faults. A wasm that is valid before `wasm-opt` and broken after it passes every
// cargo test and fails here, which is exactly how binaryen 105's mishandling of
// externref tables was found.
import {
accountFromPublicKey, contextForSpec, EXTRINSIC_MIN_SPEC, initWasm,
isReady, keypairFromMnemonic, keypairFromSeed, Scheme, SCHEME_NAME,
sign, signatureWithPublicKey, sizes, verify, WormholeBranch, wormholeAddresses, wormholeNullifiers
} from '@quantus/crypto';
let fail = 0;
const eq = (l, g, w) => { const ok = String(g) === String(w); if (!ok) fail++;
console.log(`${ok ? 'PASS' : 'FAIL'} ${l}`); if (!ok) console.log(` got ${g}\n want ${w}`); };
eq('initWasm() returns no error', initWasm(), 'null');
eq('isReady()', isReady(), true);
const s65 = sizes(Scheme.MlDsa65);
eq('ML-DSA-65 sizes', JSON.stringify(s65), '{"publicKey":1952,"secretKey":4032,"signature":3309,"signatureWithPublicKey":5261}');
eq('scheme name', SCHEME_NAME[Scheme.MlDsa65], 'ml-dsa-65');
eq('variant byte is the enum value', Scheme.MlDsa87, 0);
// crystal_alice, via the public API only
const pair87 = keypairFromSeed(new Uint8Array(32), Scheme.MlDsa87);
eq('crystal_alice account id',
Buffer.from(accountFromPublicKey(pair87.publicKey)).toString('hex'),
'1883df2ae47d1fd428a6b8237ad7b59cf0facccaacac4541ef7758be44b3c333');
// HD derivation, dev phrase, ML-DSA-65 default path
const DEV = 'bottom drive obey lake curtain smoke basket hold race lonely fit walk';
const hd = keypairFromMnemonic(DEV, '', "m/44'/189189'/0'/0'/1'", Scheme.MlDsa65);
eq('dev phrase account id (ML-DSA-65)',
Buffer.from(accountFromPublicKey(hd.publicKey)).toString('hex'),
'f647dbdefebcfcf726ba078a83481ffc6f4f33004fdfb4cedacf5a5391bc8f00');
// the signing-context boundary
const msg = new TextEncoder().encode('extrinsic payload');
const ctx = contextForSpec(EXTRINSIC_MIN_SPEC);
const sig = sign(msg, hd, ctx, Scheme.MlDsa65);
eq('signature length', sig.length, s65.signature);
eq('verifies at spec 148', verify(msg, sig, hd.publicKey, ctx, Scheme.MlDsa65), true);
eq('does NOT verify at spec 147', verify(msg, sig, hd.publicKey, contextForSpec(147), Scheme.MlDsa65), false);
eq('contextForSpec(147) is empty', contextForSpec(147).length, 0);
// the wire form
eq('sig || pk length', signatureWithPublicKey(sig, hd.publicKey).length, s65.signatureWithPublicKey);
// wormhole: the chain node's TEST_WORMHOLE_ADDRESS (qzpWh4AEtsgCyEbv4WBgFWnB9bcdF2L2jVDuyjXP9mSTyBaeU)
const NODE_PHRASE = 'orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven';
const wh = wormholeAddresses(NODE_PHRASE, '', 0, WormholeBranch.Receive, 0, 2);
eq('wormhole address count', wh.length, 2);
eq('wormhole receive 0 is the node test address',
Buffer.from(wh[0]).toString('hex'),
'dfcfd6e59c75d208e84f54a887537bcf7b04265790ec79960bf49de123404d0e');
eq('change branch differs', Buffer.from(wormholeAddresses(NODE_PHRASE, '', 0, WormholeBranch.Change, 0, 1)[0]).toString('hex') !== Buffer.from(wh[0]).toString('hex'), true);
// nullifiers: shape, determinism, and the cost of a wallet account's precompute
const n = wormholeNullifiers(NODE_PHRASE, '', 0, WormholeBranch.Receive, 0, 2, 7, 3);
eq('nullifier shape', `${n.length}x${n[0].length}x${n[0][0].length}`, '2x3x32');
eq('nullifiers differ by count', Buffer.from(n[0][0]).equals(Buffer.from(n[0][1])), false);
eq('nullifiers differ by address', Buffer.from(n[0][0]).equals(Buffer.from(n[1][0])), false);
eq('a sub-range agrees', Buffer.from(wormholeNullifiers(NODE_PHRASE, '', 0, WormholeBranch.Receive, 1, 1, 8, 1)[0][0]).toString('hex'), Buffer.from(n[1][1]).toString('hex'));
const t0 = performance.now();
wormholeNullifiers(NODE_PHRASE, '', 0, WormholeBranch.Receive, 0, 20, 0, 256);
wormholeNullifiers(NODE_PHRASE, '', 0, WormholeBranch.Change, 0, 20, 0, 256);
console.log(` 40 addresses x 256 counts: ${Math.round(performance.now() - t0)} ms`);
process.exit(fail ? 1 : 0);
@@ -0,0 +1 @@
vendor/
@@ -0,0 +1,69 @@
# Browser probes
`cargo test` and the consumer test both run in node, and node is neither a
browser nor a service worker. These two probes cover what node cannot: does the
WASM instantiate with **no DOM**, under the **extension's own CSP**, and what does
a cold start cost.
Build first with `./scripts/build-quantus.sh`, stage `vendor/` (below), then run
`node serve.mjs` from this directory.
## `index.html` + `worker.js` — automated
A module Worker, served with the exact `extension_pages` CSP from both extension
manifests:
```
script-src 'self' 'wasm-unsafe-eval'; object-src 'self'
```
A module Worker has no `window` and no `document`, which is the property that
matters — an MV3 service worker has neither either. Result on Firefox:
```
hasDOM: false hasWindow: false
initWasm: ok (9.0 ms cold)
keygen: 1.0 ms
account: matches quantus-cli
sign: 3.0 ms (4627 bytes)
verify: 1.0 ms ok
ctx sep: ok (rejected under spec-147 ctx)
```
9 ms to base64-decode 146 KB, zlib-inflate it to 234 KB and instantiate. That is
the number the MV3 lifetime question turns on: a service worker killed between
messages pays this on every wake, and 9 ms is not a problem. Those are ML-DSA-87
timings — the larger parameter set — so ML-DSA-65 is cheaper still.
The CSP is genuinely enforced here, not merely declared: an earlier version of
this page used an inline `<script>` and Firefox blocked it, which is why
`main.js` exists as a separate file.
## `manifest.json` + `sw.js` — manual
The real thing: an MV3 extension whose background service worker imports the
package at module scope and signs once. Loading an unpacked extension needs an OS
file dialog, so this cannot be driven from a script — load it by hand via
`chrome://extensions` → Developer mode → Load unpacked, then click the toolbar
icon.
It covers what the Worker probe cannot: `chrome.runtime` messaging, and the
actual MV3 kill-and-restart lifecycle rather than a stand-in for it.
## Staging `vendor/`
Both probes import from `./vendor/`, which is not checked in. Populate it from a
build:
```sh
mkdir -p vendor
cp -r ../../build vendor/quantus-crypto
cp -r ../../../wasm-util/build vendor/wasm-util
sed -i "s|from '@polkadot/wasm-util/base64'|from '../wasm-util/base64.js'|; \
s|from '@polkadot/wasm-util/fflate'|from '../wasm-util/fflate.js'|" \
vendor/quantus-crypto/init.js
```
The rewrite is needed because a browser cannot resolve bare specifiers. A real
extension build does this with a bundler; here it is one `sed` rather than a
build step, because the probe exists to test the WASM, not the bundler.
@@ -0,0 +1,5 @@
<!doctype html><meta charset="utf-8"><title>quantus-crypto worker probe</title>
<body style="font:13px ui-monospace,monospace;padding:16px;background:#111;color:#ddd">
<h3 style="font:600 14px system-ui">@quantus/crypto in a module Worker under the extension CSP</h3>
<pre id="out">running…</pre>
<script type="module" src="./main.js"></script>
@@ -0,0 +1,3 @@
const w = new Worker('./worker.js', { type: 'module' });
w.onmessage = (e) => { document.getElementById('out').textContent = e.data; };
w.onerror = (e) => { document.getElementById('out').textContent = 'worker error: ' + (e.message || 'see console'); };
@@ -0,0 +1,11 @@
{
"manifest_version": 3,
"name": "quantus-crypto MV3 probe",
"version": "0.0.1",
"description": "Loads @quantus/crypto in an MV3 service worker and signs once.",
"background": { "service_worker": "sw.js", "type": "module" },
"action": { "default_title": "probe", "default_popup": "popup.html" },
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
}
}
@@ -0,0 +1,4 @@
<!doctype html><meta charset="utf-8"><title>quantus-crypto probe</title>
<body style="font:13px system-ui;padding:12px;min-width:380px">
<pre id="out">running…</pre>
<script type="module" src="popup.js"></script>
@@ -0,0 +1,4 @@
const out = document.getElementById('out');
chrome.runtime.sendMessage({ probe: true }, (r) => {
out.textContent = r ? r.text : `no response: ${chrome.runtime.lastError?.message}`;
});
@@ -0,0 +1,15 @@
import http from 'node:http';
import fs from 'node:fs';
import path from 'node:path';
const types = { '.html': 'text/html', '.js': 'text/javascript', '.json': 'application/json', '.wasm': 'application/wasm' };
http.createServer((req, res) => {
const p = path.join(process.cwd(), decodeURIComponent(req.url.split('?')[0]));
const f = fs.existsSync(p) && fs.statSync(p).isDirectory() ? path.join(p, 'index.html') : p;
if (!fs.existsSync(f)) { res.writeHead(404); return res.end('nope'); }
res.writeHead(200, {
'Content-Type': types[path.extname(f)] || 'application/octet-stream',
// exactly the extension_pages CSP from both manifests
'Content-Security-Policy': "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
});
fs.createReadStream(f).pipe(res);
}).listen(8731, () => console.log('probe on http://127.0.0.1:8731'));
+52
View File
@@ -0,0 +1,52 @@
// MV3 service worker. Imports @quantus/crypto at module scope — i.e. on every
// cold start, which is what actually needs proving: the worker is killed between
// messages and must re-instantiate a 146 KB inlined base64 wasm each time.
import {
accountFromPublicKey, contextForSpec, initWasm, keypairFromSeed,
Scheme, sign, verify
} from './vendor/quantus-crypto/index.js';
const hex = (u8) => [...u8].map((b) => b.toString(16).padStart(2, '0')).join('');
function probe () {
const lines = [];
const t0 = performance.now();
const err = initWasm();
const tInit = performance.now() - t0;
lines.push(`context: ${typeof window === 'undefined' ? 'service worker (no DOM)' : 'page'}`);
lines.push(`initWasm: ${err === null ? 'ok' : 'FAILED — ' + err} (${tInit.toFixed(1)} ms)`);
if (err) return lines.join('\n');
const t1 = performance.now();
const pair = keypairFromSeed(new Uint8Array(32), Scheme.MlDsa87);
const tKeygen = performance.now() - t1;
const account = hex(accountFromPublicKey(pair.publicKey));
const expected = '1883df2ae47d1fd428a6b8237ad7b59cf0facccaacac4541ef7758be44b3c333';
lines.push(`keygen: ${tKeygen.toFixed(1)} ms`);
lines.push(`account: ${account.slice(0, 24)}${account === expected ? 'matches quantus-cli' : 'MISMATCH'}`);
const msg = new TextEncoder().encode('extrinsic payload');
const ctx = contextForSpec(148);
const t2 = performance.now();
const sig = sign(msg, pair, ctx, Scheme.MlDsa87);
const tSign = performance.now() - t2;
lines.push(`sign: ${tSign.toFixed(1)} ms (${sig.length} bytes)`);
lines.push(`verify: ${verify(msg, sig, pair.publicKey, ctx, Scheme.MlDsa87) ? 'ok' : 'FAILED'}`);
lines.push(`ctx sep: ${verify(msg, sig, pair.publicKey, contextForSpec(147), Scheme.MlDsa87) ? 'FAILED (verified under wrong ctx)' : 'ok (rejected under spec 147 ctx)'}`);
return lines.join('\n');
}
chrome.runtime.onMessage.addListener((_m, _s, respond) => {
try {
respond({ text: probe() });
} catch (e) {
respond({ text: `threw: ${e && e.message ? e.message : e}\n${e && e.stack ? e.stack : ''}` });
}
return true;
});
@@ -0,0 +1,32 @@
// A module Worker: no DOM, no window, same CSP as the extension pages.
import { accountFromPublicKey, contextForSpec, initWasm, keypairFromSeed, Scheme, sign, verify } from './vendor/quantus-crypto/index.js';
const hex = (u8) => [...u8].map((b) => b.toString(16).padStart(2, '0')).join('');
const lines = [];
const t0 = performance.now();
const err = initWasm();
const tInit = performance.now() - t0;
lines.push(`hasDOM: ${typeof document !== 'undefined'} hasWindow: ${typeof window !== 'undefined'}`);
lines.push(`initWasm: ${err === null ? 'ok' : 'FAILED - ' + err} (${tInit.toFixed(1)} ms cold)`);
if (err === null) {
const t1 = performance.now();
const pair = keypairFromSeed(new Uint8Array(32), Scheme.MlDsa87);
const tKeygen = performance.now() - t1;
const account = hex(accountFromPublicKey(pair.publicKey));
lines.push(`keygen: ${tKeygen.toFixed(1)} ms`);
lines.push(`account: ${account === '1883df2ae47d1fd428a6b8237ad7b59cf0facccaacac4541ef7758be44b3c333' ? 'matches quantus-cli' : 'MISMATCH ' + account}`);
const msg = new TextEncoder().encode('extrinsic payload');
const ctx = contextForSpec(148);
const t2 = performance.now();
const sig = sign(msg, pair, ctx, Scheme.MlDsa87);
const tSign = performance.now() - t2;
const t3 = performance.now();
const ok = verify(msg, sig, pair.publicKey, ctx, Scheme.MlDsa87);
const tVerify = performance.now() - t3;
lines.push(`sign: ${tSign.toFixed(1)} ms (${sig.length} bytes)`);
lines.push(`verify: ${tVerify.toFixed(1)} ms ${ok ? 'ok' : 'FAILED'}`);
lines.push(`ctx sep: ${verify(msg, sig, pair.publicKey, contextForSpec(147), Scheme.MlDsa87) ? 'FAILED' : 'ok (rejected under spec-147 ctx)'}`);
}
postMessage(lines.join('\n'));
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"composite": false,
"declaration": true,
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false
},
"exclude": [
"**/*.spec.ts"
],
"include": [
"src/**/*.ts"
],
"references": []
}
+3
View File
@@ -0,0 +1,3 @@
# @polkadot/wasm-bridge
A re-usable bridge between JS & WASM interfaces. It is used internally by `@polkadot/wasm-crypto`.
+35
View File
@@ -0,0 +1,35 @@
{
"author": "Jaco Greeff <jacogr@gmail.com>",
"bugs": "https://github.com/polkadot-js/wasm/issues",
"description": "A bridge layer between JS and Wasm",
"engines": {
"node": ">=18"
},
"homepage": "https://github.com/polkadot-js/wasm/tree/master/packages/wasm-bridge#readme",
"license": "Apache-2.0",
"name": "@polkadot/wasm-bridge",
"repository": {
"directory": "packages/wasm-bridge",
"type": "git",
"url": "https://github.com/polkadot-js/wasm.git"
},
"sideEffects": [
"./packageDetect.js",
"./packageDetect.cjs"
],
"type": "module",
"version": "7.5.4",
"main": "index.js",
"dependencies": {
"@polkadot/wasm-util": "7.5.4",
"tslib": "^2.7.0"
},
"devDependencies": {
"@polkadot/util": "^14.0.1",
"@polkadot/x-randomvalues": "^14.0.1"
},
"peerDependencies": {
"@polkadot/util": "*",
"@polkadot/x-randomvalues": "*"
}
}
+214
View File
@@ -0,0 +1,214 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
// A number of functions are "unsafe" and purposefully so - it is
// assumed that where the bridge is used, it is correctly wrapped
// in a safeguard (see withWasm in the wasm-crypto package) which
// then ensures that the internal wasm instance here is available
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { BridgeBase, InitFn, InitPromise, WasmBaseInstance, WasmImports } from './types.js';
import { stringToU8a, u8aToString } from '@polkadot/util';
import { Wbg } from './wbg.js';
/**
* @name Bridge
* @description
* Creates a bridge between the JS and WASM environments.
*
* For any bridge it is passed an function which is then called internally at the
* time of initialization. This affectively implements the layer between WASM and
* the native environment, providing all the plumbing needed for the Wbg classes.
*/
export class Bridge<C extends WasmBaseInstance> implements BridgeBase<C> {
readonly #createWasm: InitFn<C>;
readonly #heap: unknown[];
readonly #wbg: WasmImports;
#cachegetInt32: Int32Array | null;
#cachegetUint8: Uint8Array | null;
#heapNext: number;
#wasm: C | null;
#wasmError: string | null;
#wasmPromise: InitPromise<C> | null;
#type: 'asm' | 'wasm' | 'none';
constructor (createWasm: InitFn<C>) {
this.#createWasm = createWasm;
this.#cachegetInt32 = null;
this.#cachegetUint8 = null;
this.#heap = new Array(32)
.fill(undefined)
.concat(undefined, null, true, false);
this.#heapNext = this.#heap.length;
this.#type = 'none';
this.#wasm = null;
this.#wasmError = null;
this.#wasmPromise = null;
this.#wbg = { ...new Wbg(this) };
}
/** @description Returns the init error */
get error (): string | null {
return this.#wasmError;
}
/** @description Returns the init type */
get type (): 'asm' | 'wasm' | 'none' {
return this.#type;
}
/** @description Returns the created wasm interface */
get wasm (): C | null {
return this.#wasm;
}
/** @description Performs the wasm initialization */
async init (createWasm?: InitFn<C>): Promise<C | null> {
if (!this.#wasmPromise || createWasm) {
this.#wasmPromise = (createWasm || this.#createWasm)(this.#wbg);
}
const { error, type, wasm } = await this.#wasmPromise;
this.#type = type;
this.#wasm = wasm;
this.#wasmError = error;
return this.#wasm;
}
/**
* @internal
* @description Gets an object from the heap
*/
getObject (idx: number): unknown {
return this.#heap[idx];
}
/**
* @internal
* @description Removes an object from the heap
*/
dropObject (idx: number) {
if (idx < 36) {
return;
}
this.#heap[idx] = this.#heapNext;
this.#heapNext = idx;
}
/**
* @internal
* @description Retrieves and removes an object to the heap
*/
takeObject (idx: number): unknown {
const ret = this.getObject(idx);
this.dropObject(idx);
return ret;
}
/**
* @internal
* @description Adds an object to the heap
*/
addObject (obj: unknown): number {
if (this.#heapNext === this.#heap.length) {
this.#heap.push(this.#heap.length + 1);
}
const idx = this.#heapNext;
this.#heapNext = this.#heap[idx] as number;
this.#heap[idx] = obj;
return idx;
}
/**
* @internal
* @description Retrieve an Int32 in the WASM interface
*/
getInt32 (): Int32Array {
if (this.#cachegetInt32 === null || this.#cachegetInt32.buffer !== this.#wasm!.memory.buffer) {
this.#cachegetInt32 = new Int32Array(this.#wasm!.memory.buffer);
}
return this.#cachegetInt32;
}
/**
* @internal
* @description Retrieve an Uint8Array in the WASM interface
*/
getUint8 (): Uint8Array {
if (this.#cachegetUint8 === null || this.#cachegetUint8.buffer !== this.#wasm!.memory.buffer) {
this.#cachegetUint8 = new Uint8Array(this.#wasm!.memory.buffer);
}
return this.#cachegetUint8;
}
/**
* @internal
* @description Retrieves an Uint8Array in the WASM interface
*/
getU8a (ptr: number, len: number): Uint8Array {
return this.getUint8().subarray(ptr / 1, ptr / 1 + len);
}
/**
* @internal
* @description Retrieves a string in the WASM interface
*/
getString (ptr: number, len: number): string {
return u8aToString(this.getU8a(ptr, len));
}
/**
* @internal
* @description Allocates an Uint8Array in the WASM interface
*/
allocU8a (arg: Uint8Array): [number, number] {
const ptr = this.#wasm!.__wbindgen_malloc(arg.length * 1);
this.getUint8().set(arg, ptr / 1);
return [ptr, arg.length];
}
/**
* @internal
* @description Allocates a string in the WASM interface
*/
allocString (arg: string): [number, number] {
return this.allocU8a(stringToU8a(arg));
}
/**
* @internal
* @description Retrieves an Uint8Array from the WASM interface
*/
resultU8a (): Uint8Array {
const r0 = this.getInt32()[8 / 4 + 0];
const r1 = this.getInt32()[8 / 4 + 1];
const ret = this.getU8a(r0, r1).slice();
this.#wasm!.__wbindgen_free(r0, r1 * 1);
return ret;
}
/**
* @internal
* @description Retrieve a string from the WASM interface
*/
resultString (): string {
return u8aToString(this.resultU8a());
}
}
+5
View File
@@ -0,0 +1,5 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
export * from './bridge.js';
export * from './init.js';
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
import './packageDetect.js';
export * from './bundle.js';
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { InitFn, InitPromise, InitResult, WasmBaseInstance, WasmImports } from './types.js';
/**
* @name createWasmFn
* @description
* Create a WASM (or ASM.js) creator interface based on the supplied information.
*
* It will attempt to create a WASM interface first and if this fails or is not available in
* the environment, will fallback to attempting to create an ASM.js interface.
*/
export function createWasmFn <C extends WasmBaseInstance> (root: 'crypto', wasmBytes: null | Uint8Array, asmFn: null | ((wbg: WasmImports) => C)): InitFn<C> {
return async (wbg: WasmImports): InitPromise<C> => {
const result: InitResult<C> = {
error: null,
type: 'none',
wasm: null
};
try {
if (!wasmBytes?.length) {
throw new Error('No WebAssembly provided for initialization');
} else if (typeof WebAssembly !== 'object' || typeof WebAssembly.instantiate !== 'function') {
throw new Error('WebAssembly is not available in your environment');
}
const source = await WebAssembly.instantiate(wasmBytes, { wbg });
result.wasm = source.instance.exports as unknown as C;
result.type = 'wasm';
} catch (error) {
// if we have a valid supplied asm.js, return that
if (typeof asmFn === 'function') {
result.wasm = asmFn(wbg);
result.type = 'asm';
} else {
result.error = `FATAL: Unable to initialize @polkadot/wasm-${root}:: ${(error as Error).message}`;
console.error(result.error);
}
}
return result;
};
}
+4
View File
@@ -0,0 +1,4 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
export * from './index.js';
+11
View File
@@ -0,0 +1,11 @@
// Copyright 2017-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Do not edit, auto-generated by @polkadot/dev
// (packageInfo imports will be kept as-is, user-editable)
import { detectPackage } from '@polkadot/util';
import { packageInfo } from './packageInfo.js';
detectPackage(packageInfo, null, []);
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2017-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/wasm-bridge', path: 'auto', type: 'auto', version: '7.5.4' };
+47
View File
@@ -0,0 +1,47 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Use non-strong types instead of WasmImports which may not
// be available as part of the TS environment types (it needs dom)
export type WasmImports = Record<string, (...args: never[]) => unknown>;
// Use non-strong types instead of WebAssembly.Memory which may not
// be available as part of the TS environment types (it needs dom)
export interface WasmMemory { buffer: ArrayBuffer }
export declare interface InitResult<C extends WasmBaseInstance> {
error: string | null;
type: 'asm' | 'wasm' | 'none';
wasm: C | null;
}
export type InitPromise <C extends WasmBaseInstance> = Promise<InitResult<C>>;
export type InitFn <C extends WasmBaseInstance> = (wbg: WasmImports) => InitPromise<C>;
export interface BridgeBase<C extends WasmBaseInstance> extends InitResult<C> {
init (createWasm?: InitFn<C>): Promise<C | null>;
getObject (idx: number): unknown;
dropObject (idx: number): void;
takeObject (idx: number): unknown;
addObject (obj: unknown): number;
getInt32 (): Int32Array;
getUint8 (): Uint8Array;
getU8a (ptr: number, len: number): Uint8Array;
getString (ptr: number, len: number): string;
allocU8a (arg: Uint8Array): [number, number];
allocString (arg: string): [number, number];
resultU8a (): Uint8Array;
resultString (): string;
}
export interface WasmBindGen {
__wbindgen_exn_store (a: number): void;
__wbindgen_free (a: number, b: number): void;
__wbindgen_malloc (a: number): number;
__wbindgen_realloc (a: number, b: number, c: number): number;
}
export interface WasmBaseInstance extends WasmBindGen {
memory: WasmMemory;
}
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2019-2026 @polkadot/wasm-bridge authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BridgeBase, WasmBaseInstance } from './types.js';
import { getRandomValues } from '@polkadot/x-randomvalues';
const DEFAULT_CRYPTO = { getRandomValues };
const DEFAULT_SELF = { crypto: DEFAULT_CRYPTO };
/**
* @name Wbg
* @description
* This defines the internal interfaces that wasm-bindgen used to communicate
* with the host layer. None of these functions are available to the user, rather
* they are called internally from the WASM code itself.
*
* The interfaces here are exposed in the imports on the created WASM interfaces.
*
* Internally the implementation does a thin layer into the supplied bridge.
*/
export class Wbg<C extends WasmBaseInstance> {
readonly #bridge: BridgeBase<C>;
constructor (bridge: BridgeBase<C>) {
this.#bridge = bridge;
}
/** @internal */
abort = (): never => {
throw new Error('abort');
};
/** @internal */
__wbindgen_is_undefined = (idx: number): boolean => {
return this.#bridge.getObject(idx) === undefined;
};
/** @internal */
__wbindgen_throw = (ptr: number, len: number): boolean => {
throw new Error(this.#bridge.getString(ptr, len));
};
/** @internal */
__wbg_self_1b7a39e3a92c949c = (): number => {
return this.#bridge.addObject(DEFAULT_SELF);
};
/** @internal */
__wbg_require_604837428532a733 = (ptr: number, len: number): never => {
throw new Error(`Unable to require ${this.#bridge.getString(ptr, len)}`);
};
/** @internal */
__wbg_crypto_968f1772287e2df0 = (_idx: number): number => {
return this.#bridge.addObject(DEFAULT_CRYPTO);
};
/** @internal */
__wbg_getRandomValues_a3d34b4fee3c2869 = (_idx: number): number => {
return this.#bridge.addObject(DEFAULT_CRYPTO.getRandomValues);
};
/** @internal */
__wbg_getRandomValues_f5e14ab7ac8e995d = (_arg0: number, ptr: number, len: number): void => {
DEFAULT_CRYPTO.getRandomValues(this.#bridge.getU8a(ptr, len));
};
/** @internal */
__wbg_randomFillSync_d5bd2d655fdf256a = (_idx: number, _ptr: number, _len: number): never => {
throw new Error('randomFillsync is not available');
// getObject(idx).randomFillSync(getU8a(ptr, len));
};
/** @internal */
__wbindgen_object_drop_ref = (idx: number): void => {
this.#bridge.takeObject(idx);
};
}
+12
View File
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/mod.ts"
],
"references": []
}
+3
View File
@@ -0,0 +1,3 @@
## @polkadot/wasm-crypto-asmjs
Asm.js build outputs.
+26 -13
View File
@@ -1,19 +1,32 @@
{
"name": "@polkadot/wasm-crypto-asmjs",
"version": "3.2.1",
"description": "Asm.js content for wasm-crypto",
"browser": "empty.js",
"main": "empty.js",
"module": "empty.mjs",
"react-native": "data.js",
"sideEffects": false,
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [],
"contributors": [],
"license": "Apache-2.0",
"bugs": "https://github.com/polkadot-js/wasm/issues",
"homepage": "https://github.com/polkadot-js/wasm",
"description": "Asm.js content for wasm-crypto",
"engines": {
"node": ">=18"
},
"homepage": "https://github.com/polkadot-js/wasm/tree/master/packages/wasm-crypto-asmjs#readme",
"license": "Apache-2.0",
"name": "@polkadot/wasm-crypto-asmjs",
"repository": {
"directory": "packages/wasm-crypto-asmjs",
"type": "git",
"url": "https://github.com/polkadot-js/wasm.git"
},
"sideEffects": [
"./packageDetect.js",
"./packageDetect.cjs"
],
"type": "module",
"version": "7.5.4",
"main": "index.js",
"dependencies": {
"@babel/runtime": "^7.12.5"
"tslib": "^2.7.0"
},
"devDependencies": {
"@polkadot/util": "^14.0.1"
},
"peerDependencies": {
"@polkadot/util": "*"
}
}
+5
View File
@@ -0,0 +1,5 @@
// Copyright 2019-2026 @polkadot/wasm-crypto-asmjs authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { asmJsInit } from './cjs/data.js';
export { packageInfo } from './packageInfo.js';
@@ -0,0 +1,6 @@
// Copyright 2019-2026 @polkadot/wasm-crypto-wasm authors & contributors
// SPDX-License-Identifier: Apache-2.0
const data = require('../data.js');
module.exports = data;

Some files were not shown because too many files have changed in this diff Show More