@ckb-ccc/core 0.0.10-alpha.7 → 0.0.10-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/barrel.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./client/index.js";
5
5
  export * from "./fixedPoint/index.js";
6
6
  export * from "./hasher/index.js";
7
7
  export * from "./hex/index.js";
8
+ export * from "./keystore/index.js";
8
9
  export * from "./num/index.js";
9
10
  export * from "./signer/index.js";
10
11
  export * from "./utils/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
package/dist/barrel.js CHANGED
@@ -5,6 +5,7 @@ export * from "./client/index.js";
5
5
  export * from "./fixedPoint/index.js";
6
6
  export * from "./hasher/index.js";
7
7
  export * from "./hex/index.js";
8
+ export * from "./keystore/index.js";
8
9
  export * from "./num/index.js";
9
10
  export * from "./signer/index.js";
10
11
  export * from "./utils/index.js";
@@ -0,0 +1,25 @@
1
+ import { Bytes, BytesLike } from "../bytes/index.js";
2
+ export declare function keystoreEncrypt(privateKeyLike: BytesLike, chainCodeLike: BytesLike, password: string): Promise<{
3
+ id: string;
4
+ crypto: {
5
+ ciphertext: string;
6
+ cipherparams: {
7
+ iv: string;
8
+ };
9
+ cipher: string;
10
+ kdf: string;
11
+ kdfparams: {
12
+ dklen: number;
13
+ salt: string;
14
+ n: number;
15
+ r: number;
16
+ p: number;
17
+ };
18
+ mac: string;
19
+ };
20
+ }>;
21
+ export declare function keystoreDecrypt(keystore: unknown, password: string): Promise<{
22
+ privateKey: Bytes;
23
+ chainCode: Bytes;
24
+ }>;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keystore/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,SAAS,EAA0B,MAAM,mBAAmB,CAAC;AAgB7E,wBAAsB,eAAe,CACnC,cAAc,EAAE,SAAS,EACzB,aAAa,EAAE,SAAS,EACxB,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;GAsCjB;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IACT,UAAU,EAAE,KAAK,CAAC;IAClB,SAAS,EAAE,KAAK,CAAC;CAClB,CAAC,CAoED"}
@@ -0,0 +1,100 @@
1
+ import { ctr } from "@noble/ciphers/aes";
2
+ import { scryptAsync } from "@noble/hashes/scrypt";
3
+ import { keccak_256 } from "@noble/hashes/sha3";
4
+ import { randomBytes } from "@noble/hashes/utils";
5
+ import { bytesConcat, bytesFrom } from "../bytes/index.js";
6
+ import { hexFrom } from "../hex/index.js";
7
+ // The parameter r ("blockSize")
8
+ const DEFAULT_SCRYPT_PARAM_R = 8;
9
+ // The parallelization parameter p
10
+ const DEFAULT_SCRYPT_PARAM_P = 1;
11
+ // The CPU/Memory cost parameter N
12
+ const DEFAULT_SCRYPT_PARAM_N = 262144;
13
+ function mac(derivedKey, cipherText) {
14
+ return hexFrom(keccak_256(bytesConcat(derivedKey.slice(16, 32), cipherText))).slice(2);
15
+ }
16
+ export async function keystoreEncrypt(privateKeyLike, chainCodeLike, password) {
17
+ const salt = randomBytes(32);
18
+ const iv = randomBytes(16);
19
+ const kdfparams = {
20
+ dklen: 32,
21
+ salt: hexFrom(salt).slice(2),
22
+ n: DEFAULT_SCRYPT_PARAM_N,
23
+ r: DEFAULT_SCRYPT_PARAM_R,
24
+ p: DEFAULT_SCRYPT_PARAM_P,
25
+ };
26
+ const derivedKey = await scryptAsync(bytesFrom(password, "utf8"), salt, {
27
+ N: kdfparams.n,
28
+ r: kdfparams.r,
29
+ p: kdfparams.p,
30
+ dkLen: kdfparams.dklen,
31
+ });
32
+ const cipher = ctr(derivedKey.slice(0, 16), iv.map((v) => v));
33
+ const ciphertext = cipher.encrypt(bytesConcat(bytesFrom(privateKeyLike), bytesFrom(chainCodeLike)));
34
+ return {
35
+ id: hexFrom(randomBytes(16)).slice(2),
36
+ crypto: {
37
+ ciphertext: hexFrom(ciphertext).slice(2),
38
+ cipherparams: {
39
+ iv: hexFrom(iv).slice(2),
40
+ },
41
+ cipher: "aes-128-ctr",
42
+ kdf: "scrypt",
43
+ kdfparams,
44
+ mac: mac(derivedKey, ciphertext),
45
+ },
46
+ };
47
+ }
48
+ export async function keystoreDecrypt(keystore, password) {
49
+ if (typeof keystore !== "object" ||
50
+ keystore === null ||
51
+ !("crypto" in keystore)) {
52
+ throw Error("Invalid keystore");
53
+ }
54
+ const crypto = keystore.crypto;
55
+ if (typeof crypto !== "object" ||
56
+ crypto === null ||
57
+ !("kdfparams" in crypto) ||
58
+ !("ciphertext" in crypto) ||
59
+ typeof crypto.ciphertext !== "string" ||
60
+ !("mac" in crypto) ||
61
+ typeof crypto.mac !== "string" ||
62
+ !("cipherparams" in crypto) ||
63
+ typeof crypto.cipherparams !== "object" ||
64
+ crypto.cipherparams === null ||
65
+ !("iv" in crypto.cipherparams) ||
66
+ typeof crypto.cipherparams.iv !== "string") {
67
+ throw Error("Invalid crypto");
68
+ }
69
+ const kdfparams = crypto.kdfparams;
70
+ if (typeof kdfparams !== "object" ||
71
+ kdfparams === null ||
72
+ !("n" in kdfparams) ||
73
+ typeof kdfparams.n !== "number" ||
74
+ !("r" in kdfparams) ||
75
+ typeof kdfparams.r !== "number" ||
76
+ !("p" in kdfparams) ||
77
+ typeof kdfparams.p !== "number" ||
78
+ !("dklen" in kdfparams) ||
79
+ typeof kdfparams.dklen !== "number" ||
80
+ !("salt" in kdfparams) ||
81
+ typeof kdfparams.salt !== "string") {
82
+ throw Error("Invalid kdfparams");
83
+ }
84
+ const derivedKey = await scryptAsync(bytesFrom(password, "utf8"), bytesFrom(kdfparams.salt), {
85
+ N: kdfparams.n,
86
+ r: kdfparams.r,
87
+ p: kdfparams.p,
88
+ dkLen: kdfparams.dklen,
89
+ });
90
+ const ciphertext = bytesFrom(crypto.ciphertext);
91
+ if (mac(derivedKey, ciphertext) !== crypto.mac) {
92
+ throw Error("Invalid password");
93
+ }
94
+ const cipher = ctr(derivedKey.slice(0, 16), bytesFrom(crypto.cipherparams.iv));
95
+ const result = cipher.decrypt(ciphertext);
96
+ return {
97
+ privateKey: result.slice(0, 32),
98
+ chainCode: result.slice(32),
99
+ };
100
+ }
@@ -5,6 +5,7 @@ export * from "./client/index.js";
5
5
  export * from "./fixedPoint/index.js";
