noble-secp256k1
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -12,10 +12,8 @@ /*! noble-secp256k1 - MIT License (c) Paul Miller (paulmillr.com) */ | ||
constructor(x: bigint, y: bigint); | ||
static isValidPoint(x: bigint, y: bigint): boolean; | ||
private static fromCompressedHex; | ||
private static isValidPoint; | ||
private static fromUncompressedHex; | ||
static fromHex(hash: Hex): Point; | ||
static fromPrivateKey(privateKey: PrivKey): Point; | ||
static fromSignature(hash: Hex, signature: Signature, recovery: number | bigint): Point | undefined; | ||
private uncompressedHex; | ||
private compressedHex; | ||
static fromSignature(hash: Hex, signature: Signature, recovery: number): Point | undefined; | ||
toRawBytes(isCompressed?: boolean): Uint8Array; | ||
@@ -25,3 +23,3 @@ toHex(isCompressed?: boolean): string; | ||
private double; | ||
multiply(scalar: number | bigint | Uint8Array): Point; | ||
multiply(scalar: number | bigint): Point; | ||
} | ||
@@ -33,23 +31,26 @@ export declare class SignResult { | ||
static fromHex(hex: Hex): SignResult; | ||
private formatLength; | ||
private formatNumberToHex; | ||
toHex(): string; | ||
toHex(compressed?: boolean): string; | ||
} | ||
export declare const BASE_POINT: Point; | ||
export declare function recoverPublicKey(hash: Hex, signature: Signature, recovery: number | bigint): Uint8Array | undefined; | ||
export declare function recoverPublicKey(hash: Hex, signature: Signature, recovery: number): Uint8Array | undefined; | ||
export declare function getPublicKey(privateKey: Uint8Array | bigint | number, isCompressed?: boolean): Uint8Array; | ||
export declare function getPublicKey(privateKey: string, isCompressed?: boolean): string; | ||
export declare function getSharedSecret(privateA: PrivKey, publicB: PubKey): Uint8Array; | ||
declare type Options = { | ||
declare type OptsRecovered = { | ||
recovered: true; | ||
canonical?: true; | ||
k?: number | bigint; | ||
}; | ||
declare type OptionsWithK = Partial<Options>; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts: Options): [string, bigint]; | ||
export declare function sign(hash: Uint8Array, privateKey: PrivKey, opts: Options): [Uint8Array, bigint]; | ||
export declare function sign(hash: Uint8Array, privateKey: PrivKey, opts?: OptionsWithK): Uint8Array; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts?: OptionsWithK): string; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts?: OptionsWithK): string; | ||
declare type OptsNoRecovered = { | ||
recovered?: false; | ||
canonical?: true; | ||
}; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts: OptsRecovered): Promise<[string, number]>; | ||
export declare function sign(hash: Uint8Array, privateKey: PrivKey, opts: OptsRecovered): Promise<[Uint8Array, number]>; | ||
export declare function sign(hash: Uint8Array, privateKey: PrivKey, opts?: OptsNoRecovered): Promise<Uint8Array>; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts?: OptsNoRecovered): Promise<string>; | ||
export declare function sign(hash: string, privateKey: PrivKey, opts?: OptsNoRecovered): Promise<string>; | ||
export declare function verify(signature: Signature, hash: Hex, publicKey: PubKey): boolean; | ||
export declare const utils: { | ||
isValidPrivateKey(privateKey: PrivKey): boolean; | ||
}; | ||
export {}; |
326
index.js
@@ -16,14 +16,5 @@ "use strict"; | ||
} | ||
static fromCompressedHex(bytes) { | ||
const x = arrayToNumber(bytes.slice(1)); | ||
const sqrY = mod(x ** 3n + A * x + B, exports.P); | ||
let y = powMod(sqrY, (exports.P + 1n) / 4n, exports.P); | ||
const isFirstByteOdd = (bytes[0] & 1) === 1; | ||
const isYOdd = (y & 1n) === 1n; | ||
if (isFirstByteOdd !== isYOdd) { | ||
y = mod(-y, exports.P); | ||
} | ||
return new Point(x, y); | ||
} | ||
static isValidPoint(x, y) { | ||
if (x === 0n || y === 0n || x >= exports.P || y >= exports.P) | ||
return false; | ||
const sqrY = y * y; | ||
@@ -40,7 +31,27 @@ const yEquivalence = x ** 3n + A * x + B; | ||
} | ||
static fromCompressedHex(bytes) { | ||
if (bytes.length !== 33) { | ||
throw new TypeError(`Point.fromHex: compressed expects 66 bytes, not ${bytes.length * 2}`); | ||
} | ||
const x = arrayToNumber(bytes.slice(1)); | ||
const sqrY = mod(x ** 3n + A * x + B, exports.P); | ||
let y = powMod(sqrY, (exports.P + 1n) / 4n, exports.P); | ||
const isFirstByteOdd = (bytes[0] & 1) === 1; | ||
const isYOdd = (y & 1n) === 1n; | ||
if (isFirstByteOdd !== isYOdd) { | ||
y = mod(-y, exports.P); | ||
} | ||
if (!Point.isValidPoint(x, y)) { | ||
throw new TypeError('Point.fromHex: Point is not on elliptic curve'); | ||
} | ||
return new Point(x, y); | ||
} | ||
static fromUncompressedHex(bytes) { | ||
if (bytes.length !== 65) { | ||
throw new TypeError(`Point.fromHex: uncompressed expects 130 bytes, not ${bytes.length * 2}`); | ||
} | ||
const x = arrayToNumber(bytes.slice(1, 33)); | ||
const y = arrayToNumber(bytes.slice(33)); | ||
if (!this.isValidPoint(x, y)) { | ||
throw new Error("secp256k1: Point is not on elliptic curve"); | ||
throw new TypeError('Point.fromHex: Point is not on elliptic curve'); | ||
} | ||
@@ -51,5 +62,8 @@ return new Point(x, y); | ||
const bytes = hash instanceof Uint8Array ? hash : hexToArray(hash); | ||
return bytes[0] === 0x4 | ||
? this.fromUncompressedHex(bytes) | ||
: this.fromCompressedHex(bytes); | ||
const header = bytes[0]; | ||
if (header === 0x02 || header === 0x03) | ||
return this.fromCompressedHex(bytes); | ||
if (header === 0x04) | ||
return this.fromUncompressedHex(bytes); | ||
throw new TypeError('Point.fromHex: received invalid point'); | ||
} | ||
@@ -60,5 +74,5 @@ static fromPrivateKey(privateKey) { | ||
static fromSignature(hash, signature, recovery) { | ||
recovery = BigInt(recovery); | ||
recovery = Number(recovery); | ||
const sign = normalizeSignature(signature); | ||
const message = truncateHash(typeof hash === "string" ? hexToArray(hash) : hash); | ||
const message = truncateHash(typeof hash === 'string' ? hexToArray(hash) : hash); | ||
if (sign.r === 0n || sign.s === 0n) { | ||
@@ -68,3 +82,3 @@ return; | ||
let publicKeyX = sign.r; | ||
if (recovery >> 1n) { | ||
if (recovery >> 1) { | ||
if (publicKeyX >= SUBPN) { | ||
@@ -75,3 +89,3 @@ return; | ||
} | ||
const compresedHex = `$0{2n + (recovery & 1n)}${publicKeyX.toString(16)}`; | ||
const compresedHex = `0${2 + (recovery & 1)}${pad64(publicKeyX)}`; | ||
const publicKey = Point.fromHex(compresedHex); | ||
@@ -85,20 +99,18 @@ const rInv = modInverse(sign.r, exports.PRIME_ORDER); | ||
} | ||
uncompressedHex() { | ||
const yHex = this.y.toString(16).padStart(64, "0"); | ||
const xHex = this.x.toString(16).padStart(64, "0"); | ||
return `04${xHex}${yHex}`; | ||
} | ||
compressedHex() { | ||
let hex = this.x.toString(16).padStart(64, "0"); | ||
const head = this.y & 1n ? "03" : "02"; | ||
return `${head}${hex}`; | ||
} | ||
toRawBytes(isCompressed = false) { | ||
const hex = this.toHex(isCompressed); | ||
return hexToArray(hex); | ||
return hexToArray(this.toHex(isCompressed)); | ||
} | ||
toHex(isCompressed = false) { | ||
return isCompressed ? this.compressedHex() : this.uncompressedHex(); | ||
const x = pad64(this.x); | ||
if (isCompressed) { | ||
return `${this.y & 1n ? '03' : '02'}${x}`; | ||
} | ||
else { | ||
return `04${x}${pad64(this.y)}`; | ||
} | ||
} | ||
add(other) { | ||
if (!(other instanceof Point)) { | ||
throw new TypeError('Point#add: expected Point'); | ||
} | ||
const a = this; | ||
@@ -112,5 +124,13 @@ const b = other; | ||
} | ||
if (a.x === b.y && a.y == -b.y) { | ||
if (a.x === b.y && a.y === -b.y) { | ||
return new Point(0n, 0n); | ||
} | ||
if (a.x === b.x) { | ||
if (a.y === b.y) { | ||
return this.double(); | ||
} | ||
else { | ||
throw new TypeError('Point#add: cannot add points (a.x == b.x, a.y != b.y)'); | ||
} | ||
} | ||
const lamAdd = mod((b.y - a.y) * modInverse(b.x - a.x, exports.P), exports.P); | ||
@@ -129,4 +149,9 @@ const x = mod(lamAdd * lamAdd - a.x - b.x, exports.P); | ||
multiply(scalar) { | ||
let n = scalar instanceof Uint8Array ? | ||
arrayToNumber(scalar) : BigInt(scalar); | ||
if (typeof scalar !== 'number' && typeof scalar !== 'bigint') { | ||
throw new TypeError('Point#multiply: expected number or bigint'); | ||
} | ||
let n = BigInt(scalar); | ||
if (!isValidPrivateKey(n)) { | ||
throw new Error('Private key is invalid. Expected 0 < key < PRIME_ORDER'); | ||
} | ||
let Q = new Point(0n, 0n); | ||
@@ -153,2 +178,5 @@ let F = new Point(this.x, this.y); | ||
exports.Point = Point; | ||
function parseByte(str) { | ||
return Number.parseInt(str, 16) * 2; | ||
} | ||
class SignResult { | ||
@@ -160,21 +188,31 @@ constructor(r, s) { | ||
static fromHex(hex) { | ||
const hash = hex instanceof Uint8Array ? arrayToHex(hex) : hex; | ||
const rLength = parseInt(`${hash[6]}${hash[7]}`, 16) * 2; | ||
const r = BigInt(`0x${hash.substr(8, rLength)}`); | ||
const s = BigInt(`0x${hash.slice(12 + rLength)}`); | ||
const str = hex instanceof Uint8Array ? arrayToHex(hex) : hex; | ||
if (typeof str !== 'string') | ||
throw new TypeError({}.toString.call(hex)); | ||
const check1 = str.slice(0, 2); | ||
const length = parseByte(str.slice(2, 4)); | ||
const check2 = str.slice(4, 6); | ||
if (check1 !== '30' || length !== str.length - 4 || check2 !== '02') { | ||
throw new Error('SignResult.fromHex: Invalid signature'); | ||
} | ||
const rLen = parseByte(str.slice(6, 8)); | ||
const rEnd = 8 + rLen; | ||
const r = hexToNumber(str.slice(8, rEnd)); | ||
const check3 = str.slice(rEnd, rEnd + 2); | ||
if (check3 !== '02') { | ||
throw new Error('SignResult.fromHex: Invalid signature'); | ||
} | ||
const sLen = parseByte(str.slice(rEnd + 2, rEnd + 4)); | ||
const sStart = rEnd + 4; | ||
const s = hexToNumber(str.slice(sStart, sStart + sLen)); | ||
return new SignResult(r, s); | ||
} | ||
formatLength(hex) { | ||
return (hex.length / 2).toString(16).padStart(2, "0"); | ||
} | ||
formatNumberToHex(num) { | ||
const res = num.toString(16); | ||
return res.length & 1 ? `0${res}` : res; | ||
} | ||
toHex() { | ||
const rHex = `00${this.formatNumberToHex(this.r)}`; | ||
const sHex = this.formatNumberToHex(this.s); | ||
const rLen = this.formatLength(rHex); | ||
const sLen = this.formatLength(sHex); | ||
const length = this.formatNumberToHex(rHex.length / 2 + sHex.length / 2 + 4); | ||
toHex(compressed = false) { | ||
const rHex = numberToHex(this.r); | ||
const sHex = numberToHex(this.s); | ||
if (compressed) | ||
return sHex; | ||
const rLen = numberToHex(rHex.length / 2); | ||
const sLen = numberToHex(sHex.length / 2); | ||
const length = numberToHex(rHex.length / 2 + sHex.length / 2 + 4); | ||
return `30${length}02${rLen}${rHex}02${sLen}${sHex}`; | ||
@@ -185,24 +223,22 @@ } | ||
exports.BASE_POINT = new Point(55066263022277343669578718895168534326250603453777594175500187360389116729240n, 32670510020758816978083085130507043184471273380659243275938904335757337482424n); | ||
let secureRandom = (bytesLength) => new Uint8Array(bytesLength); | ||
if (typeof window == "object" && "crypto" in window) { | ||
secureRandom = (bytesLength) => { | ||
const array = new Uint8Array(bytesLength); | ||
window.crypto.getRandomValues(array); | ||
return array; | ||
let hmac; | ||
if (typeof window == 'object' && 'crypto' in window) { | ||
hmac = async (key, message) => { | ||
const ckey = await window.crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign', 'verify']); | ||
const buffer = await window.crypto.subtle.sign('HMAC', ckey, message); | ||
return new Uint8Array(buffer); | ||
}; | ||
} | ||
else if (typeof process === "object" && "node" in process.versions) { | ||
else if (typeof process === 'object' && 'node' in process.versions) { | ||
const req = require; | ||
const { randomBytes } = req("crypto"); | ||
secureRandom = (bytesLength) => { | ||
const b = randomBytes(bytesLength); | ||
return new Uint8Array(b.buffer, b.byteOffset, b.byteLength); | ||
const { createHmac } = req('crypto'); | ||
hmac = async (key, message) => { | ||
const hash = createHmac('sha256', key); | ||
hash.update(message); | ||
return Uint8Array.from(hash.digest()); | ||
}; | ||
} | ||
else { | ||
throw new Error("The environment doesn't have cryptographically secure random function"); | ||
throw new Error("The environment doesn't have hmac-sha256 function"); | ||
} | ||
function getRandomValue(bytesLength) { | ||
return arrayLEToNumber(secureRandom(bytesLength)); | ||
} | ||
function powMod(x, power, order) { | ||
@@ -220,32 +256,33 @@ let res = 1n; | ||
function arrayToHex(uint8a) { | ||
return Array.from(uint8a) | ||
.map(c => c.toString(16).padStart(2, "0")) | ||
.join(""); | ||
} | ||
function hexToArray(hash) { | ||
hash = hash.length & 1 ? `0${hash}` : hash; | ||
const len = hash.length; | ||
const result = new Uint8Array(len / 2); | ||
for (let i = 0, j = 0; i < len - 1; i += 2, j++) { | ||
result[j] = parseInt(hash[i] + hash[i + 1], 16); | ||
let hex = ''; | ||
for (let i = 0; i < uint8a.length; i++) { | ||
hex += uint8a[i].toString(16).padStart(2, '0'); | ||
} | ||
return result; | ||
return hex; | ||
} | ||
function numberToHex(num) { | ||
const hex = num.toString(16); | ||
return hex.length & 1 ? `0${hex}` : hex; | ||
} | ||
function hexToNumber(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex); | ||
} | ||
return BigInt(`0x${hex}`); | ||
} | ||
function arrayToNumber(bytes) { | ||
let value = 0n; | ||
for (let i = bytes.length - 1, j = 0; i >= 0; i--, j++) { | ||
value += (BigInt(bytes[i]) & 255n) << (8n * BigInt(j)); | ||
function hexToArray(hex) { | ||
hex = hex.length & 1 ? `0${hex}` : hex; | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
let j = i * 2; | ||
array[i] = Number.parseInt(hex.slice(j, j + 2), 16); | ||
} | ||
return value; | ||
return array; | ||
} | ||
function arrayLEToNumber(bytes) { | ||
let value = 0n; | ||
for (let i = 0; i < bytes.length; i++) { | ||
value += (BigInt(bytes[i]) & 255n) << (8n * BigInt(i)); | ||
} | ||
return value; | ||
function arrayToNumber(bytes) { | ||
return hexToNumber(arrayToHex(bytes)); | ||
} | ||
function pad64(num) { | ||
return num.toString(16).padStart(64, '0'); | ||
} | ||
function mod(a, b) { | ||
@@ -275,4 +312,4 @@ const result = a % b; | ||
function truncateHash(hash) { | ||
hash = typeof hash === "string" ? hash : arrayToHex(hash); | ||
let msg = BigInt(`0x${hash || "0"}`); | ||
hash = typeof hash === 'string' ? hash : arrayToHex(hash); | ||
let msg = hexToNumber(hash || '0'); | ||
const delta = (hash.length / 2) * 8 - PRIME_SIZE; | ||
@@ -287,22 +324,60 @@ if (delta > 0) { | ||
} | ||
function isValidPrivateKey(privateKey) { | ||
if (privateKey instanceof Uint8Array) { | ||
return privateKey.length <= 32; | ||
function concatTypedArrays(...args) { | ||
const result = new Uint8Array(args.reduce((a, arr) => a + arr.length, 0)); | ||
for (let i = 0, pad = 0; i < args.length; i++) { | ||
const arr = args[i]; | ||
result.set(arr, pad); | ||
pad += arr.length; | ||
} | ||
if (typeof privateKey === "string") { | ||
return /^[0-9a-f]{0,64}$/i.test(privateKey); | ||
return result; | ||
} | ||
async function getQRSrfc6979(hash, privateKey) { | ||
const num = typeof hash === 'string' ? hexToNumber(hash) : arrayToNumber(hash); | ||
const h1 = hexToArray(pad64(num)); | ||
const x = hexToArray(pad64(privateKey)); | ||
const h1n = arrayToNumber(h1); | ||
let v = new Uint8Array(32).fill(1); | ||
let k = new Uint8Array(32).fill(0); | ||
const b0 = Uint8Array.from([0x00]); | ||
const b1 = Uint8Array.from([0x01]); | ||
const concat = concatTypedArrays; | ||
k = await hmac(k, concat(v, b0, x, h1)); | ||
v = await hmac(k, v); | ||
k = await hmac(k, concat(v, b1, x, h1)); | ||
v = await hmac(k, v); | ||
for (let i = 0; i < 1000; i++) { | ||
v = await hmac(k, v); | ||
const T = arrayToNumber(v); | ||
let qrs; | ||
if (isValidPrivateKey(T) && (qrs = calcQRSFromK(T, h1n, privateKey))) { | ||
return qrs; | ||
} | ||
k = await hmac(k, concat(v, b0)); | ||
v = await hmac(k, v); | ||
} | ||
return privateKey.toString(16).length <= 64; | ||
throw new TypeError('secp256k1: Tried 1,000 k values for sign(), all were invalid'); | ||
} | ||
function isValidPrivateKey(privateKey) { | ||
return 0 < privateKey && privateKey < exports.PRIME_ORDER; | ||
} | ||
function calcQRSFromK(k, msg, priv) { | ||
const q = exports.BASE_POINT.multiply(k); | ||
const r = mod(q.x, exports.PRIME_ORDER); | ||
const s = mod(modInverse(k, exports.PRIME_ORDER) * (msg + r * priv), exports.PRIME_ORDER); | ||
if (r === 0n || s === 0n) | ||
return; | ||
return [q, r, s]; | ||
} | ||
function normalizePrivateKey(privateKey) { | ||
if (!isValidPrivateKey(privateKey)) { | ||
throw new Error("Private key is invalid. It should be less than 257 bit or contain valid hex string"); | ||
} | ||
let key; | ||
if (privateKey instanceof Uint8Array) { | ||
return arrayToNumber(privateKey); | ||
key = arrayToNumber(privateKey); | ||
} | ||
if (typeof privateKey === "string") { | ||
return hexToNumber(privateKey); | ||
else if (typeof privateKey === 'string') { | ||
key = hexToNumber(privateKey); | ||
} | ||
return BigInt(privateKey); | ||
else { | ||
key = BigInt(privateKey); | ||
} | ||
return key; | ||
} | ||
@@ -313,5 +388,3 @@ function normalizePublicKey(publicKey) { | ||
function normalizeSignature(signature) { | ||
return signature instanceof SignResult | ||
? signature | ||
: SignResult.fromHex(signature); | ||
return signature instanceof SignResult ? signature : SignResult.fromHex(signature); | ||
} | ||
@@ -325,3 +398,3 @@ function recoverPublicKey(hash, signature, recovery) { | ||
const point = Point.fromPrivateKey(privateKey); | ||
if (typeof privateKey === "string") { | ||
if (typeof privateKey === 'string') { | ||
return point.toHex(isCompressed); | ||
@@ -337,15 +410,15 @@ } | ||
exports.getSharedSecret = getSharedSecret; | ||
function sign(hash, privateKey, { k = getRandomValue(5), recovered, canonical } = {}) { | ||
const number = normalizePrivateKey(privateKey); | ||
k = BigInt(k); | ||
const message = truncateHash(hash); | ||
const q = exports.BASE_POINT.multiply(k); | ||
const r = mod(q.x, exports.PRIME_ORDER); | ||
let s = mod(modInverse(k, exports.PRIME_ORDER) * (message + r * number), exports.PRIME_ORDER); | ||
let recovery = (q.x === r ? 0n : 2n) | (q.y & 1n); | ||
async function sign(hash, privateKey, { recovered, canonical } = {}) { | ||
const priv = normalizePrivateKey(privateKey); | ||
if (!isValidPrivateKey(priv)) { | ||
throw new Error('Private key is invalid. Expected 0 < key < PRIME_ORDER'); | ||
} | ||
const [q, r, s] = await getQRSrfc6979(hash, priv); | ||
let recovery = (q.x === r ? 0 : 2) | Number(q.y & 1n); | ||
let adjustedS = s; | ||
if (s > HIGH_NUMBER && canonical) { | ||
s = exports.PRIME_ORDER - s; | ||
recovery ^= 1n; | ||
adjustedS = exports.PRIME_ORDER - s; | ||
recovery ^= 1; | ||
} | ||
const res = new SignResult(r, s).toHex(); | ||
const res = new SignResult(r, adjustedS).toHex(); | ||
const hashed = hash instanceof Uint8Array ? hexToArray(res) : res; | ||
@@ -356,11 +429,16 @@ return recovered ? [hashed, recovery] : hashed; | ||
function verify(signature, hash, publicKey) { | ||
const message = truncateHash(hash); | ||
const msg = truncateHash(hash); | ||
const sign = normalizeSignature(signature); | ||
const point = normalizePublicKey(publicKey); | ||
const sign = normalizeSignature(signature); | ||
const w = modInverse(sign.s, exports.PRIME_ORDER); | ||
const point1 = exports.BASE_POINT.multiply(mod(message * w, exports.PRIME_ORDER)); | ||
const point1 = exports.BASE_POINT.multiply(mod(msg * w, exports.PRIME_ORDER)); | ||
const point2 = point.multiply(mod(sign.r * w, exports.PRIME_ORDER)); | ||
const { x } = point1.add(point2); | ||
return x === sign.r; | ||
const point3 = point1.add(point2); | ||
return point3.x === sign.r; | ||
} | ||
exports.verify = verify; | ||
exports.utils = { | ||
isValidPrivateKey(privateKey) { | ||
return isValidPrivateKey(normalizePrivateKey(privateKey)); | ||
} | ||
}; |
{ | ||
"name": "noble-secp256k1", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"description": "Noble secp256k1. High-security, easily auditable, 0-dep, 1-file pubkey & ECDSA.", | ||
@@ -15,3 +15,3 @@ "main": "index.js", | ||
"jest": { | ||
"testRegex": "/.*?\\.test.ts", | ||
"testRegex": "/test/.*?\\.ts", | ||
"transform": { | ||
@@ -34,3 +34,3 @@ "^.+\\.ts$": "ts-jest" | ||
"ts-jest": "^25.2.0", | ||
"typescript": "^3.7.5" | ||
"typescript": "3.8.3" | ||
}, | ||
@@ -37,0 +37,0 @@ "keywords": [ |
@@ -5,3 +5,3 @@ # noble-secp256k1 | ||
Algorithmically resistant to timing attacks. | ||
Algorithmically resistant to timing attacks. With tens of thousands test vectors. | ||
@@ -76,11 +76,15 @@ ### This library belongs to *noble* crypto | ||
```typescript | ||
function sign(hash: Uint8Array, privateKey: Uint8Array | bigint, opts?: Options): Uint8Array; | ||
function sign(hash: string, privateKey: string | bigint, opts?: Options): string; | ||
function sign(hash: Uint8Array, privateKey: Uint8Array | bigint, opts?: Options): Promise<Uint8Array>; | ||
function sign(hash: string, privateKey: string | bigint, opts?: Options): Promise<string>; | ||
function sign(hash: Uint8Array, privateKey: Uint8Array | bigint, opts?: Options): Promise<[Uint8Array | string, number]>; | ||
``` | ||
Generates deterministic ECDSA signature as per RFC 6979. Asynchronous, so use `await`. | ||
- `hash: Uint8Array | string` - message hash which would be signed | ||
- `privateKey: Uint8Array | string | bigint` - private key which will sign the hash | ||
- `options?: Options` - *optional* object related to signature value and format | ||
- `options?.k: number | bigint` - random seed. Default is one from `crypto.getRandomValues()`. **Must be cryptographically secure**, which means `Math.random()` won't work. | ||
- `options?.recovered: boolean` - determines whether the recovered bit should be included in the result. In this case, the result would be an array of two items. | ||
- `options?.canonical: boolean` - determines whether a signature `s` should be sorted by half prime order | ||
- `options?.recovered: boolean = false` - determines whether the recovered bit should be included in the result. In this case, the result would be an array of two items. | ||
- `options?.canonical: boolean = false` - determines whether a signature `s` should be no more than 1/2 prime order | ||
- Returns DER encoded ECDSA signature, as hex uint8a / string and recovered bit if `options.recovered == true`. | ||
@@ -144,8 +148,13 @@ | ||
static fromHex(hex: Uint8Array | string); | ||
toHex() | ||
toHex(): string; | ||
} | ||
``` | ||
There is an option to have 2x speed-up by precomputing powers of two. Use `generate-precomputes` script & include the result in index.ts. | ||
## Contributing | ||
1. Clone the repository. | ||
2. `npm install` to install build dependencies like TypeScript | ||
3. `npm run compile` to compile TypeScript code | ||
4. `npm run test` to run jest on `test/index.ts` | ||
## Security | ||
@@ -152,0 +161,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
27527
478
172