Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
6 changes: 6 additions & 0 deletions .changeset/tough-beers-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ckb-lumos/crypto": minor
"@ckb-lumos/lumos": minor
---

feat: add crypto.randomBytes to replace Node's crypto.randomBytes
1 change: 1 addition & 0 deletions .github/.codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ coverage:
target: auto
threshold: 1%
base: auto
patch: off # disable codecov/patch

parsers:
gcov:
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ jobs:
- uses: pnpm/action-setup@v2
with:
version: 8.6.1
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
cache: "pnpm"
node-version: '20'

- name: Install project dependencies and build
run: |
Expand All @@ -38,9 +39,10 @@ jobs:
- uses: pnpm/action-setup@v2
with:
version: 8.6.1
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
cache: "pnpm"
node-version: '20'

- name: Install project dependencies and build
run: |
Expand All @@ -60,7 +62,7 @@ jobs:
- uses: pnpm/action-setup@v2
with:
version: 8.6.1
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
cache: "pnpm"

Expand Down
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const scopeEnumValues = [
"base",
"bi",
"crypto",
"ckb-indexer",
"common-scripts",
"config-manager",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { randomBytes } from "crypto";
import test from "ava";
import { randomBytes } from "../../crypto/src";
import { Indexer, TransactionCollector } from "../src";
import {
indexerTransactionListThatHaveOneIoTypeInput,
Expand Down
2 changes: 1 addition & 1 deletion packages/codec/tests/bytes-like.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import test from "ava";
import { molecule, number } from "../src";
import { Byte32 } from "../src/blockchain";
import { randomBytes } from "crypto";
import { randomBytes } from "../../crypto/src";
import { equal, concat, hexify } from "../src/bytes";
import { BI } from "@ckb-lumos/bi";
import { bytify } from "../lib/bytes";
Expand Down
2 changes: 1 addition & 1 deletion packages/common-scripts/tests/dao-with-custom-lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { dao } from "../src";
import { Config, predefined } from "@ckb-lumos/config-manager";
import { hexify } from "@ckb-lumos/codec/lib/bytes";
import { Uint64 } from "@ckb-lumos/codec/lib/number";
import { randomBytes } from "node:crypto";
import { randomBytes } from "../../crypto/src";

const { LINA } = predefined;

Expand Down
6 changes: 3 additions & 3 deletions packages/config-manager/tests/refresh.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import test from "ava";
import { spy } from "sinon";
import {
createLatestTypeIdResolver,
createRpcResolver,
FetchOutputsByTxHashes,
refreshScriptConfigs,
} from "../src/refresh";
import { ScriptConfigs } from "../src";
import { hexify } from "@ckb-lumos/codec/lib/bytes";
import { randomBytes } from "node:crypto";
import { OutPoint, Output, Script } from "@ckb-lumos/base";
import { spy } from "sinon";
import { randomBytes } from "../../crypto/src";
import { ScriptConfigs } from "../src";

test("refresh without update", async (t) => {
const scriptConfigs: ScriptConfigs = {
Expand Down
1 change: 1 addition & 0 deletions packages/crypto/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
1 change: 1 addition & 0 deletions packages/crypto/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib
1 change: 1 addition & 0 deletions packages/crypto/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @ckb-lumos/crypto
3 changes: 3 additions & 0 deletions packages/crypto/READMD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `@ckb-lumos/crypto`

Crypto utilities used in Lumos.
50 changes: 50 additions & 0 deletions packages/crypto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "@ckb-lumos/crypto",
"version": "0.23.0-next.0",
"description": "Crypto utilities used in Lumos",
"author": "Tom Wang <[email protected]@gmail.com>",
"homepage": "https://github.com/ckb-js/lumos#readme",
"license": "MIT",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"engines": {
"node": ">=20.0.0"
},
"directories": {
"lib": "lib",
"test": "tests"
},
"files": [
"lib",
"index.d.ts"
],
"repository": {
"type": "git",
"url": "git+https://github.com/ckb-js/lumos.git"
},
"scripts": {
"build": "pnpm run build:types && pnpm run build:js",
"build:types": "tsc --declaration --emitDeclarationOnly",
"build:js": "babel --root-mode upward src --out-dir lib --extensions .ts -s",
"fmt": "prettier --write \"{src,tests,examples}/**/*.ts\" package.json",
"lint": "eslint -c ../../.eslintrc.js \"{src,tests,examples}/**/*.ts\"",
"clean": "shx rm -rf lib",
"test": "ava **/*.test.{js,ts} --timeout=2m"
},
"bugs": {
"url": "https://github.com/ckb-js/lumos/issues"
},
"ava": {
"extensions": [
"ts",
"js"
],
"require": [
"ts-node/register"
]
},
"dependencies": {},
"publishConfig": {
"access": "public"
}
}
29 changes: 29 additions & 0 deletions packages/crypto/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Generates cryptographically secure random bytes.
* @param size The number of random bytes to generate. The `size` must not be greater than 65536.
* @returns A Uint8Array containing the random bytes.
* @throws {RangeError} If `size` is greater than 65536.
*/
export function randomBytes(
size: number
): Uint8Array & { toString(format?: "hex"): string } {
const MAX_BYTES = 65536; // limit of Crypto.getRandomValues()
if (size > MAX_BYTES) {
throw new RangeError(`size must be less than or equal to ${MAX_BYTES}`);
}

const bytes = new Uint8Array(size);
crypto.getRandomValues(bytes);

Object.defineProperty(bytes, "toString", {
value: (format?: "hex") => {
return format === "hex"
? Array.from(bytes)
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("")
: Uint8Array.prototype.toString.call(bytes);
},
});

return bytes;
}
16 changes: 16 additions & 0 deletions packages/crypto/tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import test from "ava";
import { randomBytes } from "../src";
import { hexify } from "../../codec/lib/bytes";

test("randomBytes", (t) => {
const size = 32;
const bytes = randomBytes(size);
t.is(bytes.length, size);
t.is(bytes.toString("hex"), hexify(bytes).slice(2));

const TOO_MANY_BYTES = 65538;
t.throws(() => randomBytes(TOO_MANY_BYTES), {
instanceOf: RangeError,
message: `size must be less than or equal to 65536`,
});
});
8 changes: 8 additions & 0 deletions packages/crypto/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib",
"sourceMap": true
},
"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"]
}
1 change: 1 addition & 0 deletions packages/debugger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@ckb-lumos/base": "0.23.0-next.0",
"@ckb-lumos/bi": "0.23.0-next.0",
"@ckb-lumos/codec": "0.23.0-next.0",
"@ckb-lumos/crypto": "0.23.0-next.0",
"@ckb-lumos/config-manager": "0.23.0-next.0",
"@ckb-lumos/helpers": "0.23.0-next.0",
"@ckb-lumos/rpc": "0.23.0-next.0",
Expand Down
7 changes: 3 additions & 4 deletions packages/debugger/src/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { randomBytes } from "@ckb-lumos/crypto";
import { Header, OutPoint } from "@ckb-lumos/base";
import * as crypto from "crypto";
import { ScriptConfig } from "@ckb-lumos/config-manager";
import { OutputDataLoader } from "./loader";
import { DataLoader, TestContext } from "./types";
Expand All @@ -14,9 +14,8 @@ const TRANSACTION_HASH_LENGTH = 32;

export function mockOutPoint(): OutPoint {
return {
txHash: hexify(crypto.randomBytes(TRANSACTION_HASH_LENGTH)),
index:
"0x" + Uint32.unpack(crypto.randomBytes(Uint32.byteLength)).toString(16),
txHash: hexify(randomBytes(TRANSACTION_HASH_LENGTH)),
index: "0x" + Uint32.unpack(randomBytes(Uint32.byteLength)).toString(16),
};
}

Expand Down
7 changes: 4 additions & 3 deletions packages/debugger/src/executor.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DataLoader, ExecuteResult, Executor } from "./types";
import { TransactionSkeletonType } from "@ckb-lumos/helpers";
import { randomBytes } from "@ckb-lumos/crypto";
import { spawnSync } from "child_process";
import { Hash } from "@ckb-lumos/base";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { parseDebuggerData, parseDebuggerMessage } from "./parse";
import * as crypto from 'crypto';

