LogoLogo
Duo SDK
  • Introduction
  • Overview
  • Code Stack
  • HOW TO
    • Silent Shard Duo SDK Example
      • Admin
      • Server Node
      • Client Node
        • React-Native
          • Installing Silent Shard Duo RN SDK
          • Quick start
          • Error handling
          • Hooks
            • useECDSAKeyGen
            • useECDSASignGen
            • useECDSAKeyRefresh
          • Functions
            • keyGenECDSA
            • signGenECDSA
            • keyRefreshECDSA
          • Classes
            • ECDSAP1PartyKeys class
            • ECDSAP1KeyshareV2 class
  • ADVANCED SETUP
    • Low Level API
      • Key Generation
      • Sign
      • Key Rotation
    • MPC + Account Abstraction Kits
      • Biconomy Smart Accounts
        • Quick Start
        • Using the CLI version
        • Experience this in a Biconomy x SL powered DApp
      • Stackup Account Abstraction SDK
        • Quick Start
        • Using the CLI version
        • Experience it in a Stackup x SL powered DApp
      • Resources
        • Structure of the repository
        • Integration and Hosting
  • REFERENCE
    • MetaMask Snap
    • Contact Us
Powered by GitBook
On this page
  1. ADVANCED SETUP
  2. Low Level API

Key Rotation

Key rotation boosts the security of a system relying on secret key material. That been said secret shards for each party keys are refreshed and old keys even on hands of non authorized users are useless. Specially in a wallet the key property during key rotation is the need to rotate the secret shards of each party while keeping the public key the same which represents the wallet address. The idea behind the protocol is for both parties to agree on a common randomness seed R which is computed interactively as a two party coin tossing protocol. After that each party updates its secret key shard as x1'= x1 op R and x2'= x2 inv.op R such that public key remains the same

The following details how the new shards are generated using our bindings.

/// After keygen is performed
let (keyshare1, keyshare2) = perform_keygen().unwrap();
let session_id = SessionId::random();

/// Create refresh instances for each participant using the respective keyshares.
let p1 = keyshare1.get_refresh_instance(session_id);
let p2 = keyshare2.get_refresh_instance(session_id);

// Round 1
let (p1, msg1) = p1.process(())?;
let (p2, msg2) = p2.process(msg1)?;

// Round 2
let (new_keyshare1, msg3) = p1.process(msg2)?;
let new_keyshare2 = p2.process(msg3)?;

assert_eq!(new_keyshare1.public_key, new_keyshare2.public_key);
assert_eq!(new_keyshare1.public_key, keyshare1.public_key);
assert_eq!(new_keyshare2.public_key, keyshare2.public_key);

assert_ne!(new_keyshare1.data, keyshare1.data);
assert_ne!(new_keyshare2.data, keyshare2.data);

println!("Successfully refreshed keyshare!");
const p1Keyshare = // P1Keyshare from key generation
const p2Keyshare = // P2Keyshare from key generation

const sessionId = await generateSessionId();
// Get refresh instance 
const p1Refresh = await p1Keyshare.getRefreshInstance(sessionId);
const p2Refresh = await p2Keyshare.getRefreshInstance(sessionId);

// Peform key generation with refresh instances

// Round 1
const msg1 = await p1Refresh.genMsg1();
const msg2 = await p2Refresh.processMsg1(msg1);

// Round 2
const [p1keyshare, msg3] = await p1Refresh.processMsg2(msg2);
const p2keyshare = await p2Refresh.processMsg3(msg3);

