@midnight-ntwrk/wallet-sdk-hd 3.1.0-beta.1 → 3.1.0-beta.3
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/README.md +3 -0
- package/dist/HDWallet.d.ts +5 -2
- package/dist/HDWallet.js +5 -2
- package/dist/WalletSeeds.d.ts +71 -0
- package/dist/WalletSeeds.js +82 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
This package provides support for Hierarchical Deterministic (HD) Wallet.
|
|
11
11
|
|
|
12
|
+
Key derivation follows the [Wallet Specification](../../docs/spec/Specification.md) (Key management section); the
|
|
13
|
+
[spec reference implementation](../spec-reference) provides the canonical test vectors.
|
|
14
|
+
|
|
12
15
|
To allow deterministic derivation of keys for different features, Midnight follows algorithms and structure being a mix
|
|
13
16
|
of [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki),
|
|
14
17
|
[BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) and
|
package/dist/HDWallet.d.ts
CHANGED
|
@@ -40,8 +40,11 @@ export declare class HDWallet {
|
|
|
40
40
|
static fromSeed(seed: Uint8Array): HDWalletResult;
|
|
41
41
|
selectAccount(account: number): AccountKey;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* Wipes the root key's private-key buffer, narrowing the window in which the seed is reachable.
|
|
44
|
+
*
|
|
45
|
+
* It does not reach the intermediate keys BIP32 allocates at each level of a derivation path, nor the derived keys
|
|
46
|
+
* already handed to callers — neither is reachable from here, so both are left to the garbage collector. Call this
|
|
47
|
+
* once all keys are derived, but do not read it as a guarantee that the seed is gone from the process.
|
|
45
48
|
*/
|
|
46
49
|
clear(): void;
|
|
47
50
|
}
|
package/dist/HDWallet.js
CHANGED
|
@@ -61,8 +61,11 @@ export class HDWallet {
|
|
|
61
61
|
return new AccountKey(this.rootKey, account);
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* Wipes the root key's private-key buffer, narrowing the window in which the seed is reachable.
|
|
65
|
+
*
|
|
66
|
+
* It does not reach the intermediate keys BIP32 allocates at each level of a derivation path, nor the derived keys
|
|
67
|
+
* already handed to callers — neither is reachable from here, so both are left to the garbage collector. Call this
|
|
68
|
+
* once all keys are derived, but do not read it as a guarantee that the seed is gone from the process.
|
|
66
69
|
*/
|
|
67
70
|
clear() {
|
|
68
71
|
this.rootKey.wipePrivateData();
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Role } from './HDWallet.js';
|
|
2
|
+
/**
|
|
3
|
+
* The seeds the three wallets are started from.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Plain bytes, and deliberately so: a seed is the only key material that crosses a protocol boundary, because each
|
|
7
|
+
* ledger version derives its own keys from it. Anything more specific would be a key object, which belongs to one
|
|
8
|
+
* ledger version and cannot cross.
|
|
9
|
+
*/
|
|
10
|
+
export type WalletSeeds = Readonly<{
|
|
11
|
+
/** The seed the shielded wallet derives its Zswap secret keys from. */
|
|
12
|
+
shielded: Uint8Array;
|
|
13
|
+
/** The seed the unshielded wallet's signing key is made from. */
|
|
14
|
+
unshielded: Uint8Array;
|
|
15
|
+
/** The seed the Dust wallet derives its secret key from. */
|
|
16
|
+
dust: Uint8Array;
|
|
17
|
+
}>;
|
|
18
|
+
/** How the three seeds are placed in the tree, for a caller that wants somewhere other than the first address. */
|
|
19
|
+
export type WalletSeedsOptions = Readonly<{
|
|
20
|
+
/** The account to derive within. Defaults to the first. */
|
|
21
|
+
account?: number;
|
|
22
|
+
/** The address index within each role. Defaults to the first. */
|
|
23
|
+
addressIndex?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Which role the unshielded seed comes from.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* The unshielded wallet can sign with either of two schemes, and they are different keys at different places in the
|
|
29
|
+
* tree. Defaults to {@link Roles.NightExternal}, which is the scheme that works on both sides of the protocol
|
|
30
|
+
* boundary; {@link Roles.EcdsaUnshielded} is only available from ledger-v9 onwards.
|
|
31
|
+
*/
|
|
32
|
+
unshieldedRole?: Role;
|
|
33
|
+
}>;
|
|
34
|
+
/** Raised when a master seed cannot be walked down to the three per-wallet seeds. */
|
|
35
|
+
export declare class SeedDerivationError extends Error {
|
|
36
|
+
readonly name = "SeedDerivationError";
|
|
37
|
+
constructor(message: string, options?: {
|
|
38
|
+
cause?: unknown;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The seeds an application starts its three wallets from.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* Throws rather than returning a result, because this sits at the boundary an application calls directly and its
|
|
46
|
+
* failures are programming errors rather than ordinary states: a master seed BIP32 rejects, or an index outside the
|
|
47
|
+
* tree. {@link HDWallet} remains available for a caller that would rather branch on a tagged result than catch.
|
|
48
|
+
*/
|
|
49
|
+
export declare const WalletSeeds: {
|
|
50
|
+
/**
|
|
51
|
+
* Derives the three wallets' seeds from one master seed.
|
|
52
|
+
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* The master seed itself is never retained: the BIP32 tree's private material is wiped before this returns, and the
|
|
55
|
+
* bytes the caller passed in remain the caller's own. As everywhere in this SDK, "cleared" means the SDK stops
|
|
56
|
+
* holding a reference — neither JavaScript nor WebAssembly offers a way to guarantee the bytes are gone from
|
|
57
|
+
* memory, and no wallet in any language running on a general-purpose runtime can promise otherwise.
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const seeds = WalletSeeds.fromMasterSeed(masterSeed);
|
|
61
|
+
* await facade.start(seeds);
|
|
62
|
+
* ```;
|
|
63
|
+
*
|
|
64
|
+
* @param masterSeed The master seed, as bytes.
|
|
65
|
+
* @param options Where in the tree to derive from, and which signing scheme the unshielded wallet will use.
|
|
66
|
+
* @returns The three per-wallet seeds. See {@link WalletSeeds}.
|
|
67
|
+
* @throws {@link SeedDerivationError} When the master seed cannot be read, or the account or index falls outside the
|
|
68
|
+
* tree.
|
|
69
|
+
*/
|
|
70
|
+
fromMasterSeed: (masterSeed: Uint8Array, options?: WalletSeedsOptions) => WalletSeeds;
|
|
71
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// This file is part of MIDNIGHT-WALLET-SDK.
|
|
2
|
+
// Copyright (C) Midnight Foundation
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// You may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
/**
|
|
14
|
+
* The one seed an application holds, and the three the wallets are started from.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* A Midnight wallet is three wallets, and each is started from its own seed derived from one master seed at its own
|
|
18
|
+
* place in the BIP32 tree. Everything needed to walk that tree has always been here — {@link HDWallet}, {@link Roles} —
|
|
19
|
+
* but the walk itself was left to callers, and every caller wrote it out again: select account zero, select the role,
|
|
20
|
+
* derive at index zero, wipe the tree. Naming it once is what this is.
|
|
21
|
+
*/
|
|
22
|
+
import { HDWallet } from './HDWallet.js';
|
|
23
|
+
import { Roles } from './HDWallet.js';
|
|
24
|
+
/** Raised when a master seed cannot be walked down to the three per-wallet seeds. */
|
|
25
|
+
export class SeedDerivationError extends Error {
|
|
26
|
+
name = 'SeedDerivationError';
|
|
27
|
+
constructor(message, options) {
|
|
28
|
+
super(message, options);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The seeds an application starts its three wallets from.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* Throws rather than returning a result, because this sits at the boundary an application calls directly and its
|
|
36
|
+
* failures are programming errors rather than ordinary states: a master seed BIP32 rejects, or an index outside the
|
|
37
|
+
* tree. {@link HDWallet} remains available for a caller that would rather branch on a tagged result than catch.
|
|
38
|
+
*/
|
|
39
|
+
export const WalletSeeds = {
|
|
40
|
+
/**
|
|
41
|
+
* Derives the three wallets' seeds from one master seed.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* The master seed itself is never retained: the BIP32 tree's private material is wiped before this returns, and the
|
|
45
|
+
* bytes the caller passed in remain the caller's own. As everywhere in this SDK, "cleared" means the SDK stops
|
|
46
|
+
* holding a reference — neither JavaScript nor WebAssembly offers a way to guarantee the bytes are gone from
|
|
47
|
+
* memory, and no wallet in any language running on a general-purpose runtime can promise otherwise.
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const seeds = WalletSeeds.fromMasterSeed(masterSeed);
|
|
51
|
+
* await facade.start(seeds);
|
|
52
|
+
* ```;
|
|
53
|
+
*
|
|
54
|
+
* @param masterSeed The master seed, as bytes.
|
|
55
|
+
* @param options Where in the tree to derive from, and which signing scheme the unshielded wallet will use.
|
|
56
|
+
* @returns The three per-wallet seeds. See {@link WalletSeeds}.
|
|
57
|
+
* @throws {@link SeedDerivationError} When the master seed cannot be read, or the account or index falls outside the
|
|
58
|
+
* tree.
|
|
59
|
+
*/
|
|
60
|
+
fromMasterSeed: (masterSeed, options = {}) => {
|
|
61
|
+
const { account = 0, addressIndex = 0, unshieldedRole = Roles.NightExternal } = options;
|
|
62
|
+
const opened = HDWallet.fromSeed(masterSeed);
|
|
63
|
+
if (opened.type !== 'seedOk') {
|
|
64
|
+
throw new SeedDerivationError('This master seed is not one a BIP32 tree can be built from, so no wallet seed can be derived from it.', { cause: opened.error });
|
|
65
|
+
}
|
|
66
|
+
const derived = opened.hdWallet
|
|
67
|
+
.selectAccount(account)
|
|
68
|
+
.selectRoles([Roles.Zswap, unshieldedRole, Roles.Dust])
|
|
69
|
+
.deriveKeysAt(addressIndex);
|
|
70
|
+
// Wiped whether or not the derivation succeeded: a failed walk is no reason to leave the root key live.
|
|
71
|
+
opened.hdWallet.clear();
|
|
72
|
+
if (derived.type !== 'keysDerived') {
|
|
73
|
+
throw new SeedDerivationError(`No key exists at account ${account}, address index ${addressIndex} for ${derived.roles.length === 1 ? 'role' : 'roles'} ` +
|
|
74
|
+
`${derived.roles.join(', ')}: a BIP32 account, role and index are each whole numbers below 2^31.`);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
shielded: derived.keys[Roles.Zswap],
|
|
78
|
+
unshielded: derived.keys[unshieldedRole],
|
|
79
|
+
dust: derived.keys[Roles.Dust],
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED