Skip to content

Commit

Permalink
test: MusigSigner integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Jan 6, 2024
1 parent 49fa43a commit 6ca5929
Show file tree
Hide file tree
Showing 21 changed files with 1,091 additions and 337 deletions.
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lib/proto/**/*.d.ts
lib/proto/**/*.d.ts
23 changes: 9 additions & 14 deletions lib/Core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import zkpMusigInit, { Secp256k1ZKP } from '@michael1011/secp256k1-zkp';
import zkpInit from '@vulpemventures/secp256k1-zkp';
import zkpInit, { Secp256k1ZKP } from '@vulpemventures/secp256k1-zkp';
import { BIP32Interface } from 'bip32';
import {
Network,
Expand Down Expand Up @@ -57,18 +56,16 @@ type UnblindedOutput = Omit<LiquidTxOutput, 'value'> & {
isLbtc: boolean;
};

export let zkpMusig: Secp256k1ZKP;
export let zkp: Secp256k1ZKP;
let confi: confidential.Confidential;

export const setup = async () => {
init(ecc);
initEccLib(ecc);

const zkp = await zkpInit();
confi = new confidential.Confidential(zkp);

zkpMusig = await zkpMusigInit();
initLiquid(zkpMusig);
zkp = await zkpInit();
confi = new confidential.Confidential(zkp as any);
initLiquid(zkp);
};

export const parseTransaction = (
Expand Down Expand Up @@ -245,12 +242,10 @@ export const createMusig = (
ourKeys: ECPairInterface | BIP32Interface,
theirPublicKey: Buffer,
) =>
new Musig(
zkpMusig,
ECPair.fromPrivateKey(ourKeys.privateKey!),
randomBytes(32),
[ourKeys.publicKey, theirPublicKey],
);
new Musig(zkp, ECPair.fromPrivateKey(ourKeys.privateKey!), randomBytes(32), [
ourKeys.publicKey,
theirPublicKey,
]);

export const tweakMusig = (
type: CurrencyType,
Expand Down
65 changes: 50 additions & 15 deletions lib/cli/Command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { credentials } from '@grpc/grpc-js';
import { Network } from 'bitcoinjs-lib';
import { Network, Transaction } from 'bitcoinjs-lib';
import {
Musig,
Networks,
Expand All @@ -9,14 +9,16 @@ import {
} from 'boltz-core';
import { Networks as LiquidNetworks } from 'boltz-core/dist/lib/liquid';
import { randomBytes } from 'crypto';
import { ECPairInterface } from 'ecpair';
import { Transaction as LiquidTransaction } from 'liquidjs-lib';
import { Network as LiquidNetwork } from 'liquidjs-lib/src/networks';
import { Arguments } from 'yargs';
import {
parseTransaction,
setup,
toOutputScript,
tweakMusig,
zkpMusig,
zkp,
} from '../Core';
import { ECPair } from '../ECPairHelper';
import { getHexBuffer, stringify } from '../Utils';
Expand Down Expand Up @@ -86,20 +88,20 @@ export const prepareTx = async (
// If the redeem script can be parsed as JSON, it is a swap tree
try {
const tree = SwapTreeSerializer.deserializeSwapTree(argv.redeemScript);
const theirPublicKey = keyExtractionFunc(tree);

const musig = new Musig(zkpMusig, res.keys, randomBytes(32), [
theirPublicKey,
res.keys.publicKey,
]);
const tweakedKey = tweakMusig(type, musig, tree);

const swapOutput: any = detectSwap(tweakedKey, transaction);

swapOutput.swapTree = tree;
swapOutput.internalKey = musig.getAggregatedPublicKey();

res.swapOutput = swapOutput;
const { musig, swapOutput } = musigFromExtractedKey(
type,
res.keys,
keyExtractionFunc(tree),
tree,
transaction,
);

res.swapOutput = {
...swapOutput,
swapTree: tree,
internalKey: musig.getAggregatedPublicKey(),
};
} catch (e) {
res.redeemScript = getHexBuffer(argv.redeemScript);
res.swapOutput = detectSwap(res.redeemScript, transaction);
Expand Down Expand Up @@ -141,3 +143,36 @@ export const printResponse = (response: unknown): void => {
export const printError = (error: Error): void => {
console.error(`${error.name}: ${error.message}`);
};

export const musigFromExtractedKey = (
type: CurrencyType,
ourKeys: ECPairInterface,
theirPublicKey: Buffer,
tree: Types.SwapTree,
lockupTx: Transaction | LiquidTransaction,
) => {
for (const tieBreaker of ['02', '03']) {
const compressedKey = Buffer.concat([
getHexBuffer(tieBreaker),
theirPublicKey,
]);

const musig = new Musig(zkp, ourKeys, randomBytes(32), [
compressedKey,
ourKeys.publicKey,
]);
const tweakedKey = tweakMusig(type, musig, tree);

const swapOutput = detectSwap(tweakedKey, lockupTx);
if (swapOutput !== undefined) {
return {
musig,
tweakedKey,
swapOutput,
theirPublicKey: compressedKey,
};
}
}

throw 'could not find swap output';
};
29 changes: 14 additions & 15 deletions lib/cli/TaprootHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,30 @@ import {
Types,
detectSwap,
} from 'boltz-core';
import { TaprootUtils as LiquidTaprootDetails } from 'boltz-core/dist/lib/liquid';
import { LiquidRefundDetails } from 'boltz-core/lib/liquid';
import { randomBytes } from 'crypto';
import {
LiquidRefundDetails,
TaprootUtils as LiquidTaprootDetails,
} from 'boltz-core/dist/lib/liquid';
import { ECPairInterface } from 'ecpair';
import { Network as LiquidNetwork } from 'liquidjs-lib/src/networks';
import { Transaction as LiquidTransaction } from 'liquidjs-lib/src/transaction';
import { Arguments } from 'yargs';
import {
constructClaimTransaction,
setup,
tweakMusig,
zkpMusig,
} from '../Core';
import { constructClaimTransaction, setup } from '../Core';
import { ECPair } from '../ECPairHelper';
import { getHexBuffer } from '../Utils';
import { CurrencyType } from '../consts/Enums';
import { PartialSignature } from './BoltzApiClient';
import {
currencyTypeFromNetwork,
getWalletStub,
musigFromExtractedKey,
parseNetwork,
} from './Command';

export const setupCooperativeTransaction = async (
argv: Arguments<any>,
keyExtractionFunc: (tree: Types.SwapTree) => Buffer,
lockupTx: Transaction | LiquidTransaction,
) => {
await setup();

Expand All @@ -42,13 +40,14 @@ export const setupCooperativeTransaction = async (

const swapTree = SwapTreeSerializer.deserializeSwapTree(argv.swapTree);
const keys = ECPair.fromPrivateKey(getHexBuffer(argv.privateKey));
const theirPublicKey = keyExtractionFunc(swapTree);

const musig = new Musig(zkpMusig, keys, randomBytes(32), [
theirPublicKey,
keys.publicKey,
]);
const tweakedKey = tweakMusig(currencyType, musig, swapTree);
const { musig, tweakedKey, theirPublicKey } = musigFromExtractedKey(
currencyType,
keys,
keyExtractionFunc(swapTree),
swapTree,
lockupTx,
);

return {
keys,
Expand Down
19 changes: 12 additions & 7 deletions lib/cli/commands/CooperativeClaim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { parseTransaction } from '../../Core';
import { getHexString, stringify } from '../../Utils';
import BoltzApiClient from '../BoltzApiClient';
import BuilderComponents from '../BuilderComponents';
import { currencyTypeFromNetwork, parseNetwork } from '../Command';
import {
finalizeCooperativeTransaction,
prepareCooperativeTransaction,
Expand All @@ -27,21 +28,25 @@ export const builder = {
};

export const handler = async (argv: Arguments<any>): Promise<void> => {
const { network, keys, tweakedKey, theirPublicKey, musig, currencyType } =
await setupCooperativeTransaction(
argv,
extractRefundPublicKeyFromReverseSwapTree,
);

const boltzClient = new BoltzApiClient();
const swapStatus = await boltzClient.getStatus(argv.swapId);

if (swapStatus.transaction === undefined) {
throw 'no transaction in swap status';
}

const network = parseNetwork(argv.network);
const currencyType = currencyTypeFromNetwork(argv.network);

const lockupTx = parseTransaction(currencyType, swapStatus.transaction.hex);

const { keys, tweakedKey, theirPublicKey, musig } =
await setupCooperativeTransaction(
argv,
extractRefundPublicKeyFromReverseSwapTree,
lockupTx,
);

const { details, tx } = prepareCooperativeTransaction(
argv,
network,
Expand All @@ -60,7 +65,7 @@ export const handler = async (argv: Arguments<any>): Promise<void> => {
);
console.log(
stringify({
refundTransaction: finalizeCooperativeTransaction(
claimTransaction: finalizeCooperativeTransaction(
tx,
musig,
network,
Expand Down
12 changes: 10 additions & 2 deletions lib/cli/commands/CooperativeRefund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { parseTransaction } from '../../Core';
import { getHexString, stringify } from '../../Utils';
import BoltzApiClient from '../BoltzApiClient';
import BuilderComponents from '../BuilderComponents';
import { currencyTypeFromNetwork, parseNetwork } from '../Command';
import {
finalizeCooperativeTransaction,
prepareCooperativeTransaction,
Expand All @@ -26,15 +27,22 @@ export const builder = {
};

export const handler = async (argv: Arguments<any>): Promise<void> => {
const { keys, network, currencyType, musig, tweakedKey, theirPublicKey } =
await setupCooperativeTransaction(argv, extractClaimPublicKeyFromSwapTree);
const network = parseNetwork(argv.network);
const currencyType = currencyTypeFromNetwork(argv.network);

const boltzClient = new BoltzApiClient();
const lockupTx = parseTransaction(
currencyType,
(await boltzClient.getSwapTransaction(argv.swapId)).transactionHex,
);

const { keys, musig, tweakedKey, theirPublicKey } =
await setupCooperativeTransaction(
argv,
extractClaimPublicKeyFromSwapTree,
lockupTx,
);

const { details, tx } = prepareCooperativeTransaction(
argv,
network,
Expand Down
14 changes: 14 additions & 0 deletions lib/db/Migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,13 @@ class Migration {
.getQueryInterface()
.changeColumn('swaps', 'version', attrs);

await this.sequelize
.getQueryInterface()
.addColumn('swaps', 'refundPublicKey', {
type: new DataTypes.STRING(),
allowNull: true,
});

this.logUpdatingTable('reverseSwaps');

attrs.allowNull = true;
Expand All @@ -409,6 +416,13 @@ class Migration {
.getQueryInterface()
.changeColumn('reverseSwaps', 'version', attrs);

await this.sequelize
.getQueryInterface()
.addColumn('reverseSwaps', 'claimPublicKey', {
type: new DataTypes.STRING(),
allowNull: true,
});

await this.finishMigration(versionRow.version, currencies);
break;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/db/models/ReverseSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ReverseSwapType = {
lockupAddress: string;

keyIndex?: number;
claimPublicKey?: string;
redeemScript?: string;

claimAddress?: string;
Expand Down Expand Up @@ -55,6 +56,7 @@ class ReverseSwap extends Model implements ReverseSwapType {
public lockupAddress!: string;

public keyIndex?: number;
public claimPublicKey?: string;
public redeemScript?: string;

public claimAddress?: string;
Expand Down Expand Up @@ -113,6 +115,7 @@ class ReverseSwap extends Model implements ReverseSwapType {
},
lockupAddress: { type: new DataTypes.STRING(255), allowNull: false },
keyIndex: { type: new DataTypes.INTEGER(), allowNull: true },
claimPublicKey: { type: new DataTypes.STRING(), allowNull: true },
redeemScript: { type: new DataTypes.TEXT(), allowNull: true },
claimAddress: { type: new DataTypes.STRING(255), allowNull: true },
fee: { type: new DataTypes.BIGINT(), allowNull: false },
Expand Down
3 changes: 3 additions & 0 deletions lib/db/models/Swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type SwapType = {
version: SwapVersion;

keyIndex?: number;
refundPublicKey?: string;
redeemScript?: string;

fee?: number;
Expand Down Expand Up @@ -40,6 +41,7 @@ class Swap extends Model implements SwapType {
public version!: SwapVersion;

public keyIndex?: number;
public refundPublicKey?: string;
public redeemScript?: string;

public fee?: number;
Expand Down Expand Up @@ -90,6 +92,7 @@ class Swap extends Model implements SwapType {
},
},
keyIndex: { type: new DataTypes.INTEGER(), allowNull: true },
refundPublicKey: { type: new DataTypes.STRING(), allowNull: true },
redeemScript: { type: new DataTypes.TEXT(), allowNull: true },
fee: { type: new DataTypes.BIGINT(), allowNull: true },
referral: { type: new DataTypes.STRING(255), allowNull: true },
Expand Down
Loading

0 comments on commit 6ca5929

Please sign in to comment.