// p1keyshare and p2keyshare are the new secret keyshares
// of each party with same public key
void refresh_keyshares(Handle *p1_share, Handle *p2_share, Handle *new_share1, Handle *new_share2) {
    // First we create new keygen instances for refresh 
    Handle p1_sess;
    Handle p2_sess;
    tss_buffer sess_buf, msg1, msg2,msg3, p1_share_buf,p2_share_buf, public_key, prev_public_key;
    Handle party_keys = p1_partykeys_new();

    // random session id generation. must be 32 bytes.
    srand((unsigned int) time(NULL));
    uint8_t session_id_data[32];
    for (size_t i = 0; i < sizeof(session_id_data); i++) {
        session_id_data[i] = rand() % 256;
    }

    sess_buf.ptr = session_id_data;
    sess_buf.len = sizeof(session_id_data);

    // Get public key from old keyshare to check against later
    if (p1_keyshare_public_key(*p1_share, &prev_public_key) != TSS_OK) {
        perror("Error during p1_keyshare_public_key\n"); exit(1);
    }

    // Get ephemeral(temporary) keygen instances for refresh protocol
    // It will return initialized p1 and p2 keygen instances
    p1_ephmeral(&sess_buf, party_keys, *p1_share, &p1_sess);
    p2_ephmeral(&sess_buf, *p2_share, &p2_sess);

    // Now we do keygen as usual
    // P1 keygen gen_msg1
    if (p1_keygen_gen_msg1(p1_sess, &msg1) != TSS_OK) {
        perror("Error during p1_keygen_gen_msg1\n"); exit(1);
    }

    // P2 keygen process_msg1
    if (p2_keygen_process_msg1(p2_sess, &msg1, &msg2) != TSS_OK) {
        perror("Error during p2_keygen_process_msg1\n"); exit(1);
    }

    // P1 keygen process_msg2
    if (p1_keygen_process_msg2(p1_sess, &msg2, &msg3) != TSS_OK) {
        perror("Error during p1_keygen_process_msg2\n"); exit(1);
    }

    // P2 keygen process_msg3
    if (p2_keygen_process_msg3(p2_sess, &msg3) != TSS_OK) {
        perror("Error during p2_keygen_process_msg3\n"); exit(1);
    }

    // P1 keygen finish
    if (p1_keygen_fini(p1_sess, new_share1) != TSS_OK) {
        perror("Error during p1_keygen_fini\n"); exit(1);
    }


    // P1 keyshare public key
    if (p1_keyshare_public_key(*new_share1, &p1_share_buf) != TSS_OK) {
        perror("Error during p1_keyshare_public_key\n"); exit(1);
    }

    // P2 keygen finish
    if (p2_keygen_fini(p2_sess, new_share2) != TSS_OK) {
        perror("Error during p2_keygen_fini\n"); exit(1);
    }

    // P2 keyshare public key
    if (p2_keyshare_public_key(*new_share2, &p2_share_buf) != TSS_OK) {
        perror("Error during p2_keyshare_public_key\n"); exit(1);
    }

    // Verifying keys match
    if (p1_share_buf.len != p2_share_buf.len || memcmp(p1_share_buf.ptr, p2_share_buf.ptr, p1_share_buf.len) != 0) {
        perror("Public keys do not match\n"); exit(1);
    }

    // Copying public key to output
    public_key.ptr = malloc(p1_share_buf.len);
    memcpy((void *)public_key.ptr, (void *)p1_share_buf.ptr, p1_share_buf.len);
    public_key.len = p1_share_buf.len;

    // Check the new public key is same as the old one
    // After refresh the public key of the keyshares must be the same
    if (public_key.len != prev_public_key.len || memcmp(public_key.ptr, prev_public_key.ptr, public_key.len) != 0) {
	perror("Public keys must  match after refresh\n"); exit(1);
    }
    // We have successfully refreshed our keyshares, while keeping
    // the public key of the account constant.

    // Freeing buffers
    tss_buffer_free(&msg1);
    tss_buffer_free(&msg2);
    tss_buffer_free(&msg3);
    tss_buffer_free(&prev_public_key);
    tss_buffer_free(&public_key);
    tss_buffer_free(&p1_share_buf);
    tss_buffer_free(&p2_share_buf);


    printf("Refresh successful\n");

    return;
 }

Last updated 1 year ago