const length = bytes.length
const head = bytes[0]
const tail = bytes.subarray(1)
- const x = this.sliceBytesNumBE(tail, 0, this.L)
+ const x = this.bytesToBigint(tail.subarray(0, this.L))
// No actual validation is done here: use .assertValidity()
if (length === comp && (head === 0x02 || head === 0x03)) {
// Equation is y² == x³ + ax + b. We calculate y from x.
p = this.Point(x, y, 1n)
}
// Uncompressed 65-byte point, 0x04 prefix
- if (length === uncomp && head === 0x04) p = this.Point(x, this.sliceBytesNumBE(tail, this.L, this.L2), 1n)
+ if (length === uncomp && head === 0x04) p = this.Point(x, this.bytesToBigint(tail.subarray(this.L, this.L2)), 1n)
// Validate point
return p ? p.assertValidity() : this.err('bad point: not on curve')
}
return this.G.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2)).assertValidity()
}
- static bytesToBigint = (b: Bytes): bigint => BigInt('0x' + (this.bytesToHex(b) || '0'))
- static sliceBytesNumBE = (b: Bytes, from: number, to: number) => this.bytesToBigint(b.subarray(from, to))
+ static bytesToBigint (b: Bytes): bigint {
+ let int = BigInt(b[0]), len = b.length
+ for (let i = 1; i < len; i++) {
+ int <<= 8n
+ int |= BigInt(b[i])
+ }
+ return int
+ }
/** Number to 32b. Must be 0 <= num < 2²⁵⁶. validate, pad, to bytes. */
static bigintTo32Bytes (num: bigint): Bytes {
.padStart(this.L2, '0')
)
}
+
/** Normalize private key to scalar (bigint). Verifies scalar is in range 1<s<N */
static secretKeyToScalar (secretKey: Bytes): bigint {
const num = this.bytesToBigint(this.abytes(secretKey, this.L, 'secret key'))
return this.bigintInRange(num, 1n, this.N, 'invalid secret key: outside of range')
}
- /** For Signature malleability, validates sig.s is bigger than N/2. */
- static highS = (n: bigint): boolean => n > this.N >> 1n
+
/** Creates 33/65-byte public key from 32-byte private key. */
static getPublicKey (privKey: Bytes, isCompressed = true): Bytes {
return this.G.multiply(this.secretKeyToScalar(privKey)).toBytes(isCompressed)
addRecoveryBit: (bit: number): RecoveredSignature => {
return this.Signature(r, s, bit) as RecoveredSignature
},
- hasHighS: (): boolean => {
- return this.highS(s)
- },
toBytes: (format: ECDSASignatureFormat = this.SIG_COMPACT): Bytes => {
const res = this.concatBytes(this.bigintTo32Bytes(r), this.bigintTo32Bytes(s))
if (format === this.SIG_RECOVERED) {
recoveryBit = b[0]
b = b.subarray(1)
}
- const r = this.sliceBytesNumBE(b, 0, this.L)
- const s = this.sliceBytesNumBE(b, this.L, this.L2)
+ const r = this.bytesToBigint(b.subarray(0, this.L))
+ const s = this.bytesToBigint(b.subarray(this.L, this.L2))
return this.Signature(r, s, recoveryBit)
}