From 2c641c027a73ffc71a4f3a617efa2f43351e412d Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Wed, 13 Oct 2021 17:50:08 +0100 Subject: [PATCH 01/11] feat: use noble-secp256k1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/paulmillr/noble-secp256k1#noble-secp256k1-- → 71.2KB (▼-44.8KB / 116KB) --- package.json | 1 + src/keys/secp256k1-class.js | 7 ++++--- src/keys/secp256k1.js | 39 ++++++++++++++----------------------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 5d6b8607..ce4f63fe 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "iso-random-stream": "^2.0.0", "keypair": "^1.0.1", "multiformats": "^9.4.5", + "noble-secp256k1": "^1.2.10", "node-forge": "^0.10.0", "pem-jwk": "^2.0.0", "protobufjs": "^6.11.2", diff --git a/src/keys/secp256k1-class.js b/src/keys/secp256k1-class.js index 4112f74f..b8d377cf 100644 --- a/src/keys/secp256k1-class.js +++ b/src/keys/secp256k1-class.js @@ -11,9 +11,10 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { crypto = crypto || require('./secp256k1')(randomBytes) class Secp256k1PublicKey { - constructor (key) { + constructor (key, pkey) { crypto.validatePublicKey(key) this._key = key + this._pkey = pkey } verify (data, sig) { @@ -21,7 +22,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } marshal () { - return crypto.compressPublicKey(this._key) + return crypto.compressPublicKey(this._key, this._pkey) } get bytes () { @@ -55,7 +56,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } get public () { - return new Secp256k1PublicKey(this._publicKey) + return new Secp256k1PublicKey(this._publicKey, this._key) } marshal () { diff --git a/src/keys/secp256k1.js b/src/keys/secp256k1.js index 9ca046d4..eb7a7b65 100644 --- a/src/keys/secp256k1.js +++ b/src/keys/secp256k1.js @@ -1,57 +1,48 @@ 'use strict' -const secp256k1 = require('secp256k1') +const secp = require('noble-secp256k1') +// const secp256k1 = require('secp256k1') const { sha256 } = require('multiformats/hashes/sha2') module.exports = (randomBytes) => { const privateKeyLength = 32 function generateKey () { - let privateKey - do { - privateKey = randomBytes(32) - } while (!secp256k1.privateKeyVerify(privateKey)) - return privateKey + return secp.utils.randomPrivateKey() } async function hashAndSign (key, msg) { const { digest } = await sha256.digest(msg) - const sig = secp256k1.ecdsaSign(digest, key) - return secp256k1.signatureExport(sig.signature) + + return await secp.sign(digest, key) } async function hashAndVerify (key, sig, msg) { const { digest } = await sha256.digest(msg) - sig = secp256k1.signatureImport(sig) - return secp256k1.ecdsaVerify(sig, digest, key) + + return secp.verify(sig, digest, key) } - function compressPublicKey (key) { - if (!secp256k1.publicKeyVerify(key)) { - throw new Error('Invalid public key') - } - return secp256k1.publicKeyConvert(key, true) + function compressPublicKey (key, pkey) { + const point = secp.Point.fromHex(key).toRawBytes(true) + return point } function decompressPublicKey (key) { - return secp256k1.publicKeyConvert(key, false) + const point = secp.Point.fromHex(key).toRawBytes(false) + return point } function validatePrivateKey (key) { - if (!secp256k1.privateKeyVerify(key)) { - throw new Error('Invalid private key') - } + secp.getPublicKey(key, true) } function validatePublicKey (key) { - if (!secp256k1.publicKeyVerify(key)) { - throw new Error('Invalid public key') - } + secp.Point.fromHex(key) } function computePublicKey (privateKey) { - validatePrivateKey(privateKey) - return secp256k1.publicKeyCreate(privateKey) + return secp.getPublicKey(privateKey, true) } return { From 1d1dd68799558067efc89a817523c0ecc0073ca0 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 11:20:18 +0100 Subject: [PATCH 02/11] fix: error codes --- package.json | 5 ++-- src/keys/secp256k1-class.js | 9 +++---- src/keys/secp256k1.js | 51 +++++++++++++++++++++++++++++-------- test/keys/secp256k1.spec.js | 12 +++++---- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index ce4f63fe..ef4ff610 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "release-minor": "aegir release --type minor", "release-major": "aegir release --type major", "coverage": "aegir coverage --ignore src/keys/keys.proto.js", - "size": "aegir build --bundlesize", + "size": "aegir build --bundlesize --no-types", "test:types": "npx tsc" }, "keywords": [ @@ -47,7 +47,6 @@ "node-forge": "^0.10.0", "pem-jwk": "^2.0.0", "protobufjs": "^6.11.2", - "secp256k1": "^4.0.0", "uint8arrays": "^3.0.0", "ursa-optional": "^0.10.1" }, @@ -60,7 +59,7 @@ }, "aegir": { "build": { - "bundlesizeMax": "116kB" + "bundlesizeMax": "72kB" } }, "engines": { diff --git a/src/keys/secp256k1-class.js b/src/keys/secp256k1-class.js index b8d377cf..9d5239f1 100644 --- a/src/keys/secp256k1-class.js +++ b/src/keys/secp256k1-class.js @@ -8,13 +8,12 @@ const { toString: uint8ArrayToString } = require('uint8arrays/to-string') const exporter = require('./exporter') module.exports = (keysProtobuf, randomBytes, crypto) => { - crypto = crypto || require('./secp256k1')(randomBytes) + crypto = crypto || require('./secp256k1')() class Secp256k1PublicKey { - constructor (key, pkey) { + constructor (key) { crypto.validatePublicKey(key) this._key = key - this._pkey = pkey } verify (data, sig) { @@ -22,7 +21,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } marshal () { - return crypto.compressPublicKey(this._key, this._pkey) + return crypto.compressPublicKey(this._key) } get bytes () { @@ -56,7 +55,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } get public () { - return new Secp256k1PublicKey(this._publicKey, this._key) + return new Secp256k1PublicKey(this._publicKey) } marshal () { diff --git a/src/keys/secp256k1.js b/src/keys/secp256k1.js index eb7a7b65..4874b8ad 100644 --- a/src/keys/secp256k1.js +++ b/src/keys/secp256k1.js @@ -1,29 +1,48 @@ 'use strict' +const errcode = require('err-code') const secp = require('noble-secp256k1') -// const secp256k1 = require('secp256k1') const { sha256 } = require('multiformats/hashes/sha2') -module.exports = (randomBytes) => { +module.exports = () => { const privateKeyLength = 32 function generateKey () { return secp.utils.randomPrivateKey() } + /** + * Hash and sign message with private key + * + * @param {number | bigint | (string | Uint8Array)} key + * @param {Uint8Array} msg + */ async function hashAndSign (key, msg) { const { digest } = await sha256.digest(msg) - - return await secp.sign(digest, key) + try { + return await secp.sign(digest, key) + } catch (err) { + throw errcode(err, 'ERR_INVALID_INPUT') + } } + /** + * Hash message and verify signature with public key + * + * @param {secp.Point | (string | Uint8Array)} key + * @param {(string | Uint8Array) | secp.Signature} sig + * @param {Uint8Array} msg + */ async function hashAndVerify (key, sig, msg) { const { digest } = await sha256.digest(msg) - - return secp.verify(sig, digest, key) + try { + return secp.verify(sig, digest, key) + } catch (err) { + throw errcode(err, 'ERR_INVALID_INPUT') + } } - function compressPublicKey (key, pkey) { + function compressPublicKey (key) { const point = secp.Point.fromHex(key).toRawBytes(true) return point } @@ -34,15 +53,27 @@ module.exports = (randomBytes) => { } function validatePrivateKey (key) { - secp.getPublicKey(key, true) + try { + secp.getPublicKey(key, true) + } catch (err) { + throw errcode(err, 'ERR_INVALID_PRIVATE_KEY') + } } function validatePublicKey (key) { - secp.Point.fromHex(key) + try { + secp.Point.fromHex(key) + } catch (err) { + throw errcode(err, 'ERR_INVALID_PUBLIC_KEY') + } } function computePublicKey (privateKey) { - return secp.getPublicKey(privateKey, true) + try { + return secp.getPublicKey(privateKey, true) + } catch (err) { + throw errcode(err, 'ERR_INVALID_PRIVATE_KEY') + } } return { diff --git a/test/keys/secp256k1.spec.js b/test/keys/secp256k1.spec.js index 55d6883f..8c24bad2 100644 --- a/test/keys/secp256k1.spec.js +++ b/test/keys/secp256k1.spec.js @@ -6,7 +6,7 @@ const crypto = require('../../src') const secp256k1 = crypto.keys.supportedKeys.secp256k1 const keysPBM = crypto.keys.keysPBM const randomBytes = crypto.randomBytes -const secp256k1Crypto = require('../../src/keys/secp256k1')(randomBytes) +const secp256k1Crypto = require('../../src/keys/secp256k1')() const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string') const fixtures = require('../fixtures/go-key-secp256k1') @@ -155,7 +155,7 @@ describe('handles generation of invalid key', () => { try { await secp256k1.generateKeyPair() } catch (err) { - return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') + return expect(err.code).to.equal('ERR_INVALID_PRIVATE_KEY') } throw new Error('Expected error to be thrown') }) @@ -190,6 +190,7 @@ describe('crypto functions', () => { it('errors if given a null Uint8Array to sign', async () => { try { + // @ts-ignore await secp256k1Crypto.hashAndSign(privKey, null) } catch (err) { return // expected @@ -201,7 +202,7 @@ describe('crypto functions', () => { try { await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello')) } catch (err) { - return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') + return expect(err.code).to.equal('ERR_INVALID_INPUT') } throw new Error('Expected error to be thrown') }) @@ -210,6 +211,7 @@ describe('crypto functions', () => { const sig = await secp256k1Crypto.hashAndSign(privKey, uint8ArrayFromString('hello')) try { + // @ts-ignore await secp256k1Crypto.hashAndVerify(privKey, sig, null) } catch (err) { return // expected @@ -221,7 +223,7 @@ describe('crypto functions', () => { try { await secp256k1Crypto.hashAndVerify(pubKey, uint8ArrayFromString('invalid-sig'), uint8ArrayFromString('hello')) } catch (err) { - return expect(err.message).to.equal('Signature could not be parsed') + return expect(err.code).to.equal('ERR_INVALID_INPUT') } throw new Error('Expected error to be thrown') }) @@ -230,7 +232,7 @@ describe('crypto functions', () => { try { await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello')) } catch (err) { - return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') + return expect(err.code).to.equal('ERR_INVALID_INPUT') } throw new Error('Expected error to be thrown') }) From 790536fc2e7f5bbdead1698de93659f0ef83a59c Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 12:34:38 +0100 Subject: [PATCH 03/11] fix: linter --- src/keys/secp256k1.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/keys/secp256k1.js b/src/keys/secp256k1.js index 4874b8ad..069e259f 100644 --- a/src/keys/secp256k1.js +++ b/src/keys/secp256k1.js @@ -12,8 +12,8 @@ module.exports = () => { } /** - * Hash and sign message with private key - * + * Hash and sign message with private key + * * @param {number | bigint | (string | Uint8Array)} key * @param {Uint8Array} msg */ @@ -28,7 +28,7 @@ module.exports = () => { /** * Hash message and verify signature with public key - * + * * @param {secp.Point | (string | Uint8Array)} key * @param {(string | Uint8Array) | secp.Signature} sig * @param {Uint8Array} msg @@ -38,7 +38,7 @@ module.exports = () => { try { return secp.verify(sig, digest, key) } catch (err) { - throw errcode(err, 'ERR_INVALID_INPUT') + throw errcode(err, 'ERR_INVALID_INPUT') } } From 9e26a6add5d0349bd78628854b7c7b99011d348d Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 16:16:56 +0100 Subject: [PATCH 04/11] fix: use noble-ed25519 --- package.json | 1 + src/keys/ed25519.js | 29 ++++++++++++++++++++--------- src/keys/rsa-class.js | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ef4ff610..f11f249f 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "iso-random-stream": "^2.0.0", "keypair": "^1.0.1", "multiformats": "^9.4.5", + "noble-ed25519": "^1.2.6", "noble-secp256k1": "^1.2.10", "node-forge": "^0.10.0", "pem-jwk": "^2.0.0", diff --git a/src/keys/ed25519.js b/src/keys/ed25519.js index 75b6671c..8a788447 100644 --- a/src/keys/ed25519.js +++ b/src/keys/ed25519.js @@ -1,12 +1,19 @@ 'use strict' -require('node-forge/lib/ed25519') -const forge = require('node-forge/lib/forge') -exports.publicKeyLength = forge.pki.ed25519.constants.PUBLIC_KEY_BYTE_LENGTH -exports.privateKeyLength = forge.pki.ed25519.constants.PRIVATE_KEY_BYTE_LENGTH +// require('node-forge/lib/ed25519') +// const forge = require('node-forge/lib/forge') +const ed = require('noble-ed25519') -exports.generateKey = async function () { // eslint-disable-line require-await - return forge.pki.ed25519.generateKeyPair() +exports.publicKeyLength = 32 //forge.pki.ed25519.constants.PUBLIC_KEY_BYTE_LENGTH +exports.privateKeyLength = 64 // forge.pki.ed25519.constants.PRIVATE_KEY_BYTE_LENGTH + +exports.generateKey = async function () { + // const pair= forge.pki.ed25519.generateKeyPair() + const privateKey = ed.utils.randomPrivateKey() + return { + privateKey, + publicKey: await ed.getPublicKey(privateKey) + } } // seed should be a 32 byte uint8array @@ -14,11 +21,15 @@ exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line req return forge.pki.ed25519.generateKeyPair({ seed }) } -exports.hashAndSign = async function (key, msg) { // eslint-disable-line require-await - return forge.pki.ed25519.sign({ message: msg, privateKey: key }) +exports.hashAndSign = function (key, msg) { // eslint-disable-line require-await + // return forge.pki.ed25519.sign({ message: msg, privateKey: key }) // return Uint8Array.from(nacl.sign.detached(msg, key)) + + return ed.sign(msg, key) } exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await - return forge.pki.ed25519.verify({ signature: sig, message: msg, publicKey: key }) + // return forge.pki.ed25519.verify({ signature: sig, message: msg, publicKey: key }) + + return ed.verify(sig, msg, key) } diff --git a/src/keys/rsa-class.js b/src/keys/rsa-class.js index 67b39ff6..6e028df4 100644 --- a/src/keys/rsa-class.js +++ b/src/keys/rsa-class.js @@ -6,7 +6,7 @@ const { equals: uint8ArrayEquals } = require('uint8arrays/equals') const { toString: uint8ArrayToString } = require('uint8arrays/to-string') require('node-forge/lib/sha512') -require('node-forge/lib/ed25519') +// require('node-forge/lib/ed25519') const forge = require('node-forge/lib/forge') const crypto = require('./rsa') From bded28cd4252e33f0126721c60cb45ebdaa24132 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 14 Oct 2021 18:35:35 +0200 Subject: [PATCH 05/11] fix ed25519 integration --- src/keys/ed25519.js | 54 ++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/keys/ed25519.js b/src/keys/ed25519.js index 8a788447..234ed386 100644 --- a/src/keys/ed25519.js +++ b/src/keys/ed25519.js @@ -1,35 +1,59 @@ 'use strict' -// require('node-forge/lib/ed25519') -// const forge = require('node-forge/lib/forge') const ed = require('noble-ed25519') -exports.publicKeyLength = 32 //forge.pki.ed25519.constants.PUBLIC_KEY_BYTE_LENGTH -exports.privateKeyLength = 64 // forge.pki.ed25519.constants.PRIVATE_KEY_BYTE_LENGTH +exports.publicKeyLength = 32 +exports.privateKeyLength = 64 // private key is 32 bytes actual private key and 32 bytes public key, for historical reasons exports.generateKey = async function () { - // const pair= forge.pki.ed25519.generateKeyPair() - const privateKey = ed.utils.randomPrivateKey() + // the actual private key (32 bytes) + const privateKeyRaw = ed.utils.randomPrivateKey() + const publicKey = await ed.getPublicKey(privateKeyRaw) + + // concatenated the public key to the private key + const privateKey = concatKeys(privateKeyRaw, publicKey) + return { privateKey, - publicKey: await ed.getPublicKey(privateKey) + publicKey } } // seed should be a 32 byte uint8array exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await - return forge.pki.ed25519.generateKeyPair({ seed }) + if (seed.length !== 32) { + throw new TypeError('"seed" must be 32 bytes in length.') + } else if (!(seed instanceof Uint8Array)) { + throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.') + } + + // based on node.forges algorithm, the seed is used directly as private key + const privateKeyRaw = seed; + const publicKey = await ed.getPublicKey(privateKeyRaw) + + const privateKey = concatKeys(privateKeyRaw, publicKey) + + return { + privateKey, + publicKey + } } -exports.hashAndSign = function (key, msg) { // eslint-disable-line require-await - // return forge.pki.ed25519.sign({ message: msg, privateKey: key }) - // return Uint8Array.from(nacl.sign.detached(msg, key)) +exports.hashAndSign = function (privateKey, msg) { // eslint-disable-line require-await + const privateKeyRaw = privateKey.slice(0, 32) - return ed.sign(msg, key) + return ed.sign(msg, privateKeyRaw) } -exports.hashAndVerify = async function (key, sig, msg) { // eslint-disable-line require-await - // return forge.pki.ed25519.verify({ signature: sig, message: msg, publicKey: key }) +exports.hashAndVerify = async function (publicKey, sig, msg) { // eslint-disable-line require-await + return ed.verify(sig, msg, publicKey) +} - return ed.verify(sig, msg, key) +function concatKeys(privateKeyRaw, publicKey) { + const privateKey = new Uint8Array(exports.privateKeyLength) + for (let i = 0; i < 32; i++) { + privateKey[i] = privateKeyRaw[i] + privateKey[32 + i] = publicKey[i] + } + return privateKey } From 455ce4f2b5eb485a5c7c490adfad62e484813487 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 18:11:35 +0100 Subject: [PATCH 06/11] fix: just use globalThis.crypto --- src/webcrypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webcrypto.js b/src/webcrypto.js index 1663369a..db73c508 100644 --- a/src/webcrypto.js +++ b/src/webcrypto.js @@ -5,7 +5,7 @@ // Check native crypto exists and is enabled (In insecure context `self.crypto` // exists but `self.crypto.subtle` does not). exports.get = (win = self) => { - const nativeCrypto = win.crypto || win.msCrypto + const nativeCrypto = globalThis.crypto if (!nativeCrypto || !nativeCrypto.subtle) { throw Object.assign( From 19f6f54c0db202d129c90d57d537f6fd4883538f Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 18:14:13 +0100 Subject: [PATCH 07/11] fix: web crypto error --- src/webcrypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webcrypto.js b/src/webcrypto.js index db73c508..f08d34e2 100644 --- a/src/webcrypto.js +++ b/src/webcrypto.js @@ -4,8 +4,8 @@ // Check native crypto exists and is enabled (In insecure context `self.crypto` // exists but `self.crypto.subtle` does not). -exports.get = (win = self) => { - const nativeCrypto = globalThis.crypto +exports.get = (win = globalThis) => { + const nativeCrypto = win.crypto if (!nativeCrypto || !nativeCrypto.subtle) { throw Object.assign( From 5cd1b6f85be920b69b7508f59c8db5503db9d6bc Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 18:16:12 +0100 Subject: [PATCH 08/11] fix: linter --- src/keys/ed25519.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/keys/ed25519.js b/src/keys/ed25519.js index 234ed386..b75f482a 100644 --- a/src/keys/ed25519.js +++ b/src/keys/ed25519.js @@ -2,7 +2,7 @@ const ed = require('noble-ed25519') -exports.publicKeyLength = 32 +exports.publicKeyLength = 32 exports.privateKeyLength = 64 // private key is 32 bytes actual private key and 32 bytes public key, for historical reasons exports.generateKey = async function () { @@ -28,9 +28,9 @@ exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line req } // based on node.forges algorithm, the seed is used directly as private key - const privateKeyRaw = seed; + const privateKeyRaw = seed const publicKey = await ed.getPublicKey(privateKeyRaw) - + const privateKey = concatKeys(privateKeyRaw, publicKey) return { @@ -49,7 +49,7 @@ exports.hashAndVerify = async function (publicKey, sig, msg) { // eslint-disable return ed.verify(sig, msg, publicKey) } -function concatKeys(privateKeyRaw, publicKey) { +function concatKeys (privateKeyRaw, publicKey) { const privateKey = new Uint8Array(exports.privateKeyLength) for (let i = 0; i < 32; i++) { privateKey[i] = privateKeyRaw[i] From 2770645a9fbfe4d77cc68d3de0b8a73d9f85ebb6 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 14 Oct 2021 18:16:53 +0100 Subject: [PATCH 09/11] fix: reduce size limit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f11f249f..cf293191 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ }, "aegir": { "build": { - "bundlesizeMax": "72kB" + "bundlesizeMax": "71kB" } }, "engines": { From 43e775fe4d82cc8144c3454037c9a9e0700dc584 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Tue, 19 Oct 2021 16:53:01 +0100 Subject: [PATCH 10/11] fix: fix tests and errors for hashAndVerify --- src/keys/secp256k1.js | 2 +- test/keys/secp256k1.spec.js | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/keys/secp256k1.js b/src/keys/secp256k1.js index 069e259f..e111070b 100644 --- a/src/keys/secp256k1.js +++ b/src/keys/secp256k1.js @@ -34,8 +34,8 @@ module.exports = () => { * @param {Uint8Array} msg */ async function hashAndVerify (key, sig, msg) { - const { digest } = await sha256.digest(msg) try { + const { digest } = await sha256.digest(msg) return secp.verify(sig, digest, key) } catch (err) { throw errcode(err, 'ERR_INVALID_INPUT') diff --git a/test/keys/secp256k1.spec.js b/test/keys/secp256k1.spec.js index 8c24bad2..4ae10f39 100644 --- a/test/keys/secp256k1.spec.js +++ b/test/keys/secp256k1.spec.js @@ -188,6 +188,12 @@ describe('crypto functions', () => { expect(valid).to.equal(true) }) + it('does not validate when validating a message with an invalid signature', async () => { + const result = await secp256k1Crypto.hashAndVerify(pubKey, uint8ArrayFromString('invalid-sig'), uint8ArrayFromString('hello')) + + expect(result).to.be.false() + }) + it('errors if given a null Uint8Array to sign', async () => { try { // @ts-ignore @@ -219,15 +225,6 @@ describe('crypto functions', () => { throw new Error('Expected error to be thrown') }) - it('errors when validating a message with an invalid signature', async () => { - try { - await secp256k1Crypto.hashAndVerify(pubKey, uint8ArrayFromString('invalid-sig'), uint8ArrayFromString('hello')) - } catch (err) { - return expect(err.code).to.equal('ERR_INVALID_INPUT') - } - throw new Error('Expected error to be thrown') - }) - it('errors when signing with an invalid key', async () => { try { await secp256k1Crypto.hashAndSign(uint8ArrayFromString('42'), uint8ArrayFromString('Hello')) From 562d5e10c73c7fa1d8f99de6439e151cb6d0b30e Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Thu, 21 Oct 2021 10:24:18 +0000 Subject: [PATCH 11/11] fix: feedback --- src/keys/ed25519.js | 31 ++++++++++++++++++++----------- src/keys/rsa-class.js | 1 - 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/keys/ed25519.js b/src/keys/ed25519.js index b75f482a..f0c5446c 100644 --- a/src/keys/ed25519.js +++ b/src/keys/ed25519.js @@ -2,8 +2,12 @@ const ed = require('noble-ed25519') -exports.publicKeyLength = 32 -exports.privateKeyLength = 64 // private key is 32 bytes actual private key and 32 bytes public key, for historical reasons +const PUBLIC_KEY_BYTE_LENGTH = 32 +const PRIVATE_KEY_BYTE_LENGTH = 64 // private key is actually 32 bytes but for historical reasons we concat private and public keys +const KEYS_BYTE_LENGTH = 32 + +exports.publicKeyLength = PUBLIC_KEY_BYTE_LENGTH +exports.privateKeyLength = PRIVATE_KEY_BYTE_LENGTH exports.generateKey = async function () { // the actual private key (32 bytes) @@ -19,15 +23,20 @@ exports.generateKey = async function () { } } -// seed should be a 32 byte uint8array -exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line require-await - if (seed.length !== 32) { +/** + * Generate keypair from a seed + * + * @param {Uint8Array} seed - seed should be a 32 byte uint8array + * @returns + */ +exports.generateKeyFromSeed = async function (seed) { + if (seed.length !== KEYS_BYTE_LENGTH) { throw new TypeError('"seed" must be 32 bytes in length.') } else if (!(seed instanceof Uint8Array)) { throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.') } - // based on node.forges algorithm, the seed is used directly as private key + // based on node forges algorithm, the seed is used directly as private key const privateKeyRaw = seed const publicKey = await ed.getPublicKey(privateKeyRaw) @@ -39,21 +48,21 @@ exports.generateKeyFromSeed = async function (seed) { // eslint-disable-line req } } -exports.hashAndSign = function (privateKey, msg) { // eslint-disable-line require-await - const privateKeyRaw = privateKey.slice(0, 32) +exports.hashAndSign = function (privateKey, msg) { + const privateKeyRaw = privateKey.slice(0, KEYS_BYTE_LENGTH) return ed.sign(msg, privateKeyRaw) } -exports.hashAndVerify = async function (publicKey, sig, msg) { // eslint-disable-line require-await +exports.hashAndVerify = function (publicKey, sig, msg) { return ed.verify(sig, msg, publicKey) } function concatKeys (privateKeyRaw, publicKey) { const privateKey = new Uint8Array(exports.privateKeyLength) - for (let i = 0; i < 32; i++) { + for (let i = 0; i < KEYS_BYTE_LENGTH; i++) { privateKey[i] = privateKeyRaw[i] - privateKey[32 + i] = publicKey[i] + privateKey[KEYS_BYTE_LENGTH + i] = publicKey[i] } return privateKey } diff --git a/src/keys/rsa-class.js b/src/keys/rsa-class.js index 6e028df4..597a3b57 100644 --- a/src/keys/rsa-class.js +++ b/src/keys/rsa-class.js @@ -6,7 +6,6 @@ const { equals: uint8ArrayEquals } = require('uint8arrays/equals') const { toString: uint8ArrayToString } = require('uint8arrays/to-string') require('node-forge/lib/sha512') -// require('node-forge/lib/ed25519') const forge = require('node-forge/lib/forge') const crypto = require('./rsa')