@noble/ed25519
Advanced tools
Comparing version 1.6.1 to 1.7.0
/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
import nodeCrypto from 'crypto'; | ||
import * as nodeCrypto from 'crypto'; | ||
const _0n = BigInt(0); | ||
@@ -8,3 +8,3 @@ const _1n = BigInt(1); | ||
const CURVE_ORDER = _2n ** BigInt(252) + BigInt('27742317777372353535851937790883648493'); | ||
const CURVE = { | ||
const CURVE = Object.freeze({ | ||
a: BigInt(-1), | ||
@@ -18,3 +18,3 @@ d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'), | ||
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'), | ||
}; | ||
}); | ||
export { CURVE }; | ||
@@ -593,6 +593,4 @@ const MAX_256B = _2n ** BigInt(256); | ||
} | ||
async function sha512ModqLE(...args) { | ||
const hash = await utils.sha512(concatBytes(...args)); | ||
const value = bytesToNumberLE(hash); | ||
return mod(value, CURVE.l); | ||
function modlLE(hash) { | ||
return mod(bytesToNumberLE(hash), CURVE.l); | ||
} | ||
@@ -642,3 +640,3 @@ function equalBytes(b1, b2) { | ||
} | ||
async function getExtendedPublicKey(key) { | ||
function checkPrivateKey(key) { | ||
key = | ||
@@ -650,6 +648,8 @@ typeof key === 'bigint' || typeof key === 'number' | ||
throw new Error(`Expected 32 bytes`); | ||
const hashed = await utils.sha512(key); | ||
return key; | ||
} | ||
function getKeyFromHash(hashed) { | ||
const head = adjustBytes25519(hashed.slice(0, 32)); | ||
const prefix = hashed.slice(32, 64); | ||
const scalar = mod(bytesToNumberLE(head), CURVE.l); | ||
const scalar = modlLE(head); | ||
const point = Point.BASE.multiply(scalar); | ||
@@ -659,16 +659,40 @@ const pointBytes = point.toRawBytes(); | ||
} | ||
let _sha512Sync; | ||
function sha512s(...m) { | ||
if (typeof _sha512Sync !== 'function') | ||
throw new Error('utils.sha512Sync must be set to use sync methods'); | ||
return _sha512Sync(...m); | ||
} | ||
async function getExtendedPublicKey(key) { | ||
return getKeyFromHash(await utils.sha512(checkPrivateKey(key))); | ||
} | ||
function getExtendedPublicKeySync(key) { | ||
return getKeyFromHash(sha512s(checkPrivateKey(key))); | ||
} | ||
export async function getPublicKey(privateKey) { | ||
return (await getExtendedPublicKey(privateKey)).pointBytes; | ||
} | ||
function getPublicKeySync(privateKey) { | ||
return getExtendedPublicKeySync(privateKey).pointBytes; | ||
} | ||
export async function sign(message, privateKey) { | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModqLE(prefix, message); | ||
const r = modlLE(await utils.sha512(prefix, message)); | ||
const R = Point.BASE.multiply(r); | ||
const k = await sha512ModqLE(R.toRawBytes(), pointBytes, message); | ||
const k = modlLE(await utils.sha512(R.toRawBytes(), pointBytes, message)); | ||
const s = mod(r + k * scalar, CURVE.l); | ||
return new Signature(R, s).toRawBytes(); | ||
} | ||
export async function verify(sig, message, publicKey) { | ||
function signSync(message, privateKey) { | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = getExtendedPublicKeySync(privateKey); | ||
const r = modlLE(sha512s(prefix, message)); | ||
const R = Point.BASE.multiply(r); | ||
const k = modlLE(sha512s(R.toRawBytes(), pointBytes, message)); | ||
const s = mod(r + k * scalar, CURVE.l); | ||
return new Signature(R, s).toRawBytes(); | ||
} | ||
function prepareVerification(sig, message, publicKey) { | ||
message = ensureBytes(message); | ||
if (!(publicKey instanceof Point)) | ||
@@ -678,3 +702,6 @@ publicKey = Point.fromHex(publicKey, false); | ||
const SB = ExtendedPoint.BASE.multiplyUnsafe(s); | ||
const k = await sha512ModqLE(r.toRawBytes(), publicKey.toRawBytes(), message); | ||
return { r, s, SB, pub: publicKey, msg: message }; | ||
} | ||
function finishVerification(publicKey, r, SB, hashed) { | ||
const k = modlLE(hashed); | ||
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k); | ||
@@ -684,2 +711,18 @@ const RkA = ExtendedPoint.fromAffine(r).add(kA); | ||
} | ||
export async function verify(sig, message, publicKey) { | ||
const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); | ||
const hashed = await utils.sha512(r.toRawBytes(), pub.toRawBytes(), msg); | ||
return finishVerification(pub, r, SB, hashed); | ||
} | ||
function verifySync(sig, message, publicKey) { | ||
const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); | ||
const hashed = sha512s(r.toRawBytes(), pub.toRawBytes(), msg); | ||
return finishVerification(pub, r, SB, hashed); | ||
} | ||
export const sync = { | ||
getExtendedPublicKey: getExtendedPublicKeySync, | ||
getPublicKey: getPublicKeySync, | ||
sign: signSync, | ||
verify: verifySync, | ||
}; | ||
export async function getSharedSecret(privateKey, publicKey) { | ||
@@ -781,2 +824,4 @@ const { head } = await getExtendedPublicKey(privateKey); | ||
bytesToHex, | ||
hexToBytes, | ||
concatBytes, | ||
getExtendedPublicKey, | ||
@@ -789,6 +834,3 @@ mod, | ||
throw new Error('Expected 40-1024 bytes of private key as per FIPS 186'); | ||
const num = mod(bytesToNumberLE(hash), CURVE.l); | ||
if (num === _0n || num === _1n) | ||
throw new Error('Invalid private key'); | ||
return num; | ||
return mod(bytesToNumberLE(hash), CURVE.l - _1n) + _1n; | ||
}, | ||
@@ -810,3 +852,4 @@ randomBytes: (bytesLength = 32) => { | ||
}, | ||
sha512: async (message) => { | ||
sha512: async (...messages) => { | ||
const message = concatBytes(...messages); | ||
if (crypto.web) { | ||
@@ -829,2 +872,15 @@ const buffer = await crypto.web.subtle.digest('SHA-512', message.buffer); | ||
}, | ||
sha512Sync: undefined, | ||
}; | ||
Object.defineProperties(utils, { | ||
sha512Sync: { | ||
configurable: false, | ||
get() { | ||
return _sha512Sync; | ||
}, | ||
set(val) { | ||
if (!_sha512Sync) | ||
_sha512Sync = val; | ||
}, | ||
}, | ||
}); |
/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
declare const CURVE: { | ||
declare const CURVE: Readonly<{ | ||
a: bigint; | ||
@@ -11,3 +11,3 @@ d: bigint; | ||
Gy: bigint; | ||
}; | ||
}>; | ||
export { CURVE }; | ||
@@ -92,5 +92,8 @@ declare type Hex = Uint8Array | string; | ||
export { ExtendedPoint, RistrettoPoint, Point, Signature }; | ||
declare function concatBytes(...arrays: Uint8Array[]): Uint8Array; | ||
declare function bytesToHex(uint8a: Uint8Array): string; | ||
declare function hexToBytes(hex: string): Uint8Array; | ||
declare function mod(a: bigint, b?: bigint): bigint; | ||
declare function invert(number: bigint, modulo?: bigint): bigint; | ||
declare type Sha512FnSync = undefined | ((...messages: Uint8Array[]) => Uint8Array); | ||
declare function getExtendedPublicKey(key: PrivKey): Promise<{ | ||
@@ -103,5 +106,21 @@ head: Uint8Array; | ||
}>; | ||
declare function getExtendedPublicKeySync(key: PrivKey): { | ||
head: Uint8Array; | ||
prefix: Uint8Array; | ||
scalar: bigint; | ||
point: Point; | ||
pointBytes: Uint8Array; | ||
}; | ||
export declare function getPublicKey(privateKey: PrivKey): Promise<Uint8Array>; | ||
declare function getPublicKeySync(privateKey: PrivKey): Uint8Array; | ||
export declare function sign(message: Hex, privateKey: Hex): Promise<Uint8Array>; | ||
declare function signSync(message: Hex, privateKey: Hex): Uint8Array; | ||
export declare function verify(sig: SigType, message: Hex, publicKey: PubKey): Promise<boolean>; | ||
declare function verifySync(sig: SigType, message: Hex, publicKey: PubKey): boolean; | ||
export declare const sync: { | ||
getExtendedPublicKey: typeof getExtendedPublicKeySync; | ||
getPublicKey: typeof getPublicKeySync; | ||
sign: typeof signSync; | ||
verify: typeof verifySync; | ||
}; | ||
export declare function getSharedSecret(privateKey: PrivKey, publicKey: Hex): Promise<Uint8Array>; | ||
@@ -116,2 +135,4 @@ export declare const curve25519: { | ||
bytesToHex: typeof bytesToHex; | ||
hexToBytes: typeof hexToBytes; | ||
concatBytes: typeof concatBytes; | ||
getExtendedPublicKey: typeof getExtendedPublicKey; | ||
@@ -123,4 +144,5 @@ mod: typeof mod; | ||
randomPrivateKey: () => Uint8Array; | ||
sha512: (message: Uint8Array) => Promise<Uint8Array>; | ||
sha512: (...messages: Uint8Array[]) => Promise<Uint8Array>; | ||
precompute(windowSize?: number, point?: Point): Point; | ||
sha512Sync: Sha512FnSync; | ||
}; |
101
lib/index.js
"use strict"; | ||
/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.utils = exports.curve25519 = exports.getSharedSecret = exports.verify = exports.sign = exports.getPublicKey = exports.Signature = exports.Point = exports.RistrettoPoint = exports.ExtendedPoint = exports.CURVE = void 0; | ||
const crypto_1 = __importDefault(require("crypto")); | ||
exports.utils = exports.curve25519 = exports.getSharedSecret = exports.sync = exports.verify = exports.sign = exports.getPublicKey = exports.Signature = exports.Point = exports.RistrettoPoint = exports.ExtendedPoint = exports.CURVE = void 0; | ||
const nodeCrypto = require("crypto"); | ||
const _0n = BigInt(0); | ||
@@ -14,3 +11,3 @@ const _1n = BigInt(1); | ||
const CURVE_ORDER = _2n ** BigInt(252) + BigInt('27742317777372353535851937790883648493'); | ||
const CURVE = { | ||
const CURVE = Object.freeze({ | ||
a: BigInt(-1), | ||
@@ -24,3 +21,3 @@ d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'), | ||
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'), | ||
}; | ||
}); | ||
exports.CURVE = CURVE; | ||
@@ -602,6 +599,4 @@ const MAX_256B = _2n ** BigInt(256); | ||
} | ||
async function sha512ModqLE(...args) { | ||
const hash = await exports.utils.sha512(concatBytes(...args)); | ||
const value = bytesToNumberLE(hash); | ||
return mod(value, CURVE.l); | ||
function modlLE(hash) { | ||
return mod(bytesToNumberLE(hash), CURVE.l); | ||
} | ||
@@ -651,3 +646,3 @@ function equalBytes(b1, b2) { | ||
} | ||
async function getExtendedPublicKey(key) { | ||
function checkPrivateKey(key) { | ||
key = | ||
@@ -659,6 +654,8 @@ typeof key === 'bigint' || typeof key === 'number' | ||
throw new Error(`Expected 32 bytes`); | ||
const hashed = await exports.utils.sha512(key); | ||
return key; | ||
} | ||
function getKeyFromHash(hashed) { | ||
const head = adjustBytes25519(hashed.slice(0, 32)); | ||
const prefix = hashed.slice(32, 64); | ||
const scalar = mod(bytesToNumberLE(head), CURVE.l); | ||
const scalar = modlLE(head); | ||
const point = Point.BASE.multiply(scalar); | ||
@@ -668,2 +665,14 @@ const pointBytes = point.toRawBytes(); | ||
} | ||
let _sha512Sync; | ||
function sha512s(...m) { | ||
if (typeof _sha512Sync !== 'function') | ||
throw new Error('utils.sha512Sync must be set to use sync methods'); | ||
return _sha512Sync(...m); | ||
} | ||
async function getExtendedPublicKey(key) { | ||
return getKeyFromHash(await exports.utils.sha512(checkPrivateKey(key))); | ||
} | ||
function getExtendedPublicKeySync(key) { | ||
return getKeyFromHash(sha512s(checkPrivateKey(key))); | ||
} | ||
async function getPublicKey(privateKey) { | ||
@@ -673,8 +682,11 @@ return (await getExtendedPublicKey(privateKey)).pointBytes; | ||
exports.getPublicKey = getPublicKey; | ||
function getPublicKeySync(privateKey) { | ||
return getExtendedPublicKeySync(privateKey).pointBytes; | ||
} | ||
async function sign(message, privateKey) { | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModqLE(prefix, message); | ||
const r = modlLE(await exports.utils.sha512(prefix, message)); | ||
const R = Point.BASE.multiply(r); | ||
const k = await sha512ModqLE(R.toRawBytes(), pointBytes, message); | ||
const k = modlLE(await exports.utils.sha512(R.toRawBytes(), pointBytes, message)); | ||
const s = mod(r + k * scalar, CURVE.l); | ||
@@ -684,4 +696,13 @@ return new Signature(R, s).toRawBytes(); | ||
exports.sign = sign; | ||
async function verify(sig, message, publicKey) { | ||
function signSync(message, privateKey) { | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = getExtendedPublicKeySync(privateKey); | ||
const r = modlLE(sha512s(prefix, message)); | ||
const R = Point.BASE.multiply(r); | ||
const k = modlLE(sha512s(R.toRawBytes(), pointBytes, message)); | ||
const s = mod(r + k * scalar, CURVE.l); | ||
return new Signature(R, s).toRawBytes(); | ||
} | ||
function prepareVerification(sig, message, publicKey) { | ||
message = ensureBytes(message); | ||
if (!(publicKey instanceof Point)) | ||
@@ -691,3 +712,6 @@ publicKey = Point.fromHex(publicKey, false); | ||
const SB = ExtendedPoint.BASE.multiplyUnsafe(s); | ||
const k = await sha512ModqLE(r.toRawBytes(), publicKey.toRawBytes(), message); | ||
return { r, s, SB, pub: publicKey, msg: message }; | ||
} | ||
function finishVerification(publicKey, r, SB, hashed) { | ||
const k = modlLE(hashed); | ||
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k); | ||
@@ -697,3 +721,19 @@ const RkA = ExtendedPoint.fromAffine(r).add(kA); | ||
} | ||
async function verify(sig, message, publicKey) { | ||
const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); | ||
const hashed = await exports.utils.sha512(r.toRawBytes(), pub.toRawBytes(), msg); | ||
return finishVerification(pub, r, SB, hashed); | ||
} | ||
exports.verify = verify; | ||
function verifySync(sig, message, publicKey) { | ||
const { r, SB, msg, pub } = prepareVerification(sig, message, publicKey); | ||
const hashed = sha512s(r.toRawBytes(), pub.toRawBytes(), msg); | ||
return finishVerification(pub, r, SB, hashed); | ||
} | ||
exports.sync = { | ||
getExtendedPublicKey: getExtendedPublicKeySync, | ||
getPublicKey: getPublicKeySync, | ||
sign: signSync, | ||
verify: verifySync, | ||
}; | ||
async function getSharedSecret(privateKey, publicKey) { | ||
@@ -781,3 +821,3 @@ const { head } = await getExtendedPublicKey(privateKey); | ||
const crypto = { | ||
node: crypto_1.default, | ||
node: nodeCrypto, | ||
web: typeof self === 'object' && 'crypto' in self ? self.crypto : undefined, | ||
@@ -797,2 +837,4 @@ }; | ||
bytesToHex, | ||
hexToBytes, | ||
concatBytes, | ||
getExtendedPublicKey, | ||
@@ -805,6 +847,3 @@ mod, | ||
throw new Error('Expected 40-1024 bytes of private key as per FIPS 186'); | ||
const num = mod(bytesToNumberLE(hash), CURVE.l); | ||
if (num === _0n || num === _1n) | ||
throw new Error('Invalid private key'); | ||
return num; | ||
return mod(bytesToNumberLE(hash), CURVE.l - _1n) + _1n; | ||
}, | ||
@@ -826,3 +865,4 @@ randomBytes: (bytesLength = 32) => { | ||
}, | ||
sha512: async (message) => { | ||
sha512: async (...messages) => { | ||
const message = concatBytes(...messages); | ||
if (crypto.web) { | ||
@@ -845,2 +885,15 @@ const buffer = await crypto.web.subtle.digest('SHA-512', message.buffer); | ||
}, | ||
sha512Sync: undefined, | ||
}; | ||
Object.defineProperties(exports.utils, { | ||
sha512Sync: { | ||
configurable: false, | ||
get() { | ||
return _sha512Sync; | ||
}, | ||
set(val) { | ||
if (!_sha512Sync) | ||
_sha512Sync = val; | ||
}, | ||
}, | ||
}); |
{ | ||
"name": "@noble/ed25519", | ||
"version": "1.6.1", | ||
"description": "Fastest JS implementation of ed25519. Independently audited, high-security, 0-dependency EDDSA, X25519 ECDH, ristretto255 & scalarmult", | ||
"version": "1.7.0", | ||
"description": "Fastest JS implementation of ed25519. Independently audited, high-security, 0-dependency EDDSA, X25519 ECDH & ristretto255", | ||
"files": [ | ||
@@ -16,3 +16,3 @@ "lib" | ||
"test": "jest", | ||
"bench": "node test/benchmark.js" | ||
"bench": "node test/benchmark/benchmark.js" | ||
}, | ||
@@ -30,2 +30,3 @@ "author": "Paul Miller (https://paulmillr.com)", | ||
"devDependencies": { | ||
"@noble/hashes": "1.1.2", | ||
"@rollup/plugin-node-resolve": "13.3.0", | ||
@@ -36,3 +37,3 @@ "@types/jest": "28.1.1", | ||
"jest": "28.1.0", | ||
"micro-bmark": "^0.1.3", | ||
"micro-bmark": "0.2.0", | ||
"prettier": "2.6.2", | ||
@@ -39,0 +40,0 @@ "rollup": "2.75.5", |
@@ -10,3 +10,3 @@ # noble-ed25519 ![Node CI](https://github.com/paulmillr/noble-ed25519/workflows/Node%20CI/badge.svg) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) | ||
### This library belongs to *noble* crypto | ||
### This library belongs to _noble_ crypto | ||
@@ -37,2 +37,3 @@ > **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools. | ||
// Supports both async and sync methods, see docs | ||
(async () => { | ||
@@ -54,3 +55,3 @@ // keys, messages & other inputs can be Uint8Arrays or hex strings | ||
- app.ts: `import * as ed from "https://deno.land/x/ed25519/mod.ts";` | ||
- imports.json: `{"imports": {"crypto": "https://deno.land/std@0.125.0/node/crypto.ts"}}` | ||
- imports.json: `{"imports": {"crypto": "https://deno.land/std@0.153.0/node/crypto.ts"}}` | ||
@@ -65,11 +66,14 @@ ## API | ||
- [ristretto255](#ristretto255) | ||
- [Synchronous methods](#synchronous-methods) | ||
- [Utilities](#utilities) | ||
##### `getPublicKey(privateKey)` | ||
```typescript | ||
function getPublicKey(privateKey: Uint8Array | string | bigint): Promise<Uint8Array>; | ||
``` | ||
- `privateKey: Uint8Array | string | bigint` will be used to generate public key. If you want to pass bigints, | ||
ensure they are Big-Endian. | ||
- Returns `Promise<Uint8Array>`. Uses **promises**, because ed25519 uses SHA internally; and we're using built-in browser `window.crypto`, which returns `Promise`. | ||
- Returns `Promise<Uint8Array>`. Uses **promises**, because ed25519 uses SHA internally; and we're using built-in browser `window.crypto`, which returns `Promise`. Synchronous non-promise method is available for this and others: [see below](#synchronous-methods). | ||
@@ -87,11 +91,14 @@ To generate ed25519 public key: | ||
##### `sign(message, privateKey)` | ||
```typescript | ||
function sign(message: Uint8Array | string, privateKey: Uint8Array | string): Promise<Uint8Array>; | ||
``` | ||
- `message: Uint8Array | string` - message (not message hash) which would be signed | ||
- `privateKey: Uint8Array | string` - private key which will sign the hash | ||
- Returns EdDSA signature. You can consume it with `Signature.fromHex()` method: | ||
- `Signature.fromHex(ed25519.sign(hash, privateKey))` | ||
- `Signature.fromHex(ed25519.sign(hash, privateKey))` | ||
##### `verify(signature, message, publicKey)` | ||
```typescript | ||
@@ -102,4 +109,5 @@ function verify( | ||
publicKey: Uint8Array | string | Point | ||
): Promise<boolean> | ||
): Promise<boolean>; | ||
``` | ||
- `signature: Uint8Array | string | Signature` - returned by the `sign` function | ||
@@ -115,3 +123,3 @@ - `message: Uint8Array | string` - message that needs to be verified | ||
*Not compatible with RFC8032* because rfc encorces canonical encoding of R/publicKey. There is no security risk in ZIP behavior, and there is no effect on honestly generated signatures. For additional info about verification strictness, check out [It’s 255:19AM](https://hdevalence.ca/blog/2020-10-04-its-25519am). | ||
_Not compatible with RFC8032_ because rfc encorces canonical encoding of R/publicKey. There is no security risk in ZIP behavior, and there is no effect on honestly generated signatures. For additional info about verification strictness, check out [It’s 255:19AM](https://hdevalence.ca/blog/2020-10-04-its-25519am). | ||
@@ -121,3 +129,6 @@ ##### `getSharedSecret(privateKey, publicKey)` | ||
```typescript | ||
function getSharedSecret(privateKey: Uint8Array | string | bigint, publicKey: Uint8Array | string): Promise<Uint8Array>; | ||
function getSharedSecret( | ||
privateKey: Uint8Array | string | bigint, | ||
publicKey: Uint8Array | string | ||
): Promise<Uint8Array>; | ||
``` | ||
@@ -156,3 +167,3 @@ | ||
2. Never mix `ExtendedPoint` & `RistrettoPoint`: ristretto is not a subgroup of ed25519. | ||
`ExtendedPoint` you are mixing with, may not be the representative for the set of possible points. | ||
`ExtendedPoint` you are mixing with, may not be the representative for the set of possible points. | ||
@@ -186,2 +197,18 @@ ```typescript | ||
### Synchronous methods | ||
The library is using built-in async hash functions by default in order to follow its 0-dependency approach. | ||
This means, built-in `getPublicKey`, `sync` and others are asynchronous. Some use-cases require | ||
sync versions of those. You can use them: all you need to do is make sure ed25519 knows | ||
how to hash synchronously. Redefining `ed.utils.sha512Sync` is enough: | ||
```ts | ||
import { sha512 } from '@noble/hashes/sha512'; | ||
ed.utils.sha512Sync = (...m) => sha512(ed.utils.concatBytes(...m)); | ||
const { getPublicKey, sign, verify, getExtendedPublicKey } = ed.sync; | ||
// Use it freely | ||
getPublicKey(privKey); | ||
``` | ||
### Utilities | ||
@@ -275,3 +302,3 @@ | ||
We're using built-in JS `BigInt`, which is "unsuitable for use in cryptography" as [per official spec](https://github.com/tc39/proposal-bigint#cryptography). This means that the lib is potentially vulnerable to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). But, *JIT-compiler* and *Garbage Collector* make "constant time" extremely hard to achieve in a scripting language. Which means *any other JS library doesn't use constant-time bigints*. Including bn.js or anything else. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we've hardened implementation of ec curve multiplication to be algorithmically constant time. | ||
We're using built-in JS `BigInt`, which is "unsuitable for use in cryptography" as [per official spec](https://github.com/tc39/proposal-bigint#cryptography). This means that the lib is potentially vulnerable to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). But, _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library doesn't use constant-time bigints_. Including bn.js or anything else. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we've hardened implementation of ec curve multiplication to be algorithmically constant time. | ||
@@ -282,25 +309,30 @@ We however consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector. | ||
Benchmarks done with Apple M1 on macOS 12. | ||
Benchmarks done with Apple M2 on macOS 12 with Node.js 18. | ||
getPublicKey(utils.randomPrivateKey()) x 7,600 ops/sec @ 131μs/op | ||
sign x 3,819 ops/sec @ 261μs/op | ||
verify x 762 ops/sec @ 1ms/op | ||
Point.fromHex decompression x 12,055 ops/sec @ 82μs/op | ||
ristretto255#hashToCurve x 5,617 ops/sec @ 178μs/op | ||
ristretto255 round x 5,734 ops/sec @ 174μs/op | ||
curve25519.scalarMultBase x 1,173 ops/sec @ 852μs/op | ||
ed25519.getSharedSecret x 883 ops/sec @ 1ms/op | ||
getPublicKey(utils.randomPrivateKey()) x 8,627 ops/sec @ 115μs/op | ||
sign x 4,355 ops/sec @ 229μs/op | ||
verify x 852 ops/sec @ 1ms/op | ||
verify (no decompression) x 975 ops/sec @ 1ms/op | ||
Point.fromHex decompression x 13,512 ops/sec @ 74μs/op | ||
ristretto255#hashToCurve x 6,419 ops/sec @ 155μs/op | ||
ristretto255 round x 6,451 ops/sec @ 155μs/op | ||
curve25519.scalarMultBase x 1,273 ops/sec @ 785μs/op | ||
ed25519.getSharedSecret x 968 ops/sec @ 1ms/op | ||
Compare to alternative implementations: | ||
# tweetnacl-fast@1.0.3 | ||
getPublicKey x 920 ops/sec @ 1ms/op # aka scalarMultBase | ||
sign x 519 ops/sec @ 2ms/op | ||
ristretto255 x 669 ops/sec @ 1ms/op ± 1.41% (min: 1ms, max: 8ms) | ||
sodium-native x 82,925 ops/sec @ 12μs/op | ||
# ristretto255@0.1.1 | ||
getPublicKey x 877 ops/sec @ 1ms/op # aka scalarMultBase | ||
# tweetnacl@1.0.3 (fast) | ||
getPublicKey x 2,087 ops/sec @ 479μs/op # aka scalarMultBase | ||
sign x 667 ops/sec @ 1ms/op | ||
# sodium-native@3.2.1, native bindings to libsodium, node.js-only | ||
sodium-native#sign x 58,661 ops/sec @ 17μs/op | ||
# ristretto255@0.1.2 | ||
getPublicKey x 669 ops/sec @ 1ms/op ± 1.41% (min: 1ms, max: 8ms) | ||
# sodium-native@3.4.1 | ||
# native bindings to libsodium, **node.js-only** | ||
sign x 82,925 ops/sec @ 12μs/op | ||
## Contributing | ||
@@ -307,0 +339,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83472
1901
336
11