interface DebuggerOptions {
readonly loader: DataLoader;
Expand Down Expand Up @@ -51,8 +51,9 @@ export class CKBDebugger implements Executor {
*/
private saveTmpTxFile(txSkeleton: TransactionSkeletonType): string {
const debuggerData = parseDebuggerData(txSkeleton, this.loader);
const randomHex = crypto.randomBytes(18).toString('hex');
const tempFileName = `lumos-debugger-data-${randomHex}`
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
const randomHex = randomBytes(18).toString("hex");
const tempFileName = `lumos-debugger-data-${randomHex}`;
const tmpTxPath = path.join(os.tmpdir(), `${tempFileName}.json`);
fs.writeFileSync(tmpTxPath, JSON.stringify(debuggerData));

Expand Down
2 changes: 1 addition & 1 deletion packages/debugger/tests/context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
createScriptRegistry,
} from "@ckb-lumos/experiment-tx-assembler";
import { computeScriptHash } from "@ckb-lumos/base/lib/utils";
import { randomBytes } from "@ckb-lumos/crypto";
import { HexString } from "@ckb-lumos/base";
import { CKBDebugger, CKBDebuggerDownloader, DataLoader } from "../src";
import { TransactionSkeleton } from "@ckb-lumos/helpers";
Expand All @@ -12,7 +13,6 @@ import {
getDefaultConfig,
mockOutPoint,
} from "../src/context";
import { randomBytes } from "crypto";
import { privateKeyToBlake160, signRecoverable } from "@ckb-lumos/hd/lib/key";
import { hexify } from "@ckb-lumos/codec/lib/bytes";
import {
Expand Down
1 change: 1 addition & 0 deletions packages/e2e-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@ckb-lumos/bi": "0.23.0-next.0",
"@ckb-lumos/ckb-indexer": "0.23.0-next.0",
"@ckb-lumos/codec": "0.23.0-next.0",
"@ckb-lumos/crypto": "0.23.0-next.0",
"@ckb-lumos/common-scripts": "0.23.0-next.0",
"@ckb-lumos/config-manager": "0.23.0-next.0",
"@ckb-lumos/hd": "0.23.0-next.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/e2e-test/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Script } from "@ckb-lumos/base";
import { randomBytes } from "@ckb-lumos/crypto";
import { encodeToAddress } from "@ckb-lumos/helpers";
import { randomBytes } from "crypto";
import { key } from "@ckb-lumos/hd";
import { getConfig } from "@ckb-lumos/config-manager";
import { hexify } from "@ckb-lumos/codec/lib/bytes";

// secp256k1 private key is 32-bytes length
/* eslint-disable @typescript-eslint/no-magic-numbers */
export const generateRandomPrivateKey = (): string => hexify(randomBytes(32));

export function asyncSleep(ms: number): Promise<unknown> {
Expand Down
3 changes: 2 additions & 1 deletion packages/hd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
"src"
],
"dependencies": {
"@ckb-lumos/base": "0.23.0-next.0",
"@ckb-lumos/bi": "0.23.0-next.0",
"@ckb-lumos/base": "0.23.0-next.0",
"@ckb-lumos/crypto": "0.23.0-next.0",
"bn.js": "^5.1.3",
"elliptic": "^6.5.4",
"scrypt-js": "^3.0.1",
Expand Down
26 changes: 14 additions & 12 deletions packages/hd/src/keystore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import crypto from "crypto";
import {
Cipher,
ScryptOptions,
createCipheriv,
createDecipheriv,
} from "crypto";
import { Keccak } from "sha3";
import { v4 as uuid } from "uuid";
import { ExtendedPrivateKey } from "./extended_key";
import { randomBytes } from "@ckb-lumos/crypto";
import { HexString } from "@ckb-lumos/base";
import { syncScrypt } from "scrypt-js";

Expand Down Expand Up @@ -94,8 +100,8 @@ export default class Keystore {
// Create an empty keystore object that contains empty private key
static createEmpty(): Keystore {
const saltSize = 32;
const salt: Buffer = crypto.randomBytes(saltSize);
const iv: Buffer = crypto.randomBytes(16);
const salt: Buffer = Buffer.from(randomBytes(saltSize));
const iv: Buffer = Buffer.from(randomBytes(16));
const kdfparams: KdfParams = {
dklen: 32,
salt: salt.toString("hex"),
Expand Down Expand Up @@ -125,8 +131,8 @@ export default class Keystore {
): Keystore {
const saltSize = 32;
const ivSize = 16;
const salt: Buffer = options.salt || crypto.randomBytes(saltSize);
const iv: Buffer = options.iv || crypto.randomBytes(ivSize);
const salt: Buffer = options.salt || Buffer.from(randomBytes(saltSize));
const iv: Buffer = options.iv || Buffer.from(randomBytes(ivSize));
const kdfparams: KdfParams = {
dklen: 32,
salt: salt.toString("hex"),
Expand All @@ -145,11 +151,7 @@ export default class Keystore {
)
);

const cipher: crypto.Cipher = crypto.createCipheriv(
CIPHER,
derivedKey.slice(0, 16),
iv
);
const cipher: Cipher = createCipheriv(CIPHER, derivedKey.slice(0, 16), iv);
if (!cipher) {
throw new UnsupportedCipher();
}
Expand Down Expand Up @@ -190,7 +192,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")
Expand Down Expand Up @@ -239,7 +241,7 @@ export default class Keystore {
);
}

static scryptOptions(kdfparams: KdfParams): crypto.ScryptOptions {
static scryptOptions(kdfparams: KdfParams): ScryptOptions {
return {
N: kdfparams.n,
r: kdfparams.r,
Expand Down
Loading