Skip to content

Instantly share code, notes, and snippets.

@tetratorus
Created October 12, 2022 21:20
Show Gist options
  • Save tetratorus/303f35ee0871f40e2b91a085d03ca97e to your computer and use it in GitHub Desktop.
Save tetratorus/303f35ee0871f40e2b91a085d03ca97e to your computer and use it in GitHub Desktop.
Time-locked secret shares
const NodeRSA = require('node-rsa');
const BN = require('bn.js');
const AesEncryption = require('aes-encryption');
const eccrypto = require('@toruslabs/eccrypto');
const seconds = 10;
const sqPerSecond = 20000;
const seqSquares = (base, mod, length) => {
let table = [base.umod(mod)];
let prev = base.umod(mod);
for (let i = 1; i < length; i++) {
const squared = prev.pow(new BN(2)).umod(mod);
table.push(squared);
prev = squared;
}
return table;
}
const fastExp = (mod, base, x) => {
const binary = x.toString(2).split('').reverse();
const squares = seqSquares(base, mod, binary.length);
let sum = new BN(1);
binary.map((bit, index) => {
if (bit === '1') {
sum = sum.mul(squares[index]).umod(mod);
}
})
return sum;
}
const aesKey = eccrypto.generatePrivate();
const aesEncryption = new AesEncryption();
aesEncryption.setSecretKey(aesKey.toString('hex').padStart(64, '0'));
console.log('generating 2048 bit RSA key...');
const rsa = new NodeRSA({ b: 2048 });
const p = new BN(rsa.keyPair.p.toString(16).padStart(64, '0'), 'hex');
const q = new BN(rsa.keyPair.q.toString(16).padStart(64, '0'), 'hex');
const n = new BN(rsa.keyPair.n.toString(16).padStart(64, '0'), 'hex');
const phi = p.sub(new BN(1)).mul(q.sub(new BN(1)));
const unlockedShare = eccrypto.generatePrivate();
console.log('share to time-lock', unlockedShare.toString('hex'));
const encryptedShare = aesEncryption.encrypt(unlockedShare.toString('hex'));
console.log(`time-locking share for ${seconds} seconds, assuming ${sqPerSecond} squarings per second`);
const a = new BN(2);
const t = new BN(seconds * sqPerSecond);
const e = new BN(2).pow(t).umod(phi);
const b = fastExp(n, a, e);
const timelockedShare = new BN(aesKey).umod(n).add(b).umod(n);
console.log('time-locked share', timelockedShare);
console.log('working on time-lock...');
const startTime = process.hrtime();
let B = a.umod(n);
for (let i = 0; i < t; i++) {
B = B.pow(new BN(2)).umod(n);
}
let unlockedAesKey = timelockedShare.sub(B).umod(n);
const tryAesEncryption = new AesEncryption();
tryAesEncryption.setSecretKey(unlockedAesKey.toString('hex').padStart(64, '0'));
const decryptedShare = tryAesEncryption.decrypt(encryptedShare);
console.log('unlocked share', decryptedShare.toString('hex'));
const timeTaken = process.hrtime(startTime);
console.log(`Time taken: ${timeTaken[0]} seconds, ${timeTaken[1]} nanoseconds`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment