├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── index.js
├── jsdoc.json
├── lib
├── constants.js
├── crypto.js
├── ecdsa.js
├── ecpair.js
├── ecsignature.js
├── hdnode.js
├── networks.js
├── time
│ └── slots.js
├── transactions
│ ├── crypto.js
│ ├── delegate.js
│ ├── ipfs.js
│ ├── multisignature.js
│ ├── signature.js
│ ├── transaction.js
│ └── vote.js
├── types.js
└── v2
│ └── transactions
│ ├── crypto.js
│ └── transfer.js
├── package.json
└── test
├── ark.js
├── crypto
├── fixtures.json
└── index.js
├── ecdsa
├── fixtures.json
└── index.js
├── ecpair
├── fixtures.json
└── index.js
├── ecsignature
├── fixtures.json
└── index.js
├── hdnode
├── fixtures.json
└── index.js
├── integration
├── basic.js
└── bip32.js
├── ipfs
└── index.js
├── multisignature
└── index.js
├── signature
└── index.js
├── slot
└── index.js
├── transaction
└── index.js
└── vote
└── index.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | app.js
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "mocha": true,
5 | "node": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | ],
10 | "rules": {
11 | "func-names": ["error", "never"],
12 | "max-len": ["error", 140, { "ignoreComments": true }]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Build results
27 | app.js
28 |
29 | # Compiled binary addons (http://nodejs.org/api/addons.html)
30 | build/Release
31 |
32 | # Dependency directories
33 | node_modules
34 | jspm_packages
35 |
36 | # Generated doc directory
37 | doc
38 |
39 | # Optional npm cache directory
40 | .npm
41 |
42 | # Mac OS X local settings
43 | .DS_Store
44 | .tags
45 | bundle.min.js
46 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - node
4 | - 8
5 | - 7
6 | - 6
7 |
8 | script:
9 | #- npm run lint
10 | - npm run test
11 | - npm run build:browserify
12 | - npm run clean:browserify
13 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
6 | "codezombiech.gitignore",
7 | "dbaeumer.vscode-eslint",
8 | "eg2.vscode-npm-script"
9 | ]
10 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible Node.js debug attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Mocha Tests",
11 | "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
12 | "args": [
13 | "-u",
14 | "tdd",
15 | "--timeout",
16 | "999999",
17 | "--colors",
18 | "${workspaceRoot}/test/ark.js",
19 | "${workspaceRoot}/test/*/*.js"
20 | ],
21 | "internalConsoleOptions": "openOnSessionStart"
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.tabSize": 2,
3 | "editor.insertSpaces": true,
4 | "files.trimTrailingWhitespace": true
5 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "lint",
9 | "problemMatcher": [
10 | "$eslint-stylish"
11 | ]
12 | },
13 | {
14 | "type": "npm",
15 | "script": "build",
16 | "problemMatcher": [],
17 | "group": {
18 | "kind": "build",
19 | "isDefault": true
20 | }
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # BOUNTY Program
2 | ARK has a bounty program for all accepted PR (Pull Requests) for this repository
3 |
4 | More information can be found at https://blog.ark.io/ark-github-development-bounty-113806ae9ffe
5 |
6 | Before pushing PR, please [jump in our slack #development](https://ark.io/slack) channel in order to discuss your contributions or to connect with other ARKvelopers.
7 |
8 | # Guidelines
9 | - pickup any of the existing issues or if you find an issue make a PR,
10 | - only one PR reward will be awarded per issue it fixes,
11 | - solving an open issue will increase your chances to be picked up as any of the monthly bounty winners.
12 |
13 | # Accepted PR
14 | - increase general code quality,
15 | - add meaningfull tests,
16 | - correct bug,
17 | - add new features,
18 | - improve documentation,
19 | - create something new for ARK.
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 bitcoinjs-lib contributors
4 | Copyright (c) 2016 Ark
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **:warning: DEPRECATED IN FAVOR OF https://github.com/ArkEcosystem/core/tree/master/packages/crypto :warning:***
2 |
3 | 
4 |
5 |
6 | [](https://travis-ci.org/ArkEcosystem/ark-js)
7 |
8 | # Ark JS
9 |
10 | Ark JS is a JavaScript library for sending ARK transactions. It's main benefit is that it does not require a locally installed ARK node, and instead utilizes the existing peers on the network. It can be used from the client as a [browserify](http://browserify.org/) compiled module, or on the server as a standard Node.js module.
11 |
12 | ## Installation
13 |
14 | [](https://nodei.co/npm/arkjs/)
15 |
16 | ## Building
17 |
18 | Build the browserify module for client use:
19 |
20 | ```sh
21 | npm build:browserify
22 | ```
23 |
24 | Clean:
25 |
26 | ```sh
27 | npm clean:browserify
28 | ```
29 |
30 | ## Tests
31 |
32 | ```
33 | npm test
34 | ```
35 |
36 | Tests written using mocha + schedule.js.
37 |
38 | ***
39 |
40 | ## Usage
41 |
42 | On the client:
43 |
44 | ```html
45 |
46 | ```
47 |
48 | On the server:
49 |
50 | ```js
51 | var ark = require("arkjs");
52 | ```
53 |
54 | ### Generating a key pair
55 |
56 | To generate a public / private key pair from a given passphrase:
57 |
58 | ```js
59 | var keys = ark.crypto.getKeys("passphrase");
60 | ```
61 |
62 | Returning:
63 |
64 | ```js
65 | {
66 | publicKey: "02e012f0a7cac12a74bdc17d844cbc9f637177b470019c32a53cef94c7a56e2ea9",
67 | privateKey: ""
68 | }
69 | ```
70 |
71 | To get the private key:
72 |
73 | ```js
74 | keys.d.toBuffer().toString("hex");
75 | ```
76 |
77 | Returning:
78 | ```
79 | 1e089e3c5323ad80a90767bdd5907297b4138163f027097fd3bdbeab528d2d68
80 | ```
81 |
82 |
83 | ### Generating an address
84 |
85 | To generate a unique Ark address from a given public key:
86 |
87 | ```js
88 | var address = ark.crypto.getAddress("5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09");
89 | ```
90 |
91 | Returning:
92 |
93 | ```
94 | AGihocTkwDygiFvmg6aG8jThYTic47GzU9
95 | ```
96 |
97 | ### Creating a transaction
98 |
99 | To create a signed transaction object, which can then be broadcasted onto the network:
100 |
101 | ```js
102 | var amount = 1000 * Math.pow(10, 8); // 100000000000
103 | var transaction = ark.transaction.createTransaction("AGihocTkwDygiFvmg6aG8jThYTic47GzU9", amount, null, "passphrase", "secondPassphrase");
104 | ```
105 |
106 | Returning:
107 |
108 | ```js
109 | {
110 | type: 0, // Transaction type. 0 = Normal transaction.
111 | amount: 100000000000, // The amount to send expressed as an integer value.
112 | asset: {}, // Transaction asset, dependent on tx type.
113 | fee: 100000000, // 0.1 ARK expressed as an integer value.
114 | id: "500224999259823996", // Transaction ID.
115 | recipientId: "AGihocTkwDygiFvmg6aG8jThYTic47GzU9", // Recipient ID.
116 | senderPublicKey: "56e106a1d4a53dbe22cac52fefd8fc4123cfb4ee482f8f25a4fc72eb459b38a5", // Sender's public key.
117 | signSignature: "03fdd33bed30270b97e77ada44764cc8628f6ad3bbd84718571695262a5a18baa37bd76a62dd25bc21beacd61eaf2c63af0cf34edb0d191d225f4974cd3aa509", // Sender's second passphrase signature.
118 | signature: "9419ca3cf11ed2e3fa4c63bc9a4dc18b5001648e74522bc0f22bda46a188e462da4785e5c71a43cfc0486af08d447b9340ba8b93258c4c7f50798060fff2d709", // Transaction signature.
119 | timestamp: 27953413 // Based on UTC time of genesis since epoch.
120 | }
121 | ```
122 |
123 | ### Network identification with Nethash
124 |
125 | You need to obtain the nethash in order to be sure you are broadcasting to the right network (testnet, mainnet or others). The nethash is simply the payload hash from the genesisBlock. If no nethash or wrong nethash is provided in the headers, the request will be rejected returning the expected nethash.
126 |
127 | ```json
128 | { "success": false, "message": "Request is made on the wrong network", "expected":"e2f8f69ec6ab4b12550a314bd867c46e64e429961bb427514a3a534c602ff467", "received":"wrong-nethash" }
129 | ```
130 |
131 | The nethash for a given network can be obtained at the following API endpoint:
132 |
133 | ```
134 | /api/blocks/getNetHash
135 | ```
136 |
137 | You can also get the nethash from a peer this way:
138 |
139 | On the client using [jQuery](https://jquery.com/):
140 |
141 | ```js
142 | var nethash;
143 | $.ajax({
144 | url: "https://api.arknode.net/peer/transactions/",
145 | data: JSON.stringify({}),
146 | dataType: "json",
147 | method: "POST",
148 | headers: {
149 | "Content-Type": "application/json",
150 | "os": "linux3.2.0-4-amd64",
151 | "version": "0.3.0",
152 | "port": 1,
153 | "nethash": "wrong-nethash"
154 | },
155 | success: function(data) {
156 | nethash = data.body.expected;
157 | }
158 | });
159 | ```
160 |
161 | From a server using [Request](https://github.com/request/request):
162 |
163 | ```js
164 | var nethash;
165 | request({
166 | url: "https://api.arknode.net/peer/transactions",
167 | json: { },
168 | method: "POST",
169 | headers: {
170 | "Content-Type": "application/json",
171 | "os": "linux3.2.0-4-amd64",
172 | "version": "0.3.0",
173 | "port": 1,
174 | "nethash": "wrong-nethash"
175 | }
176 | }, function(error, response, body) {
177 | nethash = body.expected;
178 | });
179 | ```
180 |
181 | ### Posting a transaction
182 |
183 | Transaction objects are sent to `/peer/transactions`, using the `POST` method.
184 |
185 | Example:
186 |
187 | ```js
188 | Method: POST
189 | Content-Type: application/json
190 |
191 | {
192 | "transactions" : [{
193 | ...
194 | }]
195 | }
196 | ```
197 |
198 | #### Sending transaction on the Client
199 |
200 | Using [jQuery](https://jquery.com/):
201 |
202 | ```js
203 | var success = function(data) {
204 | console.log(data);
205 | };
206 |
207 | $.ajax({
208 | url: "https://api.arknode.net/peer/transactions",
209 | data: JSON.stringify({ transactions: [transaction] }),
210 | dataType: "json",
211 | method: "POST",
212 | headers: {
213 | "Content-Type": "application/json",
214 | "os": "linux3.2.0-4-amd64",
215 | "version": "0.3.0",
216 | "port": 1,
217 | "nethash":nethash
218 | },
219 | success: success
220 | });
221 | ```
222 |
223 | #### Sending transaction on the Server
224 |
225 | Using [Request](https://github.com/request/request):
226 |
227 |
228 | ```js
229 | var request = require("request");
230 |
231 | var callback = function(error, response, body) {
232 | console.log(error || body);
233 | };
234 |
235 | request({
236 | url: "https://api.arknode.net/peer/transactions",
237 | json: { transactions: [transaction] },
238 | method: "POST",
239 | headers: {
240 | "Content-Type": "application/json",
241 | "os": "linux3.2.0-4-amd64",
242 | "version": "0.3.0",
243 | "port": 1,
244 | "nethash": nethash
245 | }
246 | }, callback);
247 | ```
248 |
249 | #### Peer Response
250 |
251 | Upon successfully accepting a transaction, the receiving node will respond with:
252 |
253 | ```json
254 | { "success": true, "result": "5318121831703437738" }
255 | ```
256 |
257 | If the transaction is deemed invalid, or an error is encountered, the receiving node will respond with:
258 |
259 | ```json
260 | { "success": false, "message": "Error message" }
261 | ```
262 |
263 | ***
264 |
265 | ### Other transaction types
266 |
267 | #### Creating a delegate transaction
268 |
269 | ```js
270 | var transaction = ark.delegate.createDelegate("secret", "username", "secondSecret");
271 | ```
272 |
273 | #### Creating a second signature transaction
274 |
275 | ```js
276 | var transaction = ark.signature.createSignature("secret", "secondSecret");
277 | ```
278 |
279 | #### Creating a vote transaction
280 |
281 | ```js
282 | var transaction = ark.vote.createVote("secret", ["+58199578191950019299181920120128129"], "secondSecret");
283 | ```
284 |
285 | ***
286 |
287 | ## Security
288 |
289 | If you discover a security vulnerability within this package, please send an e-mail to security@ark.io. All security vulnerabilities will be promptly addressed.
290 |
291 | ## Authors
292 | - FX Thoorens
293 | - Guillaume Verbal
294 | - Boris Povod
295 | - Oliver Beddows
296 |
297 | ## License
298 |
299 | The MIT License (MIT)
300 |
301 | Copyright (c) 2016-2017 ARK.io
302 | Copyright (c) 2016 Lisk
303 | Copyright (c) 2015 Crypti
304 |
305 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
306 |
307 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
308 |
309 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
310 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module arkjs
3 | * @license MIT
4 | */
5 |
6 | module.exports = {
7 | /** @see module:crypto */
8 | crypto: require("./lib/transactions/crypto.js"),
9 | /** @see module:delegate */
10 | delegate : require("./lib/transactions/delegate.js"),
11 | /** @see module:signature */
12 | signature : require("./lib/transactions/signature.js"),
13 | /** @see module:multisignature */
14 | multisignature : require("./lib/transactions/multisignature.js"),
15 | /** @see module:transaction */
16 | transaction : require("./lib/transactions/transaction.js"),
17 | /** @see module:vote */
18 | vote : require("./lib/transactions/vote.js"),
19 | /** @see module:ipfs */
20 | ipfs : require("./lib/transactions/ipfs.js"),
21 | /** @see module:networks */
22 | networks : require("./lib/networks.js"),
23 | /** @see module:slots */
24 | slots : require("./lib/time/slots.js"),
25 |
26 | /** @see ECPair */
27 | ECPair : require("./lib/ecpair.js"),
28 | /** @see HDNode */
29 | HDNode : require("./lib/hdnode.js"),
30 | /** @see ECSignature */
31 | ECSignature : require("./lib/ecsignature.js"),
32 | }
33 |
34 | // extra aliases for bitcoinlib-js compatibility
35 | var libCrypto = require('./lib/crypto.js')
36 | for (var method in libCrypto) {
37 | module.exports.crypto[method] = libCrypto[method]
38 | }
39 |
40 | /**
41 | * @typedef ECPoint
42 | * @property {number} x
43 | * @property {number} y
44 | */
45 |
46 | /**
47 | * @typedef Network
48 | * @property {string} messagePrefix
49 | * @property {object} bip32
50 | * @property {number} bip32.public
51 | * @property {number} bip32.private
52 | * @property {number} pubKeyHash
53 | * @property {number} wif
54 | */
55 |
56 | /**
57 | * @typedef Transaction
58 | * @property {number} amount
59 | * @property {object} asset
60 | * @property {string} id
61 | * @property {number} fee
62 | * @property {string} recipientId
63 | * @property {*} senderPublicKey
64 | * @property {string} signature
65 | * @property {string} [signSignature]
66 | * @property {number} timestamp
67 | * @property {number} type
68 | * @property {string} [vendorField]
69 | */
70 |
71 |
--------------------------------------------------------------------------------
/jsdoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["plugins/markdown"],
3 | "source": {
4 | "include": ["README.md", "index.js", "lib/"]
5 | },
6 | "opts": {
7 | "destination": "./doc",
8 | "recurse": true
9 | },
10 | "tags": {
11 | "dictionaries": ["jsdoc", "closure"]
12 | }
13 | }
--------------------------------------------------------------------------------
/lib/constants.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | fees:{
3 | send: 10000000,
4 | vote: 100000000,
5 | delegate: 2500000000,
6 | secondsignature: 500000000,
7 | multisignature: 500000000
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/crypto.js:
--------------------------------------------------------------------------------
1 | var createHash = require('create-hash')
2 |
3 | /**
4 | * @memberof module:crypto
5 | * @param {string|Buffer} buffer
6 | * @returns {Buffer}
7 | */
8 | function ripemd160 (buffer) {
9 | return createHash('rmd160').update(buffer).digest()
10 | }
11 |
12 | /**
13 | * @memberof module:crypto
14 | * @param {string|Buffer} buffer
15 | * @returns {Buffer}
16 | */
17 | function sha1 (buffer) {
18 | return createHash('sha1').update(buffer).digest()
19 | }
20 |
21 | /**
22 | * @memberof module:crypto
23 | * @param {string|Buffer} buffer
24 | * @returns {Buffer}
25 | */
26 | function sha256 (buffer) {
27 | return createHash('sha256').update(buffer).digest()
28 | }
29 |
30 | /**
31 | * @memberof module:crypto
32 | * @param {string|Buffer} buffer
33 | * @returns {Buffer}
34 | */
35 | function hash160 (buffer) {
36 | return ripemd160(sha256(buffer))
37 | }
38 |
39 | /**
40 | * @memberof module:crypto
41 | * @param {string|Buffer} buffer
42 | * @returns {Buffer}
43 | */
44 | function hash256 (buffer) {
45 | return sha256(sha256(buffer))
46 | }
47 |
48 | module.exports = {
49 | hash160: hash160,
50 | hash256: hash256,
51 | ripemd160: ripemd160,
52 | sha1: sha1,
53 | sha256: sha256
54 | }
55 |
--------------------------------------------------------------------------------
/lib/ecdsa.js:
--------------------------------------------------------------------------------
1 | /** @module ecdsa */
2 |
3 | var createHmac = require('create-hmac')
4 | var typeforce = require('typeforce')
5 | var types = require('./types')
6 |
7 | var BigInteger = require('bigi')
8 | var ECSignature = require('./ecsignature')
9 |
10 | var ZERO = new Buffer([0])
11 | var ONE = new Buffer([1])
12 |
13 | var ecurve = require('ecurve')
14 | var secp256k1 = ecurve.getCurveByName('secp256k1')
15 |
16 | /**
17 | * [Generation of k.](https://tools.ietf.org/html/rfc6979#section-3.2)
18 | *
19 | * @static
20 | * @param {Buffer} hash
21 | * @param {Buffer} x
22 | * @param {function} checkSig
23 | * @returns {BigInteger}
24 | */
25 | function deterministicGenerateK (hash, x, checkSig) {
26 | typeforce(types.tuple(
27 | types.Hash256bit,
28 | types.Buffer256bit,
29 | types.Function
30 | ), arguments)
31 |
32 | var k = new Buffer(32)
33 | var v = new Buffer(32)
34 |
35 | // Step A, ignored as hash already provided
36 | // Step B
37 | v.fill(1)
38 |
39 | // Step C
40 | k.fill(0)
41 |
42 | // Step D
43 | k = createHmac('sha256', k)
44 | .update(v)
45 | .update(ZERO)
46 | .update(x)
47 | .update(hash)
48 | .digest()
49 |
50 | // Step E
51 | v = createHmac('sha256', k).update(v).digest()
52 |
53 | // Step F
54 | k = createHmac('sha256', k)
55 | .update(v)
56 | .update(ONE)
57 | .update(x)
58 | .update(hash)
59 | .digest()
60 |
61 | // Step G
62 | v = createHmac('sha256', k).update(v).digest()
63 |
64 | // Step H1/H2a, ignored as tlen === qlen (256 bit)
65 | // Step H2b
66 | v = createHmac('sha256', k).update(v).digest()
67 |
68 | var T = BigInteger.fromBuffer(v)
69 |
70 | // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA
71 | while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) {
72 | k = createHmac('sha256', k)
73 | .update(v)
74 | .update(ZERO)
75 | .digest()
76 |
77 | v = createHmac('sha256', k).update(v).digest()
78 |
79 | // Step H1/H2a, again, ignored as tlen === qlen (256 bit)
80 | // Step H2b again
81 | v = createHmac('sha256', k).update(v).digest()
82 | T = BigInteger.fromBuffer(v)
83 | }
84 |
85 | return T
86 | }
87 |
88 | var N_OVER_TWO = secp256k1.n.shiftRight(1)
89 |
90 | /**
91 | * @static
92 | * @param {Buffer} hash
93 | * @param {BigInteger} d
94 | * @returns {ECSignature}
95 | */
96 | function sign (hash, d) {
97 | typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments)
98 |
99 | var x = d.toBuffer(32)
100 | var e = BigInteger.fromBuffer(hash)
101 | var n = secp256k1.n
102 | var G = secp256k1.G
103 |
104 | var r, s
105 | deterministicGenerateK(hash, x, function (k) {
106 | var Q = G.multiply(k)
107 |
108 | if (secp256k1.isInfinity(Q)) return false
109 |
110 | r = Q.affineX.mod(n)
111 | if (r.signum() === 0) return false
112 |
113 | s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
114 | if (s.signum() === 0) return false
115 |
116 | return true
117 | })
118 |
119 | // enforce low S values, see bip62: 'low s values in signatures'
120 | if (s.compareTo(N_OVER_TWO) > 0) {
121 | s = n.subtract(s)
122 | }
123 |
124 | return new ECSignature(r, s)
125 | }
126 |
127 | /**
128 | * @static
129 | * @param {Buffer} hash
130 | * @param {ECSignature} signature
131 | * @param {ECPoint} Q
132 | * @returns {boolean}
133 | */
134 | function verify (hash, signature, Q) {
135 | typeforce(types.tuple(
136 | types.Hash256bit,
137 | types.ECSignature,
138 | types.ECPoint
139 | ), arguments)
140 |
141 | var n = secp256k1.n
142 | var G = secp256k1.G
143 |
144 | var r = signature.r
145 | var s = signature.s
146 |
147 | // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]
148 | if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
149 | if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
150 |
151 | // 1.4.2 H = Hash(M), already done by the user
152 | // 1.4.3 e = H
153 | var e = BigInteger.fromBuffer(hash)
154 |
155 | // Compute s^-1
156 | var sInv = s.modInverse(n)
157 |
158 | // 1.4.4 Compute u1 = es^−1 mod n
159 | // u2 = rs^−1 mod n
160 | var u1 = e.multiply(sInv).mod(n)
161 | var u2 = r.multiply(sInv).mod(n)
162 |
163 | // 1.4.5 Compute R = (xR, yR)
164 | // R = u1G + u2Q
165 | var R = G.multiplyTwo(u1, Q, u2)
166 |
167 | // 1.4.5 (cont.) Enforce R is not at infinity
168 | if (secp256k1.isInfinity(R)) return false
169 |
170 | // 1.4.6 Convert the field element R.x to an integer
171 | var xR = R.affineX
172 |
173 | // 1.4.7 Set v = xR mod n
174 | var v = xR.mod(n)
175 |
176 | // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
177 | return v.equals(r)
178 | }
179 |
180 | module.exports = {
181 | deterministicGenerateK: deterministicGenerateK,
182 | sign: sign,
183 | verify: verify,
184 |
185 | // TODO: remove
186 | __curve: secp256k1
187 | }
188 |
--------------------------------------------------------------------------------
/lib/ecpair.js:
--------------------------------------------------------------------------------
1 | var base58check = require('bs58check')
2 | var bcrypto = require('./crypto')
3 | var ecdsa = require('./ecdsa')
4 | var ECSignature = require('./ecsignature')
5 | var randomBytes = require('randombytes')
6 | var typeforce = require('typeforce')
7 | var types = require('./types')
8 | var wif = require('wif')
9 |
10 | var NETWORKS = require('./networks')
11 | var BigInteger = require('bigi')
12 |
13 | var ecurve = require('ecurve')
14 | var secp256k1 = ecurve.getCurveByName('secp256k1')
15 |
16 | var secp256k1native = require('secp256k1')
17 |
18 | /**
19 | * Provide either `d` or `Q` but not both.
20 | *
21 | * @constructor
22 | * @param {BigInteger} [d] Private key.
23 | * @param {Point} [Q] Public key.
24 | * @param {object} [options]
25 | * @param {boolean} [options.compressed=true]
26 | * @param {Network} [options.network=networks.ark]
27 | */
28 | function ECPair (d, Q, options) {
29 | if (options) {
30 | typeforce({
31 | compressed: types.maybe(types.Boolean),
32 | network: types.maybe(types.Network)
33 | }, options)
34 | }
35 |
36 | options = options || {}
37 |
38 | if (d) {
39 | if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
40 | if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order')
41 | if (Q) throw new TypeError('Unexpected publicKey parameter')
42 |
43 | this.d = d
44 | } else {
45 | typeforce(types.ECPoint, Q)
46 |
47 | this.__Q = Q
48 | }
49 |
50 | /** @type {boolean} */ this.compressed = options.compressed === undefined ? true : options.compressed
51 | /** @type {Network} */ this.network = options.network || NETWORKS.ark
52 | }
53 |
54 | Object.defineProperty(ECPair.prototype, 'Q', {
55 | get: function () {
56 | if (!this.__Q && this.d) {
57 | this.__Q = secp256k1.G.multiply(this.d)
58 | }
59 |
60 | return this.__Q
61 | }
62 | })
63 |
64 | /**
65 | * @param {Buffer} buffer
66 | * @param {Network} [network=networks.ark]
67 | * @returns {ECPair}
68 | */
69 | ECPair.fromPublicKeyBuffer = function (buffer, network) {
70 | var Q = ecurve.Point.decodeFrom(secp256k1, buffer)
71 |
72 | return new ECPair(null, Q, {
73 | compressed: Q.compressed,
74 | network: network
75 | })
76 | }
77 |
78 | /**
79 | * @param {string} string
80 | * @param {Network[]|Network} network
81 | * @returns {ECPair}
82 | */
83 | ECPair.fromWIF = function (string, network) {
84 | var decoded = wif.decode(string)
85 | var version = decoded.version
86 |
87 | // [network, ...]
88 | if (types.Array(network)) {
89 | network = network.filter(function (network) {
90 | return version === network.wif
91 | }).pop()
92 |
93 | if (!network) throw new Error('Unknown network version')
94 |
95 | // network
96 | } else {
97 | network = network || NETWORKS.ark
98 |
99 | if (version !== network.wif) throw new Error('Invalid network version')
100 | }
101 |
102 | var d = BigInteger.fromBuffer(decoded.privateKey)
103 |
104 | return new ECPair(d, null, {
105 | compressed: decoded.compressed,
106 | network: network
107 | })
108 | }
109 |
110 | /**
111 | * @param {object} [options]
112 | * @param {function} [options.rng]
113 | * @param {boolean} [options.compressed=true]
114 | * @param {Network} [options.network=networks.ark]
115 | */
116 | ECPair.makeRandom = function (options) {
117 | options = options || {}
118 |
119 | var rng = options.rng || randomBytes
120 |
121 | var d
122 | do {
123 | var buffer = rng(32)
124 | typeforce(types.Buffer256bit, buffer)
125 |
126 | d = BigInteger.fromBuffer(buffer)
127 | } while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0)
128 |
129 | return new ECPair(d, null, options)
130 | }
131 |
132 | /**
133 | * @param {string} seed
134 | * @param {object} [options]
135 | * @param {boolean} [options.compressed=true]
136 | * @param {Network} [options.network=networks.ark]
137 | * @returns {ECPair}
138 | */
139 | ECPair.fromSeed = function(seed, options) {
140 | var hash = bcrypto.sha256(new Buffer(seed,"utf-8"))
141 | var d = BigInteger.fromBuffer(hash)
142 | if(d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0){
143 | throw new Error("seed cannot resolve to a compatible private key")
144 | }
145 | else{
146 | return new ECPair(d, null, options)
147 | }
148 | }
149 |
150 | /**
151 | * @returns {string}
152 | */
153 | ECPair.prototype.getAddress = function () {
154 | var payload = new Buffer(21)
155 | var hash = bcrypto.ripemd160(this.getPublicKeyBuffer())
156 | var version = this.getNetwork().pubKeyHash
157 | payload.writeUInt8(version, 0)
158 | hash.copy(payload, 1)
159 |
160 | return base58check.encode(payload)
161 | }
162 |
163 | /**
164 | * @returns {Network}
165 | */
166 | ECPair.prototype.getNetwork = function () {
167 | return this.network
168 | }
169 |
170 | ECPair.prototype.getPublicKeyBuffer = function () {
171 | return this.Q.getEncoded(this.compressed)
172 | }
173 |
174 | /**
175 | * Requires a private key (`d`) to be set.
176 | *
177 | * @param {Buffer} hash
178 | * @returns {ECSignature}
179 | */
180 | ECPair.prototype.sign = function (hash) {
181 | if (!this.d) throw new Error('Missing private key')
182 | var native=secp256k1native.sign(hash, this.d.toBuffer(32))
183 | return ECSignature.parseNativeSecp256k1(native).signature
184 | }
185 |
186 | /**
187 | * Requires a private key (`d`) to be set.
188 | *
189 | * @returns {string}
190 | */
191 | ECPair.prototype.toWIF = function () {
192 | if (!this.d) throw new Error('Missing private key')
193 |
194 | return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed)
195 | }
196 |
197 | /**
198 | * @param {Buffer} hash
199 | * @returns {boolean}
200 | */
201 | ECPair.prototype.verify = function (hash, signature) {
202 | return secp256k1native.verify(hash, signature.toNativeSecp256k1(), this.Q.getEncoded(this.compressed))
203 | }
204 |
205 | module.exports = ECPair
206 |
--------------------------------------------------------------------------------
/lib/ecsignature.js:
--------------------------------------------------------------------------------
1 | var bip66 = require('bip66')
2 | var typeforce = require('typeforce')
3 | var types = require('./types')
4 |
5 | var BigInteger = require('bigi')
6 |
7 | /**
8 | * Creates a new ECSignature.
9 | *
10 | * @constructor
11 | * @param {BigInteger} r
12 | * @param {BigInteger} s
13 | */
14 | function ECSignature (r, s) {
15 | typeforce(types.tuple(types.BigInt, types.BigInt), arguments)
16 |
17 | /** @type {BigInteger} */ this.r = r
18 | /** @type {BigInteger} */ this.s = s
19 | }
20 |
21 | /**
22 | * @typedef {Object} SignatureParseResult
23 | * @property {boolean} compressed
24 | * @property {number} i
25 | * @property {ECSignature} signature
26 | */
27 |
28 | /**
29 | * @param {*} native
30 | * @returns {SignatureParseResult}
31 | */
32 | ECSignature.parseNativeSecp256k1 = function (native) {
33 | if (native.signature.length !== 64) throw new Error('Invalid signature length')
34 |
35 | var compressed = 0
36 | var recoveryParam = native.recovery
37 |
38 | var r = BigInteger.fromBuffer(native.signature.slice(0, 32))
39 | var s = BigInteger.fromBuffer(native.signature.slice(32))
40 |
41 | return {
42 | compressed: compressed,
43 | i: recoveryParam,
44 | signature: new ECSignature(r, s)
45 | }
46 | }
47 |
48 | /**
49 | * @returns {Buffer}
50 | */
51 | ECSignature.prototype.toNativeSecp256k1 = function () {
52 | var buffer = new Buffer(64)
53 | if(this.r.toBuffer().length > 32 || this.s.toBuffer().length > 32){
54 | return buffer;
55 | }
56 |
57 | this.r.toBuffer(32).copy(buffer, 0)
58 | this.s.toBuffer(32).copy(buffer, 32)
59 |
60 | return buffer
61 | }
62 |
63 | /**
64 | * @param {Buffer} buffer
65 | * @returns {SignatureParseResult}
66 | */
67 | ECSignature.parseCompact = function (buffer) {
68 | if (buffer.length !== 65) throw new Error('Invalid signature length')
69 |
70 | var flagByte = buffer.readUInt8(0) - 27
71 | if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter')
72 |
73 | var compressed = !!(flagByte & 4)
74 | var recoveryParam = flagByte & 3
75 |
76 | var r = BigInteger.fromBuffer(buffer.slice(1, 33))
77 | var s = BigInteger.fromBuffer(buffer.slice(33))
78 |
79 | return {
80 | compressed: compressed,
81 | i: recoveryParam,
82 | signature: new ECSignature(r, s)
83 | }
84 | }
85 |
86 | /**
87 | * @param {Buffer}
88 | * @returns {ECSignature}
89 | */
90 | ECSignature.fromDER = function (buffer) {
91 | var decode = bip66.decode(buffer)
92 | var r = BigInteger.fromDERInteger(decode.r)
93 | var s = BigInteger.fromDERInteger(decode.s)
94 |
95 | return new ECSignature(r, s)
96 | }
97 |
98 | /**
99 | * BIP62: 1-byte `hashType` flag (only `0x01`, `0x02`, `0x03`, `0x81`, `0x82`, and `0x83` are allowed).
100 | *
101 | * @param {Buffer} buffer
102 | */
103 | ECSignature.parseScriptSignature = function (buffer) {
104 | var hashType = buffer.readUInt8(buffer.length - 1)
105 | var hashTypeMod = hashType & ~0x80
106 |
107 | if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('Invalid hashType ' + hashType)
108 |
109 | return {
110 | signature: ECSignature.fromDER(buffer.slice(0, -1)),
111 | hashType: hashType
112 | }
113 | }
114 |
115 | /**
116 | * @param {number} i
117 | * @param {boolean} [compressed=false]
118 | * @returns {Buffer}
119 | */
120 | ECSignature.prototype.toCompact = function (i, compressed) {
121 | if (compressed) {
122 | i += 4
123 | }
124 |
125 | i += 27
126 |
127 | var buffer = new Buffer(65)
128 | buffer.writeUInt8(i, 0)
129 |
130 | this.r.toBuffer(32).copy(buffer, 1)
131 | this.s.toBuffer(32).copy(buffer, 33)
132 |
133 | return buffer
134 | }
135 |
136 | /**
137 | * @return {Buffer}
138 | */
139 | ECSignature.prototype.toDER = function () {
140 | var r = new Buffer(this.r.toDERInteger())
141 | var s = new Buffer(this.s.toDERInteger())
142 |
143 | return bip66.encode(r, s)
144 | }
145 |
146 | /**
147 | * @param {number} hashType
148 | * @returns {Buffer}
149 | */
150 | ECSignature.prototype.toScriptSignature = function (hashType) {
151 | var hashTypeMod = hashType & ~0x80
152 | if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
153 |
154 | var hashTypeBuffer = new Buffer(1)
155 | hashTypeBuffer.writeUInt8(hashType, 0)
156 |
157 | return Buffer.concat([this.toDER(), hashTypeBuffer])
158 | }
159 |
160 | module.exports = ECSignature
161 |
--------------------------------------------------------------------------------
/lib/hdnode.js:
--------------------------------------------------------------------------------
1 | var base58check = require('bs58check')
2 | var bcrypto = require('./crypto')
3 | var createHmac = require('create-hmac')
4 | var typeforce = require('typeforce')
5 | var types = require('./types')
6 | var NETWORKS = require('./networks')
7 |
8 | var BigInteger = require('bigi')
9 | var ECPair = require('./ecpair')
10 |
11 | var ecurve = require('ecurve')
12 | var curve = ecurve.getCurveByName('secp256k1')
13 |
14 | /**
15 | * @constructor
16 | * @param {ECPair} keyPair
17 | * @param {Buffer} chainCode
18 | */
19 | function HDNode (keyPair, chainCode) {
20 | typeforce(types.tuple('ECPair', types.Buffer256bit), arguments)
21 |
22 | if (!keyPair.compressed) throw new TypeError('BIP32 only allows compressed keyPairs')
23 |
24 | /** @type {ECPair} */ this.keyPair = keyPair
25 | /** @type {Buffer} */ this.chainCode = chainCode
26 | /** @type {number} */ this.depth = 0
27 | /** @type {number} */ this.index = 0
28 | /** @type {number} */ this.parentFingerprint = 0x00000000
29 | }
30 |
31 | HDNode.HIGHEST_BIT = 0x80000000
32 | HDNode.LENGTH = 78
33 | HDNode.MASTER_SECRET = new Buffer('Bitcoin seed')
34 |
35 | /**
36 | * @param {string|Buffer} seed
37 | * @param {Network} [network]
38 | * @returns {HDNode}
39 | */
40 | HDNode.fromSeedBuffer = function (seed, network) {
41 | typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments)
42 |
43 | if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits')
44 | if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits')
45 |
46 | var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest()
47 | var IL = I.slice(0, 32)
48 | var IR = I.slice(32)
49 |
50 | // In case IL is 0 or >= n, the master key is invalid
51 | // This is handled by the ECPair constructor
52 | var pIL = BigInteger.fromBuffer(IL)
53 | var keyPair = new ECPair(pIL, null, {
54 | network: network
55 | })
56 |
57 | return new HDNode(keyPair, IR)
58 | }
59 |
60 | /**
61 | * @param {string} hex
62 | * @returns {HDNode}
63 | */
64 | HDNode.fromSeedHex = function (hex, network) {
65 | return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network)
66 | }
67 |
68 | /**
69 | * @param {Buffer|string} string
70 | * @returns {HDNode}
71 | */
72 | HDNode.fromBase58 = function (string, networks) {
73 | var buffer = base58check.decode(string)
74 | if (buffer.length !== 78) throw new Error('Invalid buffer length')
75 |
76 | // 4 bytes: version bytes
77 | var version = buffer.readUInt32BE(0)
78 | var network
79 |
80 | // list of networks?
81 | if (Array.isArray(networks)) {
82 | network = networks.filter(function (network) {
83 | return version === network.bip32.private ||
84 | version === network.bip32.public
85 | }).pop()
86 |
87 | if (!network) throw new Error('Unknown network version')
88 |
89 | // otherwise, assume a network object (or default to ark)
90 | } else {
91 | network = networks || NETWORKS.ark
92 | }
93 |
94 | if (version !== network.bip32.private &&
95 | version !== network.bip32.public) throw new Error('Invalid network version')
96 |
97 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
98 | var depth = buffer[4]
99 |
100 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
101 | var parentFingerprint = buffer.readUInt32BE(5)
102 | if (depth === 0) {
103 | if (parentFingerprint !== 0x00000000) throw new Error('Invalid parent fingerprint')
104 | }
105 |
106 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
107 | // This is encoded in MSB order. (0x00000000 if master key)
108 | var index = buffer.readUInt32BE(9)
109 | if (depth === 0 && index !== 0) throw new Error('Invalid index')
110 |
111 | // 32 bytes: the chain code
112 | var chainCode = buffer.slice(13, 45)
113 | var keyPair
114 |
115 | // 33 bytes: private key data (0x00 + k)
116 | if (version === network.bip32.private) {
117 | if (buffer.readUInt8(45) !== 0x00) throw new Error('Invalid private key')
118 |
119 | var d = BigInteger.fromBuffer(buffer.slice(46, 78))
120 | keyPair = new ECPair(d, null, { network: network })
121 |
122 | // 33 bytes: public key data (0x02 + X or 0x03 + X)
123 | } else {
124 | var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78))
125 | // Q.compressed is assumed, if somehow this assumption is broken, `new HDNode` will throw
126 |
127 | // Verify that the X coordinate in the public point corresponds to a point on the curve.
128 | // If not, the extended public key is invalid.
129 | curve.validate(Q)
130 |
131 | keyPair = new ECPair(null, Q, { network: network })
132 | }
133 |
134 | var hd = new HDNode(keyPair, chainCode)
135 | hd.depth = depth
136 | hd.index = index
137 | hd.parentFingerprint = parentFingerprint
138 |
139 | return hd
140 | }
141 |
142 | /**
143 | * @returns {string}
144 | */
145 | HDNode.prototype.getAddress = function () {
146 | return this.keyPair.getAddress()
147 | }
148 |
149 | /**
150 | * @returns {Buffer}
151 | */
152 | HDNode.prototype.getIdentifier = function () {
153 | return bcrypto.hash160(this.keyPair.getPublicKeyBuffer())
154 | }
155 |
156 | /**
157 | * @returns {Buffer}
158 | */
159 | HDNode.prototype.getFingerprint = function () {
160 | return this.getIdentifier().slice(0, 4)
161 | }
162 |
163 | /**
164 | * @returns {Network}
165 | */
166 | HDNode.prototype.getNetwork = function () {
167 | return this.keyPair.getNetwork()
168 | }
169 |
170 | /**
171 | * @returns {Buffer}
172 | */
173 | HDNode.prototype.getPublicKeyBuffer = function () {
174 | return this.keyPair.getPublicKeyBuffer()
175 | }
176 |
177 | /**
178 | * @returns {HDNode}
179 | */
180 | HDNode.prototype.neutered = function () {
181 | var neuteredKeyPair = new ECPair(null, this.keyPair.Q, {
182 | network: this.keyPair.network
183 | })
184 |
185 | var neutered = new HDNode(neuteredKeyPair, this.chainCode)
186 | neutered.depth = this.depth
187 | neutered.index = this.index
188 | neutered.parentFingerprint = this.parentFingerprint
189 |
190 | return neutered
191 | }
192 |
193 | /**
194 | * @param {Buffer} hash
195 | * @returns {ECSignature}
196 | */
197 | HDNode.prototype.sign = function (hash) {
198 | return this.keyPair.sign(hash)
199 | }
200 |
201 | /**
202 | * @param {Buffer} hash
203 | * @returns {boolean}
204 | */
205 | HDNode.prototype.verify = function (hash, signature) {
206 | return this.keyPair.verify(hash, signature)
207 | }
208 |
209 | /**
210 | * @returns {string}
211 | */
212 | HDNode.prototype.toBase58 = function () {
213 | // Version
214 | var network = this.keyPair.network
215 | var version = (!this.isNeutered()) ? network.bip32.private : network.bip32.public
216 | var buffer = new Buffer(78)
217 |
218 | // 4 bytes: version bytes
219 | buffer.writeUInt32BE(version, 0)
220 |
221 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ....
222 | buffer.writeUInt8(this.depth, 4)
223 |
224 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
225 | buffer.writeUInt32BE(this.parentFingerprint, 5)
226 |
227 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
228 | // This is encoded in big endian. (0x00000000 if master key)
229 | buffer.writeUInt32BE(this.index, 9)
230 |
231 | // 32 bytes: the chain code
232 | this.chainCode.copy(buffer, 13)
233 |
234 | // 33 bytes: the public key or private key data
235 | if (!this.isNeutered()) {
236 | // 0x00 + k for private keys
237 | buffer.writeUInt8(0, 45)
238 | this.keyPair.d.toBuffer(32).copy(buffer, 46)
239 |
240 | // 33 bytes: the public key
241 | } else {
242 | // X9.62 encoding for public keys
243 | this.keyPair.getPublicKeyBuffer().copy(buffer, 45)
244 | }
245 |
246 | return base58check.encode(buffer)
247 | }
248 |
249 | /**
250 | * https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
251 | *
252 | * @param {number} index UInt32
253 | * @returns {HDNode}
254 | */
255 | HDNode.prototype.derive = function (index) {
256 | typeforce(types.UInt32, index)
257 |
258 | var isHardened = index >= HDNode.HIGHEST_BIT
259 | var data = new Buffer(37)
260 |
261 | // Hardened child
262 | if (isHardened) {
263 | if (this.isNeutered()) throw new TypeError('Could not derive hardened child key')
264 |
265 | // data = 0x00 || ser256(kpar) || ser32(index)
266 | data[0] = 0x00
267 | this.keyPair.d.toBuffer(32).copy(data, 1)
268 | data.writeUInt32BE(index, 33)
269 |
270 | // Normal child
271 | } else {
272 | // data = serP(point(kpar)) || ser32(index)
273 | // = serP(Kpar) || ser32(index)
274 | this.keyPair.getPublicKeyBuffer().copy(data, 0)
275 | data.writeUInt32BE(index, 33)
276 | }
277 |
278 | var I = createHmac('sha512', this.chainCode).update(data).digest()
279 | var IL = I.slice(0, 32)
280 | var IR = I.slice(32)
281 |
282 | var pIL = BigInteger.fromBuffer(IL)
283 |
284 | // In case parse256(IL) >= n, proceed with the next value for i
285 | if (pIL.compareTo(curve.n) >= 0) {
286 | return this.derive(index + 1)
287 | }
288 |
289 | // Private parent key -> private child key
290 | var derivedKeyPair
291 | if (!this.isNeutered()) {
292 | // ki = parse256(IL) + kpar (mod n)
293 | var ki = pIL.add(this.keyPair.d).mod(curve.n)
294 |
295 | // In case ki == 0, proceed with the next value for i
296 | if (ki.signum() === 0) {
297 | return this.derive(index + 1)
298 | }
299 |
300 | derivedKeyPair = new ECPair(ki, null, {
301 | network: this.keyPair.network
302 | })
303 |
304 | // Public parent key -> public child key
305 | } else {
306 | // Ki = point(parse256(IL)) + Kpar
307 | // = G*IL + Kpar
308 | var Ki = curve.G.multiply(pIL).add(this.keyPair.Q)
309 |
310 | // In case Ki is the point at infinity, proceed with the next value for i
311 | if (curve.isInfinity(Ki)) {
312 | return this.derive(index + 1)
313 | }
314 |
315 | derivedKeyPair = new ECPair(null, Ki, {
316 | network: this.keyPair.network
317 | })
318 | }
319 |
320 | var hd = new HDNode(derivedKeyPair, IR)
321 | hd.depth = this.depth + 1
322 | hd.index = index
323 | hd.parentFingerprint = this.getFingerprint().readUInt32BE(0)
324 |
325 | return hd
326 | }
327 |
328 | /**
329 | * @param {number} index
330 | * @returns {HDNode}
331 | */
332 | HDNode.prototype.deriveHardened = function (index) {
333 | typeforce(types.UInt31, index)
334 |
335 | // Only derives hardened private keys by default
336 | return this.derive(index + HDNode.HIGHEST_BIT)
337 | }
338 |
339 | /**
340 | * Private `===` not neutered.
341 | * Public `===` neutered.
342 | *
343 | * @returns {boolean}
344 | */
345 | HDNode.prototype.isNeutered = function () {
346 | return !(this.keyPair.d)
347 | }
348 |
349 | /**
350 | * @param {string} path
351 | * @returns {HDNode}
352 | */
353 | HDNode.prototype.derivePath = function (path) {
354 | typeforce(types.BIP32Path, path)
355 |
356 | var splitPath = path.split('/')
357 | if (splitPath[0] === 'm') {
358 | if (this.parentFingerprint) {
359 | throw new Error('Not a master node')
360 | }
361 |
362 | splitPath = splitPath.slice(1)
363 | }
364 |
365 | return splitPath.reduce(function (prevHd, indexStr) {
366 | var index
367 | if (indexStr.slice(-1) === "'") {
368 | index = parseInt(indexStr.slice(0, -1), 10)
369 | return prevHd.deriveHardened(index)
370 | } else {
371 | index = parseInt(indexStr, 10)
372 | return prevHd.derive(index)
373 | }
374 | }, this)
375 | }
376 |
377 |
378 | module.exports = HDNode
379 |
--------------------------------------------------------------------------------
/lib/networks.js:
--------------------------------------------------------------------------------
1 | /** @module networks */
2 |
3 | module.exports = {
4 | /** @type {Network} */
5 | ark: {
6 | messagePrefix: '\x18Ark Signed Message:\n',
7 | bip32: {
8 | public: 0x2bf4968, // base58 will have a prefix 'apub'
9 | private: 0x2bf4530 // base58Priv will have a prefix 'apriv'
10 | },
11 | name: 'mainnet',
12 | nethash: '6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988',
13 | token: 'ARK',
14 | symbol: 'Ѧ',
15 | pubKeyHash: 0x17, // Addresses will begin with 'A'
16 | explorer: 'https://explorer.ark.io',
17 | wif: 0xaa, // Network prefix for wif generation
18 | activePeer: {
19 | ip: 'node1.arknet.cloud',
20 | port: 4001
21 | },
22 | peers: [
23 | { ip: '5.39.9.240', port: 4001 },
24 | { ip: '5.39.9.241', port: 4001 },
25 | { ip: '5.39.9.242', port: 4001 },
26 | { ip: '5.39.9.243', port: 4001 },
27 | { ip: '5.39.9.244', port: 4001 },
28 | { ip: '5.39.9.250', port: 4001 },
29 | { ip: '5.39.9.251', port: 4001 },
30 | { ip: '5.39.9.252', port: 4001 },
31 | { ip: '5.39.9.253', port: 4001 },
32 | { ip: '5.39.9.254', port: 4001 },
33 | { ip: '5.39.9.255', port: 4001 },
34 | { ip: '5.39.53.48', port: 4001 },
35 | { ip: '5.39.53.49', port: 4001 },
36 | { ip: '5.39.53.50', port: 4001 },
37 | { ip: '5.39.53.51', port: 4001 },
38 | { ip: '5.39.53.52', port: 4001 },
39 | { ip: '5.39.53.53', port: 4001 },
40 | { ip: '5.39.53.54', port: 4001 },
41 | { ip: '5.39.53.55', port: 4001 },
42 | { ip: '37.59.129.160', port: 4001 },
43 | { ip: '37.59.129.161', port: 4001 },
44 | { ip: '37.59.129.162', port: 4001 },
45 | { ip: '37.59.129.163', port: 4001 },
46 | { ip: '37.59.129.164', port: 4001 },
47 | { ip: '37.59.129.165', port: 4001 },
48 | { ip: '37.59.129.166', port: 4001 },
49 | { ip: '37.59.129.167', port: 4001 },
50 | { ip: '37.59.129.168', port: 4001 },
51 | { ip: '37.59.129.169', port: 4001 },
52 | { ip: '37.59.129.170', port: 4001 },
53 | { ip: '37.59.129.171', port: 4001 },
54 | { ip: '37.59.129.172', port: 4001 },
55 | { ip: '37.59.129.173', port: 4001 },
56 | { ip: '37.59.129.174', port: 4001 },
57 | { ip: '37.59.129.175', port: 4001 },
58 | { ip: '193.70.72.80', port: 4001 },
59 | { ip: '193.70.72.81', port: 4001 },
60 | { ip: '193.70.72.82', port: 4001 },
61 | { ip: '193.70.72.83', port: 4001 },
62 | { ip: '193.70.72.84', port: 4001 },
63 | { ip: '193.70.72.85', port: 4001 },
64 | { ip: '193.70.72.86', port: 4001 },
65 | { ip: '193.70.72.87', port: 4001 },
66 | { ip: '193.70.72.88', port: 4001 },
67 | { ip: '193.70.72.89', port: 4001 },
68 | { ip: '193.70.72.90', port: 4001 }
69 | ],
70 | },
71 | /** @type {Network} */
72 | testnet: {
73 | messagePrefix: '\x18Ark Testnet Signed Message:\n',
74 | bip32: {
75 | public: 0x043587cf,
76 | private: 0x04358394
77 | },
78 | name: 'devnet',
79 | nethash: '578e820911f24e039733b45e4882b73e301f813a0d2c31330dafda84534ffa23',
80 | token: 'DARK',
81 | symbol: 'DѦ',
82 | pubKeyHash: 0x52, // Addresses will begin with 'a'
83 | explorer: 'https://dexplorer.ark.io',
84 | wif: 0xba, // Network prefix for wif generation
85 | activePeer: {
86 | ip: '104.238.165.129',
87 | port: 4002
88 | },
89 | peers: [
90 | { ip: '45.63.74.5', port: 4002 },
91 | { ip: '167.114.29.50', port: 4002 },
92 | { ip: '167.114.29.45', port: 4002 },
93 | { ip: '167.114.43.35', port: 4002 },
94 | { ip: '104.129.43.144', port: 4002 },
95 | { ip: '167.114.29.58', port: 4002 },
96 | { ip: '173.253.129.20', port: 4002 },
97 | { ip: '62.113.246.106', port: 4002 },
98 | { ip: '45.76.218.117', port: 4002 },
99 | { ip: '158.69.193.185', port: 4002 },
100 | { ip: '144.217.194.188', port: 4002 },
101 | { ip: '167.114.29.57', port: 4002 },
102 | { ip: '167.114.29.40', port: 4002 },
103 | { ip: '167.114.29.63', port: 4002 },
104 | { ip: '185.177.21.65', port: 4002 },
105 | { ip: '167.114.29.62', port: 4002 },
106 | { ip: '167.114.29.54', port: 4002 },
107 | { ip: '45.76.139.131', port: 4002 },
108 | { ip: '138.68.29.19', port: 4002 },
109 | { ip: '216.174.63.138', port: 4002 },
110 | { ip: '213.32.9.98', port: 4002 },
111 | { ip: '137.74.168.191', port: 4002 },
112 | { ip: '104.236.122.76', port: 4002 },
113 | { ip: '167.114.29.47', port: 4002 },
114 | { ip: '167.114.29.37', port: 4002 },
115 | { ip: '45.63.42.140', port: 4002 },
116 | { ip: '45.33.86.168', port: 4002 },
117 | { ip: '108.61.209.209', port: 4002 },
118 | { ip: '167.114.29.33', port: 4002 },
119 | { ip: '107.170.196.22', port: 4002 },
120 | { ip: '178.62.102.209', port: 4002 },
121 | { ip: '145.239.88.3', port: 4002 },
122 | { ip: '167.114.43.37', port: 4002 },
123 | { ip: '145.239.88.2', port: 4002 },
124 | { ip: '217.182.70.37', port: 4002 },
125 | { ip: '185.5.54.0', port: 4002 },
126 | { ip: '45.76.174.177', port: 4002 },
127 | { ip: '216.174.63.137', port: 4002 },
128 | { ip: '167.114.29.59', port: 4002 },
129 | { ip: '104.238.165.129', port: 4002 },
130 | { ip: '217.182.79.88', port: 4002 },
131 | { ip: '167.114.29.61', port: 4002 },
132 | { ip: '51.255.198.137', port: 4002 },
133 | { ip: '167.114.29.38', port: 4002 },
134 | { ip: '167.114.43.33', port: 4002 },
135 | { ip: '45.77.117.174', port: 4002 },
136 | { ip: '213.32.9.97', port: 4002 },
137 | { ip: '193.70.1.222', port: 4002 },
138 | { ip: '45.76.39.61', port: 4002 },
139 | { ip: '204.10.184.45', port: 4002 },
140 | { ip: '45.76.93.4', port: 4002 },
141 | { ip: '167.114.29.46', port: 4002 },
142 | { ip: '91.121.1.174', port: 4002 },
143 | { ip: '165.227.59.129', port: 4002 },
144 | { ip: '167.114.29.44', port: 4002 },
145 | { ip: '139.99.156.231', port: 4002 },
146 | { ip: '164.8.251.90', port: 4002 },
147 | { ip: '167.114.29.56', port: 4002 },
148 | { ip: '108.61.169.37', port: 4002 },
149 | { ip: '104.238.189.78', port: 4002 },
150 | { ip: '173.254.228.67', port: 4002 },
151 | { ip: '204.10.184.46', port: 4002 },
152 | { ip: '66.70.207.89', port: 4002 },
153 | { ip: '172.110.20.39', port: 4002 },
154 | { ip: '137.74.47.141', port: 4002 },
155 | { ip: '167.114.29.41', port: 4002 },
156 | { ip: '167.114.29.52', port: 4002 },
157 | { ip: '167.114.43.41', port: 4002 },
158 | { ip: '51.254.103.18', port: 4002 },
159 | { ip: '167.114.43.47', port: 4002 },
160 | { ip: '45.76.136.154', port: 4002 },
161 | { ip: '167.114.29.39', port: 4002 },
162 | { ip: '167.114.29.34', port: 4002 },
163 | { ip: '138.197.165.165', port: 4002 },
164 | { ip: '167.114.43.34', port: 4002 },
165 | { ip: '145.239.88.101', port: 4002 },
166 | { ip: '45.76.245.155', port: 4002 },
167 | { ip: '167.114.43.43', port: 4002 },
168 | { ip: '91.134.115.30', port: 4002 },
169 | { ip: '46.231.204.207', port: 4002 },
170 | { ip: '167.114.43.46', port: 4002 },
171 | { ip: '138.197.29.215', port: 4002 },
172 | { ip: '104.238.177.174', port: 4002 },
173 | { ip: '109.154.47.137', port: 4002 },
174 | { ip: '104.207.138.122', port: 4002 },
175 | { ip: '138.68.21.196', port: 4002 },
176 | { ip: '167.114.29.36', port: 4002 },
177 | { ip: '165.227.150.45', port: 4002 },
178 | { ip: '37.59.70.165', port: 4002 },
179 | { ip: '94.177.218.138', port: 4002 },
180 | { ip: '167.114.29.55', port: 4002 },
181 | { ip: '51.254.201.227', port: 4002 },
182 | { ip: '167.114.43.48', port: 4002 },
183 | { ip: '104.154.82.122', port: 4002 },
184 | { ip: '217.182.78.226', port: 4002 },
185 | { ip: '207.154.220.137', port: 4002 },
186 | { ip: '195.181.219.91', port: 4002 },
187 | { ip: '192.155.91.248', port: 4002 },
188 | { ip: '167.114.29.53', port: 4002 },
189 | { ip: '43.224.34.53', port: 4002 },
190 | { ip: '167.114.43.40', port: 4002 },
191 | { ip: '138.197.206.43', port: 4002 }
192 | ]
193 | },
194 | /** @type {Network} */
195 | bitcoin: {
196 | messagePrefix: '\x18Bitcoin Signed Message:\n',
197 | bip32: {
198 | public: 0x0488b21e,
199 | private: 0x0488ade4
200 | },
201 | pubKeyHash: 0x00,
202 | wif: 0x80
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/lib/time/slots.js:
--------------------------------------------------------------------------------
1 | /** @module slots */
2 |
3 | /**
4 | * @param {Date} [time]
5 | * @returns {number}
6 | */
7 | function getEpochTime(time) {
8 | if (time === undefined) {
9 | time = (new Date()).getTime();
10 | }
11 | var d = beginEpochTime();
12 | var t = d.getTime();
13 | return Math.floor((time - t) / 1000);
14 | }
15 |
16 | /**
17 | * @returns {Date}
18 | */
19 | function beginEpochTime() {
20 | var d = new Date(Date.UTC(2017,2,21,13,0,0,0))
21 |
22 | return d;
23 | }
24 |
25 | var interval = 8,
26 | delegates = 51;
27 |
28 | /**
29 | * @param {Date} [time]
30 | * @returns {number}
31 | */
32 | function getTime(time) {
33 | return getEpochTime(time);
34 | }
35 |
36 | /**
37 | * @param {number} [epochTime]
38 | * @returns {number}
39 | */
40 | function getRealTime(epochTime) {
41 | if (epochTime === undefined) {
42 | epochTime = getTime()
43 | }
44 | var d = beginEpochTime();
45 | var t = Math.floor(d.getTime() / 1000) * 1000;
46 | return t + epochTime * 1000;
47 | }
48 |
49 | /**
50 | * @param {number} [epochTime]
51 | * @returns {number} an integer
52 | */
53 | function getSlotNumber(epochTime) {
54 | if (epochTime === undefined) {
55 | epochTime = getTime()
56 | }
57 |
58 | return Math.floor(epochTime / interval);
59 | }
60 |
61 | /**
62 | * @param {number} slot
63 | * @returns {number}
64 | */
65 | function getSlotTime(slot) {
66 | return slot * interval;
67 | }
68 |
69 | /**
70 | * @returns {number}
71 | */
72 | function getNextSlot() {
73 | var slot = getSlotNumber();
74 |
75 | return slot + 1;
76 | }
77 |
78 | /**
79 | * @param {number} nextSlot
80 | * @returns {number}
81 | */
82 | function getLastSlot(nextSlot) {
83 | return nextSlot + delegates;
84 | }
85 |
86 | module.exports = {
87 | interval: interval,
88 | delegates: delegates,
89 | getTime: getTime,
90 | getRealTime: getRealTime,
91 | getSlotNumber: getSlotNumber,
92 | getSlotTime: getSlotTime,
93 | getNextSlot: getNextSlot,
94 | getLastSlot: getLastSlot
95 | }
96 |
--------------------------------------------------------------------------------
/lib/transactions/crypto.js:
--------------------------------------------------------------------------------
1 | /** @module crypto */
2 |
3 | var crypto = require("crypto");
4 | var crypto_utils = require("../crypto.js");
5 | var ECPair = require("../ecpair.js");
6 | var ECSignature = require("../ecsignature.js");
7 | /** @type {Object.} */
8 | var networks = require("../networks.js")
9 |
10 | var bs58check = require('bs58check')
11 |
12 | if (typeof Buffer === "undefined") {
13 | Buffer = require("buffer/").Buffer;
14 | }
15 |
16 | var ByteBuffer = require("bytebuffer");
17 | var bignum = require("browserify-bignum");
18 |
19 |
20 | var fixedPoint = Math.pow(10, 8);
21 | // default is ark mainnet
22 | var networkVersion = 0x17;
23 |
24 | /**
25 | * @static
26 | * @param {*} obj
27 | * @returns {boolean}
28 | */
29 | function isECPair(obj) {
30 | return obj instanceof ECPair;
31 | }
32 |
33 | /**
34 | * @static
35 | * @param {ECSignature} signature
36 | * @returns {Uint8Array}
37 | */
38 | function getSignatureBytes(signature) {
39 | var bb = new ByteBuffer(33, true);
40 | var publicKeyBuffer = new Buffer(signature.publicKey, "hex");
41 |
42 | for (var i = 0; i < publicKeyBuffer.length; i++) {
43 | bb.writeByte(publicKeyBuffer[i]);
44 | }
45 |
46 | bb.flip();
47 | return new Uint8Array(bb.toArrayBuffer());
48 | }
49 |
50 | /**
51 | * @static
52 | * @param {Transaction} transaction
53 | * @param {boolean} [skipSignature=false]
54 | * @param {boolean} [skipSecondSignature=false]
55 | * @returns {Buffer}
56 | */
57 | function getBytes(transaction, skipSignature, skipSecondSignature) {
58 | var assetSize = 0,
59 | assetBytes = null;
60 |
61 | switch (transaction.type) {
62 | case 1: // Signature
63 | assetBytes = getSignatureBytes(transaction.asset.signature);
64 | assetSize = assetBytes.length;
65 | break;
66 |
67 | case 2: // Delegate
68 | assetBytes = new Buffer(transaction.asset.delegate.username, "utf8");
69 | assetSize = assetBytes.length;
70 | break;
71 |
72 | case 3: // Vote
73 | if (transaction.asset.votes !== null) {
74 | assetBytes = new Buffer(transaction.asset.votes.join(""), "utf8");
75 | assetSize = assetBytes.length;
76 | }
77 | break;
78 |
79 | case 4: // Multi-Signature
80 | var keysgroupBuffer = new Buffer(transaction.asset.multisignature.keysgroup.join(""), "utf8");
81 | var bb = new ByteBuffer(1 + 1 + keysgroupBuffer.length, true);
82 |
83 | bb.writeByte(transaction.asset.multisignature.min);
84 | bb.writeByte(transaction.asset.multisignature.lifetime);
85 |
86 | for (var i = 0; i < keysgroupBuffer.length; i++) {
87 | bb.writeByte(keysgroupBuffer[i]);
88 | }
89 |
90 | bb.flip();
91 |
92 | assetBytes = bb.toBuffer();
93 | assetSize = assetBytes.length;
94 | break;
95 |
96 | }
97 |
98 | var bb = new ByteBuffer(1 + 4 + 32 + 8 + 8 + 21 + 64 + 64 + 64 + assetSize, true);
99 | bb.writeByte(transaction.type);
100 | bb.writeInt(transaction.timestamp);
101 |
102 | var senderPublicKeyBuffer = new Buffer(transaction.senderPublicKey, "hex");
103 | for (var i = 0; i < senderPublicKeyBuffer.length; i++) {
104 | bb.writeByte(senderPublicKeyBuffer[i]);
105 | }
106 |
107 | if (transaction.recipientId) {
108 | var recipient = bs58check.decode(transaction.recipientId);
109 | for (var i = 0; i < recipient.length; i++) {
110 | bb.writeByte(recipient[i]);
111 | }
112 | } else {
113 | for (var i = 0; i < 21; i++) {
114 | bb.writeByte(0);
115 | }
116 | }
117 |
118 | if(transaction.vendorFieldHex){
119 | var vf = new Buffer(transaction.vendorFieldHex,"hex");
120 | var fillstart=vf.length;
121 | for (i = 0; i < fillstart; i++) {
122 | bb.writeByte(vf[i]);
123 | }
124 | for (i = fillstart; i < 64; i++) {
125 | bb.writeByte(0);
126 | }
127 | }
128 | else if (transaction.vendorField) {
129 | var vf = new Buffer(transaction.vendorField);
130 | var fillstart=vf.length;
131 | for (i = 0; i < fillstart; i++) {
132 | bb.writeByte(vf[i]);
133 | }
134 | for (i = fillstart; i < 64; i++) {
135 | bb.writeByte(0);
136 | }
137 | } else {
138 | for (i = 0; i < 64; i++) {
139 | bb.writeByte(0);
140 | }
141 | }
142 |
143 | bb.writeLong(transaction.amount);
144 |
145 | bb.writeLong(transaction.fee);
146 |
147 | if (assetSize > 0) {
148 | for (var i = 0; i < assetSize; i++) {
149 | bb.writeByte(assetBytes[i]);
150 | }
151 | }
152 |
153 | if (!skipSignature && transaction.signature) {
154 | var signatureBuffer = new Buffer(transaction.signature, "hex");
155 | for (var i = 0; i < signatureBuffer.length; i++) {
156 | bb.writeByte(signatureBuffer[i]);
157 | }
158 | }
159 |
160 | if (!skipSecondSignature && transaction.signSignature) {
161 | var signSignatureBuffer = new Buffer(transaction.signSignature, "hex");
162 | for (var i = 0; i < signSignatureBuffer.length; i++) {
163 | bb.writeByte(signSignatureBuffer[i]);
164 | }
165 | }
166 |
167 | bb.flip();
168 | var arrayBuffer = new Uint8Array(bb.toArrayBuffer());
169 | var buffer = [];
170 |
171 | for (var i = 0; i < arrayBuffer.length; i++) {
172 | buffer[i] = arrayBuffer[i];
173 | }
174 |
175 | return new Buffer(buffer);
176 | }
177 |
178 | /**
179 | * @static
180 | * @param {string} hexString
181 | * @returns {Transaction}
182 | */
183 | function fromBytes(hexString){
184 | var tx={};
185 | var buf = new Buffer(hexString, "hex");
186 | tx.type = buf.readInt8(0) & 0xff;
187 | tx.timestamp = buf.readUInt32LE(1);
188 | tx.senderPublicKey = hexString.substring(10,10+33*2);
189 | tx.amount = buf.readUInt32LE(38+21+64);
190 | tx.fee = buf.readUInt32LE(38+21+64+8);
191 | tx.vendorFieldHex = hexString.substring(76+42,76+42+128);
192 | tx.recipientId = bs58check.encode(buf.slice(38,38+21));
193 | if(tx.type == 0){ // transfer
194 | parseSignatures(hexString, tx, 76+42+128+32);
195 | }
196 | else if(tx.type == 1){ // second signature registration
197 | delete tx.recipientId;
198 | tx.asset = {
199 | signature : {
200 | publicKey : hexString.substring(76+42+128+32,76+42+128+32+66)
201 | }
202 | }
203 | parseSignatures(hexString, tx, 76+42+128+32+66);
204 | }
205 | else if(tx.type == 2){ // delegate registration
206 | delete tx.recipientId;
207 | // Impossible to assess size of delegate asset, trying to grab signature and derive delegate asset
208 | var offset = findAndParseSignatures(hexString, tx);
209 |
210 | tx.asset = {
211 | delegate: {
212 | username: new Buffer(hexString.substring(76+42+128+32,hexString.length-offset),"hex").toString("utf8")
213 | }
214 | };
215 | }
216 | else if(tx.type == 3){ // vote
217 | // Impossible to assess size of vote asset, trying to grab signature and derive vote asset
218 | var offset = findAndParseSignatures(hexString, tx);
219 | tx.asset = {
220 | votes: new Buffer(hexString.substring(76+42+128+32,hexString.length-offset),"hex").toString("utf8").split(",")
221 | };
222 | }
223 | else if(tx.type == 4){ // multisignature creation
224 | delete tx.recipientId;
225 | var offset = findAndParseSignatures(hexString, tx);
226 | var buffer = new Buffer(hexString.substring(76+42+128+32,hexString.length-offset),"hex")
227 | tx.asset = {
228 | multisignature: {}
229 | }
230 | tx.asset.multisignature.min = buffer.readInt8(0) & 0xff;
231 | tx.asset.multisignature.lifetime = buffer.readInt8(1) & 0xff;
232 | tx.asset.multisignature.keysgroup = [];
233 | var index = 0;
234 | while(index + 2 < buffer.length){
235 | var key = buffer.slice(index+2,index+67+2).toString("utf8");
236 | tx.asset.multisignature.keysgroup.push(key);
237 | index = index + 67;
238 | }
239 | }
240 | else if(tx.type == 5){ // ipfs
241 | delete tx.recipientId;
242 | parseSignatures(hexString, tx, 76+42+128+32);
243 | }
244 |
245 | return tx;
246 | }
247 |
248 | /**
249 | * @static
250 | * @param {string} hexString
251 | * @param {Transaction} tx
252 | * @returns {number}
253 | */
254 | function findAndParseSignatures(hexString, tx){
255 | var signature1 = new Buffer(hexString.substring(hexString.length-146), "hex");
256 | var signature2 = null;
257 | var found = false;
258 | var offset = 0;
259 | while(!found && signature1.length > 8){
260 | if(signature1[0] != 0x30){
261 | signature1 = signature1.slice(1);
262 | }
263 | else try {
264 | ECSignature.fromDER(signature1,"hex");
265 | found = true;
266 | } catch(error){
267 | signature1 = signature1.slice(1);
268 | }
269 | }
270 | if(!found){
271 | offset = 0;
272 | signature1 = null;
273 | }
274 | else {
275 | found = false;
276 | offset = signature1.length*2;
277 | var signature2 = new Buffer(hexString.substring(hexString.length-offset-146, hexString.length-offset), "hex");
278 | while(!found && signature2.length > 8){
279 | if(signature2[0] != 0x30){
280 | signature2 = signature2.slice(1);
281 | }
282 | else try {
283 | ECSignature.fromDER(signature2,"hex");
284 | found = true;
285 | } catch(error){
286 | signature2 = signature2.slice(1);
287 | }
288 | }
289 | if(!found){
290 | signature2 = null;
291 | tx.signature = signature1.toString("hex");
292 | offset = tx.signature.length;
293 | }
294 | else if(signature2){
295 | tx.signSignature = signature1.toString("hex");
296 | tx.signature = signature2.toString("hex");
297 | offset = tx.signature.length+tx.signSignature.length;
298 | }
299 | }
300 | return offset;
301 | }
302 |
303 | /**
304 | * @static
305 | * @param {string} hexString
306 | * @param {Transaction} tx
307 | * @param {number} startOffset
308 | */
309 | function parseSignatures(hexString, tx, startOffset){
310 | tx.signature = hexString.substring(startOffset);
311 | if(tx.signature.length == 0) delete tx.signature;
312 | else {
313 | var length = parseInt("0x" + tx.signature.substring(2,4), 16) + 2;
314 | tx.signature = hexString.substring(startOffset, startOffset + length*2);
315 | tx.signSignature = hexString.substring(startOffset + length*2);
316 | if(tx.signSignature.length == 0) delete tx.signSignature;
317 | }
318 | }
319 |
320 | /**
321 | * @static
322 | * @param {Transaction} transaction
323 | * @returns {string}
324 | */
325 | function getId(transaction) {
326 | return crypto.createHash("sha256").update(getBytes(transaction)).digest().toString("hex");
327 | }
328 |
329 | /**
330 | * @static
331 | * @param {Transaction} transaction
332 | * @param {boolean} [skipSignature=false]
333 | * @param {boolean} [skipSecondSignature=false]
334 | * @returns {Buffer}
335 | */
336 | function getHash(transaction, skipSignature, skipSecondSignature) {
337 | return crypto.createHash("sha256").update(getBytes(transaction, skipSignature, skipSecondSignature)).digest();
338 | }
339 |
340 | /**
341 | * @static
342 | * @param {Transaction} transaction
343 | * @returns {number}
344 | */
345 | function getFee(transaction) {
346 | switch (transaction.type) {
347 | case 0: // Normal
348 | return 0.1 * fixedPoint;
349 | break;
350 |
351 | case 1: // Signature
352 | return 100 * fixedPoint;
353 | break;
354 |
355 | case 2: // Delegate
356 | return 10000 * fixedPoint;
357 | break;
358 |
359 | case 3: // Vote
360 | return 1 * fixedPoint;
361 | break;
362 | }
363 | }
364 |
365 | /**
366 | * @static
367 | * @param {Transaction} transaction
368 | * @param {ECPair} keys
369 | * @returns {ECSignature}
370 | */
371 | function sign(transaction, keys) {
372 | var hash = getHash(transaction, true, true);
373 |
374 | var signature = keys.sign(hash).toDER().toString("hex");
375 |
376 | if (!transaction.signature) {
377 | transaction.signature = signature;
378 | }
379 | return signature;
380 |
381 | }
382 |
383 | /**
384 | * @static
385 | * @param {Transaction} transaction
386 | * @param {ECPair} keys
387 | */
388 | function secondSign(transaction, keys) {
389 | var hash = getHash(transaction, false, true);
390 |
391 | var signature = keys.sign(hash).toDER().toString("hex");
392 |
393 | if (!transaction.signSignature) {
394 | transaction.signSignature = signature;
395 | }
396 | return signature;
397 | }
398 |
399 | /**
400 | * @static
401 | * @param {Transaction} transaction
402 | * @param {Network} [network=networks.ark]
403 | */
404 | function verify(transaction, network) {
405 | network = network || networks.ark;
406 |
407 | var hash = getHash(transaction, true, true);
408 |
409 | var signatureBuffer = new Buffer(transaction.signature, "hex");
410 | var senderPublicKeyBuffer = new Buffer(transaction.senderPublicKey, "hex");
411 | var ecpair = ECPair.fromPublicKeyBuffer(senderPublicKeyBuffer, network);
412 | var ecsignature = ECSignature.fromDER(signatureBuffer);
413 | var res = ecpair.verify(hash, ecsignature);
414 |
415 | return res;
416 | }
417 |
418 | /**
419 | * @static
420 | * @param {Transaction} transaction
421 | * @param {string} publicKey
422 | * @param {Network} [network]
423 | */
424 | function verifySecondSignature(transaction, publicKey, network) {
425 | network = network || networks.ark;
426 |
427 | var hash = getHash(transaction, false, true);
428 |
429 | var signSignatureBuffer = new Buffer(transaction.signSignature, "hex");
430 | var publicKeyBuffer = new Buffer(publicKey, "hex");
431 | var ecpair = ECPair.fromPublicKeyBuffer(publicKeyBuffer, network);
432 | var ecsignature = ECSignature.fromDER(signSignatureBuffer);
433 | var res = ecpair.verify(hash, ecsignature);
434 |
435 | return res;
436 | }
437 |
438 | /**
439 | * @static
440 | * @param {string} secret
441 | * @param {Network} [network]
442 | * @returns {ECPair}
443 | */
444 | function getKeys(secret, network) {
445 | var ecpair = ECPair.fromSeed(secret, network || networks.ark);
446 |
447 | ecpair.publicKey = ecpair.getPublicKeyBuffer().toString("hex");
448 | ecpair.privateKey = '';
449 |
450 | return ecpair;
451 | }
452 |
453 | /**
454 | * @static
455 | * @param {string} publicKey
456 | * @param {number} [version]
457 | * @returns {string}
458 | */
459 | function getAddress(publicKey, version){
460 | var pubKeyRegex = /^[0-9A-Fa-f]{66}$/;
461 | if(!version){
462 | version = networkVersion;
463 | }
464 | if (!pubKeyRegex.test(publicKey))
465 | throw "publicKey is invalid";
466 | var buffer = crypto_utils.ripemd160(new Buffer(publicKey, "hex"));
467 | var payload = new Buffer(21);
468 | payload.writeUInt8(version, 0);
469 | buffer.copy(payload, 1);
470 |
471 | return bs58check.encode(payload);
472 | }
473 |
474 | /**
475 | * @static
476 | * @param {number} version
477 | */
478 | function setNetworkVersion(version){
479 | networkVersion = version;
480 | }
481 |
482 | /**
483 | * @static
484 | * @returns {number}
485 | */
486 | function getNetworkVersion(){
487 | return networkVersion;
488 | }
489 |
490 | /**
491 | * @static
492 | * @param {string} address
493 | * @param {number} [version]
494 | * @returns {boolean}
495 | */
496 | function validateAddress(address, version){
497 | if(!version){
498 | version = networkVersion;
499 | }
500 | try {
501 | var decode = bs58check.decode(address);
502 | return decode[0] == version;
503 | } catch(e){
504 | return false;
505 | }
506 | }
507 |
508 | module.exports = {
509 | getBytes: getBytes,
510 | fromBytes: fromBytes,
511 | getHash: getHash,
512 | getId: getId,
513 | getFee: getFee,
514 | sign: sign,
515 | secondSign: secondSign,
516 | getKeys: getKeys,
517 | getAddress: getAddress,
518 | validateAddress: validateAddress,
519 | verify: verify,
520 | verifySecondSignature: verifySecondSignature,
521 | fixedPoint: fixedPoint,
522 | setNetworkVersion: setNetworkVersion,
523 | getNetworkVersion: getNetworkVersion,
524 | isECPair: isECPair
525 | }
526 |
--------------------------------------------------------------------------------
/lib/transactions/delegate.js:
--------------------------------------------------------------------------------
1 | /** @module delegate */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @static
9 | * @param {string} secret
10 | * @param {string} username
11 | * @param {ECPair|string} [secondSecret]
12 | * @param {number} [feeOverride]
13 | */
14 | function createDelegate(secret, username, secondSecret, feeOverride) {
15 | if (typeof secret === 'undefined' || !username) return false;
16 |
17 | var keys = secret;
18 |
19 | if (!crypto.isECPair(secret)) {
20 | keys = crypto.getKeys(secret);
21 | }
22 |
23 | if (!keys.publicKey) {
24 | throw new Error("Invalid public key");
25 | }
26 |
27 | if (feeOverride && !Number.isInteger(feeOverride)) {
28 | throw new Error('Not a valid fee')
29 | }
30 |
31 | var transaction = {
32 | type: 2,
33 | amount: 0,
34 | fee: feeOverride || constants.fees.delegate,
35 | recipientId: null,
36 | senderPublicKey: keys.publicKey,
37 | timestamp: slots.getTime(),
38 | asset: {
39 | delegate: {
40 | username: username,
41 | publicKey: keys.publicKey
42 | }
43 | }
44 | };
45 |
46 | crypto.sign(transaction, keys);
47 |
48 | if (secondSecret) {
49 | var secondKeys = secondSecret;
50 | if (!crypto.isECPair(secondSecret)) {
51 | secondKeys = crypto.getKeys(secondSecret);
52 | }
53 | crypto.secondSign(transaction, secondKeys);
54 | }
55 |
56 | transaction.id = crypto.getId(transaction);
57 | return transaction;
58 | }
59 |
60 | module.exports = {
61 | createDelegate : createDelegate
62 | }
63 |
--------------------------------------------------------------------------------
/lib/transactions/ipfs.js:
--------------------------------------------------------------------------------
1 | /** @module ipfs */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @static
9 | * @param {string} ipfshash
10 | * @param {ECPair|string} secret
11 | * @param {ECPair|string} [secondSecret]
12 | * @param {number} [feeOverride]
13 | */
14 | function createHashRegistration(ipfshash, secret, secondSecret, feeOverride) {
15 | if (!ipfshash || typeof secret === 'undefined') return false;
16 |
17 | if (feeOverride && !Number.isInteger(feeOverride)) {
18 | throw new Error('Not a valid fee')
19 | }
20 |
21 | var transaction = {
22 | type: 5,
23 | amount:0,
24 | fee: feeOverride || constants.fees.send,
25 | timestamp: slots.getTime(),
26 | asset: {}
27 | };
28 |
29 | transaction.vendorFieldHex = new Buffer(ipfshash,"utf8").toString("hex");
30 | //filling with 0x00
31 | while(transaction.vendorFieldHex.length < 128){
32 | transaction.vendorFieldHex = "00"+transaction.vendorFieldHex;
33 | }
34 |
35 | var keys = secret;
36 |
37 | if (!crypto.isECPair(secret)) {
38 | keys = crypto.getKeys(secret);
39 | }
40 |
41 | if (!keys.publicKey) {
42 | throw new Error("Invalid public key");
43 | }
44 |
45 | transaction.senderPublicKey = keys.publicKey;
46 |
47 | crypto.sign(transaction, keys);
48 |
49 | if (secondSecret) {
50 | var secondKeys = secondSecret;
51 | if (!crypto.isECPair(secondSecret)) {
52 | secondKeys = crypto.getKeys(secondSecret);
53 | }
54 | crypto.secondSign(transaction, secondKeys);
55 | }
56 |
57 | transaction.id = crypto.getId(transaction);
58 | return transaction;
59 | }
60 |
61 | module.exports = {
62 | createHashRegistration: createHashRegistration
63 | }
64 |
--------------------------------------------------------------------------------
/lib/transactions/multisignature.js:
--------------------------------------------------------------------------------
1 | /** @module multisignature */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @static
9 | * @param {Transaction} trs
10 | * @param {string} secret
11 | */
12 | function signTransaction(trs, secret) {
13 | if (!trs || !secret) return false;
14 |
15 | var keys = secret;
16 |
17 | if (!crypto.isECPair(secret)) {
18 | keys = crypto.getKeys(secret);
19 | }
20 |
21 | var signature = crypto.sign(trs, keys);
22 |
23 | return signature;
24 | }
25 |
26 | /**
27 | * @static
28 | * @param {ECPair|string} secret
29 | * @param {ECPair|string} secondSecret
30 | * @param {*} keysgroup
31 | * @param {*} lifetime
32 | * @param {*} min
33 | * @param {number} [feeOverride]
34 | */
35 | function createMultisignature(secret, secondSecret, keysgroup, lifetime, min, feeOverride) {
36 | if (typeof secret === 'undefined' || !keysgroup || !lifetime || !min) return false;
37 |
38 | var keys = secret;
39 |
40 | if (!crypto.isECPair(secret)) {
41 | keys = crypto.getKeys(secret);
42 | }
43 |
44 | if (feeOverride && !Number.isInteger(feeOverride)) {
45 | throw new Error('Not a valid fee')
46 | }
47 |
48 | var transaction = {
49 | type: 4,
50 | amount: 0,
51 | fee: (keysgroup.length + 1) * (feeOverride || constants.fees.multisignature),
52 | recipientId: null,
53 | senderPublicKey: keys.publicKey,
54 | timestamp: slots.getTime(),
55 | asset: {
56 | multisignature: {
57 | min: min,
58 | lifetime: lifetime,
59 | keysgroup: keysgroup
60 | }
61 | }
62 | };
63 |
64 | crypto.sign(transaction, keys);
65 |
66 | if (secondSecret) {
67 | var secondKeys = secondSecret;
68 | if (!crypto.isECPair(secondSecret)) {
69 | secondKeys = crypto.getKeys(secondSecret);
70 | }
71 | crypto.secondSign(transaction, secondKeys);
72 | }
73 |
74 | transaction.id = crypto.getId(transaction);
75 | return transaction;
76 | }
77 |
78 | module.exports = {
79 | createMultisignature : createMultisignature,
80 | signTransaction: signTransaction
81 | }
82 |
--------------------------------------------------------------------------------
/lib/transactions/signature.js:
--------------------------------------------------------------------------------
1 | /** @module signature */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @param {string} secondSecret
9 | * @returns {{publicKey: ECPair}}
10 | */
11 | function newSignature(secondSecret) {
12 | var keys = crypto.getKeys(secondSecret);
13 |
14 | var signature = {
15 | publicKey: keys.publicKey
16 | };
17 |
18 | return signature;
19 | }
20 |
21 | /**
22 | * @static
23 | * @param {ECPair|string} secret
24 | * @param {string} secondSecret
25 | * @param {number} [feeOverride]
26 | * @returns {Transaction}
27 | */
28 | function createSignature(secret, secondSecret, feeOverride) {
29 | if (typeof secret === 'undefined' || !secondSecret) return false;
30 |
31 | var keys = secret;
32 |
33 | if (!crypto.isECPair(secret)) {
34 | keys = crypto.getKeys(secret);
35 | }
36 |
37 | if (!keys.publicKey) {
38 | throw new Error("Invalid public key");
39 | }
40 |
41 | if (feeOverride && !Number.isInteger(feeOverride)) {
42 | throw new Error('Not a valid fee')
43 | }
44 |
45 | var signature = newSignature(secondSecret);
46 | var transaction = {
47 | type: 1,
48 | amount: 0,
49 | fee: feeOverride || constants.fees.secondsignature,
50 | recipientId: null,
51 | senderPublicKey: keys.publicKey,
52 | timestamp: slots.getTime(),
53 | asset: {
54 | signature: signature
55 | }
56 | };
57 |
58 | crypto.sign(transaction, keys);
59 | transaction.id = crypto.getId(transaction);
60 |
61 | return transaction;
62 | }
63 |
64 | module.exports = {
65 | createSignature: createSignature
66 | }
67 |
--------------------------------------------------------------------------------
/lib/transactions/transaction.js:
--------------------------------------------------------------------------------
1 | /** @module transaction */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @static
9 | * @param {string} recipientId
10 | * @param {number} amount
11 | * @param {string|null} vendorField
12 | * @param {ECPair|string} secret
13 | * @param {ECPair|string} [secondSecret]
14 | * @param {number} [version]
15 | * @param {number} [feeOverride]
16 | * @returns {Transaction}
17 | */
18 | function createTransaction(recipientId, amount, vendorField, secret, secondSecret, version, feeOverride) {
19 | if (!recipientId || !amount || typeof secret === 'undefined') return false;
20 |
21 | if(!crypto.validateAddress(recipientId, version)){
22 | throw new Error("Wrong recipientId");
23 | }
24 |
25 | var keys = secret;
26 |
27 | if (!crypto.isECPair(secret)) {
28 | keys = crypto.getKeys(secret);
29 | }
30 |
31 | if (!keys.publicKey) {
32 | throw new Error("Invalid public key");
33 | }
34 |
35 | if (feeOverride && !Number.isInteger(feeOverride)) {
36 | throw new Error('Not a valid fee')
37 | }
38 |
39 | var transaction = {
40 | type: 0,
41 | amount: amount,
42 | fee: feeOverride || constants.fees.send,
43 | recipientId: recipientId,
44 | timestamp: slots.getTime(),
45 | asset: {}
46 | };
47 |
48 | if(vendorField){
49 | transaction.vendorField=vendorField;
50 | if(transaction.vendorField.length > 64){
51 | return null;
52 | }
53 | }
54 |
55 | transaction.senderPublicKey = keys.publicKey;
56 |
57 | crypto.sign(transaction, keys);
58 |
59 | if (secondSecret) {
60 | var secondKeys = secondSecret;
61 | if (!crypto.isECPair(secondSecret)) {
62 | secondKeys = crypto.getKeys(secondSecret);
63 | }
64 | crypto.secondSign(transaction, secondKeys);
65 | }
66 |
67 | transaction.id = crypto.getId(transaction);
68 | return transaction;
69 | }
70 |
71 | module.exports = {
72 | createTransaction: createTransaction
73 | }
74 |
--------------------------------------------------------------------------------
/lib/transactions/vote.js:
--------------------------------------------------------------------------------
1 | /** @module vote */
2 |
3 | var crypto = require("./crypto.js"),
4 | constants = require("../constants.js"),
5 | slots = require("../time/slots.js");
6 |
7 | /**
8 | * @static
9 | * @param {ECPair|string} secret
10 | * @param {Array} delegates
11 | * @param {ECPair|string} [secondSecret]
12 | * @param {number} [feeOverride]
13 | * @returns {Transaction}
14 | */
15 | function createVote(secret, delegates, secondSecret, feeOverride) {
16 | if (typeof secret === 'undefined' || !Array.isArray(delegates)) return;
17 |
18 | var keys = secret;
19 |
20 | if (!crypto.isECPair(secret)) {
21 | keys = crypto.getKeys(secret);
22 | }
23 |
24 | if (!keys.publicKey) {
25 | throw new Error("Invalid public key");
26 | }
27 |
28 | if (feeOverride && !Number.isInteger(feeOverride)) {
29 | throw new Error('Not a valid fee')
30 | }
31 |
32 | var transaction = {
33 | type: 3,
34 | amount: 0,
35 | fee: feeOverride || constants.fees.vote,
36 | recipientId: crypto.getAddress(keys.publicKey),
37 | senderPublicKey: keys.publicKey,
38 | timestamp: slots.getTime(),
39 | asset: {
40 | votes: delegates
41 | }
42 | };
43 |
44 | crypto.sign(transaction, keys);
45 |
46 | if (secondSecret) {
47 | var secondKeys = secondSecret;
48 | if (!crypto.isECPair(secondSecret)) {
49 | secondKeys = crypto.getKeys(secondSecret);
50 | }
51 | crypto.secondSign(transaction, secondKeys);
52 | }
53 |
54 | transaction.id = crypto.getId(transaction);
55 |
56 | return transaction;
57 | }
58 |
59 | module.exports = {
60 | createVote: createVote
61 | }
62 |
--------------------------------------------------------------------------------
/lib/types.js:
--------------------------------------------------------------------------------
1 | var typeforce = require('typeforce')
2 |
3 | var UINT31_MAX = Math.pow(2, 31) - 1
4 | function UInt31 (value) {
5 | return typeforce.UInt32(value) && value <= UINT31_MAX
6 | }
7 |
8 | function BIP32Path (value) {
9 | return typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
10 | }
11 | BIP32Path.toJSON = function () { return 'BIP32 derivation path' }
12 |
13 | var SATOSHI_MAX = 21 * 1e14
14 | function Satoshi (value) {
15 | return typeforce.UInt53(value) && value <= SATOSHI_MAX
16 | }
17 |
18 | // external dependent types
19 | var BigInt = typeforce.quacksLike('BigInteger')
20 | var ECPoint = typeforce.quacksLike('Point')
21 |
22 | // exposed, external API
23 | var ECSignature = typeforce.compile({ r: BigInt, s: BigInt })
24 | var Network = typeforce.compile({
25 | messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
26 | bip32: {
27 | public: typeforce.UInt32,
28 | private: typeforce.UInt32
29 | },
30 | pubKeyHash: typeforce.UInt8,
31 | wif: typeforce.UInt8
32 | })
33 |
34 | // extend typeforce types with ours
35 | var types = {
36 | BigInt: BigInt,
37 | BIP32Path: BIP32Path,
38 | Buffer256bit: typeforce.BufferN(32),
39 | ECPoint: ECPoint,
40 | ECSignature: ECSignature,
41 | Hash160bit: typeforce.BufferN(20),
42 | Hash256bit: typeforce.BufferN(32),
43 | Network: Network,
44 | Satoshi: Satoshi,
45 | UInt31: UInt31
46 | }
47 |
48 | for (var typeName in typeforce) {
49 | types[typeName] = typeforce[typeName]
50 | }
51 |
52 | module.exports = types
53 |
--------------------------------------------------------------------------------
/lib/v2/transactions/crypto.js:
--------------------------------------------------------------------------------
1 | var crypto = require("crypto");
2 | var crypto_utils = require("../../crypto.js");
3 | var ECPair = require("../../ecpair.js");
4 | var ECSignature = require("../../ecsignature.js");
5 | var networks = require("../../networks.js")
6 |
7 | var bs58check = require('bs58check')
8 |
9 | if (typeof Buffer === "undefined") {
10 | Buffer = require("buffer/").Buffer;
11 | }
12 |
13 | var ByteBuffer = require("bytebuffer");
14 |
15 |
16 | var fixedPoint = Math.pow(10, 8);
17 | // default is ark mainnet
18 | var networkVersion = 0x17;
19 |
20 |
21 | function getBytes(transaction) {
22 | var bb = new ByteBuffer(512, true);
23 | bb.writeByte(0xff); // fill, to disambiguate from v1
24 | bb.writeByte(transaction.version); // version 2
25 | bb.writeByte(transaction.network); // ark = 0x17, devnet = 0x30
26 | bb.writeByte(transaction.type);
27 | bb.writeInt(transaction.timestamp);
28 | bb.append(transaction.senderPublicKey, "hex");
29 | bb.writeLong(transaction.fee);
30 | if(transaction.vendorFieldHex){
31 | bb.writeByte(transaction.vendorFieldHex.length/2);
32 | bb.append(transaction.vendorFieldHex, "hex");
33 | }
34 | else {
35 | bb.writeByte(0x00);
36 | }
37 |
38 | switch (transaction.type) {
39 | case 0: // Transfer
40 | bb.writeLong(transaction.amount);
41 | bb.writeInt(transaction.expiration);
42 | bb.append(bs58check.decode(transaction.recipientId));
43 | break;
44 |
45 | case 1: // Signature
46 | bb.append(transaction.asset.signature.publicKey,"hex");
47 | break;
48 |
49 | case 2: // Delegate
50 | var delegateBytes = new Buffer(transaction.asset.delegate.username, "utf8");
51 | bb.writeByte(delegateBytes.length/2);
52 | bb.append(delegateBytes,"hex");
53 | break;
54 |
55 | case 3: // Vote
56 | var voteBytes = transaction.asset.votes.map(function(vote){
57 | return (vote[0] == "+" ? "01" : "00") + vote.slice(1);
58 | }).join("");
59 | bb.writeByte(transaction.asset.votes.length);
60 | bb.append(voteBytes,"hex");
61 | break;
62 |
63 | case 4: // Multi-Signature
64 | var keysgroupBuffer = new Buffer(transaction.asset.multisignature.keysgroup.join(""), "hex");
65 | bb.writeByte(transaction.asset.multisignature.min);
66 | bb.writeByte(transaction.asset.multisignature.keysgroup.length);
67 | bb.writeByte(transaction.asset.multisignature.lifetime);
68 | bb.append(keysgroupBuffer,"hex");
69 | break;
70 |
71 | case 5: // IPFS
72 | bb.writeByte(transaction.asset.ipfs.dag.length/2);
73 | bb.append(transaction.asset.ipfs.dag,"hex");
74 | break;
75 |
76 | case 6: // timelock transfer
77 | bb.writeLong(transaction.amount);
78 | bb.writeByte(transaction.timelocktype);
79 | bb.writeInt(transaction.timelock);
80 | bb.append(bs58check.decode(transaction.recipientId));
81 | break;
82 |
83 | case 7: // multipayment
84 | bb.writeInt(transaction.asset.payments.length);
85 | transaction.asset.payments.forEach(function(p) {
86 | bb.writeLong(p.amount);
87 | bb.append(bs58check.decode(p.recipientId));
88 | });
89 | break;
90 |
91 | case 8: // delegate resignation - empty payload
92 | break;
93 | }
94 | bb.flip();
95 | return bb.toBuffer();
96 | }
97 |
98 | function fromBytes(hexString){
99 | var tx={};
100 | var buf = new Buffer(hexString, "hex");
101 | tx.version = buf.readInt8(1) & 0xff;
102 | tx.network = buf.readInt8(2) & 0xff;
103 | tx.type = buf.readInt8(3) & 0xff;
104 | tx.timestamp = buf.readUInt32LE(4);
105 | tx.senderPublicKey = hexString.substring(16,16+33*2);
106 | tx.fee = buf.readUInt32LE(41);
107 | var vflength = buf.readInt8(41+8) & 0xff;
108 | if(vflength > 0){
109 | tx.vendorFieldHex=hexString.substring((41+8+1)*2,(41+8+1)*2+vflength*2);
110 | }
111 |
112 | var assetOffset = (41+8+1)*2+vflength*2;
113 |
114 | if(tx.type == 0){ // transfer
115 | tx.amount = buf.readUInt32LE(assetOffset/2);
116 | tx.expiration = buf.readUInt32LE(assetOffset/2+8);
117 | tx.recipientId = bs58check.encode(buf.slice(assetOffset/2+12,assetOffset/2+12+21));
118 | parseSignatures(hexString, tx, assetOffset+(21+12)*2);
119 | }
120 | else if(tx.type == 1){ // second signature registration
121 | tx.asset = {
122 | signature : {
123 | publicKey : hexString.substring(assetOffset,assetOffset+66)
124 | }
125 | }
126 | parseSignatures(hexString, tx, assetOffset+66);
127 | }
128 | else if(tx.type == 2){ // delegate registration
129 | var usernamelength = buf.readInt8(assetOffset/2) & 0xff;
130 |
131 | tx.asset = {
132 | delegate: {
133 | username: buf.slice(assetOffset/2+1, assetOffset/2+1 + usernamelength).toString("utf8")
134 | }
135 | };
136 | parseSignatures(hexString, tx, assetOffset + (usernamelength+1)*2);
137 | }
138 | else if(tx.type == 3){ // vote
139 | var votelength = buf.readInt8(assetOffset/2) & 0xff;
140 | tx.asset = {votes:[]};
141 | var vote;
142 | for(var i = 0; i=4"
8 | },
9 | "scripts": {
10 | "build:browserify": "browserify index.js -o app.js",
11 | "clean:browserify": "shx rm app.js",
12 | "build:docs": "jsdoc -c jsdoc.json",
13 | "clean:docs": "shx rm -r ./docs",
14 | "lint": "eslint .",
15 | "test": "mocha test/ark.js test/*/*"
16 | },
17 | "directories": {
18 | "doc": "./doc",
19 | "lib": "./lib",
20 | "test": "./test"
21 | },
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/ArkEcosystem/ark-js.git"
25 | },
26 | "homepage": "https://github.com/ArkEcosystem/ark-js",
27 | "keywords": [
28 | "api",
29 | "ark",
30 | "blockchain",
31 | "client",
32 | "cryptocurrency",
33 | "javascript",
34 | "server",
35 | "transaction"
36 | ],
37 | "bugs": "https://github.com/ArkEcosystem/ark-js/issues",
38 | "contributors": [
39 | "FX Thoorens ",
40 | "Guillaume Verbal ",
41 | "Boris Povod ",
42 | "Oliver Beddows "
43 | ],
44 | "license": "MIT",
45 | "dependencies": {
46 | "bigi": "^1.4.2",
47 | "bip66": "^1.1.5",
48 | "browserify-bignum": "^1.3.0-2",
49 | "bs58check": "^2.0.2",
50 | "buffer": "^5.0.8",
51 | "bytebuffer": "^5.0.1",
52 | "create-hash": "^1.1.3",
53 | "create-hmac": "^1.1.6",
54 | "crypto-browserify": "^3.12.0",
55 | "ecdsa": "^0.7.0",
56 | "ecurve": "^1.0.5",
57 | "js-nacl": "^1.2.2",
58 | "randombytes": "^2.0.5",
59 | "secp256k1": "^3.3.0",
60 | "typeforce": "^1.11.7",
61 | "wif": "^2.0.6"
62 | },
63 | "devDependencies": {
64 | "browserify": "^14.4.0",
65 | "eslint": "^4.10.0",
66 | "jsdoc": "^3.5.5",
67 | "marked": "^0.3.12",
68 | "mocha": "^4.0.1",
69 | "proxyquire": "^1.8.0",
70 | "should": "^13.1.3",
71 | "shx": "^0.2.2",
72 | "sinon": "^4.1.1",
73 | "sinon-test": "^2.1.2"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/test/ark.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../index.js");
4 |
5 | describe("Ark JS", function () {
6 |
7 | it("should be ok", function () {
8 | (ark).should.be.ok;
9 | });
10 |
11 | it("should be object", function () {
12 | (ark).should.be.type("object");
13 | });
14 |
15 | it("should have properties", function () {
16 | var properties = ["transaction", "signature", "vote", "delegate", "crypto"];
17 |
18 | properties.forEach(function (property) {
19 | (ark).should.have.property(property);
20 | });
21 | });
22 |
23 | });
24 |
--------------------------------------------------------------------------------
/test/crypto/fixtures.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "hex": "0000000000000001",
4 | "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8",
5 | "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284",
6 | "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633",
7 | "sha1": "cb473678976f425d6ec1339838f11011007ad27d",
8 | "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50"
9 | },
10 | {
11 | "hex": "0101010101010101",
12 | "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc",
13 | "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23",
14 | "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630",
15 | "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec",
16 | "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061"
17 | },
18 | {
19 | "hex": "ffffffffffffffff",
20 | "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4",
21 | "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad",
22 | "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120",
23 | "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089",
24 | "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca"
25 | },
26 | {
27 | "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320",
28 | "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5",
29 | "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799",
30 | "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5",
31 | "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344",
32 | "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da"
33 | }
34 | ]
35 |
--------------------------------------------------------------------------------
/test/crypto/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 | var ECPair = require('../../lib/ecpair');
5 |
6 | var ecdsa = require('../../lib/ecdsa')
7 | var ecurve = require('ecurve')
8 | var curve = ecdsa.__curve
9 |
10 | describe("crypto.js", function () {
11 |
12 | var crypto = ark.crypto;
13 |
14 | it("should be ok", function () {
15 | (crypto).should.be.ok;
16 | });
17 |
18 | it("should be object", function () {
19 | (crypto).should.be.type("object");
20 | });
21 |
22 | it("should has properties", function () {
23 | var properties = ["getBytes", "getHash", "getId", "getFee", "sign", "secondSign", "getKeys", "getAddress", "verify", "verifySecondSignature", "fixedPoint"];
24 | properties.forEach(function (property) {
25 | (crypto).should.have.property(property);
26 | });
27 | });
28 |
29 | describe("#getBytes", function () {
30 | var getBytes = crypto.getBytes;
31 | var bytes = null;
32 |
33 | it("should be ok", function () {
34 | (getBytes).should.be.ok;
35 | });
36 |
37 | it("should be a function", function () {
38 | (getBytes).should.be.type("function");
39 | });
40 |
41 | it("should return Buffer of simply transaction and buffer must be 202 length", function () {
42 | var transaction = {
43 | type: 0,
44 | amount: 1000,
45 | fee: 2000,
46 | recipientId: "AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff",
47 | timestamp: 141738,
48 | asset: {},
49 | senderPublicKey: "5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09",
50 | signature: "618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a",
51 | id: "13987348420913138422"
52 | };
53 |
54 | bytes = getBytes(transaction);
55 | (bytes).should.be.ok;
56 | (bytes).should.be.type("object");
57 | (bytes.length).should.be.equal(202);
58 | });
59 |
60 | it("should return Buffer of transaction with second signature and buffer must be 266 length", function () {
61 | var transaction = {
62 | type: 0,
63 | amount: 1000,
64 | fee: 2000,
65 | recipientId: "AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff",
66 | timestamp: 141738,
67 | asset: {},
68 | senderPublicKey: "5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09",
69 | signature: "618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a",
70 | signSignature: "618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a",
71 | id: "13987348420913138422"
72 | };
73 |
74 | bytes = getBytes(transaction);
75 | (bytes).should.be.ok;
76 | (bytes).should.be.type("object");
77 | (bytes.length).should.be.equal(266);
78 | });
79 | });
80 |
81 | describe("#getHash", function () {
82 | var getHash = crypto.getHash;
83 |
84 | it("should be ok", function () {
85 | (getHash).should.be.ok;
86 | });
87 |
88 | it("should be a function", function () {
89 | (getHash).should.be.type("function");
90 | })
91 |
92 | it("should return Buffer and Buffer most be 32 bytes length", function () {
93 | var transaction = {
94 | type: 0,
95 | amount: 1000,
96 | fee: 2000,
97 | recipientId: "AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff",
98 | timestamp: 141738,
99 | asset: {},
100 | senderPublicKey: "5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09",
101 | signature: "618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a",
102 | };
103 |
104 | var result = getHash(transaction);
105 | (result).should.be.ok;
106 | (result).should.be.type("object");
107 | (result.length).should.be.equal(32);
108 | });
109 | });
110 |
111 | describe("#getId", function () {
112 | var getId = crypto.getId;
113 |
114 | it("should be ok", function () {
115 | (getId).should.be.ok;
116 | });
117 |
118 | it("should be a function", function () {
119 | (getId).should.be.type("function");
120 | });
121 |
122 | it("should return string id and be equal to 619fd7971db6f317fdee3675c862291c976d072a0a1782410e3a6f5309022491", function () {
123 | var transaction = {
124 | type: 0,
125 | amount: 1000,
126 | fee: 2000,
127 | recipientId: "AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff",
128 | timestamp: 141738,
129 | asset: {},
130 | senderPublicKey: "5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09",
131 | signature: "618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a"
132 | };
133 |
134 | var id = getId(transaction);
135 | (id).should.be.type("string").and.equal("952e33b66c35a3805015657c008e73a0dee1efefd9af8c41adb59fe79745ccea");
136 | });
137 | });
138 |
139 | describe("#getFee", function () {
140 | var getFee = crypto.getFee;
141 |
142 | it("should be ok", function () {
143 | (getFee).should.be.ok;
144 | })
145 |
146 | it("should be a function", function () {
147 | (getFee).should.be.type("function");
148 | });
149 |
150 | it("should return number", function () {
151 | var fee = getFee({amount: 100000, type: 0});
152 | (fee).should.be.type("number");
153 | (fee).should.be.not.NaN;
154 | });
155 |
156 | it("should return 10000000", function () {
157 | var fee = getFee({amount: 100000, type: 0});
158 | (fee).should.be.type("number").and.equal(10000000);
159 | });
160 |
161 | it("should return 10000000000", function () {
162 | var fee = getFee({type: 1});
163 | (fee).should.be.type("number").and.equal(10000000000);
164 | });
165 |
166 | it("should be equal 1000000000000", function () {
167 | var fee = getFee({type: 2});
168 | (fee).should.be.type("number").and.equal(1000000000000);
169 | });
170 |
171 | it("should be equal 100000000", function () {
172 | var fee = getFee({type: 3});
173 | (fee).should.be.type("number").and.equal(100000000);
174 | });
175 | });
176 |
177 | describe("fixedPoint", function () {
178 | var fixedPoint = crypto.fixedPoint;
179 |
180 | it("should be ok", function () {
181 | (fixedPoint).should.be.ok;
182 | })
183 |
184 | it("should be number", function () {
185 | (fixedPoint).should.be.type("number").and.not.NaN;
186 | });
187 |
188 | it("should be equal 100000000", function () {
189 | (fixedPoint).should.be.equal(100000000);
190 | });
191 | });
192 |
193 | describe("#sign", function () {
194 | var sign = crypto.sign;
195 |
196 | it("should be ok", function () {
197 | (sign).should.be.ok;
198 | });
199 |
200 | it("should be a function", function () {
201 | (sign).should.be.type("function");
202 | });
203 | });
204 |
205 | describe("#secondSign", function () {
206 | var secondSign = crypto.secondSign;
207 |
208 | it("should be ok", function () {
209 | (secondSign).should.be.ok;
210 | });
211 |
212 | it("should be a function", function () {
213 | (secondSign).should.be.type("function");
214 | });
215 | });
216 |
217 | describe("#getKeys", function () {
218 | var getKeys = crypto.getKeys;
219 |
220 | it("should be ok", function () {
221 | (getKeys).should.be.ok;
222 | });
223 |
224 | it("should be a function", function () {
225 | (getKeys).should.be.type("function");
226 | });
227 |
228 | it("should return two keys in hex", function () {
229 | var keys = getKeys("secret");
230 |
231 | (keys).should.be.ok;
232 | (keys).should.be.type("object");
233 | (keys).should.have.property("publicKey");
234 | (keys).should.have.property("privateKey");
235 | (keys.publicKey).should.be.type("string").and.match(function () {
236 | try {
237 | new Buffer(keys.publicKey, "hex");
238 | } catch (e) {
239 | return false;
240 | }
241 |
242 | return true;
243 | });
244 | (keys.privateKey).should.be.type("string").and.match(function () {
245 | try {
246 | new Buffer(keys.privateKey, "hex");
247 | } catch (e) {
248 | return false;
249 | }
250 |
251 | return true;
252 | });
253 | });
254 | });
255 |
256 | describe("#getAddress", function () {
257 | var getAddress = crypto.getAddress;
258 |
259 | it("should be ok", function () {
260 | (getAddress).should.be.ok;
261 | })
262 |
263 | it("should be a function", function () {
264 | (getAddress).should.be.type("function");
265 | });
266 |
267 | it("should generate address by publicKey", function () {
268 | var keys = crypto.getKeys("secret");
269 | var address = getAddress(keys.publicKey);
270 |
271 | (address).should.be.ok;
272 | (address).should.be.type("string");
273 | (address).should.be.equal("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff");
274 | });
275 |
276 | it("should generate address by publicKey - second test", function () {
277 | var keys = crypto.getKeys("secret second test to be sure it works correctly");
278 | var address = getAddress(keys.publicKey);
279 |
280 | (address).should.be.ok;
281 | (address).should.be.type("string");
282 | (address).should.be.equal("AQSqYnjmwj1GBL5twD4K9EBXDaTHZognox");
283 | });
284 |
285 | it("should generate the same address as ECPair.getAddress()", function () {
286 | var keys = crypto.getKeys("secret second test to be sure it works correctly");
287 | var address = getAddress(keys.publicKey);
288 |
289 | var Q = ecurve.Point.decodeFrom(curve, new Buffer(keys.publicKey, 'hex'))
290 | var keyPair = new ECPair(null, Q);
291 |
292 | (address).should.be.equal(keyPair.getAddress());
293 | });
294 | });
295 |
296 | describe("#verify", function () {
297 | var verify = crypto.verify;
298 |
299 | it("should be ok", function () {
300 | (verify).should.be.ok;
301 | })
302 |
303 | it("should be function", function () {
304 | (verify).should.be.type("function");
305 | });
306 | });
307 |
308 | describe("#verifySecondSignature", function () {
309 | var verifySecondSignature = crypto.verifySecondSignature;
310 |
311 | it("should be ok", function () {
312 | (verifySecondSignature).should.be.ok;
313 | });
314 |
315 | it("should be function", function () {
316 | (verifySecondSignature).should.be.type("function");
317 | });
318 | });
319 | });
320 |
321 | describe("different networks", function () {
322 |
323 | it("validate address on tesnet should be ok", function () {
324 | ark.crypto.setNetworkVersion(0x52);
325 | ark.crypto.getNetworkVersion().should.equal(0x52);
326 | var validate = ark.crypto.validateAddress("a6fpb1BJZq4otWiVsBcuLG1ZGs5WsqqQtH");
327 | (validate).should.equal(true);
328 | ark.crypto.setNetworkVersion(0x17);
329 | ark.crypto.getNetworkVersion().should.equal(0x17);
330 | });
331 | });
332 |
333 | describe("delegate.js", function () {
334 | var delegate = ark.delegate;
335 |
336 | it("should be ok", function () {
337 | (delegate).should.be.ok;
338 | });
339 |
340 | it("should be function", function () {
341 | (delegate).should.be.type("object");
342 | });
343 |
344 | it("should have property createDelegate", function () {
345 | (delegate).should.have.property("createDelegate");
346 | });
347 |
348 | describe("#createDelegate", function () {
349 | var createDelegate = delegate.createDelegate;
350 | var trs = null;
351 |
352 | it("should be ok", function () {
353 | (createDelegate).should.be.ok;
354 | });
355 |
356 | it("should be function", function () {
357 | (createDelegate).should.be.type("function");
358 | });
359 |
360 | it("should create delegate", function () {
361 | trs = createDelegate("secret", "delegate", "secret 2");
362 | });
363 |
364 | it("should create transaction with fee override", function () {
365 | const feeOverride = 1000000
366 | trs = createDelegate('secret', 'delegate', 'second secret', feeOverride);
367 | (trs).should.be.ok;
368 | (trs.fee).should.equal(feeOverride)
369 | });
370 |
371 | it("should fail to create transaction with invalid fee override", function (done) {
372 | const feeOverride = '1000000'
373 | try {
374 | trs = createDelegate('secret', 'delegate', 'second secret', feeOverride);
375 | should.fail()
376 | } catch (error) {
377 | done()
378 | }
379 | });
380 |
381 | it("should be deserialised correctly", function () {
382 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(trs).toString("hex"));
383 | delete deserialisedTx.vendorFieldHex;
384 | var keys = Object.keys(deserialisedTx)
385 | for(key in keys){
386 | if(keys[key] == "asset"){
387 | deserialisedTx.asset.delegate.username.should.equal(trs.asset.delegate.username);
388 | }
389 | else {
390 | deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
391 | }
392 | }
393 | });
394 |
395 | describe("returned delegate", function () {
396 | var keys = ark.crypto.getKeys("secret");
397 | var secondKeys = ark.crypto.getKeys("secret 2");
398 |
399 | it("should be ok", function () {
400 | (trs).should.be.ok;
401 | });
402 |
403 | it("should be object", function () {
404 | (trs).should.be.type("object");
405 | });
406 |
407 | it("should have recipientId equal null", function () {
408 | (trs).should.have.property("recipientId").and.type("object").and.be.empty;
409 | })
410 |
411 | it("shoud have amount equal 0", function () {
412 | (trs).should.have.property("amount").and.type("number").and.equal(0);
413 | })
414 |
415 | it("should have type equal 2", function () {
416 | (trs).should.have.property("type").and.type("number").and.equal(2);
417 | });
418 |
419 | // it("should have id equal 11636400490162225218", function () {
420 | // (trs).should.have.property("id").and.type("string").and.equal('11636400490162225218');
421 | // });
422 |
423 | it("should have timestamp number", function () {
424 | (trs).should.have.property("timestamp").and.type("number");
425 | });
426 |
427 | it("should have senderPublicKey in hex", function () {
428 | (trs).should.have.property("senderPublicKey").and.type("string").and.match(function () {
429 | try {
430 | new Buffer(trs.senderPublicKey, "hex");
431 | } catch (e) {
432 | return false;
433 | }
434 |
435 | return true;
436 | }).and.equal(keys.publicKey);
437 | });
438 |
439 | it("should have signature in hex", function () {
440 | (trs).should.have.property("signature").and.type("string").and.match(function () {
441 | try {
442 | new Buffer(trs.signature, "hex");
443 | } catch (e) {
444 | return false;
445 | }
446 |
447 | return true;
448 | });
449 | });
450 |
451 | it("should have second signature in hex", function () {
452 | (trs).should.have.property("signSignature").and.type("string").and.match(function () {
453 | try {
454 | new Buffer(trs.signSignature, "hex");
455 | } catch (e) {
456 | return false;
457 | }
458 |
459 | return true;
460 | });
461 | });
462 |
463 | it("should have delegate asset", function () {
464 | (trs).should.have.property("asset").and.type("object");
465 | (trs.asset).should.have.have.property("delegate");
466 | })
467 |
468 | it("should be signed correctly", function () {
469 | var result = ark.crypto.verify(trs);
470 | (result).should.be.ok;
471 | });
472 |
473 | it("should be second signed correctly", function () {
474 | var result = ark.crypto.verifySecondSignature(trs, secondKeys.publicKey);
475 | (result).should.be.ok;
476 | });
477 |
478 | it("should not be signed correctly now", function () {
479 | trs.amount = 100;
480 | var result = ark.crypto.verify(trs);
481 | (result).should.be.not.ok;
482 | });
483 |
484 | it("should not be second signed correctly now", function () {
485 | trs.amount = 100;
486 | var result = ark.crypto.verifySecondSignature(trs, secondKeys.publicKey);
487 | (result).should.be.not.ok;
488 | });
489 |
490 | describe("delegate asset", function () {
491 | it("should be ok", function () {
492 | (trs.asset.delegate).should.be.ok;
493 | });
494 |
495 | it("should be object", function () {
496 | (trs.asset.delegate).should.be.type("object");
497 | });
498 |
499 | it("should be have property username", function () {
500 | (trs.asset.delegate).should.have.property("username").and.be.type("string").and.equal("delegate");
501 | });
502 | });
503 | });
504 | });
505 |
506 | });
507 |
--------------------------------------------------------------------------------
/test/ecdsa/fixtures.json:
--------------------------------------------------------------------------------
1 | {
2 | "valid": {
3 | "ecdsa": [
4 | {
5 | "d": "01",
6 | "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
7 | "message": "Everything should be made as simple as possible, but not simpler.",
8 | "i": 0,
9 | "signature": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
10 | },
11 | {
12 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
13 | "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
14 | "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
15 | "i": 0,
16 | "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
17 | },
18 | {
19 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
20 | "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
21 | "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
22 | "i": 0,
23 | "signature": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
24 | },
25 | {
26 | "d": "0000000000000000000000000000000000000000000000000000000000000001",
27 | "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
28 | "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
29 | "i": 1,
30 | "signature": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
31 | },
32 | {
33 | "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
34 | "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
35 | "message": "Computer science is no more about computers than astronomy is about telescopes.",
36 | "i": 0,
37 | "signature": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
38 | },
39 | {
40 | "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
41 | "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
42 | "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
43 | "i": 1,
44 | "signature": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
45 | },
46 | {
47 | "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
48 | "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
49 | "message": "The question of whether computers can think is like the question of whether submarines can swim.",
50 | "i": 1,
51 | "signature": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
52 | }
53 | ],
54 | "rfc6979": [
55 | {
56 | "message": "test data",
57 | "d": "fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e",
58 | "k0": "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e",
59 | "k1": "727fbcb59eb48b1d7d46f95a04991fc512eb9dbf9105628e3aec87428df28fd8",
60 | "k15": "398f0e2c9f79728f7b3d84d447ac3a86d8b2083c8f234a0ffa9c4043d68bd258"
61 | },
62 | {
63 | "message": "Everything should be made as simple as possible, but not simpler.",
64 | "d": "0000000000000000000000000000000000000000000000000000000000000001",
65 | "k0": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
66 | "k1": "df55b6d1b5c48184622b0ead41a0e02bfa5ac3ebdb4c34701454e80aabf36f56",
67 | "k15": "def007a9a3c2f7c769c75da9d47f2af84075af95cadd1407393dc1e26086ef87"
68 | },
69 | {
70 | "message": "Satoshi Nakamoto",
71 | "d": "0000000000000000000000000000000000000000000000000000000000000002",
72 | "k0": "d3edc1b8224e953f6ee05c8bbf7ae228f461030e47caf97cde91430b4607405e",
73 | "k1": "f86d8e43c09a6a83953f0ab6d0af59fb7446b4660119902e9967067596b58374",
74 | "k15": "241d1f57d6cfd2f73b1ada7907b199951f95ef5ad362b13aed84009656e0254a"
75 | },
76 | {
77 | "message": "Diffie Hellman",
78 | "d": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
79 | "k0": "c378a41cb17dce12340788dd3503635f54f894c306d52f6e9bc4b8f18d27afcc",
80 | "k1": "90756c96fef41152ac9abe08819c4e95f16da2af472880192c69a2b7bac29114",
81 | "k15": "7b3f53300ab0ccd0f698f4d67db87c44cf3e9e513d9df61137256652b2e94e7c"
82 | },
83 | {
84 | "message": "Japan",
85 | "d": "8080808080808080808080808080808080808080808080808080808080808080",
86 | "k0": "f471e61b51d2d8db78f3dae19d973616f57cdc54caaa81c269394b8c34edcf59",
87 | "k1": "6819d85b9730acc876fdf59e162bf309e9f63dd35550edf20869d23c2f3e6d17",
88 | "k15": "d8e8bae3ee330a198d1f5e00ad7c5f9ed7c24c357c0a004322abca5d9cd17847"
89 | },
90 | {
91 | "message": "Bitcoin",
92 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
93 | "k0": "36c848ffb2cbecc5422c33a994955b807665317c1ce2a0f59c689321aaa631cc",
94 | "k1": "4ed8de1ec952a4f5b3bd79d1ff96446bcd45cabb00fc6ca127183e14671bcb85",
95 | "k15": "56b6f47babc1662c011d3b1f93aa51a6e9b5f6512e9f2e16821a238d450a31f8"
96 | },
97 | {
98 | "message": "i2FLPP8WEus5WPjpoHwheXOMSobUJVaZM1JPMQZq",
99 | "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
100 | "k0": "6e9b434fcc6bbb081a0463c094356b47d62d7efae7da9c518ed7bac23f4e2ed6",
101 | "k1": "ae5323ae338d6117ce8520a43b92eacd2ea1312ae514d53d8e34010154c593bb",
102 | "k15": "3eaa1b61d1b8ab2f1ca71219c399f2b8b3defa624719f1e96fe3957628c2c4ea"
103 | },
104 | {
105 | "message": "lEE55EJNP7aLrMtjkeJKKux4Yg0E8E1SAJnWTCEh",
106 | "d": "3881e5286abc580bb6139fe8e83d7c8271c6fe5e5c2d640c1f0ed0e1ee37edc9",
107 | "k0": "5b606665a16da29cc1c5411d744ab554640479dd8abd3c04ff23bd6b302e7034",
108 | "k1": "f8b25263152c042807c992eacd2ac2cc5790d1e9957c394f77ea368e3d9923bd",
109 | "k15": "ea624578f7e7964ac1d84adb5b5087dd14f0ee78b49072aa19051cc15dab6f33"
110 | },
111 | {
112 | "message": "2SaVPvhxkAPrayIVKcsoQO5DKA8Uv5X/esZFlf+y",
113 | "d": "7259dff07922de7f9c4c5720d68c9745e230b32508c497dd24cb95ef18856631",
114 | "k0": "3ab6c19ab5d3aea6aa0c6da37516b1d6e28e3985019b3adb388714e8f536686b",
115 | "k1": "19af21b05004b0ce9cdca82458a371a9d2cf0dc35a813108c557b551c08eb52e",
116 | "k15": "117a32665fca1b7137a91c4739ac5719fec0cf2e146f40f8e7c21b45a07ebc6a"
117 | },
118 | {
119 | "message": "00A0OwO2THi7j5Z/jp0FmN6nn7N/DQd6eBnCS+/b",
120 | "d": "0d6ea45d62b334777d6995052965c795a4f8506044b4fd7dc59c15656a28f7aa",
121 | "k0": "79487de0c8799158294d94c0eb92ee4b567e4dc7ca18addc86e49d31ce1d2db6",
122 | "k1": "9561d2401164a48a8f600882753b3105ebdd35e2358f4f808c4f549c91490009",
123 | "k15": "b0d273634129ff4dbdf0df317d4062a1dbc58818f88878ffdb4ec511c77976c0"
124 | }
125 | ]
126 | },
127 | "invalid": {
128 | "verify": [
129 | {
130 | "description": "The wrong signature",
131 | "d": "01",
132 | "message": "foo",
133 | "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
134 | },
135 | {
136 | "description": "Invalid r value (< 0)",
137 | "d": "01",
138 | "message": "foo",
139 | "signatureRaw": {
140 | "r": "-01",
141 | "s": "02"
142 | }
143 | },
144 | {
145 | "description": "Invalid r value (== 0)",
146 | "d": "01",
147 | "message": "foo",
148 | "signatureRaw": {
149 | "r": "00",
150 | "s": "02"
151 | }
152 | },
153 | {
154 | "description": "Invalid r value (>= n)",
155 | "d": "01",
156 | "message": "foo",
157 | "signatureRaw": {
158 | "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
159 | "s": "02"
160 | }
161 | },
162 | {
163 | "description": "Invalid s value (< 0)",
164 | "d": "01",
165 | "message": "foo",
166 | "signatureRaw": {
167 | "r": "02",
168 | "s": "-01"
169 | }
170 | },
171 | {
172 | "description": "Invalid s value (== 0)",
173 | "d": "01",
174 | "message": "foo",
175 | "signatureRaw": {
176 | "r": "02",
177 | "s": "00"
178 | }
179 | },
180 | {
181 | "description": "Invalid s value (>= n)",
182 | "d": "01",
183 | "message": "foo",
184 | "signatureRaw": {
185 | "r": "02",
186 | "s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
187 | }
188 | },
189 | {
190 | "description": "Invalid r, s values (r = s = -n)",
191 | "d": "01",
192 | "message": "foo",
193 | "signatureRaw": {
194 | "r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
195 | "s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
196 | }
197 | }
198 | ]
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/test/ecdsa/index.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | var assert = require('assert')
4 | var bcrypto = require('../../lib/crypto')
5 | var ecdsa = require('../../lib/ecdsa')
6 | var sinon = require('sinon')
7 | var sinonTest = require('sinon-test')(sinon)
8 |
9 | var BigInteger = require('bigi')
10 | var ECSignature = require('../../lib/ecsignature')
11 |
12 | var curve = ecdsa.__curve
13 |
14 | var fixtures = require('./fixtures.json')
15 |
16 | describe('ecdsa', function () {
17 | describe('deterministicGenerateK', function () {
18 | function checkSig () {
19 | return true
20 | }
21 |
22 | fixtures.valid.ecdsa.forEach(function (f) {
23 | it('for "' + f.message + '"', function () {
24 | var x = BigInteger.fromHex(f.d).toBuffer(32)
25 | var h1 = bcrypto.sha256(f.message)
26 |
27 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
28 | assert.strictEqual(k.toHex(), f.k)
29 | })
30 | })
31 |
32 | it('loops until an appropriate k value is found', sinonTest(function () {
33 | this.mock(BigInteger).expects('fromBuffer')
34 | .exactly(3)
35 | .onCall(0).returns(new BigInteger('0')) // < 1
36 | .onCall(1).returns(curve.n) // > n-1
37 | .onCall(2).returns(new BigInteger('42')) // valid
38 |
39 | var x = new BigInteger('1').toBuffer(32)
40 | var h1 = new Buffer(32)
41 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
42 |
43 | assert.strictEqual(k.toString(), '42')
44 | }))
45 |
46 | it('loops until a suitable signature is found', sinonTest(function () {
47 | this.mock(BigInteger).expects('fromBuffer')
48 | .exactly(4)
49 | .onCall(0).returns(new BigInteger('0')) // < 1
50 | .onCall(1).returns(curve.n) // > n-1
51 | .onCall(2).returns(new BigInteger('42')) // valid, but 'bad' signature
52 | .onCall(3).returns(new BigInteger('53')) // valid, good signature
53 |
54 | var checkSig = this.mock()
55 | checkSig.exactly(2)
56 | checkSig.onCall(0).returns(false) // bad signature
57 | checkSig.onCall(1).returns(true) // good signature
58 |
59 | var x = new BigInteger('1').toBuffer(32)
60 | var h1 = new Buffer(32)
61 | var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
62 |
63 | assert.strictEqual(k.toString(), '53')
64 | }))
65 |
66 | fixtures.valid.rfc6979.forEach(function (f) {
67 | it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () {
68 | var x = BigInteger.fromHex(f.d).toBuffer(32)
69 | var h1 = bcrypto.sha256(f.message)
70 |
71 | var results = []
72 | ecdsa.deterministicGenerateK(h1, x, function (k) {
73 | results.push(k)
74 |
75 | return results.length === 16
76 | })
77 |
78 | assert.strictEqual(results[0].toHex(), f.k0)
79 | assert.strictEqual(results[1].toHex(), f.k1)
80 | assert.strictEqual(results[15].toHex(), f.k15)
81 | })
82 | })
83 | })
84 |
85 | describe('sign', function () {
86 | fixtures.valid.ecdsa.forEach(function (f) {
87 | it('produces a deterministic signature for "' + f.message + '"', function () {
88 | var d = BigInteger.fromHex(f.d)
89 | var hash = bcrypto.sha256(f.message)
90 | var signature = ecdsa.sign(hash, d).toDER()
91 |
92 | assert.strictEqual(signature.toString('hex'), f.signature)
93 | })
94 | })
95 |
96 | it('should sign with low S value', function () {
97 | var hash = bcrypto.sha256('Vires in numeris')
98 | var sig = ecdsa.sign(hash, BigInteger.ONE)
99 |
100 | // See BIP62 for more information
101 | var N_OVER_TWO = curve.n.shiftRight(1)
102 | assert(sig.s.compareTo(N_OVER_TWO) <= 0)
103 | })
104 | })
105 |
106 | describe('verify', function () {
107 | fixtures.valid.ecdsa.forEach(function (f) {
108 | it('verifies a valid signature for "' + f.message + '"', function () {
109 | var d = BigInteger.fromHex(f.d)
110 | var H = bcrypto.sha256(f.message)
111 | var signature = ECSignature.fromDER(new Buffer(f.signature, 'hex'))
112 | var Q = curve.G.multiply(d)
113 |
114 | assert(ecdsa.verify(H, signature, Q))
115 | })
116 | })
117 |
118 | fixtures.invalid.verify.forEach(function (f) {
119 | it('fails to verify with ' + f.description, function () {
120 | var H = bcrypto.sha256(f.message)
121 | var d = BigInteger.fromHex(f.d)
122 |
123 | var signature
124 | if (f.signature) {
125 | signature = ECSignature.fromDER(new Buffer(f.signature, 'hex'))
126 | } else if (f.signatureRaw) {
127 | signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16))
128 | }
129 |
130 | var Q = curve.G.multiply(d)
131 |
132 | assert.strictEqual(ecdsa.verify(H, signature, Q), false)
133 | })
134 | })
135 | })
136 | })
137 |
--------------------------------------------------------------------------------
/test/ecpair/fixtures.json:
--------------------------------------------------------------------------------
1 | {
2 | "valid": [
3 | {
4 | "d": "1",
5 | "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
6 | "compressed": true,
7 | "network": "ark",
8 | "address": "AcMiVQNHjggC1PyfVSvCcdWZKMisMKj8eo",
9 | "WIF": "S9aCCSFvm8kNeyFb1t6pLb5oJs9tv96ag6uA8Du6UM7zsmsNHQiz"
10 | },
11 | {
12 | "d": "1",
13 | "Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
14 | "compressed": false,
15 | "network": "ark",
16 | "address": "AXTte1XMqsiihEqTkdJwzC9q3S4MqFHWKi",
17 | "WIF": "6hTYzRJRsKyVvTnu7YWs9WvegPh5WiFrmf3JUTwPzQ8vtvPwoBG"
18 | },
19 | {
20 | "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
21 | "Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
22 | "compressed": true,
23 | "network": "ark",
24 | "address": "AL9uJWA5nd6RWn8VSUzGN7spWeZGHeudg9",
25 | "WIF": "SB3iDxYmKgjkhfDZSKgLaBrp3Ynzd3yd3ZZF2ujVBK7vLpv6hWKK"
26 | },
27 | {
28 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
29 | "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
30 | "compressed": true,
31 | "network": "ark",
32 | "address": "AHXTCefovyiq4TSAnwmszRNSXQXPbgWMiV",
33 | "WIF": "SDCe8styqokHi4pSe5jVRiYVV63Mef2TGsE1D4HhtGAL1DytHLtd"
34 | },
35 | {
36 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
37 | "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
38 | "compressed": false,
39 | "network": "ark",
40 | "address": "Ad1JqGpoWxW1EU7azNMKh3qzBbq1HGxK2M",
41 | "WIF": "6iHEQ5jbB9n9meZxCaFAAE39ii1zEyCCquca8GFCyvjSc1UFLp2"
42 | },
43 |
44 |
45 |
46 | {
47 | "d": "1",
48 | "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
49 | "compressed": true,
50 | "network": "ark",
51 | "address": "AcMiVQNHjggC1PyfVSvCcdWZKMisMKj8eo",
52 | "WIF": "S9aCCSFvm8kNeyFb1t6pLb5oJs9tv96ag6uA8Du6UM7zsmsNHQiz"
53 | },
54 | {
55 | "d": "1",
56 | "Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
57 | "compressed": false,
58 | "network": "ark",
59 | "address": "AXTte1XMqsiihEqTkdJwzC9q3S4MqFHWKi",
60 | "WIF": "6hTYzRJRsKyVvTnu7YWs9WvegPh5WiFrmf3JUTwPzQ8vtvPwoBG"
61 | },
62 | {
63 | "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
64 | "Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
65 | "compressed": true,
66 | "network": "ark",
67 | "address": "AL9uJWA5nd6RWn8VSUzGN7spWeZGHeudg9",
68 | "WIF": "SB3iDxYmKgjkhfDZSKgLaBrp3Ynzd3yd3ZZF2ujVBK7vLpv6hWKK"
69 | },
70 | {
71 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
72 | "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
73 | "compressed": true,
74 | "network": "ark",
75 | "address": "AHXTCefovyiq4TSAnwmszRNSXQXPbgWMiV",
76 | "WIF": "SDCe8styqokHi4pSe5jVRiYVV63Mef2TGsE1D4HhtGAL1DytHLtd"
77 | },
78 | {
79 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
80 | "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
81 | "compressed": false,
82 | "network": "ark",
83 | "address": "Ad1JqGpoWxW1EU7azNMKh3qzBbq1HGxK2M",
84 | "WIF": "6iHEQ5jbB9n9meZxCaFAAE39ii1zEyCCquca8GFCyvjSc1UFLp2"
85 | },
86 | {
87 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
88 | "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
89 | "compressed": true,
90 | "network": "testnet",
91 | "address": "a2U3J4Fopd4XK2fHEhRgbpRrfAj3XjRYWm",
92 | "WIF": "UaUjHTfNeGQVJM2jVJ3nAW4HU3Fo1MN5swC6AKqDjvDiWXAunqqY"
93 | },
94 | {
95 | "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
96 | "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
97 | "compressed": false,
98 | "network": "testnet",
99 | "address": "aMwtvgQoQbqhV3LhS818JSuQKN2fCAdqGx",
100 | "WIF": "7FP9Dnv6oxbmvmsEhrB9RMdYNXsUeEgDS8kJ2fFYtQqeVxBZpAC"
101 | },
102 | {
103 | "d": "115792089237316195423570985008687907852837564279074904382605163141518161494336",
104 | "Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
105 | "compressed": true,
106 | "network": "ark",
107 | "address": "AeiYjhgFV9Gx3Hn2mRB3BZbKYxehR4GimK",
108 | "WIF": "SJ9pmbcpwHfWdVGMZxVi8mAwZ45Gsdq4BeR8y6poSyje5EthYKP9"
109 | }
110 | ],
111 | "invalid": {
112 | "constructor": [
113 | {
114 | "exception": "Private key must be greater than 0",
115 | "d": "-1"
116 | },
117 | {
118 | "exception": "Private key must be greater than 0",
119 | "d": "0"
120 | },
121 | {
122 | "exception": "Private key must be less than the curve order",
123 | "d": "115792089237316195423570985008687907852837564279074904382605163141518161494337"
124 | },
125 | {
126 | "exception": "Private key must be less than the curve order",
127 | "d": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
128 | },
129 | {
130 | "exception": "Expected property \"compressed\" of type \\?Boolean, got Number 2",
131 | "d": "1",
132 | "options": {
133 | "compressed": 2
134 | }
135 | },
136 | {
137 | "exception": "Unexpected publicKey parameter",
138 | "d": "1",
139 | "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
140 | },
141 | {
142 | "exception": "Expected property \"network.messagePrefix\" of type Buffer|String, got undefined",
143 | "d": "1",
144 | "options": {
145 | "network": {}
146 | }
147 | }
148 |
149 | ],
150 | "fromWIF": [
151 | {
152 | "exception": "Invalid network version",
153 | "network": "ark",
154 | "WIF": "7FP9Dnv6oxbmvmsEhrB9RMdYNXsUeEgDS8kJ2fFYtQqeVxBZpAC"
155 | },
156 | {
157 | "exception": "Unknown network version",
158 | "WIF": "brQnSed3Fia1w9VcbbS6ZGDgJ6ENkgwuQY2LS7pEC5bKHD1fMF"
159 | },
160 | {
161 | "exception": "Invalid compression flag",
162 | "WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sfZr2ym"
163 | },
164 | {
165 | "exception": "Invalid WIF length",
166 | "WIF": "3tq8Vmhh9SN5XhjTGSWgx8iKk59XbKG6UH4oqpejRuJhfYD"
167 | },
168 | {
169 | "exception": "Invalid WIF length",
170 | "WIF": "38uMpGARR2BJy5p4dNFKYg9UsWNoBtkpbdrXDjmfvz8krCtw3T1W92ZDSR"
171 | }
172 | ]
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/test/ecpair/index.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, beforeEach */
2 | /* eslint-disable no-new */
3 |
4 | var assert = require('assert')
5 | var ecdsa = require('../../lib/ecdsa')
6 | var ecurve = require('ecurve')
7 | var proxyquire = require('proxyquire')
8 | var sinon = require('sinon')
9 | var sinonTest = require('sinon-test')(sinon)
10 |
11 | var BigInteger = require('bigi')
12 | var ECPair = require('../../lib/ecpair')
13 |
14 | var fixtures = require('./fixtures.json')
15 | var curve = ecdsa.__curve
16 |
17 | var NETWORKS = require('../../lib/networks')
18 | var NETWORKS_LIST = [] // Object.values(NETWORKS)
19 | for (var networkName in NETWORKS) {
20 | NETWORKS_LIST.push(NETWORKS[networkName])
21 | }
22 |
23 | describe('ECPair', function () {
24 | describe('constructor', function () {
25 | it('defaults to compressed', function () {
26 | var keyPair = new ECPair(BigInteger.ONE)
27 |
28 | assert.strictEqual(keyPair.compressed, true)
29 | })
30 |
31 | it('supports the uncompressed option', function () {
32 | var keyPair = new ECPair(BigInteger.ONE, null, {
33 | compressed: false
34 | })
35 |
36 | assert.strictEqual(keyPair.compressed, false)
37 | })
38 |
39 | it('supports the network option', function () {
40 | var keyPair = new ECPair(BigInteger.ONE, null, {
41 | compressed: false,
42 | network: NETWORKS.testnet
43 | })
44 |
45 | assert.strictEqual(keyPair.network, NETWORKS.testnet)
46 | })
47 |
48 | fixtures.valid.forEach(function (f) {
49 | it('calculates the public point for ' + f.WIF, function () {
50 | var d = new BigInteger(f.d)
51 | var keyPair = new ECPair(d, null, {
52 | compressed: f.compressed
53 | })
54 |
55 | assert.strictEqual(keyPair.getPublicKeyBuffer().toString('hex'), f.Q)
56 | })
57 | })
58 |
59 | fixtures.invalid.constructor.forEach(function (f) {
60 | it('throws ' + f.exception, function () {
61 | var d = f.d && new BigInteger(f.d)
62 | var Q = f.Q && ecurve.Point.decodeFrom(curve, new Buffer(f.Q, 'hex'))
63 |
64 | assert.throws(function () {
65 | new ECPair(d, Q, f.options)
66 | }, new RegExp(f.exception))
67 | })
68 | })
69 | })
70 |
71 | describe('getPublicKeyBuffer', function () {
72 | var keyPair
73 |
74 | beforeEach(function () {
75 | keyPair = new ECPair(BigInteger.ONE)
76 | })
77 |
78 | it('wraps Q.getEncoded', sinonTest(function () {
79 | this.mock(keyPair.Q).expects('getEncoded')
80 | .once().withArgs(keyPair.compressed)
81 |
82 | keyPair.getPublicKeyBuffer()
83 | }))
84 | })
85 |
86 | describe('fromWIF', function () {
87 | fixtures.valid.forEach(function (f) {
88 | it('imports ' + f.WIF + ' (' + f.network + ')', function () {
89 | var network = NETWORKS[f.network]
90 | var keyPair = ECPair.fromWIF(f.WIF, network)
91 |
92 | assert.strictEqual(keyPair.d.toString(), f.d)
93 | assert.strictEqual(keyPair.getPublicKeyBuffer().toString("hex"), f.Q)
94 | assert.strictEqual(keyPair.compressed, f.compressed)
95 | assert.strictEqual(keyPair.network, network)
96 | })
97 | })
98 |
99 | fixtures.valid.forEach(function (f) {
100 | it('imports ' + f.WIF + ' (via list of networks)', function () {
101 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
102 |
103 | assert.strictEqual(keyPair.d.toString(), f.d)
104 | assert.strictEqual(keyPair.getPublicKeyBuffer().toString("hex"), f.Q)
105 | assert.strictEqual(keyPair.compressed, f.compressed)
106 | assert.strictEqual(keyPair.network, NETWORKS[f.network])
107 | })
108 | })
109 |
110 | fixtures.invalid.fromWIF.forEach(function (f) {
111 | it('throws on ' + f.WIF, function () {
112 | assert.throws(function () {
113 | var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
114 |
115 | ECPair.fromWIF(f.WIF, networks)
116 | }, new RegExp(f.exception))
117 | })
118 | })
119 | })
120 |
121 | describe('toWIF', function () {
122 | fixtures.valid.forEach(function (f) {
123 | it('exports ' + f.WIF, function () {
124 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
125 | var result = keyPair.toWIF()
126 |
127 | assert.strictEqual(result, f.WIF)
128 | })
129 | })
130 | })
131 |
132 | describe('makeRandom', function () {
133 | var d = new Buffer('0404040404040404040404040404040404040404040404040404040404040404', 'hex')
134 | var exWIF = 'S9hzwiZ5ziKjUiFpuZX4Lri3rUocDxZSTy7YzKKHvx8TSjUrYQ27'
135 |
136 | describe('uses randombytes RNG', function () {
137 | it('generates a ECPair', function () {
138 | var stub = { randombytes: function () { return d } }
139 | var ProxiedECPair = proxyquire('../../lib/ecpair', stub)
140 |
141 | var keyPair = ProxiedECPair.makeRandom()
142 | assert.strictEqual(keyPair.toWIF(), exWIF)
143 | })
144 | })
145 |
146 | it('allows a custom RNG to be used', function () {
147 | var keyPair = ECPair.makeRandom({
148 | rng: function (size) { return d.slice(0, size) }
149 | })
150 |
151 | assert.strictEqual(keyPair.toWIF(), exWIF)
152 | })
153 |
154 | it('retains the same defaults as ECPair constructor', function () {
155 | var keyPair = ECPair.makeRandom()
156 |
157 | assert.strictEqual(keyPair.compressed, true)
158 | assert.strictEqual(keyPair.network, NETWORKS.ark)
159 | })
160 |
161 | it('supports the options parameter', function () {
162 | var keyPair = ECPair.makeRandom({
163 | compressed: false,
164 | network: NETWORKS.testnet
165 | })
166 |
167 | assert.strictEqual(keyPair.compressed, false)
168 | assert.strictEqual(keyPair.network, NETWORKS.testnet)
169 | })
170 |
171 | it('loops until d is within interval [1, n - 1] : 1', sinonTest(function () {
172 | var rng = this.mock()
173 | rng.exactly(2)
174 | rng.onCall(0).returns(BigInteger.ZERO.toBuffer(32)) // invalid length
175 | rng.onCall(1).returns(BigInteger.ONE.toBuffer(32)) // === 1
176 |
177 | ECPair.makeRandom({ rng: rng })
178 | }))
179 |
180 | it('loops until d is within interval [1, n - 1] : n - 1', sinonTest(function () {
181 | var rng = this.mock()
182 | rng.exactly(3)
183 | rng.onCall(0).returns(BigInteger.ZERO.toBuffer(32)) // < 1
184 | rng.onCall(1).returns(curve.n.toBuffer(32)) // > n-1
185 | rng.onCall(2).returns(curve.n.subtract(BigInteger.ONE).toBuffer(32)) // === n-1
186 |
187 | ECPair.makeRandom({ rng: rng })
188 | }))
189 | })
190 |
191 | describe('getAddress', function () {
192 | fixtures.valid.forEach(function (f) {
193 | it('returns ' + f.address + ' for ' + f.WIF, function () {
194 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
195 |
196 | assert.strictEqual(keyPair.getAddress(), f.address)
197 | })
198 | })
199 | })
200 |
201 | describe('getNetwork', function () {
202 | fixtures.valid.forEach(function (f) {
203 | it('returns ' + f.network + ' for ' + f.WIF, function () {
204 | var network = NETWORKS[f.network]
205 | var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
206 |
207 | assert.strictEqual(keyPair.getNetwork(), network)
208 | })
209 | })
210 | })
211 |
212 | describe('ecdsa wrappers', function () {
213 | var keyPair, hash
214 |
215 | beforeEach(function () {
216 | keyPair = ECPair.makeRandom()
217 | hash = new Buffer(32)
218 | })
219 |
220 | describe('signing', function () {
221 | // it('wraps ecdsa.sign', sinonTest(function () {
222 | // this.mock(ecdsa).expects('sign')
223 | // .once().withArgs(hash, keyPair.d)
224 | //
225 | // keyPair.sign(hash)
226 | // }))
227 |
228 | it('throws if no private key is found', function () {
229 | keyPair.d = null
230 |
231 | assert.throws(function () {
232 | keyPair.sign(hash)
233 | }, /Missing private key/)
234 | })
235 | })
236 |
237 | describe('verify', function () {
238 | var signature
239 |
240 | beforeEach(function () {
241 | signature = keyPair.sign(hash)
242 | })
243 |
244 | // it('wraps ecdsa.verify', sinonTest(function () {
245 | // this.mock(ecdsa).expects('verify')
246 | // .once().withArgs(hash, signature, keyPair.Q)
247 | //
248 | // keyPair.verify(hash, signature)
249 | // }))
250 | })
251 | })
252 | })
253 |
--------------------------------------------------------------------------------
/test/ecsignature/fixtures.json:
--------------------------------------------------------------------------------
1 | {
2 | "valid": [
3 | {
4 | "compact": {
5 | "hex": "1f33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
6 | "compressed": true,
7 | "i": 0
8 | },
9 | "scriptSignature": {
10 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
11 | "hashType": 1
12 | },
13 | "DER": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
14 | "signature": {
15 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
16 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
17 | }
18 | },
19 | {
20 | "compact": {
21 | "hex": "1b54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
22 | "compressed": false,
23 | "i": 0
24 | },
25 | "DER": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
26 | "scriptSignature": {
27 | "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
28 | "hashType": 2
29 | },
30 | "signature": {
31 | "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
32 | "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
33 | }
34 | },
35 | {
36 | "compact": {
37 | "hex": "1fff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
38 | "compressed": true,
39 | "i": 0
40 | },
41 | "scriptSignature": {
42 | "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
43 | "hashType": 3
44 | },
45 | "DER": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
46 | "signature": {
47 | "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
48 | "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
49 | }
50 | },
51 | {
52 | "compact": {
53 | "hex": "1cc0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
54 | "compressed": false,
55 | "i": 1
56 | },
57 | "scriptSignature": {
58 | "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
59 | "hashType": 129
60 | },
61 | "DER": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
62 | "signature": {
63 | "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
64 | "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
65 | }
66 | },
67 | {
68 | "compact": {
69 | "hex": "1f7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
70 | "compressed": true,
71 | "i": 0
72 | },
73 | "scriptSignature": {
74 | "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
75 | "hashType": 130
76 | },
77 | "DER": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
78 | "signature": {
79 | "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
80 | "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
81 | }
82 | },
83 | {
84 | "compact": {
85 | "hex": "1cfbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
86 | "compressed": false,
87 | "i": 1
88 | },
89 | "scriptSignature": {
90 | "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
91 | "hashType": 131
92 | },
93 | "DER": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
94 | "signature": {
95 | "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
96 | "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
97 | }
98 | },
99 | {
100 | "compact": {
101 | "hex": "20cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
102 | "compressed": true,
103 | "i": 1
104 | },
105 | "scriptSignature": {
106 | "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
107 | "hashType": 129
108 | },
109 | "DER": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
110 | "signature": {
111 | "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
112 | "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
113 | }
114 | }
115 | ],
116 | "invalid": {
117 | "compact": [
118 | {
119 | "exception": "Invalid signature parameter",
120 | "hex": "23987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62"
121 | },
122 | {
123 | "exception": "Invalid signature length",
124 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62000000"
125 | },
126 | {
127 | "exception": "Invalid signature length",
128 | "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e9379"
129 | }
130 | ],
131 | "DER": [
132 | {
133 | "exception": "DER sequence length is too short",
134 | "hex": "ffffffffffffff"
135 | },
136 | {
137 | "exception": "DER sequence length is too long",
138 | "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
139 | },
140 | {
141 | "exception": "Expected DER sequence",
142 | "hex": "00ffff0400ffffff020400ffffff"
143 | },
144 | {
145 | "exception": "DER sequence length is invalid",
146 | "hex": "30ff020400ffffff020400ffffff"
147 | },
148 | {
149 | "exception": "DER sequence length is invalid",
150 | "hex": "300c030400ffffff030400ffffff0000"
151 | },
152 | {
153 | "exception": "Expected DER integer",
154 | "hex": "300cff0400ffffff020400ffffff"
155 | },
156 | {
157 | "exception": "Expected DER integer \\(2\\)",
158 | "hex": "300c020200ffffff020400ffffff"
159 | },
160 | {
161 | "exception": "R length is zero",
162 | "hex": "30080200020400ffffff"
163 | },
164 | {
165 | "exception": "S length is zero",
166 | "hex": "3008020400ffffff0200"
167 | },
168 | {
169 | "exception": "R length is too long",
170 | "hex": "300c02dd00ffffff020400ffffff"
171 | },
172 | {
173 | "exception": "S length is invalid",
174 | "hex": "300c020400ffffff02dd00ffffff"
175 | },
176 | {
177 | "exception": "R value is negative",
178 | "hex": "300c020480000000020400ffffff"
179 | },
180 | {
181 | "exception": "S value is negative",
182 | "hex": "300c020400ffffff020480000000"
183 | },
184 | {
185 | "exception": "R value excessively padded",
186 | "hex": "300c02040000ffff020400ffffff"
187 | },
188 | {
189 | "exception": "S value excessively padded",
190 | "hex": "300c020400ffffff02040000ffff"
191 | }
192 | ],
193 | "scriptSignature": [
194 | {
195 | "exception": "Invalid hashType 7",
196 | "hashType": 7,
197 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
198 | "signature": {
199 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
200 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
201 | }
202 | },
203 | {
204 | "exception": "Invalid hashType 140",
205 | "hashType": 140,
206 | "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
207 | "signature": {
208 | "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
209 | "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
210 | }
211 | }
212 | ]
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/test/ecsignature/index.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | var assert = require('assert')
4 |
5 | var BigInteger = require('bigi')
6 | var ECSignature = require('../../lib/ecsignature')
7 |
8 | var fixtures = require('./fixtures.json')
9 |
10 | describe('ECSignature', function () {
11 | describe('toCompact', function () {
12 | fixtures.valid.forEach(function (f) {
13 | it('exports ' + f.compact.hex + ' correctly', function () {
14 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
15 |
16 | var buffer = signature.toCompact(f.compact.i, f.compact.compressed)
17 | assert.strictEqual(buffer.toString('hex'), f.compact.hex)
18 | })
19 | })
20 | })
21 |
22 | describe('parseCompact', function () {
23 | fixtures.valid.forEach(function (f) {
24 | it('imports ' + f.compact.hex + ' correctly', function () {
25 | var buffer = new Buffer(f.compact.hex, 'hex')
26 | var parsed = ECSignature.parseCompact(buffer)
27 |
28 | assert.strictEqual(parsed.compressed, f.compact.compressed)
29 | assert.strictEqual(parsed.i, f.compact.i)
30 | assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
31 | assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
32 | })
33 | })
34 |
35 | fixtures.invalid.compact.forEach(function (f) {
36 | it('throws on ' + f.hex, function () {
37 | var buffer = new Buffer(f.hex, 'hex')
38 |
39 | assert.throws(function () {
40 | ECSignature.parseCompact(buffer)
41 | }, new RegExp(f.exception))
42 | })
43 | })
44 | })
45 |
46 | describe('toDER', function () {
47 | fixtures.valid.forEach(function (f) {
48 | it('exports ' + f.DER + ' correctly', function () {
49 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
50 |
51 | var DER = signature.toDER()
52 | assert.strictEqual(DER.toString('hex'), f.DER)
53 | })
54 | })
55 | })
56 |
57 | describe('fromDER', function () {
58 | fixtures.valid.forEach(function (f) {
59 | it('imports ' + f.DER + ' correctly', function () {
60 | var buffer = new Buffer(f.DER, 'hex')
61 | var signature = ECSignature.fromDER(buffer)
62 |
63 | assert.strictEqual(signature.r.toString(), f.signature.r)
64 | assert.strictEqual(signature.s.toString(), f.signature.s)
65 | })
66 | })
67 |
68 | fixtures.invalid.DER.forEach(function (f) {
69 | it('throws "' + f.exception + '" for ' + f.hex, function () {
70 | var buffer = new Buffer(f.hex, 'hex')
71 |
72 | assert.throws(function () {
73 | ECSignature.fromDER(buffer)
74 | }, new RegExp(f.exception))
75 | })
76 | })
77 | })
78 |
79 | describe('toScriptSignature', function () {
80 | fixtures.valid.forEach(function (f) {
81 | it('exports ' + f.scriptSignature.hex + ' correctly', function () {
82 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
83 |
84 | var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType)
85 | assert.strictEqual(scriptSignature.toString('hex'), f.scriptSignature.hex)
86 | })
87 | })
88 |
89 | fixtures.invalid.scriptSignature.forEach(function (f) {
90 | it('throws ' + f.exception, function () {
91 | var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
92 |
93 | assert.throws(function () {
94 | signature.toScriptSignature(f.hashType)
95 | }, new RegExp(f.exception))
96 | })
97 | })
98 | })
99 |
100 | describe('parseScriptSignature', function () {
101 | fixtures.valid.forEach(function (f) {
102 | it('imports ' + f.scriptSignature.hex + ' correctly', function () {
103 | var buffer = new Buffer(f.scriptSignature.hex, 'hex')
104 | var parsed = ECSignature.parseScriptSignature(buffer)
105 |
106 | assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
107 | assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
108 | assert.strictEqual(parsed.hashType, f.scriptSignature.hashType)
109 | })
110 | })
111 |
112 | fixtures.invalid.scriptSignature.forEach(function (f) {
113 | it('throws on ' + f.hex, function () {
114 | var buffer = new Buffer(f.hex, 'hex')
115 |
116 | assert.throws(function () {
117 | ECSignature.parseScriptSignature(buffer)
118 | }, new RegExp(f.exception))
119 | })
120 | })
121 | })
122 | })
123 |
--------------------------------------------------------------------------------
/test/hdnode/index.js:
--------------------------------------------------------------------------------
1 | /* global describe, it, beforeEach */
2 | /* eslint-disable no-new */
3 |
4 | var assert = require('assert')
5 | var ecdsa = require('../../lib/ecdsa')
6 | var sinon = require('sinon')
7 | var sinonTest = require('sinon-test')(sinon)
8 |
9 | var BigInteger = require('bigi')
10 | var ECPair = require('../../lib/ecpair')
11 | var HDNode = require('../../lib/hdnode')
12 |
13 | var fixtures = require('./fixtures.json')
14 | var curve = ecdsa.__curve
15 |
16 | var NETWORKS = require('../../lib/networks')
17 | var NETWORKS_LIST = [] // Object.values(NETWORKS)
18 | for (var networkName in NETWORKS) {
19 | NETWORKS_LIST.push(NETWORKS[networkName])
20 | }
21 |
22 | var validAll = []
23 | fixtures.valid.forEach(function (f) {
24 | function addNetwork (n) {
25 | n.network = f.network
26 | return n
27 | }
28 |
29 | validAll = validAll.concat(addNetwork(f.master), f.children.map(addNetwork))
30 | })
31 |
32 | describe('HDNode', function () {
33 | describe('Constructor', function () {
34 | var keyPair, chainCode
35 |
36 | beforeEach(function () {
37 | var d = BigInteger.ONE
38 |
39 | keyPair = new ECPair(d, null)
40 | chainCode = new Buffer(32)
41 | chainCode.fill(1)
42 | })
43 |
44 | it('stores the keyPair/chainCode directly', function () {
45 | var hd = new HDNode(keyPair, chainCode)
46 |
47 | assert.strictEqual(hd.keyPair, keyPair)
48 | assert.strictEqual(hd.chainCode, chainCode)
49 | })
50 |
51 | it('has a default depth/index of 0', function () {
52 | var hd = new HDNode(keyPair, chainCode)
53 |
54 | assert.strictEqual(hd.depth, 0)
55 | assert.strictEqual(hd.index, 0)
56 | })
57 |
58 | it('throws on uncompressed keyPair', function () {
59 | keyPair.compressed = false
60 |
61 | assert.throws(function () {
62 | new HDNode(keyPair, chainCode)
63 | }, /BIP32 only allows compressed keyPairs/)
64 | })
65 |
66 | it('throws when an invalid length chain code is given', function () {
67 | assert.throws(function () {
68 | new HDNode(keyPair, new Buffer(20))
69 | }, /Expected property "1" of type Buffer\(Length: 32\), got Buffer\(Length: 20\)/)
70 | })
71 | })
72 |
73 | describe('fromSeed*', function () {
74 | fixtures.valid.forEach(function (f) {
75 | it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
76 | var network = NETWORKS[f.network]
77 | var hd = HDNode.fromSeedHex(f.master.seed, network)
78 |
79 | assert.strictEqual(hd.keyPair.toWIF(), f.master.wif)
80 | assert.strictEqual(hd.chainCode.toString('hex'), f.master.chainCode)
81 | })
82 | })
83 |
84 | it('throws if IL is not within interval [1, n - 1] | IL === 0', sinonTest(function () {
85 | this.mock(BigInteger).expects('fromBuffer')
86 | .once().returns(BigInteger.ZERO)
87 |
88 | assert.throws(function () {
89 | HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
90 | }, /Private key must be greater than 0/)
91 | }))
92 |
93 | it('throws if IL is not within interval [1, n - 1] | IL === n', sinonTest(function () {
94 | this.mock(BigInteger).expects('fromBuffer')
95 | .once().returns(curve.n)
96 |
97 | assert.throws(function () {
98 | HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
99 | }, /Private key must be less than the curve order/)
100 | }))
101 |
102 | it('throws on low entropy seed', function () {
103 | assert.throws(function () {
104 | HDNode.fromSeedHex('ffffffffff')
105 | }, /Seed should be at least 128 bits/)
106 | })
107 |
108 | it('throws on too high entropy seed', function () {
109 | assert.throws(function () {
110 | HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
111 | }, /Seed should be at most 512 bits/)
112 | })
113 | })
114 |
115 | describe('ECPair wrappers', function () {
116 | var keyPair, hd, hash
117 |
118 | beforeEach(function () {
119 | keyPair = ECPair.makeRandom()
120 | hash = new Buffer(32)
121 |
122 | var chainCode = new Buffer(32)
123 | hd = new HDNode(keyPair, chainCode)
124 | })
125 |
126 | describe('getAddress', function () {
127 | it('wraps keyPair.getAddress', sinonTest(function () {
128 | this.mock(keyPair).expects('getAddress')
129 | .once().withArgs().returns('foobar')
130 |
131 | assert.strictEqual(hd.getAddress(), 'foobar')
132 | }))
133 | })
134 |
135 | describe('getNetwork', function () {
136 | it('wraps keyPair.getNetwork', sinonTest(function () {
137 | this.mock(keyPair).expects('getNetwork')
138 | .once().withArgs().returns('network')
139 |
140 | assert.strictEqual(hd.getNetwork(), 'network')
141 | }))
142 | })
143 |
144 | describe('getPublicKeyBuffer', function () {
145 | it('wraps keyPair.getPublicKeyBuffer', sinonTest(function () {
146 | this.mock(keyPair).expects('getPublicKeyBuffer')
147 | .once().withArgs().returns('pubKeyBuffer')
148 |
149 | assert.strictEqual(hd.getPublicKeyBuffer(), 'pubKeyBuffer')
150 | }))
151 | })
152 |
153 | describe('sign', function () {
154 | it('wraps keyPair.sign', sinonTest(function () {
155 | this.mock(keyPair).expects('sign')
156 | .once().withArgs(hash).returns('signed')
157 |
158 | assert.strictEqual(hd.sign(hash), 'signed')
159 | }))
160 | })
161 |
162 | describe('verify', function () {
163 | var signature
164 |
165 | beforeEach(function () {
166 | signature = hd.sign(hash)
167 | })
168 |
169 | it('wraps keyPair.verify', sinonTest(function () {
170 | this.mock(keyPair).expects('verify')
171 | .once().withArgs(hash, signature).returns('verified')
172 |
173 | assert.strictEqual(hd.verify(hash, signature), 'verified')
174 | }))
175 | })
176 | })
177 |
178 | describe('fromBase58 / toBase58', function () {
179 | validAll.forEach(function (f) {
180 | it('exports ' + f.base58 + ' (public) correctly', function () {
181 | var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
182 |
183 | assert.strictEqual(hd.toBase58(), f.base58)
184 | assert.throws(function () { hd.keyPair.toWIF() }, /Missing private key/)
185 | })
186 | })
187 |
188 | validAll.forEach(function (f) {
189 | it('exports ' + f.base58Priv + ' (private) correctly', function () {
190 | var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
191 |
192 | assert.strictEqual(hd.toBase58(), f.base58Priv)
193 | assert.strictEqual(hd.keyPair.toWIF(), f.wif)
194 | })
195 | })
196 |
197 | fixtures.invalid.fromBase58.forEach(function (f) {
198 | it('throws on ' + f.string, function () {
199 | assert.throws(function () {
200 | var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
201 |
202 | HDNode.fromBase58(f.string, networks)
203 | }, new RegExp(f.exception))
204 | })
205 | })
206 | })
207 |
208 | describe('getIdentifier', function () {
209 | validAll.forEach(function (f) {
210 | it('returns the identifier for ' + f.fingerprint, function () {
211 | var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
212 |
213 | assert.strictEqual(hd.getIdentifier().toString('hex'), f.identifier)
214 | })
215 | })
216 | })
217 |
218 | describe('getFingerprint', function () {
219 | validAll.forEach(function (f) {
220 | it('returns the fingerprint for ' + f.fingerprint, function () {
221 | var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
222 |
223 | assert.strictEqual(hd.getFingerprint().toString('hex'), f.fingerprint)
224 | })
225 | })
226 | })
227 |
228 | describe('neutered / isNeutered', function () {
229 | validAll.forEach(function (f) {
230 | it('drops the private key for ' + f.fingerprint, function () {
231 | var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
232 | var hdn = hd.neutered()
233 |
234 | assert.notEqual(hdn.keyPair, hd.keyPair)
235 | assert.throws(function () { hdn.keyPair.toWIF() }, /Missing private key/)
236 | assert.strictEqual(hdn.toBase58(), f.base58)
237 | assert.strictEqual(hdn.chainCode, hd.chainCode)
238 | assert.strictEqual(hdn.depth, f.depth >>> 0)
239 | assert.strictEqual(hdn.index, f.index >>> 0)
240 | assert.strictEqual(hdn.isNeutered(), true)
241 |
242 | // does not modify the original
243 | assert.strictEqual(hd.toBase58(), f.base58Priv)
244 | assert.strictEqual(hd.isNeutered(), false)
245 | })
246 | })
247 | })
248 |
249 | describe('derive', function () {
250 | function verifyVector (hd, v) {
251 | if (hd.isNeutered()) {
252 | assert.strictEqual(hd.toBase58(), v.base58)
253 | } else {
254 | assert.strictEqual(hd.neutered().toBase58(), v.base58)
255 | assert.strictEqual(hd.toBase58(), v.base58Priv)
256 | }
257 |
258 | assert.strictEqual(hd.getFingerprint().toString('hex'), v.fingerprint)
259 | assert.strictEqual(hd.getIdentifier().toString('hex'), v.identifier)
260 | assert.strictEqual(hd.getAddress(), v.address)
261 | assert.strictEqual(hd.keyPair.toWIF(), v.wif)
262 | assert.strictEqual(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
263 | assert.strictEqual(hd.chainCode.toString('hex'), v.chainCode)
264 | assert.strictEqual(hd.depth, v.depth >>> 0)
265 | assert.strictEqual(hd.index, v.index >>> 0)
266 | }
267 |
268 | fixtures.valid.forEach(function (f) {
269 | var network = NETWORKS[f.network]
270 | var hd = HDNode.fromSeedHex(f.master.seed, network)
271 | var master = hd
272 |
273 | // testing deriving path from master
274 | f.children.forEach(function (c) {
275 | it(c.path + ' from ' + f.master.fingerprint + ' by path', function () {
276 | var child = master.derivePath(c.path)
277 | var childNoM = master.derivePath(c.path.slice(2)) // no m/ on path
278 |
279 | verifyVector(child, c)
280 | verifyVector(childNoM, c)
281 | })
282 | })
283 |
284 | // testing deriving path from children
285 | f.children.forEach(function (c, i) {
286 | var cn = master.derivePath(c.path)
287 |
288 | f.children.slice(i + 1).forEach(function (cc) {
289 | it(cc.path + ' from ' + c.fingerprint + ' by path', function () {
290 | var ipath = cc.path.slice(2).split('/').slice(i + 1).join('/')
291 | var child = cn.derivePath(ipath)
292 | verifyVector(child, cc)
293 |
294 | assert.throws(function () {
295 | cn.derivePath('m/' + ipath)
296 | }, /Not a master node/)
297 | })
298 | })
299 | })
300 |
301 | // FIXME: test data is only testing Private -> private for now
302 | f.children.forEach(function (c, i) {
303 | if (c.m === undefined) return
304 |
305 | it(c.path + ' from ' + f.master.fingerprint, function () {
306 | if (c.hardened) {
307 | hd = hd.deriveHardened(c.m)
308 | } else {
309 | hd = hd.derive(c.m)
310 | }
311 |
312 | verifyVector(hd, c)
313 | })
314 | })
315 | })
316 |
317 | it('works for Private -> public (neutered)', function () {
318 | var f = fixtures.valid[1]
319 | var c = f.children[0]
320 |
321 | var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
322 | var child = master.derive(c.m).neutered()
323 |
324 | assert.strictEqual(child.toBase58(), c.base58)
325 | })
326 |
327 | it('works for Private -> public (neutered, hardened)', function () {
328 | var f = fixtures.valid[0]
329 | var c = f.children[0]
330 |
331 | var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
332 | var child = master.deriveHardened(c.m).neutered()
333 |
334 | assert.strictEqual(c.base58, child.toBase58())
335 | })
336 |
337 | it('works for Public -> public', function () {
338 | var f = fixtures.valid[1]
339 | var c = f.children[0]
340 |
341 | var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
342 | var child = master.derive(c.m)
343 |
344 | assert.strictEqual(c.base58, child.toBase58())
345 | })
346 |
347 | it('throws on Public -> public (hardened)', function () {
348 | var f = fixtures.valid[0]
349 | var c = f.children[0]
350 |
351 | var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
352 |
353 | assert.throws(function () {
354 | master.deriveHardened(c.m)
355 | }, /Could not derive hardened child key/)
356 | })
357 |
358 | it('throws on wrong types', function () {
359 | var f = fixtures.valid[0]
360 | var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
361 |
362 | fixtures.invalid.derive.forEach(function (fx) {
363 | assert.throws(function () {
364 | master.derive(fx)
365 | }, /Expected UInt32/)
366 | })
367 |
368 | fixtures.invalid.deriveHardened.forEach(function (fx) {
369 | assert.throws(function () {
370 | master.deriveHardened(fx)
371 | }, /Expected UInt31/)
372 | })
373 |
374 | fixtures.invalid.derivePath.forEach(function (fx) {
375 | assert.throws(function () {
376 | master.derivePath(fx)
377 | }, /Expected BIP32 derivation path/)
378 | })
379 | })
380 |
381 | it('works when private key has leading zeros', function () {
382 | var key = 'xprv9s21ZrQH143K3ckY9DgU79uMTJkQRLdbCCVDh81SnxTgPzLLGax6uHeBULTtaEtcAvKjXfT7ZWtHzKjTpujMkUd9dDb8msDeAfnJxrgAYhr'
383 | var hdkey = HDNode.fromBase58(key, NETWORKS.bitcoin)
384 | assert.strictEqual(hdkey.keyPair.d.toBuffer(32).toString('hex'), '00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd')
385 | var child = hdkey.derivePath('m/44\'/0\'/0\'/0/0\'')
386 | assert.strictEqual(child.keyPair.d.toBuffer().toString('hex'), '3348069561d2a0fb925e74bf198762acc47dce7db27372257d2d959a9e6f8aeb')
387 | })
388 | })
389 | })
390 |
--------------------------------------------------------------------------------
/test/integration/basic.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | var assert = require('assert')
4 | var bigi = require('bigi')
5 | var ark = require('../../')
6 |
7 | describe('ark-js (basic)', function () {
8 | it('can generate a random ark address', function () {
9 | // for testing only
10 | function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') }
11 |
12 | // generate random keyPair
13 | var keyPair = ark.ECPair.makeRandom({ rng: rng })
14 | var address = keyPair.getAddress()
15 |
16 | assert.strictEqual(address, 'ANoMWEJ9jSdE2FgohBLLXeLzci59BDFsP4')
17 | })
18 |
19 | it('can generate an address from a SHA256 hash', function () {
20 | var hash = ark.crypto.sha256('correct horse battery staple')
21 | var d = bigi.fromBuffer(hash)
22 |
23 | var keyPair = new ark.ECPair(d)
24 | var address = keyPair.getAddress()
25 |
26 | assert.strictEqual(address, 'AG5AtmiNbgv51eLwAWnRGvkMudVd7anYP2')
27 | })
28 |
29 | it('can generate a random keypair for alternative networks', function () {
30 | // for testing only
31 | function rng () { return new Buffer('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') }
32 |
33 | var bitcoin = ark.networks.bitcoin
34 |
35 | var keyPair = ark.ECPair.makeRandom({ network: bitcoin, rng: rng })
36 | var wif = keyPair.toWIF()
37 | var address = keyPair.getAddress()
38 |
39 | assert.strictEqual(address, '182UrjSXQHy5DHUp8Xg1Nm5u979SojJY2P')
40 | assert.strictEqual(wif, 'L1Knwj9W3qK3qMKdTvmg3VfzUs3ij2LETTFhxza9LfD5dngnoLG1')
41 | })
42 |
43 | it('can import an address via WIF', function () {
44 | var keyPair = ark.ECPair.fromWIF('S9aCCSFvm8kNeyFb1t6pLb5oJs9tv96ag6uA8Du6UM7zsmsNHQiz')
45 | var address = keyPair.getAddress()
46 |
47 | assert.strictEqual(address, 'AcMiVQNHjggC1PyfVSvCcdWZKMisMKj8eo')
48 | })
49 |
50 | })
51 |
--------------------------------------------------------------------------------
/test/integration/bip32.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | var assert = require('assert')
4 | var bigi = require('bigi')
5 | var ark = require('../../')
6 | var crypto = require('crypto')
7 |
8 | var ecurve = require('ecurve')
9 | var secp256k1 = ecurve.getCurveByName('secp256k1')
10 |
11 | describe('ark-js (BIP32)', function () {
12 | it('can create a BIP32 wallet external address', function () {
13 | var path = "m/0'/0/0"
14 | var root = ark.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
15 |
16 | var child1 = root.derivePath(path)
17 |
18 | // option 2, manually
19 | var child2 = root.deriveHardened(0)
20 | .derive(0)
21 | .derive(0)
22 |
23 | assert.equal(child1.getAddress(), 'AZXdSTRFGHPokX6yfXTfHcTzzHKncioj31')
24 | assert.equal(child2.getAddress(), 'AZXdSTRFGHPokX6yfXTfHcTzzHKncioj31')
25 | })
26 |
27 | it('can create a BIP44, ark, account 0, external address', function () {
28 | var path = "m/44'/0'/0'/0/0"
29 | var root = ark.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
30 |
31 | var child1 = root.derivePath(path)
32 |
33 | // option 2, manually
34 | var child2 = root.deriveHardened(44)
35 | .deriveHardened(0)
36 | .deriveHardened(0)
37 | .derive(0)
38 | .derive(0)
39 |
40 | assert.equal(child1.getAddress(), 'AVbXc2KyxtXeAP9zQpp7ixsnaxEEQ6wZbq')
41 | assert.equal(child2.getAddress(), 'AVbXc2KyxtXeAP9zQpp7ixsnaxEEQ6wZbq')
42 | })
43 |
44 | it('can recover a BIP32 parent private key from the parent public key, and a derived, non-hardened child private key', function () {
45 | function recoverParent (master, child) {
46 | assert(!master.keyPair.d, 'You already have the parent private key')
47 | assert(child.keyPair.d, 'Missing child private key')
48 |
49 | var curve = secp256k1
50 | var QP = master.keyPair.Q
51 | var serQP = master.keyPair.getPublicKeyBuffer()
52 |
53 | var d1 = child.keyPair.d
54 | var d2
55 | var data = new Buffer(37)
56 | serQP.copy(data, 0)
57 |
58 | // search index space until we find it
59 | for (var i = 0; i < ark.HDNode.HIGHEST_BIT; ++i) {
60 | data.writeUInt32BE(i, 33)
61 |
62 | // calculate I
63 | var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
64 | var IL = I.slice(0, 32)
65 | var pIL = bigi.fromBuffer(IL)
66 |
67 | // See hdnode.js:273 to understand
68 | d2 = d1.subtract(pIL).mod(curve.n)
69 |
70 | var Qp = new ark.ECPair(d2).Q
71 | if (Qp.equals(QP)) break
72 | }
73 |
74 | var node = new ark.HDNode(new ark.ECPair(d2), master.chainCode, master.network)
75 | node.depth = master.depth
76 | node.index = master.index
77 | node.masterFingerprint = master.masterFingerprint
78 | return node
79 | }
80 |
81 | var seed = crypto.randomBytes(32)
82 | var master = ark.HDNode.fromSeedBuffer(seed)
83 | var child = master.derive(6) // m/6
84 |
85 | // now for the recovery
86 | var neuteredMaster = master.neutered()
87 | var recovered = recoverParent(neuteredMaster, child)
88 | assert.strictEqual(recovered.toBase58(), master.toBase58())
89 | })
90 | })
91 |
--------------------------------------------------------------------------------
/test/ipfs/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 |
5 | describe("ipfs.js", function () {
6 |
7 | var ipfs = ark.ipfs;
8 |
9 | it("should be ok", function () {
10 | (ipfs).should.be.ok;
11 | });
12 |
13 | it("should be object", function () {
14 | (ipfs).should.be.type("object");
15 | });
16 |
17 | it("should have createHashRegistration property", function () {
18 | (ipfs).should.have.property("createHashRegistration");
19 | });
20 |
21 | it("should create transaction with fee override", function () {
22 | const feeOverride = 1000000
23 | trs = ipfs.createHashRegistration("QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg", "secret", undefined, feeOverride);
24 | (trs).should.be.ok;
25 | (trs.fee).should.equal(feeOverride)
26 | });
27 |
28 | it("should fail to create transaction with invalid fee override", function (done) {
29 | const feeOverride = '1000000'
30 | try {
31 | trs = ipfs.createHashRegistration("QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg", "secret", undefined, feeOverride);
32 | should.fail()
33 | } catch (error) {
34 | done()
35 | }
36 | });
37 |
38 | it("should create transaction with hashid", function () {
39 | trs = ipfs.createHashRegistration("QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ/cat.jpg", "secret");
40 | (trs).should.be.ok;
41 | });
42 |
43 | it("should be deserialised correctly", function () {
44 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(trs).toString("hex"));
45 | var keys = Object.keys(deserialisedTx);
46 | for(key in keys){
47 | deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
48 | }
49 | });
50 |
51 | describe("returned transaction", function () {
52 | it("should be object", function () {
53 | (trs).should.be.type("object");
54 | });
55 |
56 | it("should have id as string", function () {
57 | (trs.id).should.be.type("string");
58 | });
59 |
60 | it("should have vendorField as string", function () {
61 | (trs.vendorFieldHex).should.be.type("string");
62 | });
63 |
64 | it("should have vendorFieldHex equal to '00000000000000000000516d5732575169376a36633755674a546172416374703774444e696b453442327158744643664c506473676154512f6361742e6a7067'", function () {
65 | (trs.vendorFieldHex).should.be.type("string").and.equal('00000000000000000000516d5732575169376a36633755674a546172416374703774444e696b453442327158744643664c506473676154512f6361742e6a7067');
66 | });
67 |
68 | it("should have type as number and equal 5", function () {
69 | (trs.type).should.be.type("number").and.equal(5);
70 | });
71 |
72 | it("should have timestamp as number", function () {
73 | (trs.timestamp).should.be.type("number").and.not.NaN;
74 | });
75 |
76 | it("should have senderPublicKey as hex string", function () {
77 | (trs.senderPublicKey).should.be.type("string").and.match(function () {
78 | try {
79 | new Buffer(trs.senderPublicKey, "hex")
80 | } catch (e) {
81 | return false;
82 | }
83 |
84 | return true;
85 | })
86 | });
87 |
88 | it("should have amount as number and equal to 0", function () {
89 | (trs.amount).should.be.type("number").and.equal(0);
90 | });
91 |
92 | it("should have empty asset object", function () {
93 | (trs.asset).should.be.type("object").and.empty;
94 | });
95 |
96 | it("should does not have second signature", function () {
97 | (trs).should.not.have.property("signSignature");
98 | });
99 |
100 | it("should have signature as hex string", function () {
101 | (trs.signature).should.be.type("string").and.match(function () {
102 | try {
103 | new Buffer(trs.signature, "hex")
104 | } catch (e) {
105 | return false;
106 | }
107 |
108 | return true;
109 | })
110 | });
111 |
112 | it("should be signed correctly", function () {
113 | var result = ark.crypto.verify(trs);
114 | (result).should.be.ok;
115 | });
116 |
117 | it("should not be signed correctly now (changed amount)", function () {
118 | trs.amount = 10000;
119 | var result = ark.crypto.verify(trs);
120 | (result).should.be.not.ok;
121 | });
122 |
123 | it("should not be signed correctly now (changed vendorField)", function () {
124 | trs.vendorField = "bouloup";
125 | var result = ark.crypto.verify(trs);
126 | (result).should.be.not.ok;
127 | });
128 | });
129 |
130 | });
131 |
--------------------------------------------------------------------------------
/test/multisignature/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 | var constants = require("../../lib/constants.js");
5 |
6 | describe("multisignature.js", function () {
7 |
8 | var multisignature = ark.multisignature;
9 |
10 | it("should be ok", function () {
11 | (multisignature).should.be.ok;
12 | });
13 |
14 | it("should be object", function () {
15 | (multisignature).should.be.type("object");
16 | });
17 |
18 | it("should have properties", function () {
19 | (multisignature).should.have.property("createMultisignature");
20 | });
21 |
22 | describe("#createMultisignature", function () {
23 | var createMultisignature = multisignature.createMultisignature;
24 | var sgn = null;
25 | var keysgroup = ["+03a02b9d5fdd1307c2ee4652ba54d492d1fd11a7d1bb3f3a44c4a05e79f19de933", "+13a02b9d5fdd1307c2ee4652ba54d492d1fd11a7d1bb3f3a44c4a05e79f19de933", "+23a02b9d5fdd1307c2ee4652ba54d492d1fd11a7d1bb3f3a44c4a05e79f19de933"];
26 |
27 | it("should be function", function () {
28 | (createMultisignature).should.be.type("function");
29 | });
30 |
31 | it("should create multisignature transaction", function () {
32 | sgn = createMultisignature("secret", "second secret", keysgroup, 255, 2);
33 | (sgn).should.be.ok;
34 | (sgn).should.be.type("object");
35 | });
36 |
37 | it("should create multisignature transaction from keys", function () {
38 | var secretKey = ark.ECPair.fromSeed("secret");
39 | secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
40 |
41 | var secondSecretKey = ark.ECPair.fromSeed("second secret");
42 | secondSecretKey.publicKey = secondSecretKey.getPublicKeyBuffer().toString("hex");
43 |
44 | sgn = createMultisignature(secretKey, secondSecretKey, keysgroup, 255, 2);
45 | (sgn).should.be.ok;
46 | (sgn).should.be.type("object");
47 | });
48 |
49 | it ("should have the correct multisignature fee", function () {
50 | sgn = createMultisignature('secret', 'second secret', keysgroup, 255, 2);
51 | sgn['fee'].should.equal((keysgroup.length + 1) * constants.fees.multisignature);
52 | });
53 |
54 | it("should create transaction with fee override", function () {
55 | const feeOverride = 1000000
56 | trs = createMultisignature('secret', 'second secret', keysgroup, 255, 2, feeOverride);
57 | (trs).should.be.ok;
58 | (trs.fee).should.equal((keysgroup.length + 1) * feeOverride)
59 | });
60 |
61 | it("should fail to create transaction with invalid fee override", function (done) {
62 | const feeOverride = '1000000'
63 | try {
64 | trs = createMultisignature('secret', 'second secret', keysgroup, 255, 2, feeOverride);
65 | should.fail()
66 | } catch (error) {
67 | done()
68 | }
69 | });
70 |
71 | it("should be deserialised correctly", function () {
72 | sgn = createMultisignature('secret key', 'second secret key', keysgroup, 255, 2);
73 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(sgn).toString("hex"));
74 | delete deserialisedTx.vendorFieldHex;
75 | var keys = Object.keys(deserialisedTx)
76 | for(key in keys){
77 | if(keys[key] == "asset"){
78 | deserialisedTx.asset.multisignature.min.should.equal(sgn.asset.multisignature.min);
79 | deserialisedTx.asset.multisignature.lifetime.should.equal(sgn.asset.multisignature.lifetime);
80 | deserialisedTx.asset.multisignature.keysgroup.length.should.equal(sgn.asset.multisignature.keysgroup.length);
81 | console.log(JSON.stringify(deserialisedTx.asset.multisignature.keysgroup));
82 | deserialisedTx.asset.multisignature.keysgroup[0].should.equal(sgn.asset.multisignature.keysgroup[0]);
83 | deserialisedTx.asset.multisignature.keysgroup[1].should.equal(sgn.asset.multisignature.keysgroup[1]);
84 | deserialisedTx.asset.multisignature.keysgroup[2].should.equal(sgn.asset.multisignature.keysgroup[2]);
85 | }
86 | else {
87 | deserialisedTx[keys[key]].should.equal(sgn[keys[key]]);
88 | }
89 | }
90 | });
91 |
92 | describe("returned multisignature transaction", function () {
93 | it("should have empty recipientId", function () {
94 | (sgn).should.have.property("recipientId").equal(null);
95 | });
96 |
97 | it("should have amount equal 0", function () {
98 | (sgn.amount).should.be.type("number").equal(0);
99 | });
100 |
101 | it("should have asset", function () {
102 | (sgn.asset).should.be.type("object");
103 | (sgn.asset).should.be.not.empty;
104 | });
105 |
106 | it("should have multisignature inside asset", function () {
107 | (sgn.asset).should.have.property("multisignature");
108 | });
109 |
110 | describe("multisignature asset", function () {
111 | it("should be ok", function () {
112 | (sgn.asset.multisignature).should.be.ok;
113 | })
114 |
115 | it("should be object", function () {
116 | (sgn.asset.multisignature).should.be.type("object");
117 | });
118 |
119 | it("should have min property", function () {
120 | (sgn.asset.multisignature).should.have.property("min");
121 | });
122 |
123 | it("should have lifetime property", function () {
124 | (sgn.asset.multisignature).should.have.property("lifetime");
125 | });
126 |
127 | it("should have keysgroup property", function () {
128 | (sgn.asset.multisignature).should.have.property("keysgroup");
129 | });
130 |
131 | it("should have 3 keys keysgroup", function () {
132 | (sgn.asset.multisignature.keysgroup.length).should.be.equal(3);
133 | });
134 | });
135 | });
136 | });
137 |
138 | });
139 |
--------------------------------------------------------------------------------
/test/signature/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 |
5 | describe("signature.js", function () {
6 |
7 | var signature = ark.signature;
8 |
9 | it("should be ok", function () {
10 | (signature).should.be.ok;
11 | });
12 |
13 | it("should be object", function () {
14 | (signature).should.be.type("object");
15 | });
16 |
17 | it("should have properties", function () {
18 | (signature).should.have.property("createSignature");
19 | });
20 |
21 | describe("#createSignature", function () {
22 | var createSignature = signature.createSignature;
23 | var sgn = null;
24 |
25 | it("should be function", function () {
26 | (createSignature).should.be.type("function");
27 | });
28 |
29 | it("should create signature transaction", function () {
30 | sgn = createSignature("secret", "second secret");
31 | (sgn).should.be.ok;
32 | (sgn).should.be.type("object");
33 | });
34 |
35 | it("should create signature transaction", function () {
36 | var secretKey = ark.ECPair.fromSeed("secret");
37 | secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
38 |
39 | sgn = createSignature(secretKey, "second secret");
40 | (sgn).should.be.ok;
41 | (sgn).should.be.type("object");
42 | });
43 |
44 | it("should create transaction with fee override", function () {
45 | const feeOverride = 1000000
46 | trs = createSignature('secret', 'second secret', feeOverride);
47 | (trs).should.be.ok;
48 | (trs.fee).should.equal(feeOverride)
49 | });
50 |
51 | it("should fail to create transaction with invalid fee override", function (done) {
52 | const feeOverride = '1000000'
53 | try {
54 | trs = createSignature('secret', 'second secret', feeOverride);
55 | should.fail()
56 | } catch (error) {
57 | done()
58 | }
59 | });
60 |
61 | it("should be deserialised correctly", function () {
62 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(sgn).toString("hex"));
63 | delete deserialisedTx.vendorFieldHex;
64 | var keys = Object.keys(deserialisedTx)
65 | for(key in keys){
66 | if(keys[key] == "asset"){
67 | deserialisedTx.asset.signature.publicKey.should.equal(sgn.asset.signature.publicKey);
68 | }
69 | else {
70 | deserialisedTx[keys[key]].should.equal(sgn[keys[key]]);
71 | }
72 | }
73 | });
74 |
75 | describe("returned signature transaction", function () {
76 | it("should have empty recipientId", function () {
77 | (sgn).should.have.property("recipientId").equal(null);
78 | });
79 |
80 | it("should have amount equal 0", function () {
81 | (sgn.amount).should.be.type("number").equal(0);
82 | });
83 |
84 | it("should have asset", function () {
85 | (sgn.asset).should.be.type("object");
86 | (sgn.asset).should.be.not.empty;
87 | });
88 |
89 | it("should have signature inside asset", function () {
90 | (sgn.asset).should.have.property("signature");
91 | });
92 |
93 | describe("signature asset", function () {
94 | it("should be ok", function () {
95 | (sgn.asset.signature).should.be.ok;
96 | })
97 |
98 | it("should be object", function () {
99 | (sgn.asset.signature).should.be.type("object");
100 | });
101 |
102 | it("should have publicKey property", function () {
103 | (sgn.asset.signature).should.have.property("publicKey");
104 | });
105 |
106 | it("should have publicKey in hex", function () {
107 | (sgn.asset.signature.publicKey).should.be.type("string").and.match(function () {
108 | try {
109 | new Buffer(sgn.asset.signature.publicKey);
110 | } catch (e) {
111 | return false;
112 | }
113 |
114 | return true;
115 | });
116 | });
117 |
118 | it("should have publicKey in 33 bytes", function () {
119 | var publicKey = new Buffer(sgn.asset.signature.publicKey, "hex");
120 | (publicKey.length).should.be.equal(33);
121 | });
122 | });
123 | });
124 | });
125 |
126 | });
127 |
--------------------------------------------------------------------------------
/test/slot/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 |
5 | describe("slots.js", function () {
6 |
7 | var slots = require("../../lib/time/slots.js");
8 |
9 | it("should be ok", function () {
10 | (slots).should.be.ok;
11 | });
12 |
13 | it("should be object", function () {
14 | (slots).should.be.type("object");
15 | });
16 |
17 | it("should have properties", function () {
18 | var properties = ["interval", "delegates", "getTime", "getRealTime", "getSlotNumber", "getSlotTime", "getNextSlot", "getLastSlot"];
19 | properties.forEach(function (property) {
20 | (slots).should.have.property(property);
21 | });
22 | });
23 |
24 | describe(".interval", function () {
25 | var interval = slots.interval;
26 |
27 | it("should be ok", function () {
28 | (interval).should.be.ok;
29 | });
30 |
31 | it("should be number and not NaN", function () {
32 | (interval).should.be.type("number").and.not.NaN;
33 | });
34 | });
35 |
36 | describe(".delegates", function () {
37 | var delegates = slots.delegates;
38 |
39 | it("should be ok", function () {
40 | (delegates).should.be.ok;
41 | });
42 |
43 | it("should be number and not NaN", function () {
44 | (delegates).should.be.type("number").and.not.NaN;
45 | });
46 | });
47 |
48 | describe("#getTime", function () {
49 | var getTime = slots.getTime;
50 |
51 | it("should be ok", function () {
52 | (getTime).should.be.ok;
53 | });
54 |
55 | it("should be a function", function () {
56 | (getTime).should.be.type("function");
57 | });
58 |
59 | it("should return epoch time as number, equal to 10", function () {
60 | var d = 1490101210000;
61 | var time = getTime(d);
62 | (time).should.be.type("number").and.equal(10);
63 | });
64 | });
65 |
66 | describe("#getRealTime", function () {
67 | var getRealTime = slots.getRealTime;
68 |
69 | it("should be ok", function () {
70 | (getRealTime).should.be.ok;
71 | });
72 |
73 | it("should be a function", function () {
74 | (getRealTime).should.be.type("function");
75 | });
76 |
77 | it("should return return real time, convert 10 to 1490101210000", function () {
78 | var d = 10;
79 | var real = getRealTime(d);
80 | (real).should.be.ok;
81 | (real).should.be.type("number").and.equal(1490101210000);
82 | });
83 | });
84 |
85 | describe("#getSlotNumber", function () {
86 | var getSlotNumber = slots.getSlotNumber;
87 |
88 | it("should be ok", function () {
89 | (getSlotNumber).should.be.ok;
90 | });
91 |
92 | it("should be a function", function () {
93 | (getSlotNumber).should.be.type("function");
94 | });
95 |
96 | it("should return slot number, equal to 1", function () {
97 | var slot = getSlotNumber(10);
98 | (slot).should.be.type("number").and.equal(1);
99 | });
100 | });
101 |
102 | describe("#getSlotTime", function () {
103 | var getSlotTime = slots.getSlotTime;
104 |
105 | it("should be ok", function () {
106 | (getSlotTime).should.be.ok;
107 | });
108 |
109 | it("should be function", function () {
110 | (getSlotTime).should.be.type("function");
111 | });
112 |
113 | it("should return slot time number, equal to ", function () {
114 | var slotTime = getSlotTime(19614);
115 | (slotTime).should.be.ok;
116 | (slotTime).should.be.type("number").and.equal(156912);
117 | });
118 | });
119 |
120 | describe("#getNextSlot", function () {
121 | var getNextSlot = slots.getNextSlot;
122 |
123 | it("should be ok", function () {
124 | (getNextSlot).should.be.ok;
125 | });
126 |
127 | it("should be function", function () {
128 | (getNextSlot).should.be.type("function");
129 | });
130 |
131 | it("should return next slot number", function () {
132 | var nextSlot = getNextSlot();
133 | (nextSlot).should.be.ok;
134 | (nextSlot).should.be.type("number").and.not.NaN;
135 | });
136 | });
137 |
138 | describe("#getLastSlot", function () {
139 | var getLastSlot = slots.getLastSlot;
140 |
141 | it("should be ok", function () {
142 | (getLastSlot).should.be.ok;
143 | });
144 |
145 | it("should be function", function () {
146 | (getLastSlot).should.be.type("function");
147 | });
148 |
149 | it("should return last slot number", function () {
150 | var lastSlot = getLastSlot(slots.getNextSlot());
151 | (lastSlot).should.be.ok;
152 | (lastSlot).should.be.type("number").and.not.NaN;
153 | });
154 | });
155 |
156 | });
157 |
--------------------------------------------------------------------------------
/test/transaction/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 |
5 | describe("transaction.js", function () {
6 |
7 | var transaction = ark.transaction;
8 |
9 | it("should be object", function () {
10 | (transaction).should.be.type("object");
11 | });
12 |
13 | it("should have properties", function () {
14 | (transaction).should.have.property("createTransaction");
15 | })
16 |
17 | describe("#createTransaction", function () {
18 | var createTransaction = transaction.createTransaction;
19 | var trs = null;
20 |
21 | it("should be a function", function () {
22 | (createTransaction).should.be.type("function");
23 | });
24 |
25 | it("should create transaction without second signature", function () {
26 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, null, "secret");
27 | (trs).should.be.ok;
28 | });
29 |
30 | it("should create transaction without second signature from keys", function () {
31 | var secretKey = ark.ECPair.fromSeed("secret");
32 | secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
33 |
34 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, null, secretKey);
35 | (trs).should.be.ok;
36 | });
37 |
38 | it("should create transaction with vendorField", function () {
39 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, "this is a test vendorfield", "secret");
40 | (trs).should.be.ok;
41 | });
42 |
43 | it("should create transaction with fee override", function () {
44 | const feeOverride = 1000000
45 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, null, "secret", undefined, undefined, feeOverride);
46 | (trs).should.be.ok;
47 | (trs.fee).should.equal(feeOverride)
48 | });
49 |
50 | it("should fail to create transaction with invalid fee override", function (done) {
51 | const feeOverride = '1000000'
52 | try {
53 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, null, "secret", undefined, undefined, feeOverride);
54 | should.fail()
55 | } catch (error) {
56 | done()
57 | }
58 | });
59 |
60 | it("should fail if transaction with vendorField length > 64", function () {
61 | var vf="z";
62 | for(i=0;i<6;i++){
63 | vf=vf+vf;
64 | }
65 | vf=vf+"z";
66 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, vf, "secret");
67 | return (trs===null).should.equal(true);
68 |
69 | });
70 |
71 | it("should be ok if transaction with vendorField length = 64", function () {
72 | var vf="z";
73 | for(i=0;i<6;i++){
74 | vf=vf+vf;
75 | }
76 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, vf, "secret");
77 | (trs).should.be.ok;
78 | });
79 |
80 | describe("returned transaction", function () {
81 | it("should be object", function () {
82 | (trs).should.be.type("object");
83 | });
84 |
85 | it("should have id as string", function () {
86 | (trs.id).should.be.type("string");
87 | });
88 |
89 | it("should have type as number and eqaul 0", function () {
90 | (trs.type).should.be.type("number").and.equal(0);
91 | });
92 |
93 | it("should have timestamp as number", function () {
94 | (trs.timestamp).should.be.type("number").and.not.NaN;
95 | });
96 |
97 | it("should have senderPublicKey as hex string", function () {
98 | (trs.senderPublicKey).should.be.type("string").and.match(function () {
99 | try {
100 | new Buffer(trs.senderPublicKey, "hex")
101 | } catch (e) {
102 | return false;
103 | }
104 |
105 | return true;
106 | })
107 | });
108 |
109 | it("should have recipientId as string and to be equal AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", function () {
110 | (trs.recipientId).should.be.type("string").and.equal("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff");
111 | });
112 |
113 | it("should have amount as number and eqaul to 1000", function () {
114 | (trs.amount).should.be.type("number").and.equal(1000);
115 | });
116 |
117 | it("should have empty asset object", function () {
118 | (trs.asset).should.be.type("object").and.empty;
119 | });
120 |
121 | it("should does not have second signature", function () {
122 | (trs).should.not.have.property("signSignature");
123 | });
124 |
125 | it("should have signature as hex string", function () {
126 | (trs.signature).should.be.type("string").and.match(function () {
127 | try {
128 | new Buffer(trs.signature, "hex")
129 | } catch (e) {
130 | return false;
131 | }
132 |
133 | return true;
134 | })
135 | });
136 |
137 | it("should be signed correctly", function () {
138 | var result = ark.crypto.verify(trs);
139 | result.should.equal(true);
140 | });
141 |
142 | it("should be deserialised correctly", function () {
143 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(trs).toString("hex"));
144 | deserialisedTx.vendorField = new Buffer(deserialisedTx.vendorFieldHex, "hex").toString("utf8")
145 | delete deserialisedTx.vendorFieldHex;
146 | var keys = Object.keys(deserialisedTx)
147 | for(key in keys){
148 | if(keys[key] != "vendorFieldHex"){
149 | deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
150 | }
151 | }
152 |
153 | });
154 |
155 | it("should not be signed correctly now", function () {
156 | trs.amount = 10000;
157 | var result = ark.crypto.verify(trs);
158 | result.should.equal(false);
159 | });
160 | });
161 | });
162 |
163 | describe("createTransaction and try to tamper signature", function(){
164 |
165 | it("should not validate overflown signatures", function(){
166 | var BigInteger = require('bigi')
167 | var bip66 = require('bip66')
168 |
169 | // custom bip66 encode for hacking away signature
170 | function BIP66_encode (r, s) {
171 | var lenR = r.length;
172 | var lenS = s.length;
173 | var signature = new Buffer(6 + lenR + lenS);
174 |
175 | // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
176 | signature[0] = 0x30;
177 | signature[1] = signature.length - 2;
178 | signature[2] = 0x02;
179 | signature[3] = r.length;
180 | r.copy(signature, 4);
181 | signature[4 + lenR] = 0x02;
182 | signature[5 + lenR] = s.length;
183 | s.copy(signature, 6 + lenR);
184 |
185 | return signature;
186 | }
187 |
188 | // The transaction to replay
189 | var old_transaction = ark.transaction.createTransaction('AacRfTLtxAkR3Mind1XdPCddj1uDkHtwzD', 1, null, 'randomstring');
190 |
191 | // Decode signature
192 | var decode = bip66.decode(Buffer(old_transaction.signature, "hex"));
193 |
194 | var r = BigInteger.fromDERInteger(decode.r);
195 | var s = BigInteger.fromDERInteger(decode.s);
196 |
197 | // Transform the signature
198 | /*
199 | result = r|00
200 | result = result - r
201 | r = r + result
202 | */
203 |
204 | result = BigInteger.fromBuffer(Buffer(r.toBuffer(r.toDERInteger().length).toString('hex') + '06', 'hex'));
205 | result = result.subtract(r);
206 | r = r.add(result);
207 |
208 | new_signature = BIP66_encode(r.toBuffer(r.toDERInteger().length), s.toBuffer(s.toDERInteger().length)).toString('hex');
209 | //
210 | // console.log("OLD TRANSACTION : ");
211 | // console.log("TXID " + ark.crypto.getId(old_transaction));
212 | // console.log("VERIFY " + ark.crypto.verify(old_transaction));
213 | // console.log("SIG " + old_transaction.signature + "\n");
214 |
215 | ark.crypto.verify(old_transaction).should.equal(true);
216 |
217 | old_transaction.signature = new_signature;
218 | //
219 | // console.log("NEW TRANSACTION : ");
220 | // console.log("TXID " + ark.crypto.getId(old_transaction));
221 | // console.log("VERIFY " + ark.crypto.verify(old_transaction));
222 | // console.log("SIG " + old_transaction.signature);
223 |
224 | ark.crypto.verify(old_transaction).should.equal(false);
225 |
226 | });
227 |
228 | });
229 |
230 | describe("#createTransaction with second secret", function () {
231 | var createTransaction = transaction.createTransaction;
232 | var trs = null;
233 | var secondSecret = "second secret";
234 | var keys = ark.crypto.getKeys(secondSecret);
235 |
236 | it("should be a function", function () {
237 | (createTransaction).should.be.type("function");
238 | });
239 |
240 | it("should not accept bitcoin address", function(){
241 | try {
242 | trs = createTransaction("14owCmVDn8SaAFZcLbZfCVu5jvc4Lq7Tm1", 1000, null, "secret", secondSecret);
243 | } catch(error){
244 | return (error).should.have.property("message").and.equal("Wrong recipientId")
245 | }
246 | true.should.equal(false);
247 | });
248 |
249 | it("should create transaction without second signature", function () {
250 | trs = createTransaction("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", 1000, null, "secret", secondSecret);
251 | (trs).should.be.ok;
252 | });
253 |
254 | describe("returned transaction", function () {
255 | it("should be object", function () {
256 | (trs).should.be.type("object");
257 | });
258 |
259 | it("should have id as string", function () {
260 | (trs.id).should.be.type("string");
261 | });
262 |
263 | it("should have type as number and eqaul 0", function () {
264 | (trs.type).should.be.type("number").and.equal(0);
265 | });
266 |
267 | it("should have timestamp as number", function () {
268 | (trs.timestamp).should.be.type("number").and.not.NaN;
269 | });
270 |
271 | it("should have senderPublicKey as hex string", function () {
272 | (trs.senderPublicKey).should.be.type("string").and.match(function () {
273 | try {
274 | new Buffer(trs.senderPublicKey, "hex")
275 | } catch (e) {
276 | return false;
277 | }
278 |
279 | return true;
280 | })
281 | });
282 |
283 | it("should have recipientId as string and to be equal AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff", function () {
284 | (trs.recipientId).should.be.type("string").and.equal("AJWRd23HNEhPLkK1ymMnwnDBX2a7QBZqff");
285 | });
286 |
287 | it("should have amount as number and eqaul to 1000", function () {
288 | (trs.amount).should.be.type("number").and.equal(1000);
289 | });
290 |
291 | it("should have empty asset object", function () {
292 | (trs.asset).should.be.type("object").and.empty;
293 | });
294 |
295 | it("should have second signature", function () {
296 | (trs).should.have.property("signSignature");
297 | });
298 |
299 | it("should have signature as hex string", function () {
300 | (trs.signature).should.be.type("string").and.match(function () {
301 | try {
302 | new Buffer(trs.signature, "hex")
303 | } catch (e) {
304 | return false;
305 | }
306 |
307 | return true;
308 | })
309 | });
310 |
311 | it("should have signSignature as hex string", function () {
312 | (trs.signSignature).should.be.type("string").and.match(function () {
313 | try {
314 | new Buffer(trs.signSignature, "hex");
315 | } catch (e) {
316 | return false;
317 | }
318 |
319 | return true;
320 | });
321 | });
322 |
323 | it("should be deserialised correctly", function () {
324 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(trs).toString("hex"));
325 | delete deserialisedTx.vendorFieldHex;
326 | var keys = Object.keys(deserialisedTx)
327 | for(key in keys){
328 | deserialisedTx[keys[key]].should.equal(trs[keys[key]]);
329 | }
330 |
331 | });
332 |
333 | it("should be signed correctly", function () {
334 | var result = ark.crypto.verify(trs);
335 | (result).should.equal(true);
336 | });
337 |
338 | it("should be second signed correctly", function () {
339 | var result = ark.crypto.verifySecondSignature(trs, keys.publicKey);
340 | (result).should.equal(true);
341 | });
342 |
343 | it("should not be signed correctly now", function () {
344 | trs.amount = 10000;
345 | var result = ark.crypto.verify(trs);
346 | (result).should.equal(false);
347 | });
348 |
349 | it("should not be second signed correctly now", function () {
350 | trs.amount = 10000;
351 | var result = ark.crypto.verifySecondSignature(trs, keys.publicKey);
352 | (result).should.equal(false);
353 | });
354 | });
355 | });
356 |
357 | });
358 |
--------------------------------------------------------------------------------
/test/vote/index.js:
--------------------------------------------------------------------------------
1 | var Buffer = require("buffer/").Buffer;
2 | var should = require("should");
3 | var ark = require("../../index.js");
4 |
5 | var NETWORKS = require('../../lib/networks');
6 |
7 | describe("vote.js", function () {
8 |
9 | var vote = ark.vote;
10 |
11 | it("should be ok", function () {
12 | (vote).should.be.ok;
13 | });
14 |
15 | it("should be object", function () {
16 | (vote).should.be.type("object");
17 | });
18 |
19 | it("should have createVote property", function () {
20 | (vote).should.have.property("createVote");
21 | });
22 |
23 | describe("#createVote", function () {
24 | var createVote = vote.createVote,
25 | vt = null,
26 | publicKey = ark.crypto.getKeys("secret").publicKey,
27 | publicKeys = ["+" + publicKey];
28 |
29 | it("should be ok", function () {
30 | (createVote).should.be.ok;
31 | });
32 |
33 | it("should be function", function () {
34 | (createVote).should.be.type("function");
35 | });
36 |
37 | it("should create vote", function () {
38 | vt = createVote("secret", publicKeys, "second secret");
39 | });
40 |
41 | it("should create vote from ecpair", function () {
42 | var secretKey = ark.ECPair.fromSeed("secret");
43 | secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
44 |
45 | var secondSecretKey = ark.ECPair.fromSeed("second secret");
46 | secondSecretKey.publicKey = secondSecretKey.getPublicKeyBuffer().toString("hex");
47 |
48 | vt = createVote(secretKey, publicKeys, secondSecretKey);
49 | });
50 |
51 | it("should create vote from wif", function () {
52 | var secretKey = ark.ECPair.fromWIF("SB3iDxYmKgjkhfDZSKgLaBrp3Ynzd3yd3ZZF2ujVBK7vLpv6hWKK", NETWORKS.ark);
53 | secretKey.publicKey = secretKey.getPublicKeyBuffer().toString("hex");
54 |
55 | var tx = createVote(secretKey, publicKeys);
56 | (tx).should.be.ok;
57 | (tx).should.be.type("object");
58 | (tx).should.have.property("recipientId").and.be.type("string").and.be.equal("AL9uJWA5nd6RWn8VSUzGN7spWeZGHeudg9");
59 | });
60 |
61 | it("should create transaction with fee override", function () {
62 | const feeOverride = 1000000
63 | trs = createVote('secret', publicKeys, 'second secret', feeOverride);
64 | (trs).should.be.ok;
65 | (trs.fee).should.equal(feeOverride)
66 | });
67 |
68 | it("should fail to create transaction with invalid fee override", function (done) {
69 | const feeOverride = '1000000'
70 | try {
71 | trs = createVote('secret', publicKeys, 'second secret', feeOverride);
72 | should.fail()
73 | } catch (error) {
74 | done()
75 | }
76 | });
77 |
78 | it("should be deserialised correctly", function () {
79 | var deserialisedTx = ark.crypto.fromBytes(ark.crypto.getBytes(vt).toString("hex"));
80 | delete deserialisedTx.vendorFieldHex;
81 | var keys = Object.keys(deserialisedTx)
82 | for(key in keys){
83 | if(keys[key] == "asset"){
84 | deserialisedTx.asset.votes[0].should.equal(vt.asset.votes[0]);
85 | }
86 | else{
87 | deserialisedTx[keys[key]].should.equal(vt[keys[key]]);
88 | }
89 | }
90 |
91 | });
92 |
93 | describe("returned vote", function () {
94 | it("should be ok", function () {
95 | (vt).should.be.ok;
96 | });
97 |
98 | it("should be object", function () {
99 | (vt).should.be.type("object");
100 | });
101 |
102 | it("should have recipientId string equal to sender", function () {
103 | (vt).should.have.property("recipientId").and.be.type("string").and.equal(ark.crypto.getAddress(publicKey))
104 | });
105 |
106 | it("should have amount number equal to 0", function () {
107 | (vt).should.have.property("amount").and.be.type("number").and.equal(0);
108 | });
109 |
110 | it("should have type number equal to 3", function () {
111 | (vt).should.have.property("type").and.be.type("number").and.equal(3);
112 | });
113 |
114 | it("should have timestamp number", function () {
115 | (vt).should.have.property("timestamp").and.be.type("number");
116 | });
117 |
118 | it("should have senderPublicKey hex string equal to sender public key", function () {
119 | (vt).should.have.property("senderPublicKey").and.be.type("string").and.match(function () {
120 | try {
121 | new Buffer(vt.senderPublicKey, "hex");
122 | } catch (e) {
123 | return false;
124 | }
125 |
126 | return true;
127 | }).and.equal(publicKey);
128 | });
129 |
130 | it("should have signature hex string", function () {
131 | (vt).should.have.property("signature").and.be.type("string").and.match(function () {
132 | try {
133 | new Buffer(vt.signature, "hex");
134 | } catch (e) {
135 | return false;
136 | }
137 |
138 | return true;
139 | });
140 | });
141 |
142 | it("should have second signature hex string", function () {
143 | (vt).should.have.property("signSignature").and.be.type("string").and.match(function () {
144 | try {
145 | new Buffer(vt.signSignature, "hex");
146 | } catch (e) {
147 | return false;
148 | }
149 |
150 | return true;
151 | });
152 | });
153 |
154 | it("should be signed correctly", function () {
155 | var result = ark.crypto.verify(vt);
156 | (result).should.be.ok;
157 | });
158 |
159 | it("should be second signed correctly", function () {
160 | var result = ark.crypto.verifySecondSignature(vt, ark.crypto.getKeys("second secret").publicKey);
161 | (result).should.be.ok;
162 | });
163 |
164 | it("should not be signed correctly now", function () {
165 | vt.amount = 100;
166 | var result = ark.crypto.verify(vt);
167 | (result).should.be.not.ok;
168 | });
169 |
170 | it("should not be second signed correctly now", function () {
171 | vt.amount = 100;
172 | var result = ark.crypto.verifySecondSignature(vt, ark.crypto.getKeys("second secret").publicKey);
173 | (result).should.be.not.ok;
174 | });
175 |
176 | it("should have asset", function () {
177 | (vt).should.have.property("asset").and.not.empty;
178 | });
179 |
180 | describe("vote asset", function () {
181 | it("should be ok", function () {
182 | (vt.asset).should.have.property("votes").and.be.ok;
183 | });
184 |
185 | it("should be object", function () {
186 | (vt.asset.votes).should.be.type("object");
187 | });
188 |
189 | it("should be not empty", function () {
190 | (vt.asset.votes).should.be.not.empty;
191 | });
192 |
193 | it("should contains one element", function () {
194 | (vt.asset.votes.length).should.be.equal(1);
195 | });
196 |
197 | it("should have public keys in hex", function () {
198 | vt.asset.votes.forEach(function (v) {
199 | (v).should.be.type("string").startWith("+").and.match(function () {
200 | try {
201 | new Buffer(v.substring(1, v.length), "hex");
202 | } catch (e) {
203 | return false;
204 | }
205 |
206 | return true;
207 | });
208 | });
209 | });
210 |
211 | it("should be equal to sender public key", function () {
212 | var v = vt.asset.votes[0];
213 | (v.substring(1, v.length)).should.be.equal(publicKey);
214 | });
215 | })
216 | });
217 | });
218 |
219 | });
220 |
--------------------------------------------------------------------------------