|
1 | 1 | 'use strict';
|
2 | 2 | Object.defineProperty(exports, '__esModule', { value: true });
|
3 |
| -exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.isTaptree = exports.isTapleaf = exports.TAPLEAF_VERSION_MASK = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.isXOnlyPoint = exports.typeforce = void 0; |
| 3 | +exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.isTaptree = exports.isTapleaf = exports.TAPLEAF_VERSION_MASK = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isXOnlyPoint = exports.isPoint = exports.typeforce = void 0; |
4 | 4 | const buffer_1 = require('buffer');
|
5 | 5 | exports.typeforce = require('typeforce');
|
6 |
| -const ZERO32 = buffer_1.Buffer.alloc(32, 0); |
7 |
| -const EC_P = buffer_1.Buffer.from( |
8 |
| - 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', |
9 |
| - 'hex', |
| 6 | +const EC_P = BigInt( |
| 7 | + `0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`, |
10 | 8 | );
|
11 |
| -function isFieldElement(c) { |
12 |
| - if (!buffer_1.Buffer.isBuffer(c)) return false; |
13 |
| - if (c.length !== 32) return false; |
14 |
| - if (c.compare(ZERO32) === 0) return false; |
15 |
| - if (c.compare(EC_P) >= 0) return false; |
16 |
| - return true; |
| 9 | +const EC_B = BigInt(7); |
| 10 | +// Idea from noble-secp256k1, to be nice to bad JS parsers |
| 11 | +const _0n = BigInt(0); |
| 12 | +const _1n = BigInt(1); |
| 13 | +const _2n = BigInt(2); |
| 14 | +const _3n = BigInt(3); |
| 15 | +const _4n = BigInt(4); |
| 16 | +const _5n = BigInt(5); |
| 17 | +const _8n = BigInt(8); |
| 18 | +function weistrass(x) { |
| 19 | + const x2 = (x * x) % EC_P; |
| 20 | + const x3 = (x2 * x) % EC_P; |
| 21 | + return (x3 /* + a=0 a*x */ + EC_B) % EC_P; |
| 22 | +} |
| 23 | +// For prime P, the Jacobi symbol is 1 iff a is a quadratic residue mod P |
| 24 | +function jacobiSymbol(a) { |
| 25 | + let p = EC_P; |
| 26 | + let sign = 1; |
| 27 | + while (a > _1n) { |
| 28 | + if (_0n === a % _2n) { |
| 29 | + if (_3n === p % _8n || _5n === p % _8n) sign = -sign; |
| 30 | + a >>= _1n; |
| 31 | + } else { |
| 32 | + if (_3n === p % _4n && _3n === a % _4n) sign = -sign; |
| 33 | + [a, p] = [p % a, a]; |
| 34 | + } |
| 35 | + } |
| 36 | + return a === _0n ? 0 : sign > 0 ? 1 : -1; |
17 | 37 | }
|
18 |
| -exports.isXOnlyPoint = isFieldElement; |
19 | 38 | function isPoint(p) {
|
20 | 39 | if (!buffer_1.Buffer.isBuffer(p)) return false;
|
21 | 40 | if (p.length < 33) return false;
|
22 | 41 | const t = p[0];
|
23 |
| - if (!isFieldElement(p.slice(1, 33))) return false; |
24 |
| - if ((t === 0x02 || t === 0x03) && p.length === 33) return true; |
25 |
| - if (!isFieldElement(p.slice(33))) return false; |
26 |
| - if (t === 0x04 && p.length === 65) return true; |
27 |
| - return false; |
| 42 | + if (p.length === 33) { |
| 43 | + return (t === 0x02 || t === 0x03) && isXOnlyPoint(p.slice(1)); |
| 44 | + } |
| 45 | + if (t !== 0x04 || p.length !== 65) return false; |
| 46 | + const x = BigInt(`0x${p.slice(1, 33).toString('hex')}`); |
| 47 | + if (x === _0n) return false; |
| 48 | + if (x >= EC_P) return false; |
| 49 | + const y = BigInt(`0x${p.slice(33).toString('hex')}`); |
| 50 | + if (y === _0n) return false; |
| 51 | + if (y >= EC_P) return false; |
| 52 | + const left = (y * y) % EC_P; |
| 53 | + const right = weistrass(x); |
| 54 | + return (left - right) % EC_P === _0n; |
28 | 55 | }
|
29 | 56 | exports.isPoint = isPoint;
|
| 57 | +function isXOnlyPoint(p) { |
| 58 | + if (!buffer_1.Buffer.isBuffer(p)) return false; |
| 59 | + if (p.length !== 32) return false; |
| 60 | + const x = BigInt(`0x${p.toString('hex')}`); |
| 61 | + if (x === _0n) return false; |
| 62 | + if (x >= EC_P) return false; |
| 63 | + const y2 = weistrass(x); |
| 64 | + return jacobiSymbol(y2) === 1; |
| 65 | +} |
| 66 | +exports.isXOnlyPoint = isXOnlyPoint; |
30 | 67 | const UINT31_MAX = Math.pow(2, 31) - 1;
|
31 | 68 | function UInt31(value) {
|
32 | 69 | return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
|
|
0 commit comments