🔂Silent Shard: Stages and General Usage for {2, 2} MPC-TSS

Ideally TSS library stack comprises of 3 major stages

The library will provide Actions for TSS

  1. Distributed key generation

  2. Create a signature

  3. Key rotation mechanism

Each Action object will create and process messages for the ping-pong protocol. Messages are encoded as JSON strings. At the end of each action, the library returns a result (KeyShare or SignatureResult) object. Action object and KeyShare object can be serialized/deserialized to/from a string.

Key generation takes place in two rounds of message passing between the two parties.

KeyGen
import {
    P1KeyGen,
    P2KeyGen,
    IP1KeyShare,
    IP2KeyShare,
    randBytes,
    IP1KeyGenResult, IP2KeyGenResult
} from "ecdsa-tss";


async function keyGen() {
  const sessionId = 'some session id';
  const x1 = await randBytes(32);
  const x2 = await randBytes(32);

  const p1KeyGen = new P1KeyGen(sessionId, x1);
  await p1KeyGen.init();

  const p2KeyGen = new P2KeyGen(sessionId, x2);

  // Round 1
  const msg1 = await p1KeyGen.processMessage(null);
  const msg2 = await p2KeyGen.processMessage(msg1.msg_to_send);

  // Round 2
  const msg3 = await p1KeyGen.processMessage(msg2.msg_to_send);
  const msg4 = await p2KeyGen.processMessage(msg3.msg_to_send);

  const p1KeyShare = msg3.p1_key_share;
  const p2KeyShare = msg4.p2_key_share;

  if (!(p1KeyShare && p2KeyShare)) {
    throw new Error('KeyGen failed');
  }
}

Signature generation takes place in 3 rounds of message passing between parties.

sign
import {
    P1Signature,
    P2Signature,
    IP1KeyShare,
    IP2KeyShare,
    randBytes,
    IP1SignatureResult, IP2SignatureResult
} from "ecdsa-tss";


async function signature(p1KeyShare: IP1KeyShare, p2KeyShare: IP2KeyShare) {
  const sessionId = 'session id for signature';
  const messageHash = await randBytes(32);
  const p1Signer = new P1Signature(sessionId, messageHash, p1KeyShare);
  const p2Signer = new P2Signature(sessionId, messageHash, p2KeyShare);

  // Round 1
  const msg1 = await p1Signer.processMessage(null);
  const msg2 = await p2Signer.processMessage(msg1.msg_to_send);

  // Round 2
  const msg3 = await p1Signer.processMessage(msg2.msg_to_send);
  const msg4 = await p2Signer.processMessage(msg3.msg_to_send);

  // Round 3
  const msg5 = await p1Signer.processMessage(msg4.msg_to_send);
  const msg6 = await p2Signer.processMessage(msg5.msg_to_send);
  
  const p1Sign = msg5.signature;
  const p2Sign = msg6.signature;

  if (!(p1Sign && p2Sign)) {
    throw new Error('Signature failed');
  }
}
Rotation
import {
    P1KeyGen,
    P2KeyGen,
    IP1KeyShare,
    IP2KeyShare,
    randBytes,
    IP1KeyGenResult, IP2KeyGenResult
} from "ecdsa-tss";


async function keyRefresh(oldP1KeyShare: IP1KeyShare, oldP2KeyShare: IP2KeyShare) {
  const sessionId = 'session id for key generation action';

  const p1KeyGen = P1KeyGen.getInstanceForKeyRefresh(sessionId, oldP1KeyShare);
  await p1KeyGen.init();

  const p2KeyGen = P2KeyGen.getInstanceForKeyRefresh(sessionId, oldP2KeyShare);

  // Round 1
  const msg1 = await p1KeyGen.processMessage(null);
  const msg2 = await p2KeyGen.processMessage(msg1.msg_to_send);

  // Round 2
  const msg3 = await p1KeyGen.processMessage(msg2.msg_to_send);
  const msg4 = await p2KeyGen.processMessage(msg3.msg_to_send);

  const p1KeyShare = msg3.p1_key_share;
  const p2KeyShare = msg4.p2_key_share;

  if (!(p1KeyShare && p2KeyShare)) {
    return null;
  }
}

While we assume that the parties already have a secure communication channel and they have a common session_id before running the actions, we do provide a wrapper as well for best case practice. To create a signature, the parties also need to choose a message hash and a public key.

Last updated