ssv-keys
Version:
Tool for splitting a validator key into a predefined threshold of shares via Shamir-Secret-Sharing (SSS), and encrypt them with a set of operator keys.
128 lines • 5.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SSVKeys = void 0;
const tslib_1 = require("tslib");
// import atob from 'atob';
const BLS_1 = tslib_1.__importDefault(require("./BLS"));
const Threshold_1 = tslib_1.__importDefault(require("./Threshold"));
const EthereumKeyStore_1 = tslib_1.__importDefault(require("./EthereumKeyStore/EthereumKeyStore"));
const Encryption_1 = tslib_1.__importDefault(require("./Encryption/Encryption"));
const operator_helper_1 = require("./helpers/operator.helper");
const KeySharesItem_1 = require("./KeyShares/KeySharesItem");
/**
* SSVKeys class provides high-level methods to easily work with entire flow:
* - getting private key from keystore file using password
* - creating shares threshold
* - creating final shares
* - building final payload which is ready to be used in web3 transaction
*/
class SSVKeys {
/**
* Extract private key from keystore data using keystore password.
* Generally can be used in browsers when the keystore data has been provided by browser.
* @param data
* @param password
*/
async extractKeys(data, password) {
const privateKey = await new EthereumKeyStore_1.default(data).getPrivateKey(password);
if (!BLS_1.default.deserializeHexStrToSecretKey) {
await BLS_1.default.init(BLS_1.default.BLS12_381);
}
return {
privateKey: `0x${privateKey}`,
publicKey: `0x${BLS_1.default.deserializeHexStrToSecretKey(privateKey).getPublicKey().serializeToHexStr()}`
};
}
/**
* Build threshold using private key and list of operators.
* @param privateKey
* @param operators
*/
async createThreshold(privateKey, operators) {
const sortedOperators = (0, operator_helper_1.operatorSortedList)(operators);
this.threshold = await new Threshold_1.default().create(privateKey, sortedOperators.map(item => item.id));
return this.threshold;
}
/**
* Encrypt operators shares using operators list (id, publicKey).
* @param operators
* @param shares
*/
async encryptShares(operators, shares) {
const sortedOperators = (0, operator_helper_1.operatorSortedList)(operators);
const decodedOperatorPublicKeys = sortedOperators.map(item => Buffer.from(item.operatorKey, 'base64').toString());
return new Encryption_1.default(decodedOperatorPublicKeys, shares).encrypt();
}
/**
* Build shares from private key, operators list
* @param privateKey
* @param operators
*/
async buildShares(privateKey, operators) {
const threshold = await this.createThreshold(privateKey, operators);
return this.encryptShares(operators, threshold.shares);
}
/**
* Getting threshold if it has been created before.
*/
getThreshold() {
return this.threshold;
}
async validateSharesPostRegistration({ shares, operatorsCount, validatorPublicKey, isAccountExists, ownerAddress, ownerNonce, blockNumber }) {
const keySharesItem = new KeySharesItem_1.KeySharesItem();
let restoredSharesPublicKeys;
let restoredSharesEncryptedKeys;
let sharesError = '';
let sharesErrorMessage = '';
let signatureError = '';
let signatureErrorMessage = '';
let errorMessage = '';
try {
const restoredShares = keySharesItem.buildSharesFromBytes(shares, operatorsCount);
const { sharesPublicKeys, encryptedKeys } = restoredShares;
restoredSharesPublicKeys = sharesPublicKeys;
restoredSharesEncryptedKeys = encryptedKeys;
}
catch (e) {
sharesError = e.stack || e.trace || e;
sharesErrorMessage = e.message;
errorMessage = 'Can not extract shares from bytes';
}
if (!sharesError && !errorMessage) {
const signatureData = { ownerNonce, publicKey: validatorPublicKey, ownerAddress };
try {
await keySharesItem.validateSingleShares(shares, signatureData);
}
catch (e) {
signatureError = e.stack || e.trace || e;
signatureErrorMessage = e.message;
errorMessage = 'Failed to validate single shares';
if (isAccountExists) {
errorMessage += `. Account exist for owner address: ${ownerAddress}`;
}
else {
errorMessage += `. Account is not synced for owner address: ${ownerAddress}`;
}
if (ownerNonce) {
errorMessage += `. Used nonce: ${ownerNonce}`;
}
errorMessage += `. Signature Data: ${JSON.stringify(signatureData)}`;
}
}
return {
isValid: !sharesError && !signatureError && !errorMessage,
isSharesValid: !sharesError,
sharesPublicKeys: restoredSharesPublicKeys,
encryptedKeys: restoredSharesEncryptedKeys,
memo: !!sharesError || !!signatureError ?
[{
message: errorMessage,
error: sharesError || signatureError,
data: `${sharesErrorMessage}${signatureErrorMessage ? '. ' + signatureErrorMessage : ''}`, blockNumber
}] : []
};
}
}
exports.SSVKeys = SSVKeys;
SSVKeys.SHARES_FORMAT_ABI = 'abi';
//# sourceMappingURL=SSVKeys.js.map