diff --git a/packages/quantus-crypto/README.md b/packages/quantus-crypto/README.md index d92c2976..4ef8d18a 100644 --- a/packages/quantus-crypto/README.md +++ b/packages/quantus-crypto/README.md @@ -28,6 +28,14 @@ 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 diff --git a/packages/quantus-crypto/package.json b/packages/quantus-crypto/package.json index 4e7ed98c..6b147191 100644 --- a/packages/quantus-crypto/package.json +++ b/packages/quantus-crypto/package.json @@ -18,7 +18,7 @@ "version": "0.1.0", "main": "index.js", "dependencies": { - "@polkadot/wasm-util": "7.5.4", + "fflate": "^0.8.2", "tslib": "^2.7.0" } } diff --git a/packages/quantus-crypto/src/base64.ts b/packages/quantus-crypto/src/base64.ts new file mode 100644 index 00000000..986f48a5 --- /dev/null +++ b/packages/quantus-crypto/src/base64.ts @@ -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(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; +} diff --git a/packages/quantus-crypto/src/init.ts b/packages/quantus-crypto/src/init.ts index eba41cc4..cadb1a18 100644 --- a/packages/quantus-crypto/src/init.ts +++ b/packages/quantus-crypto/src/init.ts @@ -1,12 +1,9 @@ // Copyright 2026 @quantus/crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 -// Deep imports, not the package index. `@polkadot/wasm-util`'s index re-exports -// `packageDetect`, whose only job is a side effect registering the package with -// `@polkadot/util` — a peer dependency we would otherwise inherit for nothing. -// These two subpaths are pure functions with no dependencies at all. -import { base64Decode } from '@polkadot/wasm-util/base64'; -import { unzlibSync } from '@polkadot/wasm-util/fflate'; +import { unzlibSync } from 'fflate'; + +import { base64Decode } from './base64.js'; import { bytes, lenOut } from './bytes.js'; import { initSync } from './generated/quantus_crypto.js'; diff --git a/packages/quantus-crypto/tsconfig.build.json b/packages/quantus-crypto/tsconfig.build.json index 23481326..44c4904c 100644 --- a/packages/quantus-crypto/tsconfig.build.json +++ b/packages/quantus-crypto/tsconfig.build.json @@ -6,14 +6,6 @@ "declaration": true, "outDir": "./build", "rootDir": "./src", - "paths": { - "@polkadot/wasm-util/base64": [ - "wasm-util/build/base64.d.ts" - ], - "@polkadot/wasm-util/fflate": [ - "wasm-util/build/fflate.d.ts" - ] - }, "emitDeclarationOnly": false }, "exclude": [ diff --git a/scripts/test-quantus-js.sh b/scripts/test-quantus-js.sh index d2036026..7b4ce90d 100755 --- a/scripts/test-quantus-js.sh +++ b/scripts/test-quantus-js.sh @@ -4,13 +4,12 @@ # Runs the consumer test against a staged node_modules rather than in-place. # -# In this repo `node_modules/@polkadot/wasm-util` symlinks to the package *source* -# directory, whose package.json carries no `exports` map — only the build output -# does. So a deep import like `@polkadot/wasm-util/base64` resolves for a real -# consumer and fails here, which would make the in-place test wrong in a way that -# has nothing to do with our package. Staging the built artifacts the way an -# install lays them out tests module resolution too, which is half of what can -# break in a published package. +# Staging the built artifact the way an install lays it out tests module +# resolution too, which is half of what can break in a published package — it is +# what caught binaryen 105 producing a wasm that fails to instantiate. +# +# `fflate`, the one runtime dependency, resolves by node walking up to the repo's +# own node_modules, which is exactly what it would do inside a real install. set -e @@ -18,10 +17,9 @@ PKG=packages/quantus-crypto STAGE=$PKG/build-test rm -rf $STAGE -mkdir -p $STAGE/node_modules/@quantus $STAGE/node_modules/@polkadot +mkdir -p $STAGE/node_modules/@quantus cp -r $PKG/build $STAGE/node_modules/@quantus/crypto -cp -r packages/wasm-util/build $STAGE/node_modules/@polkadot/wasm-util echo '{ "name": "quantus-crypto-consumer-test", "type": "module", "version": "0.0.0" }' > $STAGE/package.json cp $PKG/test/consumer.mjs $STAGE/consumer.mjs diff --git a/yarn.lock b/yarn.lock index b8539e99..38a0473b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -614,7 +614,7 @@ __metadata: version: 0.0.0-use.local resolution: "@quantus/crypto@workspace:packages/quantus-crypto" dependencies: - "@polkadot/wasm-util": "npm:7.5.4" + fflate: "npm:^0.8.2" tslib: "npm:^2.7.0" languageName: unknown linkType: soft