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