@covenance/dlc
Version:
Crypto and Bitcoin functions for Covenance DLC implementation
338 lines (337 loc) • 13 kB
TypeScript
/*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
declare const CURVE: Readonly<{
a: bigint;
b: bigint;
P: bigint;
n: bigint;
h: bigint;
Gx: bigint;
Gy: bigint;
beta: bigint;
}>;
export { CURVE };
type Hex = Uint8Array | string;
type PrivKey = Hex | bigint | number;
type PubKey = Hex | Point;
type Sig = Hex | Signature;
/**
* Jacobian Point works in 3d / jacobi coordinates: (x, y, z) ∋ (x=x/z², y=y/z³)
* Default Point works in 2d / affine coordinates: (x, y)
* We're doing calculations in jacobi, because its operations don't require costly inversion.
*/
declare class JacobianPoint {
readonly x: bigint;
readonly y: bigint;
readonly z: bigint;
constructor(x: bigint, y: bigint, z: bigint);
static readonly BASE: JacobianPoint;
static readonly ZERO: JacobianPoint;
static fromAffine(p: Point): JacobianPoint;
/**
* Takes a bunch of Jacobian Points but executes only one
* invert on all of them. invert is very slow operation,
* so this improves performance massively.
*/
static toAffineBatch(points: JacobianPoint[]): Point[];
static normalizeZ(points: JacobianPoint[]): JacobianPoint[];
/**
* Compare one point to another.
*/
equals(other: JacobianPoint): boolean;
/**
* Flips point to one corresponding to (x, -y) in Affine coordinates.
*/
negate(): JacobianPoint;
double(): JacobianPoint;
add(other: JacobianPoint): JacobianPoint;
subtract(other: JacobianPoint): JacobianPoint;
/**
* Non-constant-time multiplication. Uses double-and-add algorithm.
* It's faster, but should only be used when you don't care about
* an exposed private key e.g. sig verification, which works over *public* keys.
*/
multiplyUnsafe(scalar: bigint): JacobianPoint;
/**
* Creates a wNAF precomputation window. Used for caching.
* Default window size is set by `utils.precompute()` and is equal to 8.
* Which means we are caching 65536 points: 256 points for every bit from 0 to 256.
* @returns 65K precomputed points, depending on W
*/
private precomputeWindow;
/**
* Implements w-ary non-adjacent form for calculating ec multiplication.
* @param n
* @param affinePoint optional 2d point to save cached precompute windows on it.
* @returns real and fake (for const-time) points
*/
private wNAF;
/**
* Constant time multiplication.
* Uses wNAF method. Windowed method may be 10% faster,
* but takes 2x longer to generate and consumes 2x memory.
* @param scalar by which the point would be multiplied
* @param affinePoint optional point ot save cached precompute windows on it
* @returns New point
*/
multiply(scalar: number | bigint, affinePoint?: Point): JacobianPoint;
toAffine(invZ?: bigint): Point;
}
/**
* Default Point works in default aka affine coordinates: (x, y)
*/
export declare class Point {
readonly x: bigint;
readonly y: bigint;
/**
* Base point aka generator. public_key = Point.BASE * private_key
*/
static BASE: Point;
/**
* Identity point aka point at infinity. point = point + zero_point
*/
static ZERO: Point;
_WINDOW_SIZE?: number;
constructor(x: bigint, y: bigint);
_setWindowSize(windowSize: number): void;
hasEvenY(): boolean;
/**
* Supports compressed Schnorr and ECDSA points
* @param bytes
* @returns Point instance
*/
private static fromCompressedHex;
private static fromUncompressedHex;
/**
* Converts hash string or Uint8Array to Point.
* @param hex schnorr or ECDSA hex
*/
static fromHex(hex: Hex): Point;
static fromPrivateKey(privateKey: PrivKey): Point;
/**
* Recovers public key from ECDSA signature.
* https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
* ```
* recover(r, s, h) where
* u1 = hs^-1 mod n
* u2 = sr^-1 mod n
* Q = u1⋅G + u2⋅R
* ```
*/
static fromSignature(msgHash: Hex, signature: Sig, recovery: number): Point;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
toHexX(): string;
toRawX(): Uint8Array<ArrayBuffer>;
assertValidity(): void;
equals(other: Point): boolean;
negate(): Point;
double(): Point;
add(other: Point): Point;
subtract(other: Point): Point;
multiply(scalar: number | bigint): Point;
/**
* Efficiently calculate `aP + bQ`.
* Unsafe, can expose private key, if used incorrectly.
* TODO: Utilize Shamir's trick
* @returns non-zero affine point
*/
multiplyAndAddUnsafe(Q: Point, a: bigint, b: bigint): Point | undefined;
}
export declare class Signature {
readonly r: bigint;
readonly s: bigint;
constructor(r: bigint, s: bigint);
static fromCompact(hex: Hex): Signature;
static fromDER(hex: Hex): Signature;
static fromHex(hex: Hex): Signature;
assertValidity(): void;
hasHighS(): boolean;
normalizeS(): Signature;
toDERRawBytes(): Uint8Array<ArrayBufferLike>;
toDERHex(): string;
toRawBytes(): Uint8Array<ArrayBufferLike>;
toHex(): string;
toCompactRawBytes(): Uint8Array<ArrayBufferLike>;
toCompactHex(): string;
}
declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
/**
* Convert byte array to hex string. Uses built-in function, when available.
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
export declare function bytesToHex(bytes: Uint8Array): string;
/**
* Convert hex string to byte array. Uses built-in function, when available.
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
*/
export declare function hexToBytes(hex: string): Uint8Array;
declare function numTo32b(num: bigint): Uint8Array;
declare function mod(a: bigint, b?: bigint): bigint;
declare function invert(number: bigint, modulo?: bigint): bigint;
type U8A = Uint8Array;
type Sha256FnSync = undefined | ((...messages: Uint8Array[]) => Uint8Array);
type HmacFnSync = undefined | ((key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array);
declare function normalizePrivateKey(key: PrivKey): bigint;
/**
* Computes public key for secp256k1 private key.
* @param privateKey 32-byte private key
* @param isCompressed whether to return compact, or full key
* @returns Public key, full by default; short when isCompressed=true
*/
export declare function getPublicKey(privateKey: PrivKey, isCompressed?: boolean): Uint8Array;
/**
* Recovers public key from signature and recovery bit. Throws on invalid sig/hash.
* @param msgHash message hash
* @param signature DER or compact sig
* @param recovery 0 or 1
* @param isCompressed whether to return compact, or full key
* @returns Public key, full by default; short when isCompressed=true
*/
export declare function recoverPublicKey(msgHash: Hex, signature: Sig, recovery: number, isCompressed?: boolean): Uint8Array;
/**
* ECDH (Elliptic Curve Diffie Hellman) implementation.
* 1. Checks for validity of private key
* 2. Checks for the public key of being on-curve
* @param privateA private key
* @param publicB different public key
* @param isCompressed whether to return compact, or full key
* @returns shared public key
*/
export declare function getSharedSecret(privateA: PrivKey, publicB: PubKey, isCompressed?: boolean): Uint8Array;
type Entropy = Hex | true;
type OptsOther = {
canonical?: boolean;
der?: boolean;
extraEntropy?: Entropy;
};
type OptsRecov = {
recovered: true;
} & OptsOther;
type OptsNoRecov = {
recovered?: false;
} & OptsOther;
/**
* Signs message hash (not message: you need to hash it by yourself).
* We don't auto-hash because some users would want non-SHA256 hash.
* We are always using deterministic signatures (RFC6979 3.1) instead of
* letting user specify random k.
* HMAC-DRBG generates k, then calculates sig point Q & signature r, s based on it.
* Could receive extra entropy k' as per RFC6979 3.6 Additional data.
* k' is not generated by default, because of backwards-compatibility concerns.
* We strongly recommend to pass {extraEntropy: true}.
*
* low-s signatures are generated by default. If you don't want it, use canonical: false.
*
* ```
* sign(m, d, k) where
* (x, y) = G × k
* r = x mod n
* s = (m + dr)/k mod n
* ```
* @param opts `recovered, canonical, der, extraEntropy`
*/
declare function sign(msgHash: Hex, privKey: PrivKey, opts: OptsRecov): Promise<[U8A, number]>;
declare function sign(msgHash: Hex, privKey: PrivKey, opts?: OptsNoRecov): Promise<U8A>;
/**
* Signs message hash (not message: you need to hash it by yourself).
* Synchronous version of `sign()`: see its documentation.
* @param opts `recovered, canonical, der, extraEntropy`
*/
declare function signSync(msgHash: Hex, privKey: PrivKey, opts: OptsRecov): [U8A, number];
declare function signSync(msgHash: Hex, privKey: PrivKey, opts?: OptsNoRecov): U8A;
export { sign, signSync };
type VOpts = {
strict?: boolean;
};
/**
* Verifies a signature against message hash and public key.
* Rejects non-canonical / high-s signatures by default: to override,
* specify option `{strict: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
*
* ```
* verify(r, s, h, P) where
* U1 = hs^-1 mod n
* U2 = rs^-1 mod n
* R = U1⋅G - U2⋅P
* mod(R.x, n) == r
* ```
*/
export declare function verify(signature: Sig, msgHash: Hex, publicKey: PubKey, opts?: VOpts): boolean;
declare class SchnorrSignature {
readonly r: bigint;
readonly s: bigint;
constructor(r: bigint, s: bigint);
static fromHex(hex: Hex): SchnorrSignature;
assertValidity(): void;
toHex(): string;
toRawBytes(): Uint8Array;
}
declare function schnorrGetPublicKey(privateKey: PrivKey): Uint8Array;
/**
* Creates Schnorr signature. Improved security: verifies itself before producing an output.
* @param msg message (not message hash)
* @param privateKey private key
* @param auxRand random bytes that would be added to k. Bad RNG won't break it.
*/
declare function schnorrSign(msg: Hex, privKey: PrivKey, auxRand?: Hex): Promise<Uint8Array>;
/**
* Synchronously creates Schnorr signature. Improved security: verifies itself before
* producing an output.
* @param msg message (not message hash)
* @param privateKey private key
* @param auxRand random bytes that would be added to k. Bad RNG won't break it.
*/
declare function schnorrSignSync(msg: Hex, privKey: PrivKey, auxRand?: Hex): Uint8Array;
/**
* Verifies Schnorr signature.
*/
declare function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): Promise<boolean>;
/**
* Verifies Schnorr signature synchronously.
*/
declare function schnorrVerifySync(signature: Hex, message: Hex, publicKey: Hex): boolean;
export declare const schnorr: {
Signature: typeof SchnorrSignature;
getPublicKey: typeof schnorrGetPublicKey;
sign: typeof schnorrSign;
verify: typeof schnorrVerify;
signSync: typeof schnorrSignSync;
verifySync: typeof schnorrVerifySync;
};
export declare const utils: {
bytesToHex: typeof bytesToHex;
hexToBytes: typeof hexToBytes;
concatBytes: typeof concatBytes;
mod: typeof mod;
invert: typeof invert;
isValidPrivateKey(privateKey: PrivKey): boolean;
_bigintTo32Bytes: typeof numTo32b;
_normalizePrivateKey: typeof normalizePrivateKey;
/**
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
* and convert them into private key, with the modulo bias being neglible.
* As per FIPS 186 B.4.1.
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
* @param hash hash output from sha512, or a similar function
* @returns valid private key
*/
hashToPrivateKey: (hash: Hex) => Uint8Array;
randomBytes: (bytesLength?: number) => Uint8Array;
randomPrivateKey: () => Uint8Array;
/**
* 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.
* 2. Precomputes point multiplication table. Is done by default on first `getPublicKey()` call.
* If you want your first getPublicKey to take 0.16ms instead of 20ms, make sure to call
* utils.precompute() somewhere without arguments first.
* @param windowSize 2, 4, 8, 16
* @returns cached point
*/
precompute(windowSize?: number, point?: Point): Point;
sha256: (...messages: Uint8Array[]) => Promise<Uint8Array>;
hmacSha256: (key: Uint8Array, ...messages: Uint8Array[]) => Promise<Uint8Array>;
sha256Sync: Sha256FnSync;
hmacSha256Sync: HmacFnSync;
taggedHash: (tag: string, ...messages: Uint8Array[]) => Promise<Uint8Array>;
taggedHashSync: (tag: string, ...messages: Uint8Array[]) => Uint8Array;
_JacobianPoint: typeof JacobianPoint;
};