6
6
  export * from "./hasher/index.js";
7
7
  export * from "./hex/index.js";
8
+ export * from "./keystore/index.js";
8
9
  export * from "./num/index.js";
9
10
  export * from "./signer/index.js";
10
11
  export * from "./utils/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../src/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
@@ -21,6 +21,7 @@ __exportStar(require("./client/index.js"), exports);
21
21
  __exportStar(require("./fixedPoint/index.js"), exports);
22
22
  __exportStar(require("./hasher/index.js"), exports);
23
23
  __exportStar(require("./hex/index.js"), exports);
24
+ __exportStar(require("./keystore/index.js"), exports);
24
25
  __exportStar(require("./num/index.js"), exports);
25
26
  __exportStar(require("./signer/index.js"), exports);
26
27
  __exportStar(require("./utils/index.js"), exports);
@@ -0,0 +1,25 @@
1
+ import { Bytes, BytesLike } from "../bytes/index.js";
2
+ export declare function keystoreEncrypt(privateKeyLike: BytesLike, chainCodeLike: BytesLike, password: string): Promise<{
3
+ id: string;
4
+ crypto: {
5
+ ciphertext: string;
6
+ cipherparams: {
7
+ iv: string;
8
+ };
9
+ cipher: string;
10
+ kdf: string;
11
+ kdfparams: {
12
+ dklen: number;
13
+ salt: string;
14
+ n: number;
15
+ r: number;
16
+ p: number;
17
+ };
18
+ mac: string;
19
+ };
20
+ }>;
21
+ export declare function keystoreDecrypt(keystore: unknown, password: string): Promise<{
22
+ privateKey: Bytes;
23
+ chainCode: Bytes;
24
+ }>;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keystore/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,SAAS,EAA0B,MAAM,mBAAmB,CAAC;AAgB7E,wBAAsB,eAAe,CACnC,cAAc,EAAE,SAAS,EACzB,aAAa,EAAE,SAAS,EACxB,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;GAsCjB;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IACT,UAAU,EAAE,KAAK,CAAC;IAClB,SAAS,EAAE,KAAK,CAAC;CAClB,CAAC,CAoED"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.keystoreDecrypt = exports.keystoreEncrypt = void 0;
4
+ const aes_1 = require("@noble/ciphers/aes");
5
+ const scrypt_1 = require("@noble/hashes/scrypt");
6
+ const sha3_1 = require("@noble/hashes/sha3");
7
+ const utils_1 = require("@noble/hashes/utils");
8
+ const index_js_1 = require("../bytes/index.js");
9
+ const index_js_2 = require("../hex/index.js");
10
+ // The parameter r ("blockSize")
11
+ const DEFAULT_SCRYPT_PARAM_R = 8;
12
+ // The parallelization parameter p
13
+ const DEFAULT_SCRYPT_PARAM_P = 1;
14
+ // The CPU/Memory cost parameter N
15
+ const DEFAULT_SCRYPT_PARAM_N = 262144;
16
+ function mac(derivedKey, cipherText) {
17
+ return (0, index_js_2.hexFrom)((0, sha3_1.keccak_256)((0, index_js_1.bytesConcat)(derivedKey.slice(16, 32), cipherText))).slice(2);
18
+ }
19
+ async function keystoreEncrypt(privateKeyLike, chainCodeLike, password) {
20
+ const salt = (0, utils_1.randomBytes)(32);
21
+ const iv = (0, utils_1.randomBytes)(16);
22
+ const kdfparams = {
23
+ dklen: 32,
24
+ salt: (0, index_js_2.hexFrom)(salt).slice(2),
25
+ n: DEFAULT_SCRYPT_PARAM_N,
26
+ r: DEFAULT_SCRYPT_PARAM_R,
27
+ p: DEFAULT_SCRYPT_PARAM_P,
28
+ };
29
+ const derivedKey = await (0, scrypt_1.scryptAsync)((0, index_js_1.bytesFrom)(password, "utf8"), salt, {
30
+ N: kdfparams.n,
31
+ r: kdfparams.r,
32
+ p: kdfparams.p,
33
+ dkLen: kdfparams.dklen,
34
+ });
35
+ const cipher = (0, aes_1.ctr)(derivedKey.slice(0, 16), iv.map((v) => v));
36
+ const ciphertext = cipher.encrypt((0, index_js_1.bytesConcat)((0, index_js_1.bytesFrom)(privateKeyLike), (0, index_js_1.bytesFrom)(chainCodeLike)));
37
+ return {
38
+ id: (0, index_js_2.hexFrom)((0, utils_1.randomBytes)(16)).slice(2),
39
+ crypto: {
40
+ ciphertext: (0, index_js_2.hexFrom)(ciphertext).slice(2),
41
+ cipherparams: {
42
+ iv: (0, index_js_2.hexFrom)(iv).slice(2),
43
+ },
44
+ cipher: "aes-128-ctr",
45
+ kdf: "scrypt",
46
+ kdfparams,
47
+ mac: mac(derivedKey, ciphertext),
48
+ },
49
+ };
50
+ }
51
+ exports.keystoreEncrypt = keystoreEncrypt;
52
+ async function keystoreDecrypt(keystore, password) {
53
+ if (typeof keystore !== "object" ||
54
+ keystore === null ||
55
+ !("crypto" in keystore)) {
56
+ throw Error("Invalid keystore");
57
+ }
58
+ const crypto = keystore.crypto;
59
+ if (typeof crypto !== "object" ||
60
+ crypto === null ||
61
+ !("kdfparams" in crypto) ||
62
+ !("ciphertext" in crypto) ||
63
+ typeof crypto.ciphertext !== "string" ||
64
+ !("mac" in crypto) ||
65
+ typeof crypto.mac !== "string" ||
66
+ !("cipherparams" in crypto) ||
67
+ typeof crypto.cipherparams !== "object" ||
68
+ crypto.cipherparams === null ||
69
+ !("iv" in crypto.cipherparams) ||
70
+ typeof crypto.cipherparams.iv !== "string") {
71
+ throw Error("Invalid crypto");
72
+ }
73
+ const kdfparams = crypto.kdfparams;
74
+ if (typeof kdfparams !== "object" ||
75
+ kdfparams === null ||
76
+ !("n" in kdfparams) ||
77
+ typeof kdfparams.n !== "number" ||
78
+ !("r" in kdfparams) ||
79
+ typeof kdfparams.r !== "number" ||
80
+ !("p" in kdfparams) ||
81
+ typeof kdfparams.p !== "number" ||
82
+ !("dklen" in kdfparams) ||
83
+ typeof kdfparams.dklen !== "number" ||
84
+ !("salt" in kdfparams) ||
85
+ typeof kdfparams.salt !== "string") {
86
+ throw Error("Invalid kdfparams");
87
+ }
88
+ const derivedKey = await (0, scrypt_1.scryptAsync)((0, index_js_1.bytesFrom)(password, "utf8"), (0, index_js_1.bytesFrom)(kdfparams.salt), {
89
+ N: kdfparams.n,
90
+ r: kdfparams.r,
91
+ p: kdfparams.p,
92
+ dkLen: kdfparams.dklen,
93
+ });
94
+ const ciphertext = (0, index_js_1.bytesFrom)(crypto.ciphertext);
95
+ if (mac(derivedKey, ciphertext) !== crypto.mac) {
96
+ throw Error("Invalid password");
97
+ }
98
+ const cipher = (0, aes_1.ctr)(derivedKey.slice(0, 16), (0, index_js_1.bytesFrom)(crypto.cipherparams.iv));
99
+ const result = cipher.decrypt(ciphertext);
100
+ return {
101
+ privateKey: result.slice(0, 32),
102
+ chainCode: result.slice(32),
103
+ };
104
+ }
105
+ exports.keystoreDecrypt = keystoreDecrypt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/core",
3
- "version": "0.0.10-alpha.7",
3
+ "version": "0.0.10-alpha.8",
4
4
  "description": "Core of CCC - CKBer's Codebase",
