@noble/ed25519
Advanced tools
Comparing version 1.5.1 to 1.5.2
@@ -46,4 +46,3 @@ /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
static fromRistrettoHash(hash) { | ||
hash = ensureBytes(hash); | ||
assertLen(64, hash); | ||
hash = ensureBytes(hash, 64); | ||
const r1 = bytes255ToNumberLE(hash.slice(0, 32)); | ||
@@ -77,9 +76,8 @@ const R1 = this.calcElligatorRistrettoMap(r1); | ||
} | ||
static fromRistrettoBytes(bytes) { | ||
bytes = ensureBytes(bytes); | ||
assertLen(32, bytes); | ||
static fromRistrettoBytes(hex) { | ||
hex = ensureBytes(hex, 32); | ||
const { a, d } = CURVE; | ||
const emsg = 'ExtendedPoint.fromRistrettoBytes: Cannot convert bytes to Ristretto Point'; | ||
const s = bytes255ToNumberLE(bytes); | ||
if (!equalBytes(numberToBytesLEPadded(s, 32), bytes) || edIsNegative(s)) | ||
const s = bytes255ToNumberLE(hex); | ||
if (!equalBytes(numberToBytesLEPadded(s, 32), hex) || edIsNegative(s)) | ||
throw new Error(emsg); | ||
@@ -286,6 +284,5 @@ const s2 = mod(s * s); | ||
const { d, P } = CURVE; | ||
const bytes = ensureBytes(hex); | ||
assertLen(32, bytes); | ||
const normed = bytes.slice(); | ||
normed[31] = bytes[31] & ~0x80; | ||
hex = ensureBytes(hex, 32); | ||
const normed = hex.slice(); | ||
normed[31] = hex[31] & ~0x80; | ||
const y = bytesToNumberLE(normed); | ||
@@ -301,3 +298,3 @@ if (y >= P) | ||
const isXOdd = (x & _1n) === _1n; | ||
const isLastByteOdd = (bytes[31] & 0x80) !== 0; | ||
const isLastByteOdd = (hex[31] & 0x80) !== 0; | ||
if (isLastByteOdd !== isXOdd) { | ||
@@ -321,3 +318,4 @@ x = mod(-x); | ||
const { y } = this; | ||
return mod((_1n + y) * invert(_1n - y)); | ||
const u = mod((_1n + y) * invert(_1n - y)); | ||
return numberToBytesLEPadded(u, 32); | ||
} | ||
@@ -350,4 +348,3 @@ equals(other) { | ||
static fromHex(hex) { | ||
const bytes = ensureBytes(hex); | ||
assertLen(64, bytes); | ||
const bytes = ensureBytes(hex, 64); | ||
const r = Point.fromHex(bytes.slice(0, 32)); | ||
@@ -384,2 +381,4 @@ const s = bytesToNumberLE(bytes.slice(32, 64)); | ||
function bytesToHex(uint8a) { | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error('Uint8Array expected'); | ||
let hex = ''; | ||
@@ -402,3 +401,3 @@ for (let i = 0; i < uint8a.length; i++) { | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte)) | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
@@ -421,9 +420,4 @@ array[i] = byte; | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error(`bytesToNumberLE: expected Uint8Array, got ${uint8a}`); | ||
let value = _0n; | ||
const _8n = BigInt(8); | ||
for (let i = 0; i < uint8a.length; i++) { | ||
value += BigInt(uint8a[i]) << (_8n * BigInt(i)); | ||
} | ||
return value; | ||
throw new Error('Expected Uint8Array'); | ||
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse())); | ||
} | ||
@@ -545,50 +539,49 @@ function bytes255ToNumberLE(bytes) { | ||
} | ||
function ensureBytes(hash) { | ||
return hash instanceof Uint8Array ? Uint8Array.from(hash) : hexToBytes(hash); | ||
function ensureBytes(hex, expectedLength) { | ||
const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex); | ||
if (typeof expectedLength === 'number' && bytes.length !== expectedLength) | ||
throw new Error(`Expected ${expectedLength} bytes`); | ||
return bytes; | ||
} | ||
function assertLen(len, bytes) { | ||
if (bytes.length !== len) | ||
throw new Error(`Expected ${len} bytes`); | ||
} | ||
function normalizeScalar(num, max = CURVE.n) { | ||
if (typeof num === 'number' && num > 0 && Number.isSafeInteger(num)) | ||
return BigInt(num); | ||
if (typeof num === 'bigint' && _0n < num && num < max) | ||
return num; | ||
if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0) | ||
return BigInt(num); | ||
throw new TypeError('Expected valid scalar: 0 < scalar < max'); | ||
} | ||
function normalizePrivateKey(key) { | ||
const bytes = typeof key === 'bigint' || typeof key === 'number' | ||
? numberToBytesBEPadded(normalizeScalar(key, _2n ** BigInt(256)), 32) | ||
: ensureBytes(key); | ||
assertLen(32, bytes); | ||
function adjustBytes25519(bytes) { | ||
bytes[0] &= 248; | ||
bytes[31] &= 127; | ||
bytes[31] |= 64; | ||
return bytes; | ||
} | ||
function decodeScalar25519(n) { | ||
n = ensureBytes(n); | ||
assertLen(32, n); | ||
n[0] &= 248; | ||
n[31] &= 127; | ||
n[31] |= 64; | ||
return bytesToNumberLE(n); | ||
return bytesToNumberLE(adjustBytes25519(ensureBytes(n, 32))); | ||
} | ||
async function getExtendedPublicKey(key) { | ||
const hashed = await utils.sha512(normalizePrivateKey(key)); | ||
const head = hashed.slice(0, 32); | ||
key = | ||
typeof key === 'bigint' || typeof key === 'number' | ||
? numberToBytesBEPadded(normalizeScalar(key, _2n ** BigInt(256)), 32) | ||
: ensureBytes(key); | ||
if (key.length !== 32) | ||
throw new Error(`Expected 32 bytes`); | ||
const hashed = await utils.sha512(key); | ||
const head = adjustBytes25519(hashed.slice(0, 32)); | ||
const prefix = hashed.slice(32, 64); | ||
const scalar = mod(decodeScalar25519(head), CURVE.n); | ||
const scalar = mod(bytesToNumberLE(head), CURVE.n); | ||
const point = Point.BASE.multiply(scalar); | ||
const pubBytes = point.toRawBytes(); | ||
return { head, prefix, scalar, point, pubBytes }; | ||
const pointBytes = point.toRawBytes(); | ||
return { head, prefix, scalar, point, pointBytes }; | ||
} | ||
export async function getPublicKey(privateKey) { | ||
return (await getExtendedPublicKey(privateKey)).pubBytes; | ||
return (await getExtendedPublicKey(privateKey)).pointBytes; | ||
} | ||
export async function sign(message, privateKey) { | ||
const msg = ensureBytes(message); | ||
const { prefix, scalar: p, pubBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModnLE(prefix, msg); | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModnLE(prefix, message); | ||
const R = Point.BASE.multiply(r); | ||
const k = await sha512ModnLE(R.toRawBytes(), pubBytes, msg); | ||
const S = mod(r + k * p, CURVE.n); | ||
const k = await sha512ModnLE(R.toRawBytes(), pointBytes, message); | ||
const S = mod(r + k * scalar, CURVE.n); | ||
return new Signature(R, S).toRawBytes(); | ||
@@ -609,5 +602,5 @@ } | ||
export async function getSharedSecret(privateKey, publicKey) { | ||
const { scalar: p } = await getExtendedPublicKey(privateKey); | ||
const { head } = await getExtendedPublicKey(privateKey); | ||
const u = Point.fromHex(publicKey).toX25519(); | ||
return montgomeryLadderChecked(p, u); | ||
return curve25519.scalarMult(head, u); | ||
} | ||
@@ -670,11 +663,4 @@ Point.BASE._setWindowSize(8); | ||
} | ||
function montgomeryLadderChecked(u, p) { | ||
const pu = montgomeryLadder(u, p); | ||
if (pu === _0n) | ||
throw new Error('Invalid private or public key received'); | ||
return encodeUCoordinate(pu); | ||
} | ||
function decodeUCoordinate(uEnc) { | ||
const u = ensureBytes(uEnc); | ||
assertLen(32, u); | ||
const u = ensureBytes(uEnc, 32); | ||
u[31] &= 127; | ||
@@ -688,3 +674,6 @@ return bytesToNumberLE(u); | ||
const p = decodeScalar25519(privateKey); | ||
return montgomeryLadderChecked(u, p); | ||
const pu = montgomeryLadder(u, p); | ||
if (pu === _0n) | ||
throw new Error('Invalid private or public key received'); | ||
return encodeUCoordinate(pu); | ||
}, | ||
@@ -712,2 +701,3 @@ scalarMultBase(privateKey) { | ||
getExtendedPublicKey, | ||
mod, | ||
randomBytes: (bytesLength = 32) => { | ||
@@ -743,5 +733,5 @@ if (crypto.web) { | ||
cached._setWindowSize(windowSize); | ||
cached.multiply(_1n); | ||
cached.multiply(_2n); | ||
return cached; | ||
}, | ||
}; |
@@ -29,3 +29,3 @@ /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
private static calcElligatorRistrettoMap; | ||
static fromRistrettoBytes(bytes: Hex): ExtendedPoint; | ||
static fromRistrettoBytes(hex: Hex): ExtendedPoint; | ||
toRistrettoBytes(): Uint8Array; | ||
@@ -55,3 +55,3 @@ equals(other: ExtendedPoint): boolean; | ||
toHex(): string; | ||
toX25519(): bigint; | ||
toX25519(): Uint8Array; | ||
equals(other: Point): boolean; | ||
@@ -73,2 +73,3 @@ negate(): Point; | ||
declare function bytesToHex(uint8a: Uint8Array): string; | ||
declare function mod(a: bigint, b?: bigint): bigint; | ||
declare function getExtendedPublicKey(key: PrivKey): Promise<{ | ||
@@ -79,3 +80,3 @@ head: Uint8Array; | ||
point: Point; | ||
pubBytes: Uint8Array; | ||
pointBytes: Uint8Array; | ||
}>; | ||
@@ -95,2 +96,3 @@ export declare function getPublicKey(privateKey: PrivKey): Promise<Uint8Array>; | ||
getExtendedPublicKey: typeof getExtendedPublicKey; | ||
mod: typeof mod; | ||
randomBytes: (bytesLength?: number) => Uint8Array; | ||
@@ -97,0 +99,0 @@ randomPrivateKey: () => Uint8Array; |
120
lib/index.js
@@ -52,4 +52,3 @@ "use strict"; | ||
static fromRistrettoHash(hash) { | ||
hash = ensureBytes(hash); | ||
assertLen(64, hash); | ||
hash = ensureBytes(hash, 64); | ||
const r1 = bytes255ToNumberLE(hash.slice(0, 32)); | ||
@@ -83,9 +82,8 @@ const R1 = this.calcElligatorRistrettoMap(r1); | ||
} | ||
static fromRistrettoBytes(bytes) { | ||
bytes = ensureBytes(bytes); | ||
assertLen(32, bytes); | ||
static fromRistrettoBytes(hex) { | ||
hex = ensureBytes(hex, 32); | ||
const { a, d } = CURVE; | ||
const emsg = 'ExtendedPoint.fromRistrettoBytes: Cannot convert bytes to Ristretto Point'; | ||
const s = bytes255ToNumberLE(bytes); | ||
if (!equalBytes(numberToBytesLEPadded(s, 32), bytes) || edIsNegative(s)) | ||
const s = bytes255ToNumberLE(hex); | ||
if (!equalBytes(numberToBytesLEPadded(s, 32), hex) || edIsNegative(s)) | ||
throw new Error(emsg); | ||
@@ -293,6 +291,5 @@ const s2 = mod(s * s); | ||
const { d, P } = CURVE; | ||
const bytes = ensureBytes(hex); | ||
assertLen(32, bytes); | ||
const normed = bytes.slice(); | ||
normed[31] = bytes[31] & ~0x80; | ||
hex = ensureBytes(hex, 32); | ||
const normed = hex.slice(); | ||
normed[31] = hex[31] & ~0x80; | ||
const y = bytesToNumberLE(normed); | ||
@@ -308,3 +305,3 @@ if (y >= P) | ||
const isXOdd = (x & _1n) === _1n; | ||
const isLastByteOdd = (bytes[31] & 0x80) !== 0; | ||
const isLastByteOdd = (hex[31] & 0x80) !== 0; | ||
if (isLastByteOdd !== isXOdd) { | ||
@@ -328,3 +325,4 @@ x = mod(-x); | ||
const { y } = this; | ||
return mod((_1n + y) * invert(_1n - y)); | ||
const u = mod((_1n + y) * invert(_1n - y)); | ||
return numberToBytesLEPadded(u, 32); | ||
} | ||
@@ -358,4 +356,3 @@ equals(other) { | ||
static fromHex(hex) { | ||
const bytes = ensureBytes(hex); | ||
assertLen(64, bytes); | ||
const bytes = ensureBytes(hex, 64); | ||
const r = Point.fromHex(bytes.slice(0, 32)); | ||
@@ -392,2 +389,4 @@ const s = bytesToNumberLE(bytes.slice(32, 64)); | ||
function bytesToHex(uint8a) { | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error('Uint8Array expected'); | ||
let hex = ''; | ||
@@ -410,3 +409,3 @@ for (let i = 0; i < uint8a.length; i++) { | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte)) | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
@@ -429,9 +428,4 @@ array[i] = byte; | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error(`bytesToNumberLE: expected Uint8Array, got ${uint8a}`); | ||
let value = _0n; | ||
const _8n = BigInt(8); | ||
for (let i = 0; i < uint8a.length; i++) { | ||
value += BigInt(uint8a[i]) << (_8n * BigInt(i)); | ||
} | ||
return value; | ||
throw new Error('Expected Uint8Array'); | ||
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a).reverse())); | ||
} | ||
@@ -553,51 +547,50 @@ function bytes255ToNumberLE(bytes) { | ||
} | ||
function ensureBytes(hash) { | ||
return hash instanceof Uint8Array ? Uint8Array.from(hash) : hexToBytes(hash); | ||
function ensureBytes(hex, expectedLength) { | ||
const bytes = hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex); | ||
if (typeof expectedLength === 'number' && bytes.length !== expectedLength) | ||
throw new Error(`Expected ${expectedLength} bytes`); | ||
return bytes; | ||
} | ||
function assertLen(len, bytes) { | ||
if (bytes.length !== len) | ||
throw new Error(`Expected ${len} bytes`); | ||
} | ||
function normalizeScalar(num, max = CURVE.n) { | ||
if (typeof num === 'number' && num > 0 && Number.isSafeInteger(num)) | ||
return BigInt(num); | ||
if (typeof num === 'bigint' && _0n < num && num < max) | ||
return num; | ||
if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0) | ||
return BigInt(num); | ||
throw new TypeError('Expected valid scalar: 0 < scalar < max'); | ||
} | ||
function normalizePrivateKey(key) { | ||
const bytes = typeof key === 'bigint' || typeof key === 'number' | ||
? numberToBytesBEPadded(normalizeScalar(key, _2n ** BigInt(256)), 32) | ||
: ensureBytes(key); | ||
assertLen(32, bytes); | ||
function adjustBytes25519(bytes) { | ||
bytes[0] &= 248; | ||
bytes[31] &= 127; | ||
bytes[31] |= 64; | ||
return bytes; | ||
} | ||
function decodeScalar25519(n) { | ||
n = ensureBytes(n); | ||
assertLen(32, n); | ||
n[0] &= 248; | ||
n[31] &= 127; | ||
n[31] |= 64; | ||
return bytesToNumberLE(n); | ||
return bytesToNumberLE(adjustBytes25519(ensureBytes(n, 32))); | ||
} | ||
async function getExtendedPublicKey(key) { | ||
const hashed = await exports.utils.sha512(normalizePrivateKey(key)); | ||
const head = hashed.slice(0, 32); | ||
key = | ||
typeof key === 'bigint' || typeof key === 'number' | ||
? numberToBytesBEPadded(normalizeScalar(key, _2n ** BigInt(256)), 32) | ||
: ensureBytes(key); | ||
if (key.length !== 32) | ||
throw new Error(`Expected 32 bytes`); | ||
const hashed = await exports.utils.sha512(key); | ||
const head = adjustBytes25519(hashed.slice(0, 32)); | ||
const prefix = hashed.slice(32, 64); | ||
const scalar = mod(decodeScalar25519(head), CURVE.n); | ||
const scalar = mod(bytesToNumberLE(head), CURVE.n); | ||
const point = Point.BASE.multiply(scalar); | ||
const pubBytes = point.toRawBytes(); | ||
return { head, prefix, scalar, point, pubBytes }; | ||
const pointBytes = point.toRawBytes(); | ||
return { head, prefix, scalar, point, pointBytes }; | ||
} | ||
async function getPublicKey(privateKey) { | ||
return (await getExtendedPublicKey(privateKey)).pubBytes; | ||
return (await getExtendedPublicKey(privateKey)).pointBytes; | ||
} | ||
exports.getPublicKey = getPublicKey; | ||
async function sign(message, privateKey) { | ||
const msg = ensureBytes(message); | ||
const { prefix, scalar: p, pubBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModnLE(prefix, msg); | ||
message = ensureBytes(message); | ||
const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey); | ||
const r = await sha512ModnLE(prefix, message); | ||
const R = Point.BASE.multiply(r); | ||
const k = await sha512ModnLE(R.toRawBytes(), pubBytes, msg); | ||
const S = mod(r + k * p, CURVE.n); | ||
const k = await sha512ModnLE(R.toRawBytes(), pointBytes, message); | ||
const S = mod(r + k * scalar, CURVE.n); | ||
return new Signature(R, S).toRawBytes(); | ||
@@ -620,5 +613,5 @@ } | ||
async function getSharedSecret(privateKey, publicKey) { | ||
const { scalar: p } = await getExtendedPublicKey(privateKey); | ||
const { head } = await getExtendedPublicKey(privateKey); | ||
const u = Point.fromHex(publicKey).toX25519(); | ||
return montgomeryLadderChecked(p, u); | ||
return exports.curve25519.scalarMult(head, u); | ||
} | ||
@@ -682,11 +675,4 @@ exports.getSharedSecret = getSharedSecret; | ||
} | ||
function montgomeryLadderChecked(u, p) { | ||
const pu = montgomeryLadder(u, p); | ||
if (pu === _0n) | ||
throw new Error('Invalid private or public key received'); | ||
return encodeUCoordinate(pu); | ||
} | ||
function decodeUCoordinate(uEnc) { | ||
const u = ensureBytes(uEnc); | ||
assertLen(32, u); | ||
const u = ensureBytes(uEnc, 32); | ||
u[31] &= 127; | ||
@@ -700,3 +686,6 @@ return bytesToNumberLE(u); | ||
const p = decodeScalar25519(privateKey); | ||
return montgomeryLadderChecked(u, p); | ||
const pu = montgomeryLadder(u, p); | ||
if (pu === _0n) | ||
throw new Error('Invalid private or public key received'); | ||
return encodeUCoordinate(pu); | ||
}, | ||
@@ -724,2 +713,3 @@ scalarMultBase(privateKey) { | ||
getExtendedPublicKey, | ||
mod, | ||
randomBytes: (bytesLength = 32) => { | ||
@@ -755,5 +745,5 @@ if (crypto.web) { | ||
cached._setWindowSize(windowSize); | ||
cached.multiply(_1n); | ||
cached.multiply(_2n); | ||
return cached; | ||
}, | ||
}; |
{ | ||
"name": "@noble/ed25519", | ||
"version": "1.5.1", | ||
"version": "1.5.2", | ||
"description": "Fastest JS implementation of ed25519 & ristretto255. Auditable, high-security, 0-dependency EDDSA, X25519 ECDH & scalarmult", | ||
@@ -5,0 +5,0 @@ "files": [ |
@@ -81,3 +81,4 @@ # 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) | ||
``` | ||
- `privateKey: Uint8Array | string | bigint` will be used to generate public key. | ||
- `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`. | ||
@@ -205,3 +206,3 @@ | ||
static fromPrivateKey(privateKey: string | Uint8Array); | ||
toX25519(): bigint; // Converts to Curve25519 u coordinate | ||
toX25519(): Uint8Array; // Converts to Curve25519 u coordinate in LE form | ||
toRawBytes(): Uint8Array; | ||
@@ -231,3 +232,3 @@ toHex(): string; // Compact representation of a Point | ||
utils.precompute(W, point); | ||
// returns { head, prefix, scalar, point, pubBytes } | ||
// returns { head, prefix, scalar, point, pointBytes } | ||
utils.getExtendedPublicKey(privateKey); | ||
@@ -255,11 +256,11 @@ ``` | ||
``` | ||
getPublicKey(utils.randomPrivateKey()) x 6,790 ops/sec @ 147μs/op | ||
sign x 3,276 ops/sec @ 305μs/op | ||
getPublicKey(utils.randomPrivateKey()) x 6,835 ops/sec @ 146μs/op | ||
sign x 3,474 ops/sec @ 287μs/op | ||
verify x 726 ops/sec @ 1ms/op | ||
verifyBatch x 842 ops/sec @ 1ms/op | ||
Point.fromHex decompression x 11,332 ops/sec @ 88μs/op | ||
ristretto255#fromHash x 5,428 ops/sec @ 184μs/op | ||
ristretto255 round x 5,467 ops/sec @ 182μs/op | ||
getSharedSecret x 778 ops/sec @ 1285μs/op | ||
curve25519.scalarMultBase x 1,010 ops/sec @ 989μs/op | ||
verifyBatch x 888 ops/sec @ 1ms/op | ||
Point.fromHex decompression x 11,783 ops/sec @ 84μs/op | ||
ristretto255#fromHash x 5,482 ops/sec @ 182μs/op | ||
ristretto255 round x 5,621 ops/sec @ 177μs/op | ||
curve25519.scalarMultBase x 1,042 ops/sec @ 959μs/op | ||
ed25519.getSharedSecret x 801 ops/sec @ 1ms/op | ||
``` | ||
@@ -266,0 +267,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
68382
288
1553