Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: reduce bundle size #544

Draft
wants to merge 46 commits into
base: develop
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
caa5661
chore: unnecessary yarn
homura May 7, 2023
e3797f2
chore: missing dependencies
homura May 7, 2023
6d7cbda
chore: update to typescript 5
homura May 7, 2023
489e9ae
chore: remove unnecessary code
homura May 7, 2023
ea82a6e
chore: keep ts-node in same ver
homura May 7, 2023
7808dff
chore: update eslint
homura May 7, 2023
f9a2016
chore(website): correct dependencies
homura May 7, 2023
af5377f
fix: eslint error
homura May 10, 2023
7bb29d4
fix(website): correct the doc org
homura May 10, 2023
7a88d35
chore: move pkg manager to pnpm
homura May 10, 2023
7ece45e
chore: prettier before commit
homura May 10, 2023
95497b6
chore: migrate ci from yarn to pnpm
homura May 11, 2023
86f642b
fix: missing shx
homura May 11, 2023
c1270ec
chore: update lock file
homura May 11, 2023
ab43374
fix: e2e test failed
homura May 11, 2023
6944dc8
chore: merge with the latest
homura May 25, 2023
2abbe87
test(ckb-indexer): optimize test flow
homura May 26, 2023
feecc49
chore: debug ci
homura May 26, 2023
fc32bbe
chore: use npm to replace lerna when test
homura May 26, 2023
04de306
feat(utils): utility function library for lumos
homura Jun 4, 2023
b5eef2c
feat(runner): download/config ckb and light client binaries
homura Jun 4, 2023
00690b2
feat(runner): upgrade to ckb@0.109.x and light-client@0.2.4
homura Jun 4, 2023
08a8d1e
chore: update dependencies
homura Jun 4, 2023
ce5931f
Merge remote-tracking branch 'origin/develop' into pnpm-ts-5
homura Jun 4, 2023
a69db38
chore: bump to 0.20.0-alpha.3
homura Jun 4, 2023
cf458e4
fix(runner): check existence in findFileSync
homura Jun 4, 2023
9234e41
chore: update lockfile
homura Jun 4, 2023
4344178
fix: ensure port are free when running tests
homura Jun 4, 2023
7c4ffd4
chore: upgrade typedoc to build api
homura Jun 5, 2023
e042d44
refactor: remove unused code
homura Jun 5, 2023
ef08748
feat(crypto): low-level crypto primitives pkg for both nodejs and bro…
homura Jun 6, 2023
dbd30f2
chore: bundle playground for lumos
homura Jun 6, 2023
ab5ddd8
chore: remove unnecessary crypto-browserify
homura Jun 6, 2023
cb3b309
chore: update pnpm-related
homura Jun 6, 2023
82b2a96
chore(crypto): ci error
homura Jun 6, 2023
c31567c
chore: typo
homura Jun 7, 2023
f5c83f0
chore: replace yarn with npx/npm
homura Jun 7, 2023
453a962
ci: update to the latest pnpm
homura Jun 7, 2023
146fe8e
refactor(base): remove unused isDeepEqual
homura Jun 7, 2023
72dd1c7
chore: reduce size by bundling via buffer@5.6.0
homura Jun 7, 2023
a4ba1e1
refactor(hd): rm unused scrypt
homura Jun 7, 2023
ecd434b
Merge branch 'pnpm-ts-5' into reduce-bundle-size
homura Jun 7, 2023
5c6be0a
fix: revert to scrypt-js since noble is incompatible
homura Jun 8, 2023
1197215
Merge remote-tracking branch 'ckb-js/develop' into reduce-bundle-size
homura Jul 24, 2023
dbd8b89
chore: incorrect package version
homura Jul 24, 2023
9ac391e
fix: typedoc build error
homura Jul 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ const scopeEnumValues = [
"utils",
"runner",
"e2e-test",
"crypto",
];
const Configuration = {
extends: ["@commitlint/config-conventional"],
2 changes: 2 additions & 0 deletions devtools/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lib
stats.json
10 changes: 10 additions & 0 deletions devtools/bundler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Bundler

A Lumos bundler playground to test, check and analyze the bundled code.

## Usage

```bash
npm run bundle-stats
npm run bundle-analyze
```
29 changes: 29 additions & 0 deletions devtools/bundler/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@ckb-lumos/bundler",
"version": "0.20.0",
"homepage": "https://github.com/ckb-js/lumos#readme",
"bugs": {
"url": "https://github.com/ckb-js/lumos/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ckb-js/lumos.git"
},
"license": "MIT",
"author": "",
"scripts": {
"bundle-stats": "webpack --profile --json > stats.json",
"bundle-analyze": "webpack-bundle-analyzer stats.json"
},
"dependencies": {
"@ckb-lumos/lumos": "0.20.0",
"@types/webpack-bundle-analyzer": "^4.6.0",
"buffer": "^5.6.0",
"fork-ts-checker-webpack-plugin": "^6.4.0",
"ts-loader": "^9.4.3",
"unminified-webpack-plugin": "^3.0.0",
"webpack": "^5.64.1",
"webpack-bundle-analyzer": "^4.9.0",
"webpack-cli": "^4.9.1"
}
}
1 change: 1 addition & 0 deletions devtools/bundler/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "@ckb-lumos/lumos";
8 changes: 8 additions & 0 deletions devtools/bundler/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": ["src"]
}
39 changes: 39 additions & 0 deletions devtools/bundler/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const path = require("path");
const webpack = require("webpack");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");

