From edc8bfbd31ca2ec2f053dad3627de77be1e41600 Mon Sep 17 00:00:00 2001 From: shantilu Date: Fri, 23 Aug 2019 11:44:59 +0800 Subject: [PATCH] form setup --- package-lock.json | 104 ++++++-- package.json | 12 +- public/chart.svg | 90 +++++++ public/index.html | 4 + public/price.png | Bin 0 -> 32145 bytes src/components/HelloWorld.vue | 448 ++++++++++++++++++++++------------ src/ecc/src/AccountLogin.js | 45 ++++ src/ecc/src/BrainKey.js | 8 + src/ecc/src/PrivateKey.js | 165 +++++++++++++ src/ecc/src/PublicKey.js | 175 +++++++++++++ src/ecc/src/ecdsa.js | 217 ++++++++++++++++ src/ecc/src/ecsignature.js | 127 ++++++++++ src/ecc/src/enforce_types.js | 42 ++++ src/ecc/src/hash.js | 54 ++++ src/ecc/src/signature.js | 155 ++++++++++++ src/plugins/vuetify.js | 3 + 16 files changed, 1478 insertions(+), 171 deletions(-) create mode 100644 public/chart.svg create mode 100644 public/price.png create mode 100644 src/ecc/src/AccountLogin.js create mode 100644 src/ecc/src/BrainKey.js create mode 100644 src/ecc/src/PrivateKey.js create mode 100644 src/ecc/src/PublicKey.js create mode 100644 src/ecc/src/ecdsa.js create mode 100644 src/ecc/src/ecsignature.js create mode 100644 src/ecc/src/enforce_types.js create mode 100644 src/ecc/src/hash.js create mode 100644 src/ecc/src/signature.js diff --git a/package-lock.json b/package-lock.json index fa7fa09..164ccf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1959,6 +1959,43 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -2139,6 +2176,14 @@ } } }, + "base-x": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.6.tgz", + "integrity": "sha512-4PaF8u2+AlViJxRVjurkLTxpp7CaFRD/jo5rPT9ONnKxyhQ8f59yzamEvq7EkriG56yn5On4ONyaG75HLqr46w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -2178,6 +2223,11 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, + "bigi": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", + "integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU=" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -2392,6 +2442,14 @@ "node-releases": "^1.1.25" } }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -2427,6 +2485,14 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -2654,7 +2720,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -3223,7 +3288,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -3236,7 +3300,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3278,6 +3341,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -3591,8 +3659,7 @@ "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" }, "deep-is": { "version": "0.1.3", @@ -3984,6 +4051,15 @@ "safer-buffer": "^2.1.0" } }, + "ecurve": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", + "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", + "requires": { + "bigi": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -6023,7 +6099,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -6453,8 +6528,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "inquirer": { "version": "3.3.0", @@ -7128,8 +7202,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash.defaultsdeep": { "version": "4.6.1", @@ -7182,6 +7255,11 @@ "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", "dev": true }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7244,7 +7322,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -9456,7 +9533,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -9509,8 +9585,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -9765,7 +9840,6 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" diff --git a/package.json b/package.json index e0bbe3c..e976f5e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,17 @@ "core-js": "^2.6.5", "vue": "^2.6.10", "vuetify": "^2.0.0", - "lodash": "^4.17.14" + "lodash": "^4.17.14", + "axios": "^0.19.0", + + "bigi": "^1.4.2", + "bs58": "^4.0.1", + "bytebuffer": "^5.0.1", + "create-hash": "^1.1.3", + "create-hmac": "^1.1.6", + "crypto-js": "^3.1.9-1", + "deep-equal": "^1.0.1", + "ecurve": "^1.0.5" }, "devDependencies": { "@mdi/font": "^4.1.95", diff --git a/public/chart.svg b/public/chart.svg new file mode 100644 index 0000000..c3d8274 --- /dev/null +++ b/public/chart.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + 12:00 + + + 12:05 + + + 12:10 + + + 12:15 + + + 12:20 + + + 12:25 + + + 12:30 + + + + + 2000.0 + + + 2010.0 + + + 2020.0 + + + 2030.0 + + + 2040.0 + + + 2050.0 + + + + + + + + + + + 2028.5 + + + + + + + + + 2006.7 + + + + + + + + 2047.4 + + + + + + diff --git a/public/index.html b/public/index.html index c2953fb..163525c 100644 --- a/public/index.html +++ b/public/index.html @@ -15,5 +15,9 @@
+ + + + diff --git a/public/price.png b/public/price.png new file mode 100644 index 0000000000000000000000000000000000000000..a97ac766321136a4058d5b992a84506c95e63a6e GIT binary patch literal 32145 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�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 Ji=^)a{tvmp5|aP` literal 0 HcmV?d00001 diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 30dab1c..1a42a77 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -12,24 +12,24 @@ - + -
BBB-全网门槛最低合约产品
-
低手续费、低合约单价
下载即用,操作简单
+
BBB-首个去中心化数字资产合约产品
+
低手续费、透明公平
杠杆交易,规则简单
- - + + mdi-eye-outline + > + + @@ -93,13 +98,86 @@ - + +
- + + + + +
+ 所有交易上链公开透明
+ 杜绝人为操作价格 +
+
+ + + + + + + + + +
不同杠杆产品
+ 1USDT即可交易 + +
+
+ + + + + + + +
+ 详尽指标展示
+ 轻松掌握平仓时机 +
+
+ + + + + + + +
+ +
+ @@ -113,78 +191,141 @@ no-gutters > - {{ link }} + {{item.title}} + + + + + 联系我们 + + diff --git a/src/ecc/src/AccountLogin.js b/src/ecc/src/AccountLogin.js new file mode 100644 index 0000000..37d82c9 --- /dev/null +++ b/src/ecc/src/AccountLogin.js @@ -0,0 +1,45 @@ +const PrivateKey = require("./PrivateKey"); + +const normalize_brainKey = function (brainKey) { + if (!(typeof brainKey === 'string')) { + throw new Error("string required for brainKey"); + } + + brainKey = brainKey.trim(); + return brainKey.split(/[\t\n\v\f\r ]+/).join(' '); +} + +const generateKeys = function (accountName, password, role = "active") { + + if (!accountName || !password) { + throw new Error("Account name or password required"); + } + if (password.length < 12) { + throw new Error("Password must have at least 12 characters"); + } + + let seed = accountName + role + password; + return PrivateKey.fromSeed(normalize_brainKey(seed)); + +} + +// const checkKeys = function ({accountName, password, auths}) { +// if (!accountName || !password || !auths) { +// throw new Error("checkKeys: Missing inputs"); +// } +// let hasKey = false; +// +// for (let role in auths) { +// let {privKeys, pubKeys} = this.generateKeys(accountName, password, [role]); +// auths[role].forEach(key => { +// if (key[0] === pubKeys[role]) { +// hasKey = true; +// this.set(role, {priv: privKeys[role], pub: pubKeys[role]}); +// } +// }); +// }; +// +// return hasKey; +// } + +exports.generateKeys = generateKeys; diff --git a/src/ecc/src/BrainKey.js b/src/ecc/src/BrainKey.js new file mode 100644 index 0000000..af60405 --- /dev/null +++ b/src/ecc/src/BrainKey.js @@ -0,0 +1,8 @@ + +export default function normalize(brainKey) { + if (typeof brainKey !== 'string') { + throw new Error("string required for brainKey"); + } + brainKey = brainKey.trim(); + return brainKey.split(/[\t\n\v\f\r ]+/).join(' '); +} diff --git a/src/ecc/src/PrivateKey.js b/src/ecc/src/PrivateKey.js new file mode 100644 index 0000000..5385256 --- /dev/null +++ b/src/ecc/src/PrivateKey.js @@ -0,0 +1,165 @@ +const ecurve = require('ecurve'); +const {Point, getCurveByName} = require('ecurve'); +const BigInteger = require('bigi'); +const {encode, decode} = require('bs58'); +const { sha256, sha512 } = require('./hash'); +const PublicKey = require('./PublicKey'); +const deepEqual = require("deep-equal"); +const assert = require("assert"); + +const secp256k1 = getCurveByName('secp256k1'); +const {G, n} = secp256k1; + +class PrivateKey { + + /** + @private see static functions + @param {BigInteger} + */ + constructor(d) { this.d = d; } + + static fromBuffer(buf) { + if (!Buffer.isBuffer(buf)) { + throw new Error("Expecting paramter to be a Buffer type"); + } + if (32 !== buf.length) { + console.log(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack); + } + if (buf.length === 0) { + throw new Error("Empty buffer"); + } + return new PrivateKey(BigInteger.fromBuffer(buf)); + } + + /** @arg {string} seed - any length string. This is private, the same seed produces the same private key every time. */ + static fromSeed(seed) { // generate_private_key + if (!(typeof seed === 'string')) { + throw new Error('seed must be of type string'); + } + return PrivateKey.fromBuffer(sha256(seed)); + } + + /** @return {string} Wallet Import Format (still a secret, Not encrypted) */ + static fromWif(_private_wif) { + var private_wif = new Buffer(decode(_private_wif)); + var version = private_wif.readUInt8(0); + assert.equal(0x80, version, `Expected version ${0x80}, instead got ${version}`); + // checksum includes the version + var private_key = private_wif.slice(0, -4); + var checksum = private_wif.slice(-4); + var new_checksum = sha256(private_key); + new_checksum = sha256(new_checksum); + new_checksum = new_checksum.slice(0, 4); + var isEqual = deepEqual(checksum, new_checksum); //, 'Invalid checksum' + if (!isEqual) { + throw new Error("Checksum did not match"); + } + private_key = private_key.slice(1); + return PrivateKey.fromBuffer(private_key); + } + + toWif() { + var private_key = this.toBuffer(); + // checksum includes the version + private_key = Buffer.concat([new Buffer([0x80]), private_key]); + var checksum = sha256(private_key); + checksum = sha256(checksum); + checksum = checksum.slice(0, 4); + var private_wif = Buffer.concat([private_key, checksum]); + return encode(private_wif); + } + + /** + @return {Point} + */ + toPublicKeyPoint() { + var Q; + return Q = secp256k1.G.multiply(this.d); + } + + toPublicKey() { + if (this.public_key) { return this.public_key; } + return this.public_key = PublicKey.fromPoint(this.toPublicKeyPoint()); + } + + toBuffer() { + return this.d.toBuffer(32); + } + + + /** ECIES */ + get_shared_secret(public_key, legacy = false) { + public_key = toPublic(public_key) + let KB = public_key.toUncompressed().toBuffer() + let KBP = Point.fromAffine( + secp256k1, + BigInteger.fromBuffer( KB.slice( 1,33 )), // x + BigInteger.fromBuffer( KB.slice( 33,65 )) // y + ) + let r = this.toBuffer() + let P = KBP.multiply(BigInteger.fromBuffer(r)) + let S = P.affineX.toBuffer({size: 32}) + /* + the input to sha512 must be exactly 32-bytes, to match the c++ implementation + of get_shared_secret. Right now S will be shorter if the most significant + byte(s) is zero. Pad it back to the full 32-bytes + */ + if (!legacy && S.length < 32) { + let pad = new Buffer(32 - S.length).fill(0); + S = Buffer.concat([pad, S]); + } + + // SHA512 used in ECIES + return sha512(S) + } + + // /** ECIES (does not always match the Point.fromAffine version above) */ + // get_shared_secret(public_key){ + // public_key = toPublic(public_key) + // var P = public_key.Q.multiply( this.d ); + // var S = P.affineX.toBuffer({size: 32}); + // // ECIES, adds an extra sha512 + // return sha512(S); + // } + + /** @throws {Error} - overflow of the key could not be derived */ + child( offset ) { + offset = Buffer.concat([ this.toPublicKey().toBuffer(), offset ]) + offset = sha256( offset ) + let c = BigInteger.fromBuffer(offset) + + if (c.compareTo(n) >= 0) + throw new Error("Child offset went out of bounds, try again") + + let derived = this.d.add(c)//.mod(n) + + if( derived.signum() === 0 ) + throw new Error("Child offset derived to an invalid key, try again") + + return new PrivateKey( derived ) + } + + /* */ + + toByteBuffer() { + var b = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN); + this.appendByteBuffer(b); + return b.copy(0, b.offset); + } + + static fromHex(hex) { + return PrivateKey.fromBuffer(new Buffer(hex, 'hex')); + } + + toHex() { + return this.toBuffer().toString('hex'); + } + + /* */ +} + +module.exports = PrivateKey; +// export default PrivateKey; + +let toPublic = data => data == null ? data : + data.Q ? data : PublicKey.fromStringOrThrow(data) diff --git a/src/ecc/src/PublicKey.js b/src/ecc/src/PublicKey.js new file mode 100644 index 0000000..7541e74 --- /dev/null +++ b/src/ecc/src/PublicKey.js @@ -0,0 +1,175 @@ +// const {ChainConfig} = require('cybexjs-ws'); + +// const ecurve = require('ecurve'); +const {Point, getCurveByName} = require('ecurve'); +const BigInteger = require('bigi'); +const { encode, decode } = require('bs58'); +const { sha256, sha512, ripemd160 } = require('./hash'); +const deepEqual = require("deep-equal"); +const assert = require("assert"); + +const secp256k1 = getCurveByName('secp256k1'); +const {G, n} = secp256k1; + +class PublicKey { + + /** @param {Point} public key */ + constructor(Q) { this.Q = Q; } + + static fromBinary(bin) { + return PublicKey.fromBuffer(new Buffer(bin, 'binary')); + } + + static fromBuffer(buffer) { + if (buffer.toString('hex') === '000000000000000000000000000000000000000000000000000000000000000000') + return new PublicKey(null); + return new PublicKey(Point.decodeFrom(secp256k1, buffer)); + } + + toBuffer(compressed = this.Q? this.Q.compressed : null) { + if (this.Q === null) + return new Buffer('000000000000000000000000000000000000000000000000000000000000000000', 'hex'); + return this.Q.getEncoded(compressed); + } + + static fromPoint(point) { + return new PublicKey(point); + } + + toUncompressed() { + var buf = this.Q.getEncoded(false); + var point = Point.decodeFrom(secp256k1, buf); + return PublicKey.fromPoint(point); + } + + /** cyb::blockchain::address (unique but not a full public key) */ + toBlockchainAddress() { + var pub_buf = this.toBuffer(); + var pub_sha = sha512(pub_buf); + return ripemd160(pub_sha); + } + + /** Alias for {@link toPublicKeyString} */ + toString(address_prefix = "CYB") { + return this.toPublicKeyString(address_prefix) + } + + /** + Full public key + {return} string + */ + toPublicKeyString(address_prefix = "CYB") { + var pub_buf = this.toBuffer(); + var checksum = ripemd160(pub_buf); + var addy = Buffer.concat([pub_buf, checksum.slice(0, 4)]); + return address_prefix + encode(addy); + } + + /** + @arg {string} public_key - like GPHXyz... + @arg {string} address_prefix - like GPH + @return PublicKey or `null` (if the public_key string is invalid) + */ + static fromPublicKeyString(public_key, address_prefix = "CYB") { + try { + return PublicKey.fromStringOrThrow(public_key, address_prefix) + } catch (e) { + return null; + } + } + + /** + @arg {string} public_key - like GPHXyz... + @arg {string} address_prefix - like GPH + @throws {Error} if public key is invalid + @return PublicKey + */ + static fromStringOrThrow(public_key, address_prefix = "CYB") { + var prefix = public_key.slice(0, address_prefix.length); + assert.equal( + address_prefix, prefix, + `Expecting key to begin with ${address_prefix}, instead got ${prefix}`); + public_key = public_key.slice(address_prefix.length); + + public_key = new Buffer(decode(public_key), 'binary'); + var checksum = public_key.slice(-4); + public_key = public_key.slice(0, -4); + var new_checksum = ripemd160(public_key); + new_checksum = new_checksum.slice(0, 4); + var isEqual = deepEqual(checksum, new_checksum); //, 'Invalid checksum' + if (!isEqual) { + throw new Error("Checksum did not match"); + } + return PublicKey.fromBuffer(public_key); + } + + toAddressString(address_prefix = "CYB") { + var pub_buf = this.toBuffer(); + var pub_sha = sha512(pub_buf); + var addy = ripemd160(pub_sha); + var checksum = ripemd160(addy); + addy = Buffer.concat([addy, checksum.slice(0, 4)]); + return address_prefix + encode(addy); + } + + toPtsAddy() { + var pub_buf = this.toBuffer(); + var pub_sha = sha256(pub_buf); + var addy = ripemd160(pub_sha); + addy = Buffer.concat([new Buffer([0x38]), addy]); //version 56(decimal) + + var checksum = sha256(addy); + checksum = sha256(checksum); + + addy = Buffer.concat([addy, checksum.slice(0, 4)]); + return encode(addy); + } + + child( offset ) { + + assert(Buffer.isBuffer(offset), "Buffer required: offset") + assert.equal(offset.length, 32, "offset length") + + offset = Buffer.concat([ this.toBuffer(), offset ]) + offset = sha256( offset ) + + let c = BigInteger.fromBuffer( offset ) + + if (c.compareTo(n) >= 0) + throw new Error("Child offset went out of bounds, try again") + + + let cG = G.multiply(c) + let Qprime = this.Q.add(cG) + + if( secp256k1.isInfinity(Qprime) ) + throw new Error("Child offset derived to an invalid key, try again") + + return PublicKey.fromPoint(Qprime) + } + + /* */ + + toByteBuffer() { + var b = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN); + this.appendByteBuffer(b); + return b.copy(0, b.offset); + } + + static fromHex(hex) { + return PublicKey.fromBuffer(new Buffer(hex, 'hex')); + } + + toHex() { + return this.toBuffer().toString('hex'); + } + + static fromPublicKeyStringHex(hex) { + return PublicKey.fromPublicKeyString(new Buffer(hex, 'hex')); + } + + /* */ +} + +module.exports = PublicKey; +// export default PublicKey; diff --git a/src/ecc/src/ecdsa.js b/src/ecc/src/ecdsa.js new file mode 100644 index 0000000..fe00ca6 --- /dev/null +++ b/src/ecc/src/ecdsa.js @@ -0,0 +1,217 @@ +const assert = require('assert'); // from github.com/bitcoinjs/bitcoinjs-lib from github.com/cryptocoinjs/ecdsa +const {sha256, HmacSHA256 } = require('./hash'); +const enforceType = require('./enforce_types'); + +const BigInteger = require('bigi'); +const ECSignature = require('./ecsignature'); + +// https://tools.ietf.org/html/rfc6979#section-3.2 +function deterministicGenerateK(curve, hash, d, checkSig, nonce) { + + enforceType('Buffer', hash) + enforceType(BigInteger, d) + + if (nonce) { + hash = sha256(Buffer.concat([hash, new Buffer(nonce)])) + } + + // sanity check + assert.equal(hash.length, 32, 'Hash must be 256 bit') + + var x = d.toBuffer(32) + var k = new Buffer(32) + var v = new Buffer(32) + + // Step B + v.fill(1) + + // Step C + k.fill(0) + + // Step D + k = HmacSHA256(Buffer.concat([v, new Buffer([0]), x, hash]), k) + + // Step E + v = HmacSHA256(v, k) + + // Step F + k = HmacSHA256(Buffer.concat([v, new Buffer([1]), x, hash]), k) + + // Step G + v = HmacSHA256(v, k) + + // Step H1/H2a, ignored as tlen === qlen (256 bit) + // Step H2b + v = HmacSHA256(v, k) + + var T = BigInteger.fromBuffer(v) + + // Step H3, repeat until T is within the interval [1, n - 1] + while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) { + k = HmacSHA256(Buffer.concat([v, new Buffer([0])]), k) + v = HmacSHA256(v, k) + + // Step H1/H2a, again, ignored as tlen === qlen (256 bit) + // Step H2b again + v = HmacSHA256(v, k) + + T = BigInteger.fromBuffer(v) + } + + return T + +} + +function sign(curve, hash, d, nonce) { + + var e = BigInteger.fromBuffer(hash) + var n = curve.n + var G = curve.G + + var r, s + var k = deterministicGenerateK(curve, hash, d, function (k) { + // find canonically valid signature + var Q = G.multiply(k) + + if (curve.isInfinity(Q)) return false + + r = Q.affineX.mod(n) + if (r.signum() === 0) return false + + s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n) + if (s.signum() === 0) return false + + return true + }, nonce) + + var N_OVER_TWO = n.shiftRight(1) + + // enforce low S values, see bip62: 'low s values in signatures' + if (s.compareTo(N_OVER_TWO) > 0) { + s = n.subtract(s) + } + + return new ECSignature(r, s) +} + +function verifyRaw(curve, e, signature, Q) { + var n = curve.n + var G = curve.G + + var r = signature.r + var s = signature.s + + // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] + if (r.signum() <= 0 || r.compareTo(n) >= 0) return false + if (s.signum() <= 0 || s.compareTo(n) >= 0) return false + + // c = s^-1 mod n + var c = s.modInverse(n) + + // 1.4.4 Compute u1 = es^−1 mod n + // u2 = rs^−1 mod n + var u1 = e.multiply(c).mod(n) + var u2 = r.multiply(c).mod(n) + + // 1.4.5 Compute R = (xR, yR) = u1G + u2Q + var R = G.multiplyTwo(u1, Q, u2) + + // 1.4.5 (cont.) Enforce R is not at infinity + if (curve.isInfinity(R)) return false + + // 1.4.6 Convert the field element R.x to an integer + var xR = R.affineX + + // 1.4.7 Set v = xR mod n + var v = xR.mod(n) + + // 1.4.8 If v = r, output "valid", and if v != r, output "invalid" + return v.equals(r) +} + +function verify(curve, hash, signature, Q) { + // 1.4.2 H = Hash(M), already done by the user + // 1.4.3 e = H + var e = BigInteger.fromBuffer(hash) + return verifyRaw(curve, e, signature, Q) +} + +/** + * Recover a public key from a signature. + * + * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public + * Key Recovery Operation". + * + * http://www.secg.org/download/aid-780/sec1-v2.pdf + */ +function recoverPubKey(curve, e, signature, i) { + assert.strictEqual(i & 3, i, 'Recovery param is more than two bits') + + var n = curve.n + var G = curve.G + + var r = signature.r + var s = signature.s + + assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value') + assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value') + + // A set LSB signifies that the y-coordinate is odd + var isYOdd = i & 1 + + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1 + + // 1.1 Let x = r + jn + var x = isSecondKey ? r.add(n) : r + var R = curve.pointFromX(isYOdd, x) + + // 1.4 Check that nR is at infinity + var nR = R.multiply(n) + assert(curve.isInfinity(nR), 'nR is not a valid curve point') + + // Compute -e from e + var eNeg = e.negate().mod(n) + + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + var rInv = r.modInverse(n) + + var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv) + curve.validate(Q) + + return Q +} + +/** + * Calculate pubkey extraction parameter. + * + * When extracting a pubkey from a signature, we have to + * distinguish four different cases. Rather than putting this + * burden on the verifier, Bitcoin includes a 2-bit value with the + * signature. + * + * This function simply tries all four cases and returns the value + * that resulted in a successful pubkey recovery. + */ +function calcPubKeyRecoveryParam(curve, e, signature, Q) { + for (var i = 0; i < 4; i++) { + var Qprime = recoverPubKey(curve, e, signature, i) + + // 1.6.2 Verify Q + if (Qprime.equals(Q)) { + return i + } + } + + throw new Error('Unable to find valid recovery factor') +} + +// export { calcPubKeyRecoveryParam, deterministicGenerateK, recoverPubKey, sign, verify, verifyRaw }; +exports.calcPubKeyRecoveryParam = calcPubKeyRecoveryParam; +exports.deterministicGenerateK = deterministicGenerateK; +exports.recoverPubKey = recoverPubKey; +exports.sign = sign; +exports.verify = verify; +exports.verifyRaw = verifyRaw; \ No newline at end of file diff --git a/src/ecc/src/ecsignature.js b/src/ecc/src/ecsignature.js new file mode 100644 index 0000000..326ef2b --- /dev/null +++ b/src/ecc/src/ecsignature.js @@ -0,0 +1,127 @@ +const assert = require("assert"); // from https://github.com/bitcoinjs/bitcoinjs-lib +const enforceType = require('./enforce_types'); + +const BigInteger = require('bigi'); + +function ECSignature(r, s) { + enforceType(BigInteger, r) + enforceType(BigInteger, s) + + this.r = r + this.s = s +} + +// Import operations +ECSignature.parseCompact = function(buffer) { + assert.equal(buffer.length, 65, 'Invalid signature length') + var i = buffer.readUInt8(0) - 27 + + // At most 3 bits + assert.equal(i, i & 7, 'Invalid signature parameter') + var compressed = !!(i & 4) + + // Recovery param only + i = i & 3 + + var r = BigInteger.fromBuffer(buffer.slice(1, 33)) + var s = BigInteger.fromBuffer(buffer.slice(33)) + + return { + compressed: compressed, + i: i, + signature: new ECSignature(r, s) + } +} + +ECSignature.fromDER = function(buffer) { + assert.equal(buffer.readUInt8(0), 0x30, 'Not a DER sequence') + assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length') + assert.equal(buffer.readUInt8(2), 0x02, 'Expected a DER integer') + + var rLen = buffer.readUInt8(3) + assert(rLen > 0, 'R length is zero') + + var offset = 4 + rLen + assert.equal(buffer.readUInt8(offset), 0x02, 'Expected a DER integer (2)') + + var sLen = buffer.readUInt8(offset + 1) + assert(sLen > 0, 'S length is zero') + + var rB = buffer.slice(4, offset) + var sB = buffer.slice(offset + 2) + offset += 2 + sLen + + if (rLen > 1 && rB.readUInt8(0) === 0x00) { + assert(rB.readUInt8(1) & 0x80, 'R value excessively padded') + } + + if (sLen > 1 && sB.readUInt8(0) === 0x00) { + assert(sB.readUInt8(1) & 0x80, 'S value excessively padded') + } + + assert.equal(offset, buffer.length, 'Invalid DER encoding') + var r = BigInteger.fromDERInteger(rB) + var s = BigInteger.fromDERInteger(sB) + + assert(r.signum() >= 0, 'R value is negative') + assert(s.signum() >= 0, 'S value is negative') + + return new ECSignature(r, s) +} + +// FIXME: 0x00, 0x04, 0x80 are SIGHASH_* boundary constants, importing Transaction causes a circular dependency +ECSignature.parseScriptSignature = function(buffer) { + var hashType = buffer.readUInt8(buffer.length - 1) + var hashTypeMod = hashType & ~0x80 + + assert(hashTypeMod > 0x00 && hashTypeMod < 0x04, 'Invalid hashType') + + return { + signature: ECSignature.fromDER(buffer.slice(0, -1)), + hashType: hashType + } +} + +// Export operations +ECSignature.prototype.toCompact = function(i, compressed) { + if (compressed) i += 4 + i += 27 + + var buffer = new Buffer(65) + buffer.writeUInt8(i, 0) + + this.r.toBuffer(32).copy(buffer, 1) + this.s.toBuffer(32).copy(buffer, 33) + + return buffer +} + +ECSignature.prototype.toDER = function() { + var rBa = this.r.toDERInteger() + var sBa = this.s.toDERInteger() + + var sequence = [] + + // INTEGER + sequence.push(0x02, rBa.length) + sequence = sequence.concat(rBa) + + // INTEGER + sequence.push(0x02, sBa.length) + sequence = sequence.concat(sBa) + + // SEQUENCE + sequence.unshift(0x30, sequence.length) + + return new Buffer(sequence) +} + +ECSignature.prototype.toScriptSignature = function(hashType) { + var hashTypeBuffer = new Buffer(1) + hashTypeBuffer.writeUInt8(hashType, 0) + + return Buffer.concat([this.toDER(), hashTypeBuffer]) +} + +// export default ECSignature +module.exports = ECSignature; \ No newline at end of file diff --git a/src/ecc/src/enforce_types.js b/src/ecc/src/enforce_types.js new file mode 100644 index 0000000..01d24c4 --- /dev/null +++ b/src/ecc/src/enforce_types.js @@ -0,0 +1,42 @@ +function enforce(type, value) { // Copied from https://github.com/bitcoinjs/bitcoinjs-lib + switch (type) { + case 'Array': { + if (Array.isArray(value)) return + break + } + + case 'Boolean': { + if (typeof value === 'boolean') return + break + } + + case 'Buffer': { + if (Buffer.isBuffer(value)) return + break + } + + case 'Number': { + if (typeof value === 'number') return + break + } + + case 'String': { + if (typeof value === 'string') return + break + } + + default: { + if (getName(value.constructor) === getName(type)) return + } + } + + throw new TypeError('Expected ' + (getName(type) || type) + ', got ' + value) +} + +function getName(fn) { + // Why not fn.name: https://kangax.github.io/compat-table6/#function_name_property + var match = fn.toString().match(/function (.*?)\(/) + return match ? match[1] : null +} + +module.exports = enforce; \ No newline at end of file diff --git a/src/ecc/src/hash.js b/src/ecc/src/hash.js new file mode 100644 index 0000000..2c02039 --- /dev/null +++ b/src/ecc/src/hash.js @@ -0,0 +1,54 @@ +const createHash =require("create-hash"); +const createHmac =require("create-hmac"); + +/** @arg {string|Buffer} data + @arg {string} [digest = null] - 'hex', 'binary' or 'base64' + @return {string|Buffer} - Buffer when digest is null, or string +*/ +function sha1(data, encoding) { + return createHash('sha1').update(data).digest(encoding) +} + +/** @arg {string|Buffer} data + @arg {string} [digest = null] - 'hex', 'binary' or 'base64' + @return {string|Buffer} - Buffer when digest is null, or string +*/ +function sha256(data, encoding) { + return createHash('sha256').update(data).digest(encoding) +} + +/** @arg {string|Buffer} data + @arg {string} [digest = null] - 'hex', 'binary' or 'base64' + @return {string|Buffer} - Buffer when digest is null, or string +*/ +function sha512(data, encoding) { + return createHash('sha512').update(data).digest(encoding) +} + +function HmacSHA256(buffer, secret) { + return createHmac('sha256', secret).update(buffer).digest() +} + +function ripemd160(data) { + return createHash('rmd160').update(data).digest() +} + +// function hash160(buffer) { +// return ripemd160(sha256(buffer)) +// } +// +// function hash256(buffer) { +// return sha256(sha256(buffer)) +// } + +// +// function HmacSHA512(buffer, secret) { +// return crypto.createHmac('sha512', secret).update(buffer).digest() +// } + +// export { sha1, sha256, sha512, HmacSHA256, ripemd160 }; +exports.sha1 = sha1; +exports.sha256 = sha256; +exports.sha512 = sha512; +exports.HmacSHA256 = HmacSHA256; +exports.ripemd160 = ripemd160; \ No newline at end of file diff --git a/src/ecc/src/signature.js b/src/ecc/src/signature.js new file mode 100644 index 0000000..b8971b6 --- /dev/null +++ b/src/ecc/src/signature.js @@ -0,0 +1,155 @@ +const { sign, recoverPubKey, verify, calcPubKeyRecoveryParam } = require('./ecdsa'); +const { sha256 } = require('./hash'); +const {getCurveByName} = require('ecurve'); + +const assert = require("assert"); +const BigInteger = require('bigi'); +const PublicKey = require('./PublicKey'); + +var secp256k1 = getCurveByName('secp256k1'); + +class Signature { + + constructor(r1, s1, i1) { + this.r = r1; + this.s = s1; + this.i = i1; + assert.equal(this.r != null, true, 'Missing parameter'); + assert.equal(this.s != null, true, 'Missing parameter'); + assert.equal(this.i != null, true, 'Missing parameter'); + } + + static fromBuffer(buf) { + var i, r, s; + assert.equal(buf.length, 65, 'Invalid signature length'); + i = buf.readUInt8(0); + assert.equal(i - 27, i - 27 & 7, 'Invalid signature parameter'); + r = BigInteger.fromBuffer(buf.slice(1, 33)); + s = BigInteger.fromBuffer(buf.slice(33)); + return new Signature(r, s, i); + }; + + toBuffer() { + var buf; + buf = new Buffer(65); + buf.writeUInt8(this.i, 0); + this.r.toBuffer(32).copy(buf, 1); + this.s.toBuffer(32).copy(buf, 33); + return buf; + }; + + recoverPublicKeyFromBuffer(buffer) { + return this.recoverPublicKey(sha256(buffer)); + }; + + /** + @return {PublicKey} + */ + recoverPublicKey(sha256_buffer) { + let Q, e, i; + e = BigInteger.fromBuffer(sha256_buffer); + i = this.i; + i -= 27; + i = i & 3; + Q = recoverPubKey(secp256k1, e, this, i); + return PublicKey.fromPoint(Q); + }; + + + /** + @param {Buffer} buf + @param {PrivateKey} private_key + @return {Signature} + */ + static signBuffer(buf, private_key) { + var _hash = sha256(buf); + return Signature.signBufferSha256(_hash, private_key) + } + + /** Sign a buffer of exactally 32 bytes in size (sha256(text)) + @param {Buffer} buf - 32 bytes binary + @param {PrivateKey} private_key + @return {Signature} + */ + static signBufferSha256(buf_sha256, private_key) { + if( buf_sha256.length !== 32 || ! Buffer.isBuffer(buf_sha256) ) + throw new Error("buf_sha256: 32 byte buffer requred") + var der, e, ecsignature, i, lenR, lenS, nonce; + i = null; + nonce = 0; + e = BigInteger.fromBuffer(buf_sha256); + while (true) { + ecsignature = sign(secp256k1, buf_sha256, private_key.d, nonce++); + der = ecsignature.toDER(); + lenR = der[3]; + lenS = der[5 + lenR]; + if (lenR === 32 && lenS === 32) { + i = calcPubKeyRecoveryParam(secp256k1, e, ecsignature, private_key.toPublicKey().Q); + i += 4; // compressed + i += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate) + break; + } + if (nonce % 10 === 0) { + console.log("WARN: " + nonce + " attempts to find canonical signature"); + } + } + return new Signature(ecsignature.r, ecsignature.s, i); + }; + + static sign(string, private_key) { + return Signature.signBuffer(new Buffer(string), private_key); + }; + + + /** + @param {Buffer} un-hashed + @param {./PublicKey} + @return {boolean} + */ + verifyBuffer(buf, public_key) { + var _hash = sha256(buf); + return this.verifyHash(_hash, public_key); + }; + + verifyHash(hash, public_key) { + assert.equal(hash.length, 32, "A SHA 256 should be 32 bytes long, instead got " + hash.length); + return verify(secp256k1, hash, { + r: this.r, + s: this.s + }, public_key.Q); + }; + + + /* */ + + toByteBuffer() { + var b; + b = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN); + this.appendByteBuffer(b); + return b.copy(0, b.offset); + }; + + static fromHex(hex) { + return Signature.fromBuffer(new Buffer(hex, "hex")); + }; + + toHex() { + return this.toBuffer().toString("hex"); + }; + + static signHex(hex, private_key) { + var buf; + buf = new Buffer(hex, 'hex'); + return Signature.signBuffer(buf, private_key); + }; + + verifyHex(hex, public_key) { + var buf; + buf = new Buffer(hex, 'hex'); + return this.verifyBuffer(buf, public_key); + }; + +} + +// export default Signature; +module.exports = Signature; \ No newline at end of file diff --git a/src/plugins/vuetify.js b/src/plugins/vuetify.js index d1adb68..12bc370 100644 --- a/src/plugins/vuetify.js +++ b/src/plugins/vuetify.js @@ -14,6 +14,9 @@ export default new Vuetify({ secondary: colors.red.darken2, // #FFCDD2 accent: colors.red.lighten1, // #3F51B5 }, + dark:{ + primary: "#c62c43", // #c62c43 + } }, }, icons: {