@covenance/dlc
Version:
Crypto and Bitcoin functions for Covenance DLC implementation
108 lines • 4.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAdaptorSig = createAdaptorSig;
exports.adaptSig = adaptSig;
exports.verifyAdaptorSig = verifyAdaptorSig;
exports.generateEvenYPrivateKey = generateEvenYPrivateKey;
const secp256k1_1 = require("./secp256k1");
const utils_1 = require("../utils");
const general_1 = require("./general");
/**
* Counterparty function to create an adaptor signature for a specific event outcome
* @param counterpartyPrivKey - Counterparty's private key
* @param oracleSigPoint - Oracle's signature point for the event outcome
* @param cetSighash - Sighash of the event outcome CET
* @returns Counterparty's adaptor signature
*/
async function createAdaptorSig(counterpartyPrivKey, oracleSigPoint, cetSighash, tag = Uint8Array.from(Buffer.from('7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c', 'hex')) // SHA256('BIP0340/challenge')
) {
let r_cp;
let r_cpBigInt;
let R_cp;
let R_prime_cp;
// Generate nonce UNTIL (R_cp + S_i).y is even
do {
// Generate random nonce
r_cp = secp256k1_1.utils.randomPrivateKey();
r_cpBigInt = BigInt('0x' + (0, utils_1.bytesToHex)(r_cp));
// Compute R_cp = r_cp * G
R_cp = secp256k1_1.Point.fromPrivateKey(r_cpBigInt);
// Compute R'_cp = R_cp + S_i
R_prime_cp = R_cp.add(oracleSigPoint);
} while ((R_prime_cp.y & 1n) === 1n);
// Fail if r = 0
if (r_cpBigInt === 0n) {
throw new Error('Generated nonce is zero');
}
// Get counterparty's public key
const P_cp = secp256k1_1.Point.fromPrivateKey(counterpartyPrivKey);
// Compute H(tag||tag||R'_cp||P_cp||cet_i)
const hashInput = new Uint8Array([
...tag,
...tag,
...R_prime_cp.toRawBytes(true).slice(1),
...P_cp.toRawBytes(true).slice(1),
...cetSighash
]);
const hash = await (0, utils_1.sha256)(hashInput);
const e = (0, general_1.mod)(BigInt('0x' + (0, utils_1.bytesToHex)(hash)), secp256k1_1.CURVE.n);
// Compute s'_cp = r_cp + H(R'_cp||P_cp||cet_i)x_cp
const x_cp = BigInt('0x' + (0, utils_1.bytesToHex)(counterpartyPrivKey));
const s_prime_cp = (0, general_1.mod)(r_cpBigInt + e * x_cp, secp256k1_1.CURVE.n);
return { R_prime: R_prime_cp, s_prime: s_prime_cp };
}
/**
* Counterparty function to adapt (finalize) an adaptor signature
* @param adaptorSig - The adaptor signature to finalize
* @param s - The oracle's scalar value (s) from their signature or repayment secret
* @returns The final signature
*/
function adaptSig(adaptorSig, s) {
// Compute s_cp = s'_cp + s
const s_cp = adaptorSig.s_prime + s;
return { R: adaptorSig.R_prime, s: (0, general_1.mod)(s_cp, secp256k1_1.CURVE.n) };
}
/**
* Function to verify an adaptor signature
* @param adaptorSig - The adaptor signature to verify
* @param counterpartyPubKey - The counterparty's public key
* @param cetSighash - The sighash of the event outcome CET
* @param oracleSigPoint - The oracle's signature point for the event outcome
* @returns Boolean indicating whether the adaptor signature is valid
*/
async function verifyAdaptorSig(adaptorSig, counterpartyPubKey, cetSighash, oracleSigPoint, tag = Uint8Array.from(Buffer.from('7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c', 'hex')) // SHA256('BIP0340/challenge')
) {
// Compute H(tag||tag||R'_cp||P_cp||cet_i)
const hashInput = new Uint8Array([
...tag,
...tag,
...adaptorSig.R_prime.toRawBytes(true).slice(1),
...counterpartyPubKey.toRawBytes(true).slice(1),
...cetSighash
]);
const hash = await (0, utils_1.sha256)(hashInput);
const e = (0, general_1.mod)(BigInt('0x' + (0, utils_1.bytesToHex)(hash)), secp256k1_1.CURVE.n);
// Compute s'_cp * G
const sG = secp256k1_1.Point.BASE.multiply(adaptorSig.s_prime);
// Compute R_cp = R'_cp - S_i
const R_cp = adaptorSig.R_prime.subtract(oracleSigPoint);
// Compute R_cp + e * P_cp
const rightSide = R_cp.add(counterpartyPubKey.multiply(e));
// Verify s'_cp * G = R_cp + e * P_cp
return sG.equals(rightSide);
}
/**
* Function to generate a private key which produces a public key with even y.
* This is to avoid doing BIP-340 secret-key parity adjustment (flip if public key has odd Y) each time an adaptor signature is created.
* @returns A private key which produces a public key with even y.
*/
function generateEvenYPrivateKey() {
let privKey = BigInt('0x' + (0, utils_1.bytesToHex)(secp256k1_1.utils.randomPrivateKey()));
let pubKey = secp256k1_1.Point.fromPrivateKey(privKey);
if ((pubKey.y & 1n) === 1n) {
privKey = secp256k1_1.CURVE.n - privKey; // negate secret
pubKey = secp256k1_1.Point.fromPrivateKey(privKey); // now pubKey.y is even
}
return Buffer.from(privKey.toString(16).padStart(64, "0"), "hex");
}
//# sourceMappingURL=counterparty.js.map