module.exports = {
mode: "production",
devtool: "source-map",
entry: { output: "./src/index.ts" },
output: {
path: path.join(__dirname, "lib"),
filename: "lumos.min.js",
library: "lumos",
libraryTarget: "umd",
globalObject: "this",
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
options: {},
},
],
},
resolve: {
extensions: [".ts", ".js", ".json"],
fallback: {
// https://www.npmjs.com/package/buffer#usage
buffer: require.resolve("buffer/"),
path: false,
fs: false,
stream: false,
},
},
plugins: [
new ForkTsCheckerWebpackPlugin({ async: false }),
new webpack.ProvidePlugin({ Buffer: ["buffer", "Buffer"] }),
],
};
4 changes: 1 addition & 3 deletions packages/base/package.json
Original file line number Diff line number Diff line change
@@ -48,10 +48,8 @@
"@ckb-lumos/codec": "0.20.0",
"@ckb-lumos/toolkit": "0.20.0",
"@types/blake2b": "^2.1.0",
"@types/lodash.isequal": "^4.5.5",
"blake2b": "^2.1.3",
"js-xxhash": "^1.0.4",
"lodash.isequal": "^4.5.0"
"js-xxhash": "^1.0.4"
},
"devDependencies": {
"jsbi": "^4.1.0"
6 changes: 0 additions & 6 deletions packages/base/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import blake2b, { Blake2b } from "blake2b";
import isEqual from "lodash.isequal";
import { xxHash32 } from "js-xxhash";
import { bytes, number, BytesLike } from "@ckb-lumos/codec";
import { BI, BIish } from "@ckb-lumos/bi";
@@ -170,10 +169,6 @@ function assertHexadecimal(debugPath: string, str: string): void {
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
function isDeepEqual(a: any, b: any): boolean {
return isEqual(a, b);
}
// Buffer.from('TYPE_ID')
const TYPE_ID_CODE_HASH =
"0x00000000000000000000000000000000000000000000000000545950455f4944";
@@ -287,6 +282,5 @@ export {
hashCode,
assertHexString,
assertHexadecimal,
isDeepEqual,
generateTypeIdScript,
};
8 changes: 6 additions & 2 deletions packages/base/tests/since.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const test = require("ava");
const { BI } = require("@ckb-lumos/bi");

const { since, utils } = require("../src");
const { since } = require("../src");

const {
parseSinceCompatible,
@@ -91,7 +91,11 @@ test.before(() => {
test("parsedSince", (t) => {
fixtrues.forEach((v) => {
const parsed = parseSinceCompatible(v.since);
t.true(utils.isDeepEqual(parsed, v.parsed));
t.is(parsed.type, v.parsed.type);
t.is(parsed.relative, v.parsed.relative);
BI.isBI(parsed.value)
? t.true(parsed.value.eq(v.parsed.value))
: t.deepEqual(parsed.value, v.parsed.value);
});
});

1 change: 1 addition & 0 deletions packages/crypto/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
20 changes: 20 additions & 0 deletions packages/crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# @ckb-lumos/crypto

Low-level cryptographic primitives for Lumos, works in both Node.js and browsers. The API is compatible with `node:crypto`

## Usage

The `package.json` defined the entry point for both Node.js and browsers. You can just import

```ts
import { createHash } from "@ckb-lumos/crypto";
```

### Manually

```typescript
// In Node.js
import { createHash } from "@ckb-lumos/crypto";
// In browsers
import { createHash } from "@ckb-lumos/crypto/lib/crypto-browser";
```
58 changes: 58 additions & 0 deletions packages/crypto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@ckb-lumos/crypto",
"version": "0.20.0",
"description": "Crypto library for Lumos",
"author": "",
"homepage": "https://github.com/ckb-js/lumos#readme",
"license": "MIT",
"browser": "./lib/crypto-browser.js",
"types": "lib/crypto.d.ts",
"main": "./lib/crypto.js",
"sideEffects": false,
"engines": {
"node": ">=12.0.0"
},
"directories": {
"lib": "lib",
"test": "tests"
},
"files": [
"lib",
"src"
],
"dependencies": {
"@noble/hashes": "1.3.1",
"@noble/secp256k1": "2.0.0",
"@types/aes-js": "^3.1.1",
"browserify-aes": "^1.2.0",
"scrypt-js": "^3.0.1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ckb-js/lumos.git"
},
"scripts": {
"fmt": "prettier --write \"{src,tests,examples}/**/*.ts\" package.json",
"lint": "eslint -c ../../.eslintrc.js \"{src,tests,examples}/**/*.ts\"",
"build": "npm run build:types && npm run build:js",
"build:types": "tsc --declaration --emitDeclarationOnly",
"build:js": "babel --root-mode upward src --out-dir lib --extensions .ts -s",
"clean": "rm -rf lib",
"prepublishOnly": "npm run clean && npm run build",
"release": "npm publish"
},
"bugs": {
"url": "https://github.com/ckb-js/lumos/issues"
},
"ava": {
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
},
"publishConfig": {
"access": "public"
}
}
67 changes: 67 additions & 0 deletions packages/crypto/src/crypto-browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="./third.d.ts" />
import { hmac } from "@noble/hashes/hmac";
import { sha512 } from "@noble/hashes/sha512";
import { sha256 } from "@noble/hashes/sha256";
import { ripemd160 } from "@noble/hashes/ripemd160";
// the noble/hashes is not compatible with the https://ethereum.org/en/developers/docs/data-structures-and-encoding/web3-secret-storage/#scrypt
// import { scrypt } from "@noble/hashes/scrypt";
import { randomBytes as _randomBytes } from "@noble/hashes/utils";
import { pbkdf2 as _pbkdf2 } from "@noble/hashes/pbkdf2";
import type { Hash, HashAlgo } from "./types";
// TODO may replace with the crypto.subtle API
import {
createCipheriv as _createCipheriv,
createDecipheriv as _createDecipheriv,
} from "browserify-aes";
import { Cipher } from "./types";

function _createHash(algorithm: HashAlgo) {
if (algorithm === "sha512") return sha512;
if (algorithm === "sha256") return sha256;
if (algorithm === "ripemd160") return ripemd160;
throw new Error(`Unknown hash algorithm ${algorithm}`);
}

export function createHash(algorithm: HashAlgo): Hash {
return _createHash(algorithm).create();
}

export function createHmac(algorithm: HashAlgo, key: Uint8Array): Hash {
return hmac.create(_createHash(algorithm), key);
}

export function randomBytes(bytesLen: number): Uint8Array {
return _randomBytes(bytesLen);
}

export function createCipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher {
return _createCipheriv(algorithm, key, iv);
}

export function createDecipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher {
return _createDecipheriv(algorithm, key, iv);
}

export function pbkdf2Sync(
password: Uint8Array,
salt: Uint8Array,
iterations: number,
keyLen: number,
digest: HashAlgo
): Uint8Array {
return _pbkdf2(_createHash(digest), password, salt, {
dkLen: keyLen,
c: iterations,
});
}

export { scryptSync, scrypt } from "./scrypt";
50 changes: 50 additions & 0 deletions packages/crypto/src/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
createHmac as _createHmac,
createHash as _createHash,
scryptSync as _scryptSync,
randomBytes as _randomBytes,
createCipheriv as _createCipheriv,
createDecipheriv as _createDecipheriv,
pbkdf2Sync as _pbkdf2Sync,
} from "node:crypto";
import type { Cipher, Hash, HashAlgo } from "./types";

export function createHash(algorithm: HashAlgo): Hash {
return _createHash(algorithm);
}

export function createHmac(algorithm: HashAlgo, key: Uint8Array): Hash {
return _createHmac(algorithm, key);
}

export function randomBytes(bytesLen: number): Uint8Array {
return _randomBytes(bytesLen);
}

export function createCipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher {
return _createCipheriv(algorithm, key, iv);
}

export function createDecipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher {
return _createDecipheriv(algorithm, key, iv);
}

export function pbkdf2Sync(
password: Uint8Array,
salt: Uint8Array,
iterations: number,
keyLen: number,
digest: HashAlgo
): Uint8Array {
return _pbkdf2Sync(password, salt, iterations, keyLen, digest);
}

export { scryptSync, scrypt } from "./scrypt";
32 changes: 32 additions & 0 deletions packages/crypto/src/scrypt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { syncScrypt as _scryptSync, scrypt as _scrypt } from "scrypt-js";
import { ScryptOptions } from "./types";

function assertOptions(
options: ScryptOptions
): asserts options is Required<ScryptOptions> {
if (!options.r || !options.p || !options.N) {
throw new Error(
`Invalid scrypt options ${JSON.stringify(options)}, r, p, N are required`
);
}
}

export function scryptSync(
password: Uint8Array,
salt: Uint8Array,
dkLen: number,
options: ScryptOptions
): Uint8Array {
assertOptions(options);
return _scryptSync(password, salt, options.N, options.r, options.p, dkLen);
}

export function scrypt(
password: Uint8Array,
salt: Uint8Array,
dkLen: number,
options: ScryptOptions
): Promise<Uint8Array> {
assertOptions(options);
return _scrypt(password, salt, options.N, options.r, options.p, dkLen);
}
18 changes: 18 additions & 0 deletions packages/crypto/src/third.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
declare module "browserify-aes" {
interface Cipher {
update(data: Uint8Array): Uint8Array;
final(): Uint8Array;
}

export function createCipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher;

export function createDecipheriv(
algorithm: string,
key: Uint8Array,
iv: Uint8Array
): Cipher;
}
22 changes: 22 additions & 0 deletions packages/crypto/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface Hash {
update(data: Uint8Array): Hash;
digest(): Uint8Array;
}

export type HashAlgo = "sha512" | "sha256" | "ripemd160";

export type CreateHmac = (algorithm: HashAlgo, bytes: Uint8Array) => Hash;

export type ScryptOptions = {
// cost factor
N?: number;
// block size
r?: number;
// parallelization
p?: number;
};

export interface Cipher {
update(data: Uint8Array): Uint8Array;
final(): Uint8Array;
}
7 changes: 7 additions & 0 deletions packages/crypto/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib"
},
"include": ["src"]
}
4 changes: 4 additions & 0 deletions packages/crypto/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["../../typedoc.base.json"],
"entryPoints": ["src/index.ts"]
}
3 changes: 1 addition & 2 deletions packages/hd/README.md
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ resolve: {
buffer: require.resolve('buffer/'),
stream: require.resolve('stream-browserify'),
path: require.resolve('path-browserify'),
crypto: require.resolve('crypto-browserify'),
},
plugins: [
new webpack.ProvidePlugin({
@@ -55,4 +54,4 @@ resolve: {
}
```

You'll need to install `buffer`, `stream-browserify`, `path-browserify` and `crypto-browserify` also.
You'll need to install `buffer`, `stream-browserify`, `path-browserify` also.
11 changes: 7 additions & 4 deletions packages/hd/package.json
Original file line number Diff line number Diff line change
@@ -21,9 +21,10 @@
"dependencies": {
"@ckb-lumos/base": "0.20.0",
"@ckb-lumos/bi": "0.20.0",
"bn.js": "^5.1.3",
"@ckb-lumos/codec": "0.20.0",
"@ckb-lumos/crypto": "0.20.0",
"bn.js": "^4.11.6",
"elliptic": "^6.5.4",
"scrypt-js": "^3.0.1",
"sha3": "^2.1.3",
"uuid": "^8.3.0"
},
@@ -34,8 +35,10 @@
"scripts": {
"fmt": "prettier --write \"{src,tests}/**/*.ts\" package.json",
"lint": "eslint -c ../../.eslintrc.js \"{src,tests}/**/*.ts\"",
"test": "ava **/*.test.ts --timeout=5m",
"build": "pnpm run build:types && pnpm run build:js",
"test": "npm run test:node && npm run test:browser",
"test:node": "ava **/*.test.ts --timeout=5m",
"test:browser": "echo 'export * from \"@ckb-lumos/crypto/lib/crypto-browser\"' > src/crypto.ts && ava **/*.test.ts --timeout=5m && echo 'export * from \"@ckb-lumos/crypto\"' > src/crypto.ts",
"build": "npm run build:types && npm run build:js",
"build:types": "tsc --declaration --emitDeclarationOnly",
"build:js": "babel --root-mode upward src --out-dir lib --extensions .ts -s",
"clean": "rm -rf lib"
1 change: 1 addition & 0 deletions packages/hd/src/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "@ckb-lumos/crypto";
31 changes: 18 additions & 13 deletions packages/hd/src/keychain.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import crypto from "crypto";
import { ec as EC } from "elliptic";
import BN from "bn.js";
import { privateToPublic } from "./key";
import { createHash, createHmac } from "./crypto";

const ec = new EC("secp256k1");

@@ -12,11 +12,11 @@ export default class Keychain {
privateKey: Buffer = EMPTY_BUFFER;
publicKey: Buffer = EMPTY_BUFFER;
chainCode: Buffer = EMPTY_BUFFER;
index: number = 0;
depth: number = 0;
index = 0;
depth = 0;
identifier: Buffer = EMPTY_BUFFER;
fingerprint: number = 0;
parentFingerprint: number = 0;
fingerprint = 0;
parentFingerprint = 0;

constructor(privateKey: Buffer, chainCode: Buffer) {
this.privateKey = privateKey;
@@ -33,11 +33,13 @@ export default class Keychain {
}

public static fromSeed(seed: Buffer): Keychain {
const i = crypto
.createHmac("sha512", Buffer.from("Bitcoin seed", "utf8"))
const i = createHmac("sha512", Buffer.from("Bitcoin seed", "utf8"))
.update(seed)
.digest();
const keychain = new Keychain(i.slice(0, 32), i.slice(32));
const keychain = new Keychain(
Buffer.from(i.slice(0, 32)),
Buffer.from(i.slice(32))
);
keychain.calculateFingerprint();
return keychain;
}
@@ -47,7 +49,7 @@ export default class Keychain {
public static fromPublicKey(
publicKey: Buffer,
chainCode: Buffer,
path: String
path: string
): Keychain {
const keychain = new Keychain(EMPTY_BUFFER, chainCode);
keychain.publicKey = publicKey;
@@ -74,7 +76,9 @@ export default class Keychain {
data = Buffer.concat([this.publicKey, indexBuffer]);
}

const i = crypto.createHmac("sha512", this.chainCode).update(data).digest();
const i = Buffer.from(
createHmac("sha512", this.chainCode).update(data).digest()
);
const il = i.slice(0, 32);
const ir = i.slice(32);

@@ -102,6 +106,7 @@ export default class Keychain {
return this;
}

// eslint-disable-next-line @typescript-eslint/no-this-alias
let bip32: Keychain = this;

let entries = path.split("/");
@@ -117,13 +122,13 @@ export default class Keychain {
return bip32;
}

isNeutered(): Boolean {
isNeutered(): boolean {
return this.privateKey === EMPTY_BUFFER;
}

hash160(data: Buffer): Buffer {
const sha256 = crypto.createHash("sha256").update(data).digest();
return crypto.createHash("ripemd160").update(sha256).digest();
const sha256 = createHash("sha256").update(data).digest();
return Buffer.from(createHash("ripemd160").update(sha256).digest());
}

private static privateKeyAdd(privateKey: Buffer, factor: Buffer): Buffer {
61 changes: 35 additions & 26 deletions packages/hd/src/keystore.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import crypto from "crypto";
import { Keccak } from "sha3";
import { v4 as uuid } from "uuid";
import { ExtendedPrivateKey } from "./extended_key";
import { HexString } from "@ckb-lumos/base";
import { syncScrypt } from "scrypt-js";
import {
createCipheriv,
createDecipheriv,
randomBytes,
scryptSync,
} from "./crypto";

export type HexStringWithoutPrefix = string;

@@ -123,8 +127,8 @@ export default class Keystore {

// Create an empty keystore object that contains empty private key
static createEmpty(): Keystore {
const salt: Buffer = crypto.randomBytes(32);
const iv: Buffer = crypto.randomBytes(16);
const salt: Buffer = Buffer.from(randomBytes(32));
const iv: Buffer = Buffer.from(randomBytes(16));
const kdfparams: KdfParams = {
dklen: 32,
salt: salt.toString("hex"),
@@ -152,8 +156,8 @@ export default class Keystore {
password: string,
options: { salt?: Buffer; iv?: Buffer } = {}
): Keystore {
const salt: Buffer = options.salt || crypto.randomBytes(32);
const iv: Buffer = options.iv || crypto.randomBytes(16);
const salt: Buffer = options.salt || Buffer.from(randomBytes(32));
const iv: Buffer = options.iv || Buffer.from(randomBytes(16));
const kdfparams: KdfParams = {
dklen: 32,
salt: salt.toString("hex"),
@@ -162,21 +166,14 @@ export default class Keystore {
p: 1,
};
const derivedKey: Buffer = Buffer.from(
syncScrypt(
Buffer.from(password),
salt,
kdfparams.n,
kdfparams.r,
kdfparams.p,
kdfparams.dklen
)
scryptSync(Buffer.from(password), salt, kdfparams.dklen, {
N: kdfparams.n,
r: kdfparams.r,
p: kdfparams.p,
})
);

const cipher: crypto.Cipher = crypto.createCipheriv(
CIPHER,
derivedKey.slice(0, 16),
iv
);
const cipher = createCipheriv(CIPHER, derivedKey.slice(0, 16), iv);
if (!cipher) {
throw new UnsupportedCipher();
}
@@ -214,7 +211,7 @@ export default class Keystore {
if (Keystore.mac(derivedKey, ciphertext) !== this.crypto.mac) {
throw new IncorrectPassword();
}
const decipher = crypto.createDecipheriv(
const decipher = createDecipheriv(
this.crypto.cipher,
derivedKey.slice(0, 16),
Buffer.from(this.crypto.cipherparams.iv, "hex")
@@ -240,13 +237,15 @@ export default class Keystore {
derivedKey(password: string): Buffer {
const { kdfparams } = this.crypto;
return Buffer.from(
syncScrypt(
scryptSync(
Buffer.from(password),
Buffer.from(kdfparams.salt, "hex"),
kdfparams.n,
kdfparams.r,
kdfparams.p,
kdfparams.dklen
kdfparams.dklen,
{
N: kdfparams.n,
r: kdfparams.r,
p: kdfparams.p,
}
)
);
}
@@ -257,7 +256,7 @@ export default class Keystore {
.digest("hex");
}

static scryptOptions(kdfparams: KdfParams): crypto.ScryptOptions {
static scryptOptions(kdfparams: KdfParams): ScryptOptions {
return {
N: kdfparams.n,
r: kdfparams.r,
@@ -266,3 +265,13 @@ export default class Keystore {
};
}
}

interface ScryptOptions {
cost?: number | undefined;
blockSize?: number | undefined;
parallelization?: number | undefined;
N?: number | undefined;
r?: number | undefined;
p?: number | undefined;
maxmem?: number | undefined;
}
46 changes: 12 additions & 34 deletions packages/hd/src/mnemonic/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import crypto from "crypto";
import wordList from "./word_list";
import { HexString } from "@ckb-lumos/base";
import { createHash, pbkdf2Sync, randomBytes } from "../crypto";
import { bytes } from "@ckb-lumos/codec";

const RADIX = 2048;
const PBKDF2_ROUNDS = 2048;
@@ -28,7 +29,7 @@ if (wordList.length !== RADIX) {
);
}

function bytesToBinary(bytes: Buffer): string {
function bytesToBinary(bytes: Uint8Array): string {
return bytes.reduce((binary, byte) => {
return binary + byte.toString(2).padStart(8, "0");
}, "");
@@ -37,57 +38,35 @@ function bytesToBinary(bytes: Buffer): string {
function deriveChecksumBits(entropyBuffer: Buffer): string {
const ENT = entropyBuffer.length * 8;
const CS = ENT / 32;
const hash = crypto.createHash("sha256").update(entropyBuffer).digest();
const hash = createHash("sha256").update(entropyBuffer).digest();
return bytesToBinary(hash).slice(0, CS);
}

function salt(password: string = ""): string {
function salt(password = ""): string {
return `mnemonic${password}`;
}

export function mnemonicToSeedSync(
mnemonic: string = "",
password: string = ""
): Buffer {
export function mnemonicToSeedSync(mnemonic = "", password = ""): Buffer {
const mnemonicBuffer = Buffer.from(mnemonic.normalize("NFKD"), "utf8");
const saltBuffer = Buffer.from(salt(password.normalize("NFKD")), "utf8");
return crypto.pbkdf2Sync(
mnemonicBuffer,
saltBuffer,
PBKDF2_ROUNDS,
KEY_LEN,
"sha512"
return Buffer.from(
pbkdf2Sync(mnemonicBuffer, saltBuffer, PBKDF2_ROUNDS, KEY_LEN, "sha512")
);
}

export function mnemonicToSeed(
mnemonic: string = "",
password: string = ""
): Promise<Buffer> {
export function mnemonicToSeed(mnemonic = "", password = ""): Promise<Buffer> {
return new Promise((resolve, reject) => {
try {
const mnemonicBuffer = Buffer.from(mnemonic.normalize("NFKD"), "utf8");
const saltBuffer = Buffer.from(salt(password.normalize("NFKD")), "utf8");
crypto.pbkdf2(
mnemonicBuffer,
saltBuffer,
PBKDF2_ROUNDS,
KEY_LEN,
"sha512",
(err, data) => {
if (err) {
reject(err);
}
resolve(data);
}
);
pbkdf2Sync(mnemonicBuffer, saltBuffer, PBKDF2_ROUNDS, KEY_LEN, "sha512");
} catch (error) {
reject(error);
}
});
}

export function mnemonicToEntropy(mnemonic: string = ""): HexString {
export function mnemonicToEntropy(mnemonic = ""): HexString {
const words = mnemonic.normalize("NFKD").split(" ");
if (words.length < MIN_WORDS_SIZE) {
throw new Error(WORDS_TOO_SHORT);
@@ -172,8 +151,7 @@ export function validateMnemonic(mnemonic: string): boolean {
// Generate 12 words mnemonic code
export function generateMnemonic(): string {
const entropySize = 16;
const entropy: HexString =
"0x" + crypto.randomBytes(entropySize).toString("hex");
const entropy: HexString = bytes.hexify(randomBytes(entropySize));
return entropyToMnemonic(entropy);
}

1 change: 0 additions & 1 deletion packages/lumos/package.json
Original file line number Diff line number Diff line change
@@ -46,7 +46,6 @@
},
"devDependencies": {
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"fork-ts-checker-webpack-plugin": "^6.4.0",
"ts-loader": "^9.2.6",
"unminified-webpack-plugin": "^3.0.0",
1 change: 0 additions & 1 deletion packages/lumos/webpack.config.js
Original file line number Diff line number Diff line change
@@ -32,7 +32,6 @@ module.exports = {
fallback: {
// https://www.npmjs.com/package/buffer#usage
buffer: require.resolve("buffer/"),
crypto: require.resolve("crypto-browserify"),
path: false,
fs: false,
stream: false,
412 changes: 153 additions & 259 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion typedoc.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@
"packages/e2e-test",
"packages/testkit",
"packages/molecule",
"packages/toolkit"
"packages/toolkit",
"packages/crypto"
],
"logLevel": "Verbose",
"skipErrorChecking": true,
1 change: 0 additions & 1 deletion website/docusaurus.config.js
Original file line number Diff line number Diff line change
@@ -67,7 +67,6 @@ const config = {
return {
resolve: {
fallback: {
crypto: require.resolve("crypto-browserify"),
buffer: require.resolve("buffer/"),
path: false,
fs: false,