* fix: use lnbits linting, change to uv - formatting - prettier - pyright * dont ignore packagejson * readd poetry lock for integration tests * fix pyright * fix mypy * fix test? * fix lnbits version * fixup tests * fixup!
521 lines
13 KiB
JavaScript
521 lines
13 KiB
JavaScript
/*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
|
|
const B256 = 2n ** 256n,
|
|
P = B256 - 0x1000003d1n,
|
|
N = B256 - 0x14551231950b75fc4402da1732fc9bebfn,
|
|
Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,
|
|
Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n,
|
|
CURVE = {p: P, n: N, a: 0n, b: 7n, Gx, Gy},
|
|
fLen = 32,
|
|
crv = t => mod(mod(t * t) * t + CURVE.b),
|
|
err = (t = '') => {
|
|
throw new Error(t)
|
|
},
|
|
big = t => 'bigint' == typeof t,
|
|
str = t => 'string' == typeof t,
|
|
fe = t => big(t) && 0n < t && t < P,
|
|
ge = t => big(t) && 0n < t && t < N,
|
|
isu8 = t =>
|
|
t instanceof Uint8Array ||
|
|
(null != t && 'object' == typeof t && 'Uint8Array' === t.constructor.name),
|
|
au8 = (t, n) =>
|
|
!isu8(t) || ('number' == typeof n && n > 0 && t.length !== n)
|
|
? err('Uint8Array expected')
|
|
: t,
|
|
u8n = t => new Uint8Array(t),
|
|
toU8 = (t, n) => au8(str(t) ? h2b(t) : u8n(au8(t)), n),
|
|
mod = (t, n = P) => {
|
|
let e = t % n
|
|
return e >= 0n ? e : n + e
|
|
},
|
|
isPoint = t => (t instanceof Point ? t : err('Point expected'))
|
|
class Point {
|
|
constructor(t, n, e) {
|
|
;((this.px = t), (this.py = n), (this.pz = e))
|
|
}
|
|
static fromAffine(t) {
|
|
return 0n === t.x && 0n === t.y ? Point.ZERO : new Point(t.x, t.y, 1n)
|
|
}
|
|
static fromHex(t) {
|
|
let n
|
|
const e = (t = toU8(t))[0],
|
|
r = t.subarray(1),
|
|
o = slcNum(r, 0, 32),
|
|
i = t.length
|
|
if (33 === i && [2, 3].includes(e)) {
|
|
fe(o) || err('Point hex invalid: x not FE')
|
|
let t = sqrt(crv(o))
|
|
;(!(1 & ~e) !== (1n === (1n & t)) && (t = mod(-t)),
|
|
(n = new Point(o, t, 1n)))
|
|
}
|
|
return (
|
|
65 === i && 4 === e && (n = new Point(o, slcNum(r, 32, 64), 1n)),
|
|
n ? n.ok() : err('Point is not on curve')
|
|
)
|
|
}
|
|
static fromPrivateKey(t) {
|
|
return G.mul(toPriv(t))
|
|
}
|
|
get x() {
|
|
return this.aff().x
|
|
}
|
|
get y() {
|
|
return this.aff().y
|
|
}
|
|
equals(t) {
|
|
const {px: n, py: e, pz: r} = this,
|
|
{px: o, py: i, pz: s} = isPoint(t),
|
|
a = mod(n * s),
|
|
c = mod(o * r),
|
|
d = mod(e * s),
|
|
u = mod(i * r)
|
|
return a === c && d === u
|
|
}
|
|
negate() {
|
|
return new Point(this.px, mod(-this.py), this.pz)
|
|
}
|
|
double() {
|
|
return this.add(this)
|
|
}
|
|
add(t) {
|
|
const {px: n, py: e, pz: r} = this,
|
|
{px: o, py: i, pz: s} = isPoint(t),
|
|
{a, b: c} = CURVE
|
|
let d = 0n,
|
|
u = 0n,
|
|
m = 0n
|
|
const h = mod(3n * c)
|
|
let l = mod(n * o),
|
|
y = mod(e * i),
|
|
f = mod(r * s),
|
|
p = mod(n + e),
|
|
b = mod(o + i)
|
|
;((p = mod(p * b)), (b = mod(l + y)), (p = mod(p - b)), (b = mod(n + r)))
|
|
let g = mod(o + s)
|
|
return (
|
|
(b = mod(b * g)),
|
|
(g = mod(l + f)),
|
|
(b = mod(b - g)),
|
|
(g = mod(e + r)),
|
|
(d = mod(i + s)),
|
|
(g = mod(g * d)),
|
|
(d = mod(y + f)),
|
|
(g = mod(g - d)),
|
|
(m = mod(a * b)),
|
|
(d = mod(h * f)),
|
|
(m = mod(d + m)),
|
|
(d = mod(y - m)),
|
|
(m = mod(y + m)),
|
|
(u = mod(d * m)),
|
|
(y = mod(l + l)),
|
|
(y = mod(y + l)),
|
|
(f = mod(a * f)),
|
|
(b = mod(h * b)),
|
|
(y = mod(y + f)),
|
|
(f = mod(l - f)),
|
|
(f = mod(a * f)),
|
|
(b = mod(b + f)),
|
|
(l = mod(y * b)),
|
|
(u = mod(u + l)),
|
|
(l = mod(g * b)),
|
|
(d = mod(p * d)),
|
|
(d = mod(d - l)),
|
|
(l = mod(p * y)),
|
|
(m = mod(g * m)),
|
|
(m = mod(m + l)),
|
|
new Point(d, u, m)
|
|
)
|
|
}
|
|
mul(t, n = !0) {
|
|
if (!n && 0n === t) return I
|
|
if ((ge(t) || err('invalid scalar'), this.equals(G))) return wNAF(t).p
|
|
let e = I,
|
|
r = G
|
|
for (let o = this; t > 0n; o = o.double(), t >>= 1n)
|
|
1n & t ? (e = e.add(o)) : n && (r = r.add(o))
|
|
return e
|
|
}
|
|
mulAddQUns(t, n, e) {
|
|
return this.mul(n, !1).add(t.mul(e, !1)).ok()
|
|
}
|
|
toAffine() {
|
|
const {px: t, py: n, pz: e} = this
|
|
if (this.equals(I)) return {x: 0n, y: 0n}
|
|
if (1n === e) return {x: t, y: n}
|
|
const r = inv(e)
|
|
return (
|
|
1n !== mod(e * r) && err('invalid inverse'),
|
|
{x: mod(t * r), y: mod(n * r)}
|
|
)
|
|
}
|
|
assertValidity() {
|
|
const {x: t, y: n} = this.aff()
|
|
return (
|
|
(fe(t) && fe(n)) || err('Point invalid: x or y'),
|
|
mod(n * n) === crv(t) ? this : err('Point invalid: not on curve')
|
|
)
|
|
}
|
|
multiply(t) {
|
|
return this.mul(t)
|
|
}
|
|
aff() {
|
|
return this.toAffine()
|
|
}
|
|
ok() {
|
|
return this.assertValidity()
|
|
}
|
|
toHex(t = !0) {
|
|
const {x: n, y: e} = this.aff()
|
|
return (
|
|
(t ? (0n === (1n & e) ? '02' : '03') : '04') + n2h(n) + (t ? '' : n2h(e))
|
|
)
|
|
}
|
|
toRawBytes(t = !0) {
|
|
return h2b(this.toHex(t))
|
|
}
|
|
}
|
|
;((Point.BASE = new Point(Gx, Gy, 1n)), (Point.ZERO = new Point(0n, 1n, 0n)))
|
|
const {BASE: G, ZERO: I} = Point,
|
|
padh = (t, n) => t.toString(16).padStart(n, '0'),
|
|
b2h = t =>
|
|
Array.from(t)
|
|
.map(t => padh(t, 2))
|
|
.join(''),
|
|
h2b = t => {
|
|
const n = t.length
|
|
;(!str(t) || n % 2) && err('hex invalid 1')
|
|
const e = u8n(n / 2)
|
|
for (let n = 0; n < e.length; n++) {
|
|
const r = 2 * n,
|
|
o = t.slice(r, r + 2),
|
|
i = Number.parseInt(o, 16)
|
|
;((Number.isNaN(i) || i < 0) && err('hex invalid 2'), (e[n] = i))
|
|
}
|
|
return e
|
|
},
|
|
b2n = t => BigInt('0x' + (b2h(t) || '0')),
|
|
slcNum = (t, n, e) => b2n(t.slice(n, e)),
|
|
n2b = t =>
|
|
big(t) && t >= 0n && t < B256 ? h2b(padh(t, 64)) : err('bigint expected'),
|
|
n2h = t => b2h(n2b(t)),
|
|
concatB = (...t) => {
|
|
const n = u8n(t.reduce((t, n) => t + au8(n).length, 0))
|
|
let e = 0
|
|
return (
|
|
t.forEach(t => {
|
|
;(n.set(t, e), (e += t.length))
|
|
}),
|
|
n
|
|
)
|
|
},
|
|
inv = (t, n = P) => {
|
|
;(0n === t || n <= 0n) && err('no inverse n=' + t + ' mod=' + n)
|
|
let e = mod(t, n),
|
|
r = n,
|
|
o = 0n,
|
|
i = 1n,
|
|
s = 1n,
|
|
a = 0n
|
|
for (; 0n !== e; ) {
|
|
const t = r / e,
|
|
n = r % e,
|
|
c = o - s * t,
|
|
d = i - a * t
|
|
;((r = e), (e = n), (o = s), (i = a), (s = c), (a = d))
|
|
}
|
|
return 1n === r ? mod(o, n) : err('no inverse')
|
|
},
|
|
sqrt = t => {
|
|
let n = 1n
|
|
for (let e = t, r = (P + 1n) / 4n; r > 0n; r >>= 1n)
|
|
(1n & r && (n = (n * e) % P), (e = (e * e) % P))
|
|
return mod(n * n) === t ? n : err('sqrt invalid')
|
|
},
|
|
toPriv = t => (
|
|
big(t) || (t = b2n(toU8(t, 32))),
|
|
ge(t) ? t : err('private key out of range')
|
|
),
|
|
moreThanHalfN = t => t > N >> 1n,
|
|
getPublicKey = (t, n = !0) => Point.fromPrivateKey(t).toRawBytes(n)
|
|
class Signature {
|
|
constructor(t, n, e) {
|
|
;((this.r = t), (this.s = n), (this.recovery = e), this.assertValidity())
|
|
}
|
|
static fromCompact(t) {
|
|
return (
|
|
(t = toU8(t, 64)),
|
|
new Signature(slcNum(t, 0, 32), slcNum(t, 32, 64))
|
|
)
|
|
}
|
|
assertValidity() {
|
|
return ge(this.r) && ge(this.s) ? this : err()
|
|
}
|
|
addRecoveryBit(t) {
|
|
return new Signature(this.r, this.s, t)
|
|
}
|
|
hasHighS() {
|
|
return moreThanHalfN(this.s)
|
|
}
|
|
normalizeS() {
|
|
return this.hasHighS()
|
|
? new Signature(this.r, mod(this.s, N), this.recovery)
|
|
: this
|
|
}
|
|
recoverPublicKey(t) {
|
|
const {r: n, s: e, recovery: r} = this
|
|
;[0, 1, 2, 3].includes(r) || err('recovery id invalid')
|
|
const o = bits2int_modN(toU8(t, 32)),
|
|
i = 2 === r || 3 === r ? n + N : n
|
|
i >= P && err('q.x invalid')
|
|
const s = 1 & r ? '03' : '02',
|
|
a = Point.fromHex(s + n2h(i)),
|
|
c = inv(i, N),
|
|
d = mod(-o * c, N),
|
|
u = mod(e * c, N)
|
|
return G.mulAddQUns(a, d, u)
|
|
}
|
|
toCompactRawBytes() {
|
|
return h2b(this.toCompactHex())
|
|
}
|
|
toCompactHex() {
|
|
return n2h(this.r) + n2h(this.s)
|
|
}
|
|
}
|
|
const bits2int = t => {
|
|
const n = 8 * t.length - 256,
|
|
e = b2n(t)
|
|
return n > 0 ? e >> BigInt(n) : e
|
|
},
|
|
bits2int_modN = t => mod(bits2int(t), N),
|
|
i2o = t => n2b(t),
|
|
cr = () =>
|
|
'object' == typeof globalThis && 'crypto' in globalThis
|
|
? globalThis.crypto
|
|
: void 0
|
|
let _hmacSync
|
|
const optS = {lowS: !0},
|
|
optV = {lowS: !0},
|
|
prepSig = (t, n, e = optS) => {
|
|
;['der', 'recovered', 'canonical'].some(t => t in e) &&
|
|
err('sign() legacy options not supported')
|
|
let {lowS: r} = e
|
|
null == r && (r = !0)
|
|
const o = bits2int_modN(toU8(t)),
|
|
i = i2o(o),
|
|
s = toPriv(n),
|
|
a = [i2o(s), i]
|
|
let c = e.extraEntropy
|
|
if (c) {
|
|
!0 === c && (c = etc.randomBytes(32))
|
|
const t = toU8(c)
|
|
;(32 !== t.length && err(), a.push(t))
|
|
}
|
|
const d = o
|
|
return {
|
|
seed: concatB(...a),
|
|
k2sig: t => {
|
|
const n = bits2int(t)
|
|
if (!ge(n)) return
|
|
const e = inv(n, N),
|
|
o = G.mul(n).aff(),
|
|
i = mod(o.x, N)
|
|
if (0n === i) return
|
|
const a = mod(e * mod(d + mod(s * i, N), N), N)
|
|
if (0n === a) return
|
|
let c = a,
|
|
u = (o.x === i ? 0 : 2) | Number(1n & o.y)
|
|
return (
|
|
r && moreThanHalfN(a) && ((c = mod(-a, N)), (u ^= 1)),
|
|
new Signature(i, c, u)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
function hmacDrbg(t) {
|
|
let n = u8n(32),
|
|
e = u8n(32),
|
|
r = 0
|
|
const o = () => {
|
|
;(n.fill(1), e.fill(0), (r = 0))
|
|
},
|
|
i = 'drbg: tried 1000 values'
|
|
if (t) {
|
|
const t = (...t) => etc.hmacSha256Async(e, n, ...t),
|
|
s = async (r = u8n()) => {
|
|
;((e = await t(u8n([0]), r)),
|
|
(n = await t()),
|
|
0 !== r.length && ((e = await t(u8n([1]), r)), (n = await t())))
|
|
},
|
|
a = async () => (r++ >= 1e3 && err(i), (n = await t()), n)
|
|
return async (t, n) => {
|
|
let e
|
|
for (o(), await s(t); !(e = n(await a())); ) await s()
|
|
return (o(), e)
|
|
}
|
|
}
|
|
{
|
|
const t = (...t) => {
|
|
const r = _hmacSync
|
|
return (r || err('etc.hmacSha256Sync not set'), r(e, n, ...t))
|
|
},
|
|
s = (r = u8n()) => {
|
|
;((e = t(u8n([0]), r)),
|
|
(n = t()),
|
|
0 !== r.length && ((e = t(u8n([1]), r)), (n = t())))
|
|
},
|
|
a = () => (r++ >= 1e3 && err(i), (n = t()), n)
|
|
return (t, n) => {
|
|
let e
|
|
for (o(), s(t); !(e = n(a())); ) s()
|
|
return (o(), e)
|
|
}
|
|
}
|
|
}
|
|
const signAsync = async (t, n, e = optS) => {
|
|
const {seed: r, k2sig: o} = prepSig(t, n, e)
|
|
return hmacDrbg(!0)(r, o)
|
|
},
|
|
sign = (t, n, e = optS) => {
|
|
const {seed: r, k2sig: o} = prepSig(t, n, e)
|
|
return hmacDrbg(!1)(r, o)
|
|
},
|
|
verify = (t, n, e, r = optV) => {
|
|
let o,
|
|
i,
|
|
s,
|
|
{lowS: a} = r
|
|
;(null == a && (a = !0),
|
|
'strict' in r && err('verify() legacy options not supported'))
|
|
const c = t && 'object' == typeof t && 'r' in t
|
|
c || 64 === toU8(t).length || err('signature must be 64 bytes')
|
|
try {
|
|
;((o = c
|
|
? new Signature(t.r, t.s).assertValidity()
|
|
: Signature.fromCompact(t)),
|
|
(i = bits2int_modN(toU8(n))),
|
|
(s = e instanceof Point ? e.ok() : Point.fromHex(e)))
|
|
} catch (t) {
|
|
return !1
|
|
}
|
|
if (!o) return !1
|
|
const {r: d, s: u} = o
|
|
if (a && moreThanHalfN(u)) return !1
|
|
let m
|
|
try {
|
|
const t = inv(u, N),
|
|
n = mod(i * t, N),
|
|
e = mod(d * t, N)
|
|
m = G.mulAddQUns(s, n, e).aff()
|
|
} catch (t) {
|
|
return !1
|
|
}
|
|
if (!m) return !1
|
|
return mod(m.x, N) === d
|
|
},
|
|
getSharedSecret = (t, n, e = !0) =>
|
|
Point.fromHex(n).mul(toPriv(t)).toRawBytes(e),
|
|
hashToPrivateKey = t => {
|
|
;((t = toU8(t)).length < 40 || t.length > 1024) &&
|
|
err('expected proper params')
|
|
const n = mod(b2n(t), N - 1n) + 1n
|
|
return n2b(n)
|
|
},
|
|
etc = {
|
|
hexToBytes: h2b,
|
|
bytesToHex: b2h,
|
|
concatBytes: concatB,
|
|
bytesToNumberBE: b2n,
|
|
numberToBytesBE: n2b,
|
|
mod,
|
|
invert: inv,
|
|
hmacSha256Async: async (t, ...n) => {
|
|
const e = cr(),
|
|
r = e && e.subtle
|
|
if (!r) return err('etc.hmacSha256Async not set')
|
|
const o = await r.importKey(
|
|
'raw',
|
|
t,
|
|
{name: 'HMAC', hash: {name: 'SHA-256'}},
|
|
!1,
|
|
['sign']
|
|
)
|
|
return u8n(await r.sign('HMAC', o, concatB(...n)))
|
|
},
|
|
hmacSha256Sync: _hmacSync,
|
|
hashToPrivateKey,
|
|
randomBytes: (t = 32) => {
|
|
const n = cr()
|
|
return (
|
|
(n && n.getRandomValues) ||
|
|
err('crypto.getRandomValues must be defined'),
|
|
n.getRandomValues(u8n(t))
|
|
)
|
|
}
|
|
},
|
|
utils = {
|
|
normPrivateKeyToScalar: toPriv,
|
|
isValidPrivateKey: t => {
|
|
try {
|
|
return !!toPriv(t)
|
|
} catch (t) {
|
|
return !1
|
|
}
|
|
},
|
|
randomPrivateKey: () => hashToPrivateKey(etc.randomBytes(48)),
|
|
precompute: (t = 8, n = G) => (n.multiply(3n), n)
|
|
}
|
|
Object.defineProperties(etc, {
|
|
hmacSha256Sync: {
|
|
configurable: !1,
|
|
get: () => _hmacSync,
|
|
set(t) {
|
|
_hmacSync || (_hmacSync = t)
|
|
}
|
|
}
|
|
})
|
|
const W = 8,
|
|
precompute = () => {
|
|
const t = []
|
|
let n = G,
|
|
e = n
|
|
for (let r = 0; r < 33; r++) {
|
|
;((e = n), t.push(e))
|
|
for (let r = 1; r < 128; r++) ((e = e.add(n)), t.push(e))
|
|
n = e.double()
|
|
}
|
|
return t
|
|
}
|
|
let Gpows
|
|
const wNAF = t => {
|
|
const n = Gpows || (Gpows = precompute()),
|
|
e = (t, n) => {
|
|
let e = n.negate()
|
|
return t ? e : n
|
|
}
|
|
let r = I,
|
|
o = G
|
|
const i = BigInt(255),
|
|
s = BigInt(8)
|
|
for (let a = 0; a < 33; a++) {
|
|
const c = 128 * a
|
|
let d = Number(t & i)
|
|
;((t >>= s), d > 128 && ((d -= 256), (t += 1n)))
|
|
const u = c,
|
|
m = c + Math.abs(d) - 1,
|
|
h = a % 2 != 0,
|
|
l = d < 0
|
|
0 === d ? (o = o.add(e(h, n[u]))) : (r = r.add(e(l, n[m])))
|
|
}
|
|
return {p: r, f: o}
|
|
}
|
|
export {
|
|
getPublicKey,
|
|
sign,
|
|
signAsync,
|
|
verify,
|
|
CURVE,
|
|
getSharedSecret,
|
|
etc,
|
|
utils,
|
|
Point as ProjectivePoint,
|
|
Signature
|
|
}
|