/*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
-import { Point, Signature, getPublicKey, hashes } from "@noble/secp256k1"
-import { randomBytes } from "crypto"
-import { _verify } from "../wallet/verify"
-
/**
* 5KB JS implementation of secp256k1 ECDSA / Schnorr signatures & ECDH.
* Compliant with RFC6979 & BIP340.
return Secp256k1.secp256k1_CURVE
}
/** Create 3d xyz point from 2d xy. (0, 0) => (0, 1, 0), not (0, 0, 1) */
- static fromAffine (ap: AffinePoint): Point {
+ static fromAffine (ap: AffinePoint): Secp256k1['Point'] {
const { x, y } = ap
return x === 0n && y === 0n ? Secp256k1.I : new Secp256k1.Point(x, y, 1n)
}
/** Convert Uint8Array or hex string to Point. */
- static fromBytes (bytes: Bytes): Point {
+ static fromBytes (bytes: Bytes): Secp256k1['Point'] {
Secp256k1.abytes(bytes)
const { publicKey: comp, publicKeyUncompressed: uncomp } = Secp256k1.lengths // e.g. for 32-byte: 33, 65
- let p: Point | undefined = undefined
+ let p: Secp256k1['Point'] | undefined = undefined
const length = bytes.length
const head = bytes[0]
const tail = bytes.subarray(1)
const evenY = Secp256k1.isEven(y)
const evenH = Secp256k1.isEven(Secp256k1.big(head))
if (evenH !== evenY) y = Secp256k1.M(-y)
- p = new Point(x, y, 1n)
+ p = new this(x, y, 1n)
}
// Uncompressed 65-byte point, 0x04 prefix
- if (length === uncomp && head === 0x04) p = new Point(x, Secp256k1.sliceBytesNumBE(tail, Secp256k1.L, Secp256k1.L2), 1n)
+ if (length === uncomp && head === 0x04) p = new this(x, Secp256k1.sliceBytesNumBE(tail, Secp256k1.L, Secp256k1.L2), 1n)
// Validate point
return p ? p.assertValidity() : Secp256k1.err('bad point: not on curve')
}
- static fromHex (hex: string): Point {
+ static fromHex (hex: string): Secp256k1['Point'] {
return Secp256k1.Point.fromBytes(Secp256k1.hexToBytes(hex))
}
get x (): bigint {
return this.toAffine().y
}
/** Equality check: compare points P&Q. */
- equals (other: Point): boolean {
+ equals (other: Secp256k1['Point']): boolean {
const { X: X1, Y: Y1, Z: Z1 } = this
const { X: X2, Y: Y2, Z: Z2 } = Secp256k1.apoint(other) // checks class equality
const X1Z2 = Secp256k1.M(X1 * Z2)
return this.equals(Secp256k1.I)
}
/** Flip point over y coordinate. */
- negate (): Point {
- return new Point(this.X, Secp256k1.M(-this.Y), this.Z)
+ negate (): Secp256k1['Point'] {
+ return new Secp256k1.Point(this.X, Secp256k1.M(-this.Y), this.Z)
}
/** Point doubling: P+P, complete formula. */
- double (): Point {
+ double (): Secp256k1['Point'] {
return this.add(this)
}
/**
* Cost: `12M + 0S + 3*a + 3*b3 + 23add`.
*/
// prettier-ignore
- add (other: Point): Point {
+ add (other: Secp256k1['Point']): Secp256k1['Point'] {
const { X: X1, Y: Y1, Z: Z1 } = this
const { X: X2, Y: Y2, Z: Z2 } = Secp256k1.apoint(other)
const a = 0n
t0 = Secp256k1.M(t5 * t4) // step 35
X3 = Secp256k1.M(t3 * X3); X3 = Secp256k1.M(X3 - t0); t0 = Secp256k1.M(t3 * t1); Z3 = Secp256k1.M(t5 * Z3)
Z3 = Secp256k1.M(Z3 + t0) // step 40
- return new Point(X3, Y3, Z3)
+ return new Secp256k1.Point(X3, Y3, Z3)
}
- subtract (other: Point): Point {
+ subtract (other: Secp256k1['Point']): Secp256k1['Point'] {
return this.add(Secp256k1.apoint(other).negate())
}
/**
* @param n scalar by which point is multiplied
* @param safe safe mode guards against timing attacks; unsafe mode is faster
*/
- multiply (n: bigint, safe = true): Point {
+ multiply (n: bigint, safe = true): Secp256k1['Point'] {
if (!safe && n === 0n) return Secp256k1.I
Secp256k1.FnIsValidNot0(n)
if (n === 1n) return this
- if (this.equals(Secp256k1.G)) return wNAF(n).p
+ if (this.equals(Secp256k1.G)) return Secp256k1.wNAF(n).p
// init result point & fake point
let p = Secp256k1.I
let f = Secp256k1.G
- for (let d: Point = this; n > 0n; d = d.double(), n >>= 1n) {
+ for (let d: Secp256k1['Point'] = this; n > 0n; d = d.double(), n >>= 1n) {
// if bit is present, add to point
// if not present, add to fake, for timing safety
if (n & 1n) p = p.add(d)
}
return p
}
- multiplyUnsafe (scalar: bigint): Point {
+ multiplyUnsafe (scalar: bigint): Secp256k1['Point'] {
return this.multiply(scalar, false)
}
/** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
return { x: Secp256k1.M(x * iz), y: Secp256k1.M(y * iz) }
}
/** Checks if the point is valid and on-curve. */
- assertValidity (): Point {
+ assertValidity (): Secp256k1['Point'] {
const { x, y } = this.toAffine() // convert to 2d xy affine point.
Secp256k1.FpIsValidNot0(x) // must be in range 1 <= x,y < P
Secp256k1.FpIsValidNot0(y)
return Secp256k1.bytesToHex(this.toBytes(isCompressed))
}
}
+
/** Generator / base point */
- static G: Point = new Point(this.Gx, this.Gy, 1n)
+ static G: Secp256k1['Point'] = new this.Point(this.Gx, this.Gy, 1n)
/** Identity / zero point */
- static I: Point = new Point(0n, 1n, 0n)
+ static I: Secp256k1['Point'] = new this.Point(0n, 1n, 0n)
// Static aliases
static {
this.Point.BASE = this.G
this.Point.ZERO = this.I
}
/** `Q = u1⋅G + u2⋅R`. Verifies Q is not ZERO. Unsafe: non-CT. */
- static doubleScalarMulUns = (R: Point, u1: bigint, u2: bigint): Point => {
+ static doubleScalarMulUns = (R: Secp256k1['Point'], u1: bigint, u2: bigint): Secp256k1['Point'] => {
return this.G.multiply(u1, false).add(R.multiply(u2, false)).assertValidity()
}
static bytesToNumBE = (b: Bytes): bigint => this.big('0x' + (this.bytesToHex(b) || '0'))
}
const r = Secp256k1.sliceBytesNumBE(b, 0, Secp256k1.L)
const s = Secp256k1.sliceBytesNumBE(b, Secp256k1.L, Secp256k1.L2)
- return new Signature(r, s, rec)
+ return new this(r, s, rec)
}
addRecoveryBit (bit: number): RecoveredSignature {
- return new Signature(this.r, this.s, bit) as RecoveredSignature
+ return new Secp256k1.Signature(this.r, this.s, bit) as RecoveredSignature
}
hasHighS (): boolean {
return Secp256k1.highS(this.s)
k.fill(0)
}
// h = hmac(K || V || ...)
- const h = (...b: Bytes[]) => hashes.hmacSha256Async(k, this.concatBytes(v, ...b))
+ const h = (...b: Bytes[]) => this.hashes.hmacSha256Async(k, this.concatBytes(v, ...b))
const reseed = async (seed = this.NULL) => {
// HMAC-DRBG reseed() function. Steps D-G
k = await h(this.byte0, seed) // k = hmac(K || V || 0x00 || seed)
): T => {
let { lowS, extraEntropy } = opts // generates low-s sigs by default
// RFC6979 3.2: we skip step A
- const int2octets = numTo32b // int to octets
- const h1i = bits2int_modN(messageHash) // msg bigint
+ const int2octets = this.numTo32b // int to octets
+ const h1i = this.bits2int_modN(messageHash) // msg bigint
const h1o = int2octets(h1i) // msg octets
- const d = secretKeyToScalar(secretKey) // validate private key, convert to bigint
+ const d = this.secretKeyToScalar(secretKey) // validate private key, convert to bigint
const seedArgs = [int2octets(d), h1o] // Step D of RFC6979 3.2
/** RFC6979 3.6: additional k' (optional). See {@link ECDSAExtraEntropy}. */
if (extraEntropy != null && extraEntropy !== false) {
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
// gen random bytes OR pass as-is
- const e = extraEntropy === true ? randomBytes(L) : extraEntropy
- seedArgs.push(abytes(e, undefined, 'extraEntropy')) // check for being bytes
+ const e = extraEntropy === true ? this.randomBytes(this.L) : extraEntropy
+ seedArgs.push(this.abytes(e, undefined, 'extraEntropy')) // check for being bytes
}
- const seed = concatBytes(...seedArgs)
+ const seed = this.concatBytes(...seedArgs)
const m = h1i // convert msg to bigint
// Converts signature params into point w r/s, checks result for validity.
// To transform k => Signature:
const k2sig = (kBytes: Bytes): Bytes | undefined => {
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
// Important: all mod() calls here must be done over N
- const k = bits2int(kBytes)
- if (!(1n <= k && k < N)) return // Valid scalars (including k) must be in 1..N-1
- const ik = invert(k, N) // k^-1 mod n
- const q = G.multiply(k).toAffine() // q = k⋅G
- const r = modN(q.x) // r = q.x mod n
+ const k = this.bits2int(kBytes)
+ if (!(1n <= k && k < this.N)) return // Valid scalars (including k) must be in 1..N-1
+ const ik = this.invert(k, this.N) // k^-1 mod n
+ const q = this.G.multiply(k).toAffine() // q = k⋅G
+ const r = this.modN(q.x) // r = q.x mod n
if (r === 0n) return
- const s = modN(ik * modN(m + r * d)) // s = k^-1(m + rd) mod n
+ const s = this.modN(ik * this.modN(m + r * d)) // s = k^-1(m + rd) mod n
if (s === 0n) return
let recovery = (q.x === r ? 0 : 2) | Number(q.y & 1n) // recovery bit (2 or 3, when q.x > n)
let normS = s // normalized S
- if (lowS && highS(s)) {
+ if (lowS && this.highS(s)) {
// if lowS was passed, ensure s is always
- normS = modN(-s) // in the bottom half of CURVE.n
+ normS = this.modN(-s) // in the bottom half of CURVE.n
recovery ^= 1
}
- const sig = new Signature(r, normS, recovery) as RecoveredSignature // use normS, not s
+ const sig = new this.Signature(r, normS, recovery) as RecoveredSignature // use normS, not s
return sig.toBytes(opts.format)
}
return hmacDrbg(seed, k2sig)
// Follows [SEC1](https://secg.org/sec1-v2.pdf) 4.1.4.
static _verify = (sig: Bytes, messageHash: Bytes, publicKey: Bytes, opts: ECDSAVerifyOpts = {}) => {
const { lowS, format } = opts
- if (sig instanceof Signature) err('Signature must be in Uint8Array, use .toBytes()')
- assertSigLength(sig, format)
- abytes(publicKey, undefined, 'publicKey')
+ if (sig instanceof this.Signature) this.err('Signature must be in Uint8Array, use .toBytes()')
+ this.assertSigLength(sig, format)
+ this.abytes(publicKey, undefined, 'publicKey')
try {
- const { r, s } = Signature.fromBytes(sig, format)
- const h = bits2int_modN(messageHash) // Truncate hash
- const P = Point.fromBytes(publicKey) // Validate public key
- if (lowS && highS(s)) return false // lowS bans sig.s >= CURVE.n/2
- const is = invert(s, N) // s^-1
- const u1 = modN(h * is) // u1 = hs^-1 mod n
- const u2 = modN(r * is) // u2 = rs^-1 mod n
- const R = doubleScalarMulUns(P, u1, u2).toAffine() // R = u1⋅G + u2⋅P
+ const { r, s } = this.Signature.fromBytes(sig, format)
+ const h = this.bits2int_modN(messageHash) // Truncate hash
+ const P = this.Point.fromBytes(publicKey) // Validate public key
+ if (lowS && this.highS(s)) return false // lowS bans sig.s >= CURVE.n/2
+ const is = this.invert(s, this.N) // s^-1
+ const u1 = this.modN(h * is) // u1 = hs^-1 mod n
+ const u2 = this.modN(r * is) // u2 = rs^-1 mod n
+ const R = this.doubleScalarMulUns(P, u1, u2).toAffine() // R = u1⋅G + u2⋅P
// Stop if R is identity / zero point. Check is done inside `doubleScalarMulUns`
- const v = modN(R.x) // R.x must be in N's field, not P's
+ const v = this.modN(R.x) // R.x must be in N's field, not P's
return v === r // mod(R.x, n) == r
} catch (error) {
return false
static setDefaults = (opts: ECDSASignOpts): Required<ECDSASignOpts> => {
const res: ECDSASignOpts = {}
- Object.keys(defaultSignOpts).forEach((k: string) => {
+ Object.keys(this.defaultSignOpts).forEach((k: string) => {
// @ts-ignore
res[k] = opts[k] ?? defaultSignOpts[k]
})
* ```
*/
static sign = (message: Bytes, secretKey: Bytes, opts: ECDSASignOpts = {}): Bytes => {
- opts = setDefaults(opts)
- message = prepMsg(message, opts, false) as Bytes
- return _sign(message, secretKey, opts, hmacDrbg)
+ opts = this.setDefaults(opts)
+ message = this.prepMsg(message, opts, false) as Bytes
+ return this._sign(message, secretKey, opts, this.hmacDrbg)
}
/**
secretKey: Bytes,
opts: ECDSASignOpts = {}
): Promise<Bytes> => {
- opts = setDefaults(opts)
- message = await prepMsg(message, opts, true)
- return _sign(message, secretKey, opts, hmacDrbgAsync)
+ opts = this.setDefaults(opts)
+ message = await this.prepMsg(message, opts, true)
+ return this._sign(message, secretKey, opts, this.hmacDrbgAsync)
}
/**
publicKey: Bytes,
opts: ECDSAVerifyOpts = {}
): boolean => {
- opts = setDefaults(opts)
- message = prepMsg(message, opts, false) as Bytes
- return _verify(signature, message, publicKey, opts)
+ opts = this.setDefaults(opts)
+ message = this.prepMsg(message, opts, false) as Bytes
+ return this._verify(signature, message, publicKey, opts)
}
/**
publicKey: Bytes,
opts: ECDSAVerifyOpts = {}
): Promise<boolean> => {
- opts = setDefaults(opts)
- message = await prepMsg(message, opts, true)
- return _verify(sig, message, publicKey, opts)
+ opts = this.setDefaults(opts)
+ message = await this.prepMsg(message, opts, true)
+ return this._verify(sig, message, publicKey, opts)
}
static _recover = (signature: Bytes, messageHash: Bytes) => {
- const sig = Signature.fromBytes(signature, 'recovered')
+ const sig = this.Signature.fromBytes(signature, 'recovered')
const { r, s, recovery } = sig
// 0 or 1 recovery id determines sign of "y" coordinate.
// 2 or 3 means q.x was >N.
- assertRecoveryBit(recovery)
- const h = bits2int_modN(abytes(messageHash, L)) // Truncate hash
- const radj = recovery === 2 || recovery === 3 ? r + N : r
- FpIsValidNot0(radj) // ensure q.x is still a field element
- const head = getPrefix(big(recovery!)) // head is 0x02 or 0x03
- const Rb = concatBytes(head, numTo32b(radj)) // concat head + r
- const R = Point.fromBytes(Rb)
- const ir = invert(radj, N) // r^-1
- const u1 = modN(-h * ir) // -hr^-1
- const u2 = modN(s * ir) // sr^-1
- const point = doubleScalarMulUns(R, u1, u2) // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
+ this.assertRecoveryBit(recovery)
+ const h = this.bits2int_modN(this.abytes(messageHash, this.L)) // Truncate hash
+ const radj = recovery === 2 || recovery === 3 ? r + this.N : r
+ this.FpIsValidNot0(radj) // ensure q.x is still a field element
+ const head = this.getPrefix(this.big(recovery!)) // head is 0x02 or 0x03
+ const Rb = this.concatBytes(head, this.numTo32b(radj)) // concat head + r
+ const R = this.Point.fromBytes(Rb)
+ const ir = this.invert(radj, this.N) // r^-1
+ const u1 = this.modN(-h * ir) // -hr^-1
+ const u2 = this.modN(s * ir) // sr^-1
+ const point = this.doubleScalarMulUns(R, u1, u2) // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
return point.toBytes()
}
* Follows [SEC1](https://secg.org/sec1-v2.pdf) 4.1.6.
*/
static recoverPublicKey = (signature: Bytes, message: Bytes, opts: ECDSARecoverOpts = {}): Bytes => {
- message = prepMsg(message, setDefaults(opts), false) as Bytes
- return _recover(signature, message)
+ message = this.prepMsg(message, this.setDefaults(opts), false) as Bytes
+ return this._recover(signature, message)
}
static recoverPublicKeyAsync = async (
message: Bytes,
opts: ECDSARecoverOpts = {}
): Promise<Bytes> => {
- message = await prepMsg(message, setDefaults(opts), true)
- return _recover(signature, message)
+ message = await this.prepMsg(message, this.setDefaults(opts), true)
+ return this._recover(signature, message)
}
/**
* @returns public key C
*/
static getSharedSecret = (secretKeyA: Bytes, publicKeyB: Bytes, isCompressed = true): Bytes => {
- return Point.fromBytes(publicKeyB).multiply(secretKeyToScalar(secretKeyA)).toBytes(isCompressed)
+ return this.Point.fromBytes(publicKeyB).multiply(this.secretKeyToScalar(secretKeyA)).toBytes(isCompressed)
}
// FIPS 186 B.4.1 compliant key generation produces private keys
// with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1
- static randomSecretKey = (seed = randomBytes(lengths.seed)) => {
- abytes(seed)
- if (seed.length < lengths.seed || seed.length > 1024) err('expected 40-1024b')
- const num = M(bytesToNumBE(seed), N - 1n)
- return numTo32b(num + 1n)
+ static randomSecretKey = (seed = this.randomBytes(this.lengths.seed)) => {
+ this.abytes(seed)
+ if (seed.length < this.lengths.seed || seed.length > 1024) this.err('expected 40-1024b')
+ const num = this.M(this.bytesToNumBE(seed), this.N - 1n)
+ return this.numTo32b(num + 1n)
}
static createKeygen = (getPublicKey: (secretKey: Bytes) => Bytes) => (seed?: Bytes): KeysSecPub => {
const secretKey = this.randomSecretKey(seed)
return { secretKey, publicKey: getPublicKey(secretKey) }
}
- static keygen: KeygenFn = this.createKeygen(getPublicKey)
+ static keygen: KeygenFn = this.createKeygen(this.getPublicKey)
/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */
static etc = {
numberToBytesBE: this.numTo32b as (n: bigint) => Bytes,
mod: this.M as (a: bigint, md?: bigint) => bigint,
invert: this.invert as (num: bigint, md?: bigint) => bigint, // math utilities
- randomBytes: randomBytes as (len?: number) => Bytes,
+ randomBytes: this.randomBytes as (len?: number) => Bytes,
secretKeyToScalar: this.secretKeyToScalar as typeof this.secretKeyToScalar,
abytes: this.abytes as typeof this.abytes,
}
static T_NONCE = 'nonce'
static T_CHALLENGE = 'challenge'
static taggedHash = (tag: string, ...messages: Bytes[]): Bytes => {
- const fn = callHash('sha256')
- const tagH = fn(getTag(tag))
- return fn(concatBytes(tagH, tagH, ...messages))
+ const fn = this.callHash('sha256')
+ const tagH = fn(this.getTag(tag))
+ return fn(this.concatBytes(tagH, tagH, ...messages))
}
static taggedHashAsync = async (tag: string, ...messages: Bytes[]): Promise<Bytes> => {
- const fn = hashes.sha256Async
- const tagH = await fn(getTag(tag))
- return await fn(concatBytes(tagH, tagH, ...messages))
+ const fn = this.hashes.sha256Async
+ const tagH = await fn(this.getTag(tag))
+ return await fn(this.concatBytes(tagH, tagH, ...messages))
}
// ECDSA compact points are 33-byte. Schnorr is 32: we strip first byte 0x02 or 0x03
// Calculate point, scalar and bytes
static extpubSchnorr = (priv: Bytes) => {
- const d_ = secretKeyToScalar(priv)
- const p = G.multiply(d_) // P = d'⋅G; 0 < d' < n check is done inside
+ const d_ = this.secretKeyToScalar(priv)
+ const p = this.G.multiply(d_) // P = d'⋅G; 0 < d' < n check is done inside
const { x, y } = p.assertValidity().toAffine() // validate Point is not at infinity
- const d = isEven(y) ? d_ : modN(-d_)
- const px = numTo32b(x)
+ const d = this.isEven(y) ? d_ : this.modN(-d_)
+ const px = this.numTo32b(x)
return { d, px }
}
- static bytesModN = (bytes: Bytes) => modN(bytesToNumBE(bytes))
- static challenge = (...args: Bytes[]): bigint => bytesModN(taggedHash(T_CHALLENGE, ...args))
+ static bytesModN = (bytes: Bytes) => this.modN(this.bytesToNumBE(bytes))
+ static challenge = (...args: Bytes[]): bigint => this.bytesModN(this.taggedHash(this.T_CHALLENGE, ...args))
static challengeAsync = async (...args: Bytes[]): Promise<bigint> =>
- bytesModN(await taggedHashAsync(T_CHALLENGE, ...args))
+ this.bytesModN(await this.taggedHashAsync(this.T_CHALLENGE, ...args))
/**
* Schnorr public key is just `x` coordinate of Point as per BIP340.
*/
static pubSchnorr = (secretKey: Bytes): Bytes => {
- return extpubSchnorr(secretKey).px // d'=int(sk). Fail if d'=0 or d'≥n. Ret bytes(d'⋅G)
+ return this.extpubSchnorr(secretKey).px // d'=int(sk). Fail if d'=0 or d'≥n. Ret bytes(d'⋅G)
}
- static keygenSchnorr: KeygenFn = createKeygen(pubSchnorr)
+ static keygenSchnorr: KeygenFn = this.createKeygen(this.pubSchnorr)
// Common preparation fn for both sync and async signing
static prepSigSchnorr = (message: Bytes, secretKey: Bytes, auxRand: Bytes) => {
- const { px, d } = extpubSchnorr(secretKey)
- return { m: abytes(message), px, d, a: abytes(auxRand, L) }
+ const { px, d } = this.extpubSchnorr(secretKey)
+ return { m: this.abytes(message), px, d, a: this.abytes(auxRand, this.L) }
}
static extractK = (rand: Bytes) => {
- const k_ = bytesModN(rand) // Let k' = int(rand) mod n
- if (k_ === 0n) err('sign failed: k is zero') // Fail if k' = 0.
- const { px, d } = extpubSchnorr(numTo32b(k_)) // Let R = k'⋅G.
+ const k_ = this.bytesModN(rand) // Let k' = int(rand) mod n
+ if (k_ === 0n) this.err('sign failed: k is zero') // Fail if k' = 0.
+ const { px, d } = this.extpubSchnorr(this.numTo32b(k_)) // Let R = k'⋅G.
return { rx: px, k: d }
}
// Common signature creation helper
static createSigSchnorr = (k: bigint, px: Bytes, e: bigint, d: bigint): Bytes => {
- return concatBytes(px, numTo32b(modN(k + e * d)))
+ return this.concatBytes(px, this.numTo32b(this.modN(k + e * d)))
}
static E_INVSIG = 'invalid signature produced'
* Creates Schnorr signature as per BIP340. Verifies itself before returning anything.
* auxRand is optional and is not the sole source of k generation: bad CSPRNG won't be dangerous.
*/
- static signSchnorr = (message: Bytes, secretKey: Bytes, auxRand: Bytes = randomBytes(L)): Bytes => {
- const { m, px, d, a } = prepSigSchnorr(message, secretKey, auxRand)
- const aux = taggedHash(T_AUX, a)
+ static signSchnorr = (message: Bytes, secretKey: Bytes, auxRand: Bytes = this.randomBytes(this.L)): Bytes => {
+ const { m, px, d, a } = this.prepSigSchnorr(message, secretKey, auxRand)
+ const aux = this.taggedHash(this.T_AUX, a)
// Let t be the byte-wise xor of bytes(d) and hash/aux(a)
- const t = numTo32b(d ^ bytesToNumBE(aux))
+ const t = this.numTo32b(d ^ this.bytesToNumBE(aux))
// Let rand = hash/nonce(t || bytes(P) || m)
- const rand = taggedHash(T_NONCE, t, px, m)
- const { rx, k } = extractK(rand)
+ const rand = this.taggedHash(this.T_NONCE, t, px, m)
+ const { rx, k } = this.extractK(rand)
// Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
- const e = challenge(rx, px, m)
- const sig = createSigSchnorr(k, rx, e, d)
+ const e = this.challenge(rx, px, m)
+ const sig = this.createSigSchnorr(k, rx, e, d)
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
- if (!verifySchnorr(sig, m, px)) err(E_INVSIG)
+ if (!this.verifySchnorr(sig, m, px)) this.err(this.E_INVSIG)
return sig
}
static signSchnorrAsync = async (
message: Bytes,
secretKey: Bytes,
- auxRand: Bytes = randomBytes(L)
+ auxRand: Bytes = this.randomBytes(this.L)
): Promise<Bytes> => {
- const { m, px, d, a } = prepSigSchnorr(message, secretKey, auxRand)
- const aux = await taggedHashAsync(T_AUX, a)
+ const { m, px, d, a } = this.prepSigSchnorr(message, secretKey, auxRand)
+ const aux = await this.taggedHashAsync(this.T_AUX, a)
// Let t be the byte-wise xor of bytes(d) and hash/aux(a)
- const t = numTo32b(d ^ bytesToNumBE(aux))
+ const t = this.numTo32b(d ^ this.bytesToNumBE(aux))
// Let rand = hash/nonce(t || bytes(P) || m)
- const rand = await taggedHashAsync(T_NONCE, t, px, m)
- const { rx, k } = extractK(rand)
+ const rand = await this.taggedHashAsync(this.T_NONCE, t, px, m)
+ const { rx, k } = this.extractK(rand)
// Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
- const e = await challengeAsync(rx, px, m)
- const sig = createSigSchnorr(k, rx, e, d)
+ const e = await this.challengeAsync(rx, px, m)
+ const sig = this.createSigSchnorr(k, rx, e, d)
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
- if (!(await verifySchnorrAsync(sig, m, px))) err(E_INVSIG)
+ if (!(await this.verifySchnorrAsync(sig, m, px))) this.err(this.E_INVSIG)
return sig
}
const y_ = this.isEven(y) ? y : this.M(-y)
// Return the unique point P such that x(P) = x and
// y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
- const P_ = new Point(x, y_, 1n).assertValidity()
+ const P_ = new this.Point(x, y_, 1n).assertValidity()
const px = this.numTo32b(P_.toAffine().x)
// P = lift_x(int(pk)); fail if that fails
const r = this.sliceBytesNumBE(sig, 0, this.L) // Let r = int(sig[0:32]); fail if r ≥ p.
static pwindows = Math.ceil(this.scalarBits / this.W) + 1 // 33 for W=8, NOT 32 - see wNAF loop
static pwindowSize = 2 ** (this.W - 1) // 128 for W=8
static precompute = () => {
- const points: Point[] = []
+ const points: Secp256k1['Point'][] = []
let p = this.G
let b = p
for (let w = 0; w < this.pwindows; w++) {
}
return points
}
- static Gpows: Point[] | undefined = undefined // precomputes for base point G
+ static Gpows: Secp256k1['Point'][] | undefined = undefined // precomputes for base point G
// const-time negate
- static ctneg = (cnd: boolean, p: Point) => {
+ static ctneg = (cnd: boolean, p: Secp256k1['Point']) => {
const n = p.negate()
return cnd ? n : p
}
*
* !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
*/
- static wNAF = (n: bigint): { p: Point; f: Point } => {
+ static wNAF = (n: bigint): { p: Secp256k1['Point']; f: Secp256k1['Point'] } => {
const comp = this.Gpows || (this.Gpows = this.precompute())
let p = this.I
let f = this.G // f must be G, or could become I in the end