"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidVError = exports.InvalidYParityError = exports.InvalidSError = exports.InvalidRError = exports.MissingPropertiesError = exports.InvalidSerializedSizeError = void 0;
exports.assert = assert;
exports.fromBytes = fromBytes;
exports.fromHex = fromHex;
exports.extract = extract;
exports.from = from;
exports.fromDerBytes = fromDerBytes;
exports.fromDerHex = fromDerHex;
exports.fromLegacy = fromLegacy;
exports.fromRpc = fromRpc;
exports.fromTuple = fromTuple;
exports.toBytes = toBytes;
exports.toHex = toHex;
exports.toDerBytes = toDerBytes;
exports.toDerHex = toDerHex;
exports.toLegacy = toLegacy;
exports.toRpc = toRpc;
exports.toTuple = toTuple;
exports.validate = validate;
exports.vToYParity = vToYParity;
exports.yParityToV = yParityToV;
const secp256k1_1 = require("@noble/curves/secp256k1");
const Bytes = require("./Bytes.js");
const Errors = require("./Errors.js");
const Hex = require("./Hex.js");
const Json = require("./Json.js");
const Solidity = require("./Solidity.js");
function assert(signature, options = {}) {
    const { recovered } = options;
    if (typeof signature.r === 'undefined')
        throw new MissingPropertiesError({ signature });
    if (typeof signature.s === 'undefined')
        throw new MissingPropertiesError({ signature });
    if (recovered && typeof signature.yParity === 'undefined')
        throw new MissingPropertiesError({ signature });
    if (signature.r < 0n || signature.r > Solidity.maxUint256)
        throw new InvalidRError({ value: signature.r });
    if (signature.s < 0n || signature.s > Solidity.maxUint256)
        throw new InvalidSError({ value: signature.s });
    if (typeof signature.yParity === 'number' &&
        signature.yParity !== 0 &&
        signature.yParity !== 1)
        throw new InvalidYParityError({ value: signature.yParity });
}
function fromBytes(signature) {
    return fromHex(Hex.fromBytes(signature));
}
function fromHex(signature) {
    if (signature.length !== 130 && signature.length !== 132)
        throw new InvalidSerializedSizeError({ signature });
    const r = BigInt(Hex.slice(signature, 0, 32));
    const s = BigInt(Hex.slice(signature, 32, 64));
    const yParity = (() => {
        const yParity = Number(`0x${signature.slice(130)}`);
        if (Number.isNaN(yParity))
            return undefined;
        try {
            return vToYParity(yParity);
        }
        catch {
            throw new InvalidYParityError({ value: yParity });
        }
    })();
    if (typeof yParity === 'undefined')
        return {
            r,
            s,
        };
    return {
        r,
        s,
        yParity,
    };
}
function extract(value) {
    if (typeof value.r === 'undefined')
        return undefined;
    if (typeof value.s === 'undefined')
        return undefined;
    return from(value);
}
function from(signature) {
    const signature_ = (() => {
        if (typeof signature === 'string')
            return fromHex(signature);
        if (signature instanceof Uint8Array)
            return fromBytes(signature);
        if (typeof signature.r === 'string')
            return fromRpc(signature);
        if (signature.v)
            return fromLegacy(signature);
        return {
            r: signature.r,
            s: signature.s,
            ...(typeof signature.yParity !== 'undefined'
                ? { yParity: signature.yParity }
                : {}),
        };
    })();
    assert(signature_);
    return signature_;
}
function fromDerBytes(signature) {
    return fromDerHex(Hex.fromBytes(signature));
}
function fromDerHex(signature) {
    const { r, s } = secp256k1_1.secp256k1.Signature.fromDER(Hex.from(signature).slice(2));
    return { r, s };
}
function fromLegacy(signature) {
    return {
        r: signature.r,
        s: signature.s,
        yParity: vToYParity(signature.v),
    };
}
function fromRpc(signature) {
    const yParity = (() => {
        const v = signature.v ? Number(signature.v) : undefined;
        let yParity = signature.yParity ? Number(signature.yParity) : undefined;
        if (typeof v === 'number' && typeof yParity !== 'number')
            yParity = vToYParity(v);
        if (typeof yParity !== 'number')
            throw new InvalidYParityError({ value: signature.yParity });
        return yParity;
    })();
    return {
        r: BigInt(signature.r),
        s: BigInt(signature.s),
        yParity,
    };
}
function fromTuple(tuple) {
    const [yParity, r, s] = tuple;
    return from({
        r: r === '0x' ? 0n : BigInt(r),
        s: s === '0x' ? 0n : BigInt(s),
        yParity: yParity === '0x' ? 0 : Number(yParity),
    });
}
function toBytes(signature) {
    return Bytes.fromHex(toHex(signature));
}
function toHex(signature) {
    assert(signature);
    const r = signature.r;
    const s = signature.s;
    const signature_ = Hex.concat(Hex.fromNumber(r, { size: 32 }), Hex.fromNumber(s, { size: 32 }), typeof signature.yParity === 'number'
        ? Hex.fromNumber(yParityToV(signature.yParity), { size: 1 })
        : '0x');
    return signature_;
}
function toDerBytes(signature) {
    const sig = new secp256k1_1.secp256k1.Signature(signature.r, signature.s);
    return sig.toDERRawBytes();
}
function toDerHex(signature) {
    const sig = new secp256k1_1.secp256k1.Signature(signature.r, signature.s);
    return `0x${sig.toDERHex()}`;
}
function toLegacy(signature) {
    return {
        r: signature.r,
        s: signature.s,
        v: yParityToV(signature.yParity),
    };
}
function toRpc(signature) {
    const { r, s, yParity } = signature;
    return {
        r: Hex.fromNumber(r, { size: 32 }),
        s: Hex.fromNumber(s, { size: 32 }),
        yParity: yParity === 0 ? '0x0' : '0x1',
    };
}
function toTuple(signature) {
    const { r, s, yParity } = signature;
    return [
        yParity ? '0x01' : '0x',
        r === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(r)),
        s === 0n ? '0x' : Hex.trimLeft(Hex.fromNumber(s)),
    ];
}
function validate(signature, options = {}) {
    try {
        assert(signature, options);
        return true;
    }
    catch {
        return false;
    }
}
function vToYParity(v) {
    if (v === 0 || v === 27)
        return 0;
    if (v === 1 || v === 28)
        return 1;
    if (v >= 35)
        return v % 2 === 0 ? 1 : 0;
    throw new InvalidVError({ value: v });
}
function yParityToV(yParity) {
    if (yParity === 0)
        return 27;
    if (yParity === 1)
        return 28;
    throw new InvalidYParityError({ value: yParity });
}
class InvalidSerializedSizeError extends Errors.BaseError {
    constructor({ signature }) {
        super(`Value \`${signature}\` is an invalid signature size.`, {
            metaMessages: [
                'Expected: 64 bytes or 65 bytes.',
                `Received ${Hex.size(Hex.from(signature))} bytes.`,
            ],
        });
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.InvalidSerializedSizeError'
        });
    }
}
exports.InvalidSerializedSizeError = InvalidSerializedSizeError;
class MissingPropertiesError extends Errors.BaseError {
    constructor({ signature }) {
        super(`Signature \`${Json.stringify(signature)}\` is missing either an \`r\`, \`s\`, or \`yParity\` property.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.MissingPropertiesError'
        });
    }
}
exports.MissingPropertiesError = MissingPropertiesError;
class InvalidRError extends Errors.BaseError {
    constructor({ value }) {
        super(`Value \`${value}\` is an invalid r value. r must be a positive integer less than 2^256.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.InvalidRError'
        });
    }
}
exports.InvalidRError = InvalidRError;
class InvalidSError extends Errors.BaseError {
    constructor({ value }) {
        super(`Value \`${value}\` is an invalid s value. s must be a positive integer less than 2^256.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.InvalidSError'
        });
    }
}
exports.InvalidSError = InvalidSError;
class InvalidYParityError extends Errors.BaseError {
    constructor({ value }) {
        super(`Value \`${value}\` is an invalid y-parity value. Y-parity must be 0 or 1.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.InvalidYParityError'
        });
    }
}
exports.InvalidYParityError = InvalidYParityError;
class InvalidVError extends Errors.BaseError {
    constructor({ value }) {
        super(`Value \`${value}\` is an invalid v value. v must be 27, 28 or >=35.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'Signature.InvalidVError'
        });
    }
}
exports.InvalidVError = InvalidVError;
//# sourceMappingURL=Signature.js.map