5
5
  "author": "Hanssen0 <hanssen0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -59,6 +59,7 @@
59
59
  "dependencies": {
60
60
  "@ckb-lumos/helpers": "^0.22.2",
61
61
  "@joyid/ckb": "^1.0.1",
62
+ "@noble/ciphers": "^0.5.3",
62
63
  "@noble/curves": "^1.4.2",
63
64
  "@noble/hashes": "^1.4.0",
64
65
  "abort-controller": "^3.0.0",
@@ -69,5 +70,5 @@
69
70
  "cross-fetch": "^4.0.0",
70
71
  "ethers": "^6.13.1"
71
72
  },
72
- "gitHead": "0ef41cccd370b5a190b09a4da45a29752b5383ff"
73
+ "gitHead": "b7481af6b71cd5d525462984750c9f0cb20800af"
73
74
  }
package/src/barrel.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./client/index.js";
5
5
  export * from "./fixedPoint/index.js";
6
6
  export * from "./hasher/index.js";
7
7
  export * from "./hex/index.js";
8
+ export * from "./keystore/index.js";
8
9
  export * from "./num/index.js";
9
10
  export * from "./signer/index.js";
10
11
  export * from "./utils/index.js";
@@ -0,0 +1,138 @@
1
+ import { ctr } from "@noble/ciphers/aes";
2
+ import { scryptAsync } from "@noble/hashes/scrypt";
3
+ import { keccak_256 } from "@noble/hashes/sha3";
4
+ import { randomBytes } from "@noble/hashes/utils";
5
+ import { Bytes, BytesLike, bytesConcat, bytesFrom } from "../bytes/index.js";
6
+ import { hexFrom } from "../hex/index.js";
7
+
8
+ // The parameter r ("blockSize")
9
+ const DEFAULT_SCRYPT_PARAM_R = 8;
10
+ // The parallelization parameter p
11
+ const DEFAULT_SCRYPT_PARAM_P = 1;
12
+ // The CPU/Memory cost parameter N
13
+ const DEFAULT_SCRYPT_PARAM_N = 262144;
14
+
15
+ function mac(derivedKey: Bytes, cipherText: Bytes) {
16
+ return hexFrom(
17
+ keccak_256(bytesConcat(derivedKey.slice(16, 32), cipherText)),
18
+ ).slice(2);
19
+ }
20
+
21
+ export async function keystoreEncrypt(
22
+ privateKeyLike: BytesLike,
23
+ chainCodeLike: BytesLike,
24
+ password: string,
25
+ ) {
26
+ const salt = randomBytes(32);
27
+ const iv = randomBytes(16);
28
+ const kdfparams = {
29
+ dklen: 32,
30
+ salt: hexFrom(salt).slice(2),
31
+ n: DEFAULT_SCRYPT_PARAM_N,
32
+ r: DEFAULT_SCRYPT_PARAM_R,
33
+ p: DEFAULT_SCRYPT_PARAM_P,
34
+ };
35
+ const derivedKey = await scryptAsync(bytesFrom(password, "utf8"), salt, {
36
+ N: kdfparams.n,
37
+ r: kdfparams.r,
38
+ p: kdfparams.p,
39
+ dkLen: kdfparams.dklen,
40
+ });
41
+ const cipher = ctr(
42
+ derivedKey.slice(0, 16),
43
+ iv.map((v) => v),
44
+ );
45
+ const ciphertext = cipher.encrypt(
46
+ bytesConcat(bytesFrom(privateKeyLike), bytesFrom(chainCodeLike)),
47
+ );
48
+
49
+ return {
50
+ id: hexFrom(randomBytes(16)).slice(2),
51
+ crypto: {
52
+ ciphertext: hexFrom(ciphertext).slice(2),
53
+ cipherparams: {
54
+ iv: hexFrom(iv).slice(2),
55
+ },
56
+ cipher: "aes-128-ctr",
57
+ kdf: "scrypt",
58
+ kdfparams,
59
+ mac: mac(derivedKey, ciphertext),
60
+ },
61
+ };
62
+ }
63
+
64
+ export async function keystoreDecrypt(
65
+ keystore: unknown,
66
+ password: string,
67
+ ): Promise<{
68
+ privateKey: Bytes;
69
+ chainCode: Bytes;
70
+ }> {
71
+ if (
72
+ typeof keystore !== "object" ||
73
+ keystore === null ||
74
+ !("crypto" in keystore)
75
+ ) {
76
+ throw Error("Invalid keystore");
77
+ }
78
+ const crypto = keystore.crypto;
79
+
80
+ if (
81
+ typeof crypto !== "object" ||
82
+ crypto === null ||
83
+ !("kdfparams" in crypto) ||
84
+ !("ciphertext" in crypto) ||
85
+ typeof crypto.ciphertext !== "string" ||
86
+ !("mac" in crypto) ||
87
+ typeof crypto.mac !== "string" ||
88
+ !("cipherparams" in crypto) ||
89
+ typeof crypto.cipherparams !== "object" ||
90
+ crypto.cipherparams === null ||
91
+ !("iv" in crypto.cipherparams) ||
92
+ typeof crypto.cipherparams.iv !== "string"
93
+ ) {
94
+ throw Error("Invalid crypto");
95
+ }
96
+ const kdfparams = crypto.kdfparams;
97
+
98
+ if (
99
+ typeof kdfparams !== "object" ||
100
+ kdfparams === null ||
101
+ !("n" in kdfparams) ||
102
+ typeof kdfparams.n !== "number" ||
103
+ !("r" in kdfparams) ||
104
+ typeof kdfparams.r !== "number" ||
105
+ !("p" in kdfparams) ||
106
+ typeof kdfparams.p !== "number" ||
107
+ !("dklen" in kdfparams) ||
108
+ typeof kdfparams.dklen !== "number" ||
109
+ !("salt" in kdfparams) ||
110
+ typeof kdfparams.salt !== "string"
111
+ ) {
112
+ throw Error("Invalid kdfparams");
113
+ }
114
+
115
+ const derivedKey = await scryptAsync(
116
+ bytesFrom(password, "utf8"),
117
+ bytesFrom(kdfparams.salt),
118
+ {
119
+ N: kdfparams.n,
120
+ r: kdfparams.r,
121
+ p: kdfparams.p,
122
+ dkLen: kdfparams.dklen,
123
+ },
124
+ );
125
+ const ciphertext = bytesFrom(crypto.ciphertext);
126
+ if (mac(derivedKey, ciphertext) !== crypto.mac) {
127
+ throw Error("Invalid password");
128
+ }
129
+ const cipher = ctr(
130
+ derivedKey.slice(0, 16),
131
+ bytesFrom(crypto.cipherparams.iv),
132
+ );
133
+ const result = cipher.decrypt(ciphertext);
134
+ return {
135
+ privateKey: result.slice(0, 32),
136
+ chainCode: result.slice(32),
137
+ };
138
+ }