@neuraiproject/neurai-key 2.5.0

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.
Files changed (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +173 -0
  3. package/index.ts +119 -0
  4. package/package.json +45 -0
  5. package/test.js +71 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Raven Rebels
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # neurai-key
2
+
3
+ Generate Neurai addresses from a mnemonic phrase following the standards BIP32, BIP39, BIP44.
4
+
5
+ That is, use your 12 words to get addresses for Neurai mainnet and testnet.
6
+
7
+
8
+ ## Example get external and internal (change) addresses by path
9
+
10
+ A simple and "spot on" way to generate/derive addresses.
11
+
12
+ If you need brutal performance check out getAddressByPath example below.
13
+
14
+ ```
15
+ import NeuraiKey from "@neuraiproject/neurai-key";
16
+ //Or import as CommonsJS module
17
+ //const NeuraiKey = require("@neuraiproject/neurai-key");
18
+
19
+ const mnemonic = NeuraiKey.generateMnemonic();
20
+ const ACCOUNT = 0; //default is zero
21
+ const POSITION = 0; //the first address for this wallet
22
+ const network = "xna"; //or xna-test for testnet
23
+ const addressPair = NeuraiKey.getAddressPair(
24
+ network,
25
+ mnemonic,
26
+ ACCOUNT,
27
+ POSITION
28
+ );
29
+
30
+ console.info("Mnemonic", mnemonic);
31
+
32
+ console.log(addressPair);
33
+ ```
34
+
35
+ Outputs
36
+
37
+ ```
38
+ Mnemonic wrong breeze brick wrestle exotic erode news clown copy install marble promote
39
+ {
40
+ internal: {
41
+ address: 'RC7Vn28tGaNrJtBm8MX5RCeCvzMpqZ1MgG',
42
+ path: "m/44'/175'/0'/1/0",
43
+ privateKey: 'a2c71a4284ed6792debd68d830a10515051fd166ce00535bf9fd19573ed5413b',
44
+ WIF: 'L2g8U3ZNBLBQcy5f6C67h2eosps3MGkNmeNnk6Y8fZiMdSB9TuCJ'
45
+ },
46
+ external: {
47
+ address: 'RE8YxTSYYcftnbX56rnAEwaiddqaqt8UgX',
48
+ path: "m/44'/175'/0'/0/0",
49
+ privateKey: 'b998a218e6bfde7162460893f79afc14b82b14e368507f5a85de28848ea96439',
50
+ WIF: 'L3SV871B2mpUPTvj4U38UEp3Ah3wCVukF7tG2btHgjkiUSXRftSw'
51
+ },
52
+ position: 0
53
+ }
54
+ ```
55
+
56
+ ## Example get the first public address for a wallet by BIP44 path
57
+
58
+ Note this is the fastest way to generate/derive addresses since we can re-use the hdKey object.
59
+
60
+ BUT its more technical since you have to provide the full BIP44 path.
61
+
62
+ ```
63
+ import NeuraiKey from "@neuraiproject/neurai-key";
64
+
65
+ //use NeuraiKey.generateMnemonic() to generate mnemonic codes
66
+ const mnemonic =
67
+ "Mnemonic erosion total live dial hamster helmet top response cash obey anger balcony";
68
+ const path = "m/44'/175'/0'/0/0";
69
+ const network = "xna"; //or xna-test for testnet
70
+ const hdKey = NeuraiKey.getHDKey("xna", mnemonic);
71
+
72
+ const address = NeuraiKey.getAddressByPath(network, hdKey, path);
73
+
74
+ console.log(address);
75
+
76
+ ```
77
+
78
+ Outputs
79
+
80
+ ```
81
+ {
82
+ address: 'RWj697pj6PijkEcJLW3BLPG4GKre3BtgRP',
83
+ path: "m/44'/175'/0'/0/0",
84
+ privateKey: 'a5592434532a09a73350906f7846d272135a56b5a34d900659b31d2bb1aa6dfe',
85
+ WIF: 'L2m8GmGYVAkvUEtLdhbFidQW2Zn3fULpE7sbWgmXChygNEBPd1PK'
86
+ }
87
+ ```
88
+
89
+ ## How to import into your project
90
+
91
+ ### ES6 module
92
+
93
+ ```
94
+ //As ES6 module
95
+ import NeuraiKey from "@neuraiproject/neurai-key";
96
+ ```
97
+
98
+ ### CommonsJS module
99
+
100
+ ```
101
+ //As CommonsJS module
102
+ const NeuraiKey = require("@neuraiproject/neurai-key");
103
+ ```
104
+
105
+ ### Browserify
106
+
107
+ ```
108
+ //A browseriy:d version, with all the dependencies bundled for the web
109
+ <html>
110
+ <body>
111
+ <script src="./node_modules/@neuraiproject/neurai-key/dist/NeuraiKey.js"></script>
112
+ <script>
113
+ alert(NeuraiKey.generateMnemonic());
114
+ </script>
115
+ </body>
116
+ </html>
117
+ ```
118
+
119
+ ## install
120
+
121
+ ` npm install @neuraiproject/neurai-key`
122
+
123
+ ## build
124
+
125
+ ` npm run build`
126
+
127
+ ## test
128
+
129
+ `npm test`
130
+
131
+ Note, the tests run on the built version, so you need to build before you run the tests
132
+
133
+ ## BIP32
134
+
135
+ > BIP32 is the specification which introduced the standard for hierarchical deterministic (HD) wallets and extended keys to Bitcoin. Deterministic wallets can generate multiple "child" key pair chains from a master private "root" key in a deterministic way.[5][6] With the adoption of this standard, keys could be transferred between wallet software with a single extended private key (xprv), greatly improving the interoperability of wallets.
136
+
137
+ Quote from: https://en.m.wikipedia.org/wiki/Bitcoin_Improvement_Proposals#BIP32
138
+
139
+ Source: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
140
+
141
+ ## BIP39
142
+
143
+ > BIP39 is a proposal describing the use of plain language words chosen from a specific word list,[8] and the process for using such a string to derive a random seed used to generate a wallet as described in BIP32. This approach of utilizing a mnemonic phrase offered a much more user friendly experience for backup and recovery of cryptocurrency wallets.
144
+
145
+ Quote from: https://en.m.wikipedia.org/wiki/Bitcoin_Improvement_Proposals#BIP39
146
+
147
+ Source: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
148
+
149
+ ## BIP44
150
+
151
+ > BIP44 defines a logical hierarchy for deterministic wallets based on an algorithm described in BIP32 and purpose scheme described in BIP43. It allows the handling of multiple coins, multiple accounts, external and internal chains per account and millions of addresses per chain
152
+
153
+ Quote from: https://en.m.wikipedia.org/wiki/Bitcoin_Improvement_Proposals#BIP44
154
+
155
+ Source: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
156
+
157
+ `m / purpose' / coin_type' / account' / change / address_index`
158
+
159
+ So in the case of Neurai the path m/44'/175'/0'/0/0 says "give me the first address"
160
+
161
+ The first part m/44'/175' says that the purpose is to use BIP44 with Neurai (175). Consider that static code.
162
+
163
+ Accounts is deprecated and should be 0
164
+
165
+ Change: should be 0 or 1, 0 for external addresses and 1 for the change address
166
+
167
+ ### Address gap limit
168
+
169
+ > Address gap limit is currently set to 20. If the software hits 20 unused addresses in a row, it expects there are no used addresses beyond this point and stops searching the address chain. We scan just the external chains, because internal chains receive only coins that come from the associated external chains.
170
+ >
171
+ > Wallet software should warn when the user is trying to exceed the gap limit on an external chain by generating a new address.
172
+
173
+ Source: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
package/index.ts ADDED
@@ -0,0 +1,119 @@
1
+ //Gives us meta data about coins/chains
2
+ //import { chains } from "@hyperbitjs/chains";
3
+ import { chains } from "@neuraiproject/chains";
4
+
5
+ //bip39 from mnemonic to seed
6
+ import * as bip39 from "bip39";
7
+
8
+ const CoinKey = require("coinkey");
9
+
10
+ //From seed to key
11
+ const HDKey = require("hdkey");
12
+
13
+ //Could not declare Network as enum, something wrong with parcel bundler
14
+ export type Network = "xna" | "xna-test";
15
+
16
+ function getNetwork(name: Network) {
17
+ const c = name.toLowerCase(); //Just to be sure
18
+ const map = {
19
+ xna: chains.xna.main.versions,
20
+ "xna-test": chains.xna.test.versions,
21
+ };
22
+
23
+ const network = map[c];
24
+ if (!network) {
25
+ throw new Error("network must be of value " + Object.keys(map).toString());
26
+ }
27
+ return network;
28
+ }
29
+
30
+ /**
31
+ * @param network - should have value "xna", "xna-test"
32
+ * @param mnemonic - your mnemonic
33
+ * @param account - accounts in BIP44 starts from 0, 0 is the default account
34
+ * @param position - starts from 0
35
+ */
36
+ export function getAddressPair(
37
+ network: Network,
38
+ mnemonic: string,
39
+ account: number,
40
+ position: number
41
+ ) {
42
+ const hdKey = getHDKey(network, mnemonic);
43
+ const chain = getNetwork(network);
44
+ const coin_type = chain.bip44;
45
+ //coint_type should always be 1 according to SLIP-0044
46
+ //https://github.com/satoshilabs/slips/blob/master/slip-0044.md
47
+
48
+ //Syntax of BIP44
49
+ //m / purpose' / coin_type' / account' / change / address_index
50
+ const externalPath = `m/44'/${coin_type}'/${account}'/0/${position}`;
51
+ const externalAddress = getAddressByPath(network, hdKey, externalPath);
52
+
53
+ //change address
54
+ const internalPath = `m/44'/${coin_type}'/${account}'/1/${position}`;
55
+ const internalAddress = getAddressByPath(network, hdKey, internalPath);
56
+ return {
57
+ internal: internalAddress,
58
+ external: externalAddress,
59
+ position,
60
+ };
61
+ }
62
+
63
+ export function getHDKey(network: Network, mnemonic: string): any {
64
+ const chain = getNetwork(network);
65
+ const seed = bip39.mnemonicToSeedSync(mnemonic).toString("hex");
66
+ //From the seed, get a hdKey, can we use CoinKey instead?
67
+ const hdKey = HDKey.fromMasterSeed(Buffer.from(seed, "hex"), chain.bip32);
68
+ return hdKey;
69
+ }
70
+
71
+ export function getAddressByPath(network: Network, hdKey: any, path: string) {
72
+ const chain = getNetwork(network);
73
+ const derived = hdKey.derive(path);
74
+ var ck2 = new CoinKey(derived.privateKey, chain);
75
+
76
+ return {
77
+ address: ck2.publicAddress,
78
+ path: path,
79
+ privateKey: ck2.privateKey.toString("hex"),
80
+ WIF: ck2.privateWif,
81
+ };
82
+ }
83
+
84
+ export function generateMnemonic() {
85
+ return bip39.generateMnemonic();
86
+ }
87
+
88
+ export function isMnemonicValid(mnemonic: string) {
89
+ return bip39.validateMnemonic(mnemonic);
90
+ }
91
+ /**
92
+ *
93
+ * @param privateKeyWIF
94
+ * @param network should be "xna" or "xna-test"
95
+ * @returns object {address, privateKey (hex), WIF}
96
+ */
97
+
98
+ export function getAddressByWIF(network: Network, privateKeyWIF: string) {
99
+ const coinKey = CoinKey.fromWif(privateKeyWIF);
100
+ coinKey.versions = getNetwork(network);
101
+
102
+ return {
103
+ address: coinKey.publicAddress,
104
+ privateKey: coinKey.privateKey.toString("hex"),
105
+ WIF: coinKey.privateWif,
106
+ };
107
+ }
108
+
109
+ export const entropyToMnemonic = bip39.entropyToMnemonic;
110
+
111
+ export default {
112
+ entropyToMnemonic,
113
+ getAddressByPath,
114
+ getAddressByWIF,
115
+ getAddressPair,
116
+ getHDKey,
117
+ generateMnemonic,
118
+ isMnemonicValid,
119
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@neuraiproject/neurai-key",
3
+ "version": "2.5.0",
4
+ "description": "Generate Neurai addresses from mnemonic code. BIP32, BIP39, BIP44",
5
+ "source": "index.ts",
6
+ "main": "dist/main.js",
7
+ "module": "dist/module.js",
8
+ "types": "dist/types.d.ts",
9
+ "scripts": {
10
+ "browserify": "browserify ./dist/main.js --standalone NeuraiKey -o ./dist/NeuraiKey.js",
11
+ "build": "npx parcel build && npm run browserify",
12
+ "test": "jest ./test.js"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/neuraiproject/neurai-key.git"
17
+ },
18
+ "keywords": [
19
+ "Neurai",
20
+ "BIP44",
21
+ "BIP39"
22
+ ],
23
+ "author": "Raven Rebels / Dick Henrik Larsson",
24
+ "license": "MIT",
25
+ "bugs": {
26
+ "url": "https://github.com/neuraiproject/neurai-key/issues"
27
+ },
28
+ "homepage": "https://github.com/neuraiproject/neurai-key#readme",
29
+ "dependencies": {
30
+ "@hyperbitjs/chains": "^0.2.0",
31
+ "bip39": "^3.0.4",
32
+ "coinkey": "^3.0.0",
33
+ "hdkey": "^2.0.1"
34
+ },
35
+ "devDependencies": {
36
+ "@parcel/packager-ts": "^2.8.3",
37
+ "@parcel/transformer-typescript-types": "^2.8.3",
38
+ "@types/hdkey": "^2.0.1",
39
+ "@types/node": "^18.14.0",
40
+ "browserify": "^17.0.0",
41
+ "jest": "^29.4.0",
42
+ "parcel": "^2.8.3",
43
+ "typescript": "^4.9.4"
44
+ }
45
+ }
package/test.js ADDED
@@ -0,0 +1,71 @@
1
+ const NeuraiKey = require("./dist/main");
2
+
3
+ test("Random mnemonic should contain 12 words", () => {
4
+ const mnemonic = NeuraiKey.generateMnemonic();
5
+ expect(mnemonic.split(" ").length).toBe(12);
6
+ });
7
+
8
+ test("Validate address on main-net", () => {
9
+ const network = "xna";
10
+ const mnemonic =
11
+ "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
12
+ const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
13
+ expect(address.external.address).toBe("RKbP9SMo2KTKWsiTrEDhTWPuaTwfuPiN8G");
14
+ });
15
+
16
+ test("Validate address on test-net", () => {
17
+ const network = "xna-test";
18
+ const mnemonic =
19
+ "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
20
+ const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
21
+ expect(address.external.address).toBe("n1nUspcdAaDAMfx2ksZJ5cDa7UKVEGstrX");
22
+ });
23
+
24
+ test("Validate Wallet Import Format (WIF) main-net ", () => {
25
+ const network = "xna";
26
+ const mnemonic =
27
+ "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
28
+ const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
29
+
30
+ expect(address.internal.address).toBe("RLnvUoy29k3QiQgtR6PL416rSNfHTuwhyU");
31
+ expect(address.external.WIF).toBe(
32
+ "KyWuYcev1hJ7YJZTjWx8coXNRm4jRbMEhgVVVC8vDcTaKRCMASUE"
33
+ );
34
+ });
35
+
36
+ test("Validate Wallet Import Format (WIF) test-net ", () => {
37
+ const network = "xna-test";
38
+ const mnemonic =
39
+ "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
40
+ const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
41
+
42
+ expect(address.external.WIF).toBe(
43
+ "cPchRRmzZXtPeFLHfrh8qcwaRaziJCS4gcAMBVVQh1EiehNyBtKB"
44
+ );
45
+ });
46
+
47
+ test("Validate get public address from Wallet Import Format (WIF) main-et ", () => {
48
+ const network = "xna";
49
+ const WIF = "KyWuYcev1hJ7YJZTjWx8coXNRm4jRbMEhgVVVC8vDcTaKRCMASUE";
50
+ const addressObject = NeuraiKey.getAddressByWIF(network, WIF);
51
+
52
+ expect(addressObject.address).toBe("RKbP9SMo2KTKWsiTrEDhTWPuaTwfuPiN8G");
53
+ });
54
+
55
+ test("Valid bytes to mnemonic", () => {
56
+ const hexString = "a10a95fb55808c5f15dc97ecbcd26cf0";
57
+ const bytes = Uint8Array.from(Buffer.from(hexString, "hex"));
58
+ const mnemonic = NeuraiKey.entropyToMnemonic(bytes);
59
+ expect(mnemonic).toBe(
60
+ "patient feed learn prison angle convince first napkin uncover track open theory"
61
+ );
62
+ });
63
+
64
+ test("Non valid bytes to mnemonic should fail", () => {
65
+ const hexString = "a10a94fb55808c5f15dc97ecbcd26cf0";
66
+ const bytes = Uint8Array.from(Buffer.from(hexString, "hex"));
67
+ const mnemonic = NeuraiKey.entropyToMnemonic(bytes);
68
+ expect(mnemonic).not.toBe(
69
+ "patient feed learn prison angle convince first napkin uncover track open theory"
70
+ );
71
+ });