@toruslabs/eccrypto
Advanced tools
+47
-52
@@ -51,18 +51,16 @@ /******/ (() => { // webpackBootstrap | ||
| sign: () => (/* binding */ sign), | ||
| uint8ArrayToBigInt: () => (/* binding */ uint8ArrayToBigInt), | ||
| verify: () => (/* binding */ verify) | ||
| }); | ||
| ;// external "@noble/curves/abstract/utils" | ||
| const utils_namespaceObject = require("@noble/curves/abstract/utils"); | ||
| ;// external "@noble/curves/secp256k1" | ||
| const secp256k1_namespaceObject = require("@noble/curves/secp256k1"); | ||
| ;// external "elliptic" | ||
| const external_elliptic_namespaceObject = require("elliptic"); | ||
| ;// ./src/index.ts | ||
| const ec = new external_elliptic_namespaceObject.ec("secp256k1"); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| const browserCrypto = globalThis.crypto || globalThis.msCrypto || {}; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; | ||
| const EC_GROUP_ORDER = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); | ||
| const EC_GROUP_ORDER = Buffer.from("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "hex"); | ||
| const ZERO32 = Buffer.alloc(32, 0); | ||
| function assert(condition, message) { | ||
@@ -73,14 +71,12 @@ if (!condition) { | ||
| } | ||
| function uint8ArrayToBigInt(arr) { | ||
| let result = 0n; | ||
| for (let i = 0; i < arr.length; i++) { | ||
| result = result << 8n | BigInt(arr[i]); | ||
| } | ||
| return result; | ||
| function isScalar(x) { | ||
| return Buffer.isBuffer(x) && x.length === 32; | ||
| } | ||
| function isValidPrivateKey(privateKey) { | ||
| const privateKeyBigInt = uint8ArrayToBigInt(privateKey); | ||
| return privateKeyBigInt > 0n && | ||
| if (!isScalar(privateKey)) { | ||
| return false; | ||
| } | ||
| return privateKey.compare(ZERO32) > 0 && | ||
| // > 0 | ||
| privateKeyBigInt < EC_GROUP_ORDER; // < G | ||
| privateKey.compare(EC_GROUP_ORDER) < 0; // < G | ||
| } | ||
@@ -105,7 +101,7 @@ | ||
| if (typeof browserCrypto.getRandomValues === "undefined") { | ||
| return browserCrypto.randomBytes(size); | ||
| return Buffer.from(browserCrypto.randomBytes(size)); | ||
| } | ||
| const arr = new Uint8Array(size); | ||
| browserCrypto.getRandomValues(arr); | ||
| return arr; | ||
| return Buffer.from(arr); | ||
| } | ||
@@ -135,3 +131,3 @@ async function sha512(msg) { | ||
| const result = await subtle[op](encAlgorithm, cryptoKey, data); | ||
| return new Uint8Array(result); | ||
| return Buffer.from(new Uint8Array(result)); | ||
| } else if (op === "encrypt" && browserCrypto.createCipheriv) { | ||
@@ -142,3 +138,3 @@ // This is available if crypto is polyfilled in react native environment | ||
| const secondChunk = cipher.final(); | ||
| return (0,utils_namespaceObject.concatBytes)(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } else if (op === "decrypt" && browserCrypto.createDecipheriv) { | ||
@@ -148,3 +144,3 @@ const decipher = browserCrypto.createDecipheriv("aes-256-cbc", key, iv); | ||
| const secondChunk = decipher.final(); | ||
| return (0,utils_namespaceObject.concatBytes)(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } | ||
@@ -166,6 +162,6 @@ throw new Error(`Unsupported operation: ${op}`); | ||
| const sig = await subtle.sign("HMAC", cryptoKey, msg); | ||
| const result = new Uint8Array(sig); | ||
| const result = Buffer.from(new Uint8Array(sig)); | ||
| return result; | ||
| } | ||
| const hmac = browserCrypto.createHmac("sha256", key); | ||
| const hmac = browserCrypto.createHmac("sha256", Buffer.from(key)); | ||
| hmac.update(msg); | ||
@@ -197,3 +193,3 @@ const result = hmac.digest(); | ||
| // encoding except `hex`. | ||
| return secp256k1_namespaceObject.secp256k1.getPublicKey(privateKey, false); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("array")); | ||
| }; | ||
@@ -210,3 +206,3 @@ | ||
| const compressed = true; | ||
| return secp256k1_namespaceObject.secp256k1.getPublicKey(privateKey, compressed); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "array")); | ||
| }; | ||
@@ -224,3 +220,5 @@ | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| return secp256k1_namespaceObject.secp256k1.sign(msg, privateKey).toDERRawBytes(); | ||
| return Buffer.from(ec.sign(msg, privateKey, { | ||
| canonical: true | ||
| }).toDER()); | ||
| }; | ||
@@ -237,8 +235,10 @@ const verify = async function (publicKey, msg, sig) { | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| if (secp256k1_namespaceObject.secp256k1.verify(sig, msg, publicKey)) return null; | ||
| if (ec.verify(msg, sig, publicKey)) { | ||
| return null; | ||
| } | ||
| throw new Error("Bad signature"); | ||
| }; | ||
| const derive = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -253,18 +253,11 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| // unpad to match previous implementation | ||
| // elliptic return BN and we return Buffer(BN.toArray()) | ||
| // match by unpadding | ||
| const sharedSecret = secp256k1_namespaceObject.secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| const Px = sharedSecret.subarray(sharedSecret.length - 32); | ||
| let i = 0; | ||
| while (i < Px.length && Px[i] === 0) { | ||
| i++; | ||
| } | ||
| return Px.subarray(i); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toArray()); | ||
| }; | ||
| const deriveUnpadded = derive; | ||
| const derivePadded = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -279,4 +272,6 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| const Px = secp256k1_namespaceObject.secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| return Px.subarray(Px.length - 32); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toString(16, 64), "hex"); | ||
| }; | ||
@@ -296,6 +291,6 @@ const encrypt = async function (publicKeyTo, msg, opts) { | ||
| const macKey = hash.slice(32); | ||
| const data = await aesCbcEncrypt(iv, encryptionKey, msg); | ||
| const data = await aesCbcEncrypt(iv, Buffer.from(encryptionKey), msg); | ||
| const ciphertext = data; | ||
| const dataToMac = (0,utils_namespaceObject.concatBytes)(iv, ephemPublicKey, ciphertext); | ||
| const mac = await hmacSha256Sign(macKey, dataToMac); | ||
| const dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); | ||
| const mac = await hmacSha256Sign(Buffer.from(macKey), dataToMac); | ||
| return { | ||
@@ -315,4 +310,4 @@ iv, | ||
| const macKey = hash.slice(32); | ||
| const dataToMac = (0,utils_namespaceObject.concatBytes)(opts.iv, opts.ephemPublicKey, opts.ciphertext); | ||
| const macGood = await hmacSha256Verify(macKey, dataToMac, opts.mac); | ||
| const dataToMac = Buffer.concat([opts.iv, opts.ephemPublicKey, opts.ciphertext]); | ||
| const macGood = await hmacSha256Verify(Buffer.from(macKey), dataToMac, opts.mac); | ||
| if (!macGood && padding === false) { | ||
@@ -323,4 +318,4 @@ return decrypt(privateKey, opts, true); | ||
| } | ||
| const msg = await aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext); | ||
| return new Uint8Array(msg); | ||
| const msg = await aesCbcDecrypt(opts.iv, Buffer.from(encryptionKey), opts.ciphertext); | ||
| return Buffer.from(new Uint8Array(msg)); | ||
| }; | ||
@@ -327,0 +322,0 @@ module.exports = __webpack_exports__; |
+47
-49
@@ -1,9 +0,10 @@ | ||
| import { concatBytes } from '@noble/curves/abstract/utils'; | ||
| import { secp256k1 } from '@noble/curves/secp256k1'; | ||
| import { ec as ec$1 } from 'elliptic'; | ||
| const ec = new ec$1("secp256k1"); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| const browserCrypto = globalThis.crypto || globalThis.msCrypto || {}; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; | ||
| const EC_GROUP_ORDER = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); | ||
| const EC_GROUP_ORDER = Buffer.from("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "hex"); | ||
| const ZERO32 = Buffer.alloc(32, 0); | ||
| function assert(condition, message) { | ||
@@ -14,14 +15,12 @@ if (!condition) { | ||
| } | ||
| function uint8ArrayToBigInt(arr) { | ||
| let result = 0n; | ||
| for (let i = 0; i < arr.length; i++) { | ||
| result = result << 8n | BigInt(arr[i]); | ||
| } | ||
| return result; | ||
| function isScalar(x) { | ||
| return Buffer.isBuffer(x) && x.length === 32; | ||
| } | ||
| function isValidPrivateKey(privateKey) { | ||
| const privateKeyBigInt = uint8ArrayToBigInt(privateKey); | ||
| return privateKeyBigInt > 0n && | ||
| if (!isScalar(privateKey)) { | ||
| return false; | ||
| } | ||
| return privateKey.compare(ZERO32) > 0 && | ||
| // > 0 | ||
| privateKeyBigInt < EC_GROUP_ORDER; // < G | ||
| privateKey.compare(EC_GROUP_ORDER) < 0; // < G | ||
| } | ||
@@ -46,7 +45,7 @@ | ||
| if (typeof browserCrypto.getRandomValues === "undefined") { | ||
| return browserCrypto.randomBytes(size); | ||
| return Buffer.from(browserCrypto.randomBytes(size)); | ||
| } | ||
| const arr = new Uint8Array(size); | ||
| browserCrypto.getRandomValues(arr); | ||
| return arr; | ||
| return Buffer.from(arr); | ||
| } | ||
@@ -76,3 +75,3 @@ async function sha512(msg) { | ||
| const result = await subtle[op](encAlgorithm, cryptoKey, data); | ||
| return new Uint8Array(result); | ||
| return Buffer.from(new Uint8Array(result)); | ||
| } else if (op === "encrypt" && browserCrypto.createCipheriv) { | ||
@@ -83,3 +82,3 @@ // This is available if crypto is polyfilled in react native environment | ||
| const secondChunk = cipher.final(); | ||
| return concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } else if (op === "decrypt" && browserCrypto.createDecipheriv) { | ||
@@ -89,3 +88,3 @@ const decipher = browserCrypto.createDecipheriv("aes-256-cbc", key, iv); | ||
| const secondChunk = decipher.final(); | ||
| return concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } | ||
@@ -107,6 +106,6 @@ throw new Error(`Unsupported operation: ${op}`); | ||
| const sig = await subtle.sign("HMAC", cryptoKey, msg); | ||
| const result = new Uint8Array(sig); | ||
| const result = Buffer.from(new Uint8Array(sig)); | ||
| return result; | ||
| } | ||
| const hmac = browserCrypto.createHmac("sha256", key); | ||
| const hmac = browserCrypto.createHmac("sha256", Buffer.from(key)); | ||
| hmac.update(msg); | ||
@@ -138,3 +137,3 @@ const result = hmac.digest(); | ||
| // encoding except `hex`. | ||
| return secp256k1.getPublicKey(privateKey, false); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("array")); | ||
| }; | ||
@@ -151,3 +150,3 @@ | ||
| const compressed = true; | ||
| return secp256k1.getPublicKey(privateKey, compressed); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "array")); | ||
| }; | ||
@@ -165,3 +164,5 @@ | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| return secp256k1.sign(msg, privateKey).toDERRawBytes(); | ||
| return Buffer.from(ec.sign(msg, privateKey, { | ||
| canonical: true | ||
| }).toDER()); | ||
| }; | ||
@@ -178,8 +179,10 @@ const verify = async function (publicKey, msg, sig) { | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| if (secp256k1.verify(sig, msg, publicKey)) return null; | ||
| if (ec.verify(msg, sig, publicKey)) { | ||
| return null; | ||
| } | ||
| throw new Error("Bad signature"); | ||
| }; | ||
| const derive = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -194,18 +197,11 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| // unpad to match previous implementation | ||
| // elliptic return BN and we return Buffer(BN.toArray()) | ||
| // match by unpadding | ||
| const sharedSecret = secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| const Px = sharedSecret.subarray(sharedSecret.length - 32); | ||
| let i = 0; | ||
| while (i < Px.length && Px[i] === 0) { | ||
| i++; | ||
| } | ||
| return Px.subarray(i); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toArray()); | ||
| }; | ||
| const deriveUnpadded = derive; | ||
| const derivePadded = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -220,4 +216,6 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| const Px = secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| return Px.subarray(Px.length - 32); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toString(16, 64), "hex"); | ||
| }; | ||
@@ -237,6 +235,6 @@ const encrypt = async function (publicKeyTo, msg, opts) { | ||
| const macKey = hash.slice(32); | ||
| const data = await aesCbcEncrypt(iv, encryptionKey, msg); | ||
| const data = await aesCbcEncrypt(iv, Buffer.from(encryptionKey), msg); | ||
| const ciphertext = data; | ||
| const dataToMac = concatBytes(iv, ephemPublicKey, ciphertext); | ||
| const mac = await hmacSha256Sign(macKey, dataToMac); | ||
| const dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); | ||
| const mac = await hmacSha256Sign(Buffer.from(macKey), dataToMac); | ||
| return { | ||
@@ -256,4 +254,4 @@ iv, | ||
| const macKey = hash.slice(32); | ||
| const dataToMac = concatBytes(opts.iv, opts.ephemPublicKey, opts.ciphertext); | ||
| const macGood = await hmacSha256Verify(macKey, dataToMac, opts.mac); | ||
| const dataToMac = Buffer.concat([opts.iv, opts.ephemPublicKey, opts.ciphertext]); | ||
| const macGood = await hmacSha256Verify(Buffer.from(macKey), dataToMac, opts.mac); | ||
| if (!macGood && padding === false) { | ||
@@ -264,6 +262,6 @@ return decrypt(privateKey, opts, true); | ||
| } | ||
| const msg = await aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext); | ||
| return new Uint8Array(msg); | ||
| const msg = await aesCbcDecrypt(opts.iv, Buffer.from(encryptionKey), opts.ciphertext); | ||
| return Buffer.from(new Uint8Array(msg)); | ||
| }; | ||
| export { decrypt, derive, derivePadded, deriveUnpadded, encrypt, generatePrivate, getPublic, getPublicCompressed, sign, uint8ArrayToBigInt, verify }; | ||
| export { decrypt, derive, derivePadded, deriveUnpadded, encrypt, generatePrivate, getPublic, getPublicCompressed, sign, verify }; |
@@ -1,1 +0,8 @@ | ||
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | ||
| /*! | ||
| * The buffer module from node.js, for the browser. | ||
| * | ||
| * @author Feross Aboukhadijeh <https://feross.org> | ||
| * @license MIT | ||
| */ | ||
| /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ |
+46
-49
| 'use strict'; | ||
| var utils = require('@noble/curves/abstract/utils'); | ||
| var secp256k1 = require('@noble/curves/secp256k1'); | ||
| var elliptic = require('elliptic'); | ||
| const ec = new elliptic.ec("secp256k1"); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| const browserCrypto = globalThis.crypto || globalThis.msCrypto || {}; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; | ||
| const EC_GROUP_ORDER = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); | ||
| const EC_GROUP_ORDER = Buffer.from("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "hex"); | ||
| const ZERO32 = Buffer.alloc(32, 0); | ||
| function assert(condition, message) { | ||
@@ -16,14 +17,12 @@ if (!condition) { | ||
| } | ||
| function uint8ArrayToBigInt(arr) { | ||
| let result = 0n; | ||
| for (let i = 0; i < arr.length; i++) { | ||
| result = result << 8n | BigInt(arr[i]); | ||
| } | ||
| return result; | ||
| function isScalar(x) { | ||
| return Buffer.isBuffer(x) && x.length === 32; | ||
| } | ||
| function isValidPrivateKey(privateKey) { | ||
| const privateKeyBigInt = uint8ArrayToBigInt(privateKey); | ||
| return privateKeyBigInt > 0n && | ||
| if (!isScalar(privateKey)) { | ||
| return false; | ||
| } | ||
| return privateKey.compare(ZERO32) > 0 && | ||
| // > 0 | ||
| privateKeyBigInt < EC_GROUP_ORDER; // < G | ||
| privateKey.compare(EC_GROUP_ORDER) < 0; // < G | ||
| } | ||
@@ -48,7 +47,7 @@ | ||
| if (typeof browserCrypto.getRandomValues === "undefined") { | ||
| return browserCrypto.randomBytes(size); | ||
| return Buffer.from(browserCrypto.randomBytes(size)); | ||
| } | ||
| const arr = new Uint8Array(size); | ||
| browserCrypto.getRandomValues(arr); | ||
| return arr; | ||
| return Buffer.from(arr); | ||
| } | ||
@@ -78,3 +77,3 @@ async function sha512(msg) { | ||
| const result = await subtle[op](encAlgorithm, cryptoKey, data); | ||
| return new Uint8Array(result); | ||
| return Buffer.from(new Uint8Array(result)); | ||
| } else if (op === "encrypt" && browserCrypto.createCipheriv) { | ||
@@ -85,3 +84,3 @@ // This is available if crypto is polyfilled in react native environment | ||
| const secondChunk = cipher.final(); | ||
| return utils.concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } else if (op === "decrypt" && browserCrypto.createDecipheriv) { | ||
@@ -91,3 +90,3 @@ const decipher = browserCrypto.createDecipheriv("aes-256-cbc", key, iv); | ||
| const secondChunk = decipher.final(); | ||
| return utils.concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } | ||
@@ -109,6 +108,6 @@ throw new Error(`Unsupported operation: ${op}`); | ||
| const sig = await subtle.sign("HMAC", cryptoKey, msg); | ||
| const result = new Uint8Array(sig); | ||
| const result = Buffer.from(new Uint8Array(sig)); | ||
| return result; | ||
| } | ||
| const hmac = browserCrypto.createHmac("sha256", key); | ||
| const hmac = browserCrypto.createHmac("sha256", Buffer.from(key)); | ||
| hmac.update(msg); | ||
@@ -140,3 +139,3 @@ const result = hmac.digest(); | ||
| // encoding except `hex`. | ||
| return secp256k1.secp256k1.getPublicKey(privateKey, false); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("array")); | ||
| }; | ||
@@ -153,3 +152,3 @@ | ||
| const compressed = true; | ||
| return secp256k1.secp256k1.getPublicKey(privateKey, compressed); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "array")); | ||
| }; | ||
@@ -167,3 +166,5 @@ | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| return secp256k1.secp256k1.sign(msg, privateKey).toDERRawBytes(); | ||
| return Buffer.from(ec.sign(msg, privateKey, { | ||
| canonical: true | ||
| }).toDER()); | ||
| }; | ||
@@ -180,8 +181,10 @@ const verify = async function (publicKey, msg, sig) { | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| if (secp256k1.secp256k1.verify(sig, msg, publicKey)) return null; | ||
| if (ec.verify(msg, sig, publicKey)) { | ||
| return null; | ||
| } | ||
| throw new Error("Bad signature"); | ||
| }; | ||
| const derive = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -196,18 +199,11 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| // unpad to match previous implementation | ||
| // elliptic return BN and we return Buffer(BN.toArray()) | ||
| // match by unpadding | ||
| const sharedSecret = secp256k1.secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| const Px = sharedSecret.subarray(sharedSecret.length - 32); | ||
| let i = 0; | ||
| while (i < Px.length && Px[i] === 0) { | ||
| i++; | ||
| } | ||
| return Px.subarray(i); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toArray()); | ||
| }; | ||
| const deriveUnpadded = derive; | ||
| const derivePadded = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -222,4 +218,6 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| const Px = secp256k1.secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| return Px.subarray(Px.length - 32); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toString(16, 64), "hex"); | ||
| }; | ||
@@ -239,6 +237,6 @@ const encrypt = async function (publicKeyTo, msg, opts) { | ||
| const macKey = hash.slice(32); | ||
| const data = await aesCbcEncrypt(iv, encryptionKey, msg); | ||
| const data = await aesCbcEncrypt(iv, Buffer.from(encryptionKey), msg); | ||
| const ciphertext = data; | ||
| const dataToMac = utils.concatBytes(iv, ephemPublicKey, ciphertext); | ||
| const mac = await hmacSha256Sign(macKey, dataToMac); | ||
| const dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); | ||
| const mac = await hmacSha256Sign(Buffer.from(macKey), dataToMac); | ||
| return { | ||
@@ -258,4 +256,4 @@ iv, | ||
| const macKey = hash.slice(32); | ||
| const dataToMac = utils.concatBytes(opts.iv, opts.ephemPublicKey, opts.ciphertext); | ||
| const macGood = await hmacSha256Verify(macKey, dataToMac, opts.mac); | ||
| const dataToMac = Buffer.concat([opts.iv, opts.ephemPublicKey, opts.ciphertext]); | ||
| const macGood = await hmacSha256Verify(Buffer.from(macKey), dataToMac, opts.mac); | ||
| if (!macGood && padding === false) { | ||
@@ -266,4 +264,4 @@ return decrypt(privateKey, opts, true); | ||
| } | ||
| const msg = await aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext); | ||
| return new Uint8Array(msg); | ||
| const msg = await aesCbcDecrypt(opts.iv, Buffer.from(encryptionKey), opts.ciphertext); | ||
| return Buffer.from(new Uint8Array(msg)); | ||
| }; | ||
@@ -280,3 +278,2 @@ | ||
| exports.sign = sign; | ||
| exports.uint8ArrayToBigInt = uint8ArrayToBigInt; | ||
| exports.verify = verify; |
+47
-49
@@ -1,9 +0,10 @@ | ||
| import { concatBytes } from '@noble/curves/abstract/utils'; | ||
| import { secp256k1 } from '@noble/curves/secp256k1'; | ||
| import { ec as ec$1 } from 'elliptic'; | ||
| const ec = new ec$1("secp256k1"); | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| const browserCrypto = globalThis.crypto || globalThis.msCrypto || {}; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, n/no-unsupported-features/node-builtins | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const subtle = browserCrypto.subtle || browserCrypto.webkitSubtle; | ||
| const EC_GROUP_ORDER = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); | ||
| const EC_GROUP_ORDER = Buffer.from("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", "hex"); | ||
| const ZERO32 = Buffer.alloc(32, 0); | ||
| function assert(condition, message) { | ||
@@ -14,14 +15,12 @@ if (!condition) { | ||
| } | ||
| function uint8ArrayToBigInt(arr) { | ||
| let result = 0n; | ||
| for (let i = 0; i < arr.length; i++) { | ||
| result = result << 8n | BigInt(arr[i]); | ||
| } | ||
| return result; | ||
| function isScalar(x) { | ||
| return Buffer.isBuffer(x) && x.length === 32; | ||
| } | ||
| function isValidPrivateKey(privateKey) { | ||
| const privateKeyBigInt = uint8ArrayToBigInt(privateKey); | ||
| return privateKeyBigInt > 0n && | ||
| if (!isScalar(privateKey)) { | ||
| return false; | ||
| } | ||
| return privateKey.compare(ZERO32) > 0 && | ||
| // > 0 | ||
| privateKeyBigInt < EC_GROUP_ORDER; // < G | ||
| privateKey.compare(EC_GROUP_ORDER) < 0; // < G | ||
| } | ||
@@ -46,7 +45,7 @@ | ||
| if (typeof browserCrypto.getRandomValues === "undefined") { | ||
| return browserCrypto.randomBytes(size); | ||
| return Buffer.from(browserCrypto.randomBytes(size)); | ||
| } | ||
| const arr = new Uint8Array(size); | ||
| browserCrypto.getRandomValues(arr); | ||
| return arr; | ||
| return Buffer.from(arr); | ||
| } | ||
@@ -76,3 +75,3 @@ async function sha512(msg) { | ||
| const result = await subtle[op](encAlgorithm, cryptoKey, data); | ||
| return new Uint8Array(result); | ||
| return Buffer.from(new Uint8Array(result)); | ||
| } else if (op === "encrypt" && browserCrypto.createCipheriv) { | ||
@@ -83,3 +82,3 @@ // This is available if crypto is polyfilled in react native environment | ||
| const secondChunk = cipher.final(); | ||
| return concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } else if (op === "decrypt" && browserCrypto.createDecipheriv) { | ||
@@ -89,3 +88,3 @@ const decipher = browserCrypto.createDecipheriv("aes-256-cbc", key, iv); | ||
| const secondChunk = decipher.final(); | ||
| return concatBytes(firstChunk, secondChunk); | ||
| return Buffer.concat([firstChunk, secondChunk]); | ||
| } | ||
@@ -107,6 +106,6 @@ throw new Error(`Unsupported operation: ${op}`); | ||
| const sig = await subtle.sign("HMAC", cryptoKey, msg); | ||
| const result = new Uint8Array(sig); | ||
| const result = Buffer.from(new Uint8Array(sig)); | ||
| return result; | ||
| } | ||
| const hmac = browserCrypto.createHmac("sha256", key); | ||
| const hmac = browserCrypto.createHmac("sha256", Buffer.from(key)); | ||
| hmac.update(msg); | ||
@@ -138,3 +137,3 @@ const result = hmac.digest(); | ||
| // encoding except `hex`. | ||
| return secp256k1.getPublicKey(privateKey, false); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic("array")); | ||
| }; | ||
@@ -151,3 +150,3 @@ | ||
| const compressed = true; | ||
| return secp256k1.getPublicKey(privateKey, compressed); | ||
| return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(compressed, "array")); | ||
| }; | ||
@@ -165,3 +164,5 @@ | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| return secp256k1.sign(msg, privateKey).toDERRawBytes(); | ||
| return Buffer.from(ec.sign(msg, privateKey, { | ||
| canonical: true | ||
| }).toDER()); | ||
| }; | ||
@@ -178,8 +179,10 @@ const verify = async function (publicKey, msg, sig) { | ||
| assert(msg.length <= 32, "Message is too long"); | ||
| if (secp256k1.verify(sig, msg, publicKey)) return null; | ||
| if (ec.verify(msg, sig, publicKey)) { | ||
| return null; | ||
| } | ||
| throw new Error("Bad signature"); | ||
| }; | ||
| const derive = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -194,18 +197,11 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| // unpad to match previous implementation | ||
| // elliptic return BN and we return Buffer(BN.toArray()) | ||
| // match by unpadding | ||
| const sharedSecret = secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| const Px = sharedSecret.subarray(sharedSecret.length - 32); | ||
| let i = 0; | ||
| while (i < Px.length && Px[i] === 0) { | ||
| i++; | ||
| } | ||
| return Px.subarray(i); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toArray()); | ||
| }; | ||
| const deriveUnpadded = derive; | ||
| const derivePadded = async function (privateKeyA, publicKeyB) { | ||
| // assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| // assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(Buffer.isBuffer(privateKeyA), "Bad private key"); | ||
| assert(Buffer.isBuffer(publicKeyB), "Bad public key"); | ||
| assert(privateKeyA.length === 32, "Bad private key"); | ||
@@ -220,4 +216,6 @@ assert(isValidPrivateKey(privateKeyA), "Bad private key"); | ||
| } | ||
| const Px = secp256k1.getSharedSecret(privateKeyA, publicKeyB); | ||
| return Px.subarray(Px.length - 32); | ||
| const keyA = ec.keyFromPrivate(privateKeyA); | ||
| const keyB = ec.keyFromPublic(publicKeyB); | ||
| const Px = keyA.derive(keyB.getPublic()); // BN instance | ||
| return Buffer.from(Px.toString(16, 64), "hex"); | ||
| }; | ||
@@ -237,6 +235,6 @@ const encrypt = async function (publicKeyTo, msg, opts) { | ||
| const macKey = hash.slice(32); | ||
| const data = await aesCbcEncrypt(iv, encryptionKey, msg); | ||
| const data = await aesCbcEncrypt(iv, Buffer.from(encryptionKey), msg); | ||
| const ciphertext = data; | ||
| const dataToMac = concatBytes(iv, ephemPublicKey, ciphertext); | ||
| const mac = await hmacSha256Sign(macKey, dataToMac); | ||
| const dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]); | ||
| const mac = await hmacSha256Sign(Buffer.from(macKey), dataToMac); | ||
| return { | ||
@@ -256,4 +254,4 @@ iv, | ||
| const macKey = hash.slice(32); | ||
| const dataToMac = concatBytes(opts.iv, opts.ephemPublicKey, opts.ciphertext); | ||
| const macGood = await hmacSha256Verify(macKey, dataToMac, opts.mac); | ||
| const dataToMac = Buffer.concat([opts.iv, opts.ephemPublicKey, opts.ciphertext]); | ||
| const macGood = await hmacSha256Verify(Buffer.from(macKey), dataToMac, opts.mac); | ||
| if (!macGood && padding === false) { | ||
@@ -264,6 +262,6 @@ return decrypt(privateKey, opts, true); | ||
| } | ||
| const msg = await aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext); | ||
| return new Uint8Array(msg); | ||
| const msg = await aesCbcDecrypt(opts.iv, Buffer.from(encryptionKey), opts.ciphertext); | ||
| return Buffer.from(new Uint8Array(msg)); | ||
| }; | ||
| export { decrypt, derive, derivePadded, deriveUnpadded, encrypt, generatePrivate, getPublic, getPublicCompressed, sign, uint8ArrayToBigInt, verify }; | ||
| export { decrypt, derive, derivePadded, deriveUnpadded, encrypt, generatePrivate, getPublic, getPublicCompressed, sign, verify }; |
+16
-17
| export interface Ecies { | ||
| iv: Uint8Array; | ||
| ephemPublicKey: Uint8Array; | ||
| ciphertext: Uint8Array; | ||
| mac: Uint8Array; | ||
| iv: Buffer; | ||
| ephemPublicKey: Buffer; | ||
| ciphertext: Buffer; | ||
| mac: Buffer; | ||
| } | ||
| export declare function uint8ArrayToBigInt(arr: Uint8Array): bigint; | ||
| /** | ||
@@ -12,17 +11,17 @@ * Generate a new valid private key. Will use the window.crypto or window.msCrypto as source | ||
| */ | ||
| export declare const generatePrivate: () => Uint8Array; | ||
| export declare const getPublic: (privateKey: Uint8Array) => Uint8Array; | ||
| export declare const generatePrivate: () => Buffer; | ||
| export declare const getPublic: (privateKey: Buffer) => Buffer; | ||
| /** | ||
| * Get compressed version of public key. | ||
| */ | ||
| export declare const getPublicCompressed: (privateKey: Uint8Array) => Uint8Array; | ||
| export declare const sign: (privateKey: Uint8Array, msg: Uint8Array) => Promise<Uint8Array>; | ||
| export declare const verify: (publicKey: Uint8Array, msg: Uint8Array, sig: Uint8Array) => Promise<null>; | ||
| export declare const derive: (privateKeyA: Uint8Array, publicKeyB: Uint8Array) => Promise<Uint8Array>; | ||
| export declare const deriveUnpadded: (privateKeyA: Uint8Array, publicKeyB: Uint8Array) => Promise<Uint8Array>; | ||
| export declare const derivePadded: (privateKeyA: Uint8Array, publicKeyB: Uint8Array) => Promise<Uint8Array>; | ||
| export declare const encrypt: (publicKeyTo: Uint8Array, msg: Uint8Array, opts?: { | ||
| iv?: Uint8Array; | ||
| ephemPrivateKey?: Uint8Array; | ||
| export declare const getPublicCompressed: (privateKey: Buffer) => Buffer; | ||
| export declare const sign: (privateKey: Buffer, msg: Buffer) => Promise<Buffer>; | ||
| export declare const verify: (publicKey: Buffer, msg: Buffer, sig: Buffer) => Promise<null>; | ||
| export declare const derive: (privateKeyA: Buffer, publicKeyB: Buffer) => Promise<Buffer>; | ||
| export declare const deriveUnpadded: (privateKeyA: Buffer, publicKeyB: Buffer) => Promise<Buffer>; | ||
| export declare const derivePadded: (privateKeyA: Buffer, publicKeyB: Buffer) => Promise<Buffer>; | ||
| export declare const encrypt: (publicKeyTo: Buffer, msg: Buffer, opts?: { | ||
| iv?: Buffer; | ||
| ephemPrivateKey?: Buffer; | ||
| }) => Promise<Ecies>; | ||
| export declare const decrypt: (privateKey: Uint8Array, opts: Ecies, _padding?: boolean) => Promise<Uint8Array>; | ||
| export declare const decrypt: (privateKey: Buffer, opts: Ecies, _padding?: boolean) => Promise<Buffer>; |
+23
-31
| { | ||
| "name": "@toruslabs/eccrypto", | ||
| "version": "6.0.0-0", | ||
| "version": "6.0.0", | ||
| "description": "JavaScript Elliptic curve cryptography library, includes fix to browser.js so that encrypt/decrypt works", | ||
@@ -11,9 +11,10 @@ "main": "./dist/lib.cjs/index.js", | ||
| "build": "torus-scripts build", | ||
| "lint": "eslint --fix 'src/**/*.ts'", | ||
| "release": "torus-scripts release", | ||
| "test": "ECCRYPTO_NO_FALLBACK=1 mocha && karma start", | ||
| "test:ci": "ECCRYPTO_NO_FALLBACK=1 mocha && npm run k", | ||
| "m": "mocha", | ||
| "k": "xvfb-run -a karma start", | ||
| "kc": "xvfb-run -a karma start --browsers Chromium", | ||
| "kf": "xvfb-run -a karma start --browsers Firefox" | ||
| "test:ci": "npm run test:node && npm run test:browsers", | ||
| "test:node": "vitest run --config test/configs/node.config.mts --coverage", | ||
| "test:chrome": "vitest run --config test/configs/chrome.config.mts --coverage", | ||
| "test:firefox": "vitest run --config test/configs/firefox.config.mts --coverage", | ||
| "test:safari": "vitest run --config test/configs/safari.config.mts --coverage", | ||
| "test:browsers": "npm run test:chrome && npm run test:firefox && npm run test:safari" | ||
| }, | ||
@@ -36,2 +37,3 @@ "repository": { | ||
| "K-256", | ||
| "elliptic", | ||
| "curve" | ||
@@ -46,35 +48,25 @@ ], | ||
| "devDependencies": { | ||
| "@babel/cli": "^7.25.9", | ||
| "@babel/core": "^7.25.9", | ||
| "@babel/plugin-transform-runtime": "^7.25.9", | ||
| "@babel/preset-env": "^7.25.9", | ||
| "@babel/runtime": "^7.25.9", | ||
| "@toruslabs/config": "^2.2.0", | ||
| "@toruslabs/eslint-config-node": "^3.3.4", | ||
| "@toruslabs/torus-scripts": "^6.1.5", | ||
| "@babel/runtime": "^7.26.0", | ||
| "@toruslabs/config": "^3.0.0", | ||
| "@toruslabs/eslint-config-node": "^4.0.2", | ||
| "@toruslabs/eslint-config-typescript": "^4.0.2", | ||
| "@toruslabs/torus-scripts": "^7.0.2", | ||
| "@types/buffer-equal": "^1.0.2", | ||
| "@types/chai": "^4.3.16", | ||
| "@types/elliptic": "^6.4.18", | ||
| "@vitest/browser": "^2.1.8", | ||
| "@vitest/coverage-istanbul": "^2.1.8", | ||
| "browserify": "^17.0.1", | ||
| "buffer-equal": "^1.0.1", | ||
| "chai": "^4.3.7", | ||
| "eslint": "^8.46.0", | ||
| "karma": "^6.4.4", | ||
| "karma-browserify": "^8.1.0", | ||
| "karma-chrome-launcher": "^3.2.0", | ||
| "karma-cli": "^2.0.0", | ||
| "karma-firefox-launcher": "^2.1.3", | ||
| "karma-mocha": "^2.0.1", | ||
| "karma-mocha-reporter": "^2.2.5", | ||
| "karma-webkit-launcher": "^2.6.0", | ||
| "mocha": "^10.7.3", | ||
| "playwright": "^1.48.1", | ||
| "typescript": "^5.6.3" | ||
| "eslint": "^9.17.0", | ||
| "playwright": "^1.49.1", | ||
| "typescript": "^5.7.2", | ||
| "vitest": "^2.1.8" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.x", | ||
| "node": ">=20.x", | ||
| "npm": ">=9.x" | ||
| }, | ||
| "dependencies": { | ||
| "@noble/curves": "^1.6.0" | ||
| "elliptic": "^6.6.1" | ||
| } | ||
| } |
Sorry, the diff of this file is too big to display
Mixed license
LicensePackage contains multiple licenses.
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Mixed license
LicensePackage contains multiple licenses.
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
217879
133.84%15
-40%0
-100%1071
-0.74%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed