Skip to content

Commit

Permalink
feat(sdk-lib-mpc): combine partial signatures util support
Browse files Browse the repository at this point in the history
Ticket: HSM-341
  • Loading branch information
islamaminBitGo committed Apr 15, 2024
1 parent 23869a7 commit 6596fd2
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 4 deletions.
11 changes: 9 additions & 2 deletions modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { SignSession, Keyshare, Message } from '@silencelaboratories/dkls-wasm-ll-node';
import { DeserializedBroadcastMessage, DeserializedMessages, DklsSignature, DsgState } from './types';
import {
DeserializedBroadcastMessage,
DeserializedMessages,
DklsSignature,
DsgState,
PartialSignatureR,
} from './types';
import { decode } from 'cbor';

export class Dsg {
Expand Down Expand Up @@ -98,7 +104,7 @@ export class Dsg {
* @param messagesForIthRound - messages to process the current round
* @returns {DeserializedMessages} - messages to send to other parties for the next round
*/
handleIncomingMessages(messagesForIthRound: DeserializedMessages): DeserializedMessages {
handleIncomingMessages(messagesForIthRound: DeserializedMessages): DeserializedMessages & Partial<PartialSignatureR> {
let nextRoundMessages: Message[] = [];
let nextRoundDeserializedMessages: DeserializedMessages = { broadcastMessages: [], p2pMessages: [] };
this._restoreSession();
Expand Down Expand Up @@ -134,6 +140,7 @@ export class Dsg {
},
],
p2pMessages: [],
r: decode(this.dsgSession.toBytes()).round.WaitMsg4.r,
};
} else {
// Update round data.
Expand Down
1 change: 1 addition & 0 deletions modules/sdk-lib-mpc/src/tss/ecdsa-dkls/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * as DklsDkg from './dkg';
export * as DklsDsg from './dsg';
export * as DklsTypes from './types';
export * as DklsComms from './commsLayer';
export * as DklsUtils from './util';
3 changes: 3 additions & 0 deletions modules/sdk-lib-mpc/src/tss/ecdsa-dkls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export type DklsSignature = {
R: Uint8Array;
S: Uint8Array;
};
export type PartialSignatureR = {
r: Uint8Array;
};
export type SerializedBroadcastMessage = BroadcastMessage<string>;
export type DeserializedBroadcastMessage = BroadcastMessage<Uint8Array>;
export type SerializedP2PMessage = P2PMessage<string, string>;
Expand Down
29 changes: 29 additions & 0 deletions modules/sdk-lib-mpc/src/tss/ecdsa-dkls/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Signature } from '@noble/secp256k1';
import { Secp256k1Curve } from '../../curves';
import { bigIntFromBufferBE, bigIntToBufferBE } from '../../util';
import { DklsSignature } from './types';
import { decode } from 'cbor';

/**
* Combines partial signatures from parties participating in DSG.
* @param round4MessagePayloads - round 4 message payloads from participating parties
* @param rHex - hex representation of the r value in the signature
* @returns {DeserializedMessages} - messages to send to other parties for the next round
*/
export function combinePartialSignatures(round4MessagePayloads: Uint8Array[], rHex: string): DklsSignature {
const r = bigIntFromBufferBE(Buffer.from(rHex, 'hex').subarray(1));
const s0Arr = round4MessagePayloads.map((p) => decode(p).s_0);
const s1Arr = round4MessagePayloads.map((p) => decode(p).s_1);
const s0BigInts = s0Arr.map((s0) => bigIntFromBufferBE(Buffer.from(s0)));
const s1BigInts = s1Arr.map((s1) => bigIntFromBufferBE(Buffer.from(s1)));
const secp256k1Curve = new Secp256k1Curve();
const s0Sum = s0BigInts.slice(1).reduce((sumSoFar, s0) => secp256k1Curve.scalarAdd(sumSoFar, s0), s0BigInts[0]);
const s1Sum = s1BigInts.slice(1).reduce((sumSoFar, s1) => secp256k1Curve.scalarAdd(sumSoFar, s1), s1BigInts[0]);
const s = secp256k1Curve.scalarMult(s0Sum, secp256k1Curve.scalarInvert(s1Sum));
const sig = new Signature(r, s);
const normalizedSig = sig.normalizeS();
return {
R: new Uint8Array(bigIntToBufferBE(normalizedSig.r)),
S: new Uint8Array(bigIntToBufferBE(normalizedSig.s)),
};
}
13 changes: 11 additions & 2 deletions modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { DklsDsg } from '../../../../src/tss/ecdsa-dkls';
import { DklsDsg, DklsUtils } from '../../../../src/tss/ecdsa-dkls';
import * as fs from 'fs';
import * as crypto from 'crypto';
import should from 'should';
import { Keyshare } from '@silencelaboratories/dkls-wasm-ll-node';
import { decode } from 'cbor';
import { Secp256k1Bip32HdTree, bigIntFromBufferBE, bigIntToBufferBE } from '../../../../src';

import * as secp256k1 from 'secp256k1';

describe('DKLS Dsg 2x3', function () {
Expand Down Expand Up @@ -91,6 +90,16 @@ describe('DKLS Dsg 2x3', function () {
broadcastMessages: party2Round4Messages.broadcastMessages,
});
should.exist(party1.signature);
const combinedSigUsingUtil = DklsUtils.combinePartialSignatures(
[party1Round4Messages.broadcastMessages[0].payload, party2Round4Messages.broadcastMessages[0].payload],
Buffer.from(party1Round4Messages.r!).toString('hex')
);
(
(combinedSigUsingUtil.R.every((p) => party1.signature.R.includes(p)) &&
party1.signature.R.every((p) => combinedSigUsingUtil.R.includes(p))) ||
(party1.signature.S.every((p) => combinedSigUsingUtil.S.includes(p)) &&
combinedSigUsingUtil.S.every((p) => party1.signature.S.includes(p)))
).should.equal(true);
// ////////////
party2.handleIncomingMessages({
p2pMessages: [],
Expand Down

0 comments on commit 6596fd2

Please sign in to comment.