smartledger-sdk
Version:
A comprehensive blockchain and cryptographic operations SDK for JavaScript
104 lines (91 loc) • 3.42 kB
JavaScript
import sss from "shamirs-secret-sharing";
import { Buffer } from "buffer";
export class SecretSharer {
constructor() {
this.sss = sss;
}
/**
* Split a secret into multiple shares using Shamir's Secret Sharing
* @param {string} secret - The secret to split
* @param {number} shares - Number of shares to create
* @param {number} threshold - Minimum number of shares needed to reconstruct
* @returns {Array<Buffer>} Array of secret shares
*/
splitSecret(secret, shares, threshold) {
if (!secret || typeof secret !== "string") {
throw new Error("Secret must be a non-empty string");
}
if (!Number.isInteger(shares) || shares < 2) {
throw new Error("Number of shares must be an integer >= 2");
}
if (!Number.isInteger(threshold) || threshold < 2 || threshold > shares) {
throw new Error(
"Threshold must be an integer >= 2 and <= number of shares"
);
}
const secretBuffer = Buffer.from(secret, "utf8");
const result = this.sss.split(secretBuffer, { shares, threshold });
return Array.from(result);
}
/**
* Combine shares to reconstruct the original secret
* @param {Array<Buffer>} shares - Array of shares to combine
* @returns {string} The reconstructed secret
*/
combineShares(shares) {
if (!Array.isArray(shares) || shares.length < 2) {
throw new Error("Must provide at least 2 shares");
}
try {
const recoveredBuffer = this.sss.combine(shares);
return recoveredBuffer.toString("utf8");
} catch (error) {
throw new Error("Failed to reconstruct secret: " + error.message);
}
}
/**
* Convert a share to a hex string for storage or transmission
* @param {Buffer} share - The share to convert
* @returns {string} Hex string representation of the share
*/
shareToHex(share) {
if (!Buffer.isBuffer(share)) {
// Convert Uint8Array to Buffer if needed
if (share instanceof Uint8Array) {
share = Buffer.from(share);
} else {
throw new Error("Share must be a Buffer or Uint8Array");
}
}
return share.toString("hex");
}
/**
* Convert a hex string back to a share Buffer
* @param {string} hexShare - Hex string representation of a share
* @returns {Buffer} The share as a Buffer
*/
hexToShare(hexShare) {
if (typeof hexShare !== "string" || !/^[0-9a-fA-F]+$/.test(hexShare)) {
throw new Error("Invalid hex string");
}
return Buffer.from(hexShare, "hex");
}
}
// Example usage
if (import.meta.url === `file://${process.cwd()}/SecretSharer.js`) {
const sharer = new SecretSharer();
const secret = "my secret";
console.log("\nExample of Shamir's Secret Sharing:");
console.log("-----------------------------------");
console.log("Original secret:", secret);
// Split the secret into 3 shares (need 2 to reconstruct)
const shares = sharer.splitSecret(secret, 3, 2);
console.log("\nGenerated", shares.length, "shares (need 2 to reconstruct):");
const hexShares = shares.map((share) => sharer.shareToHex(share));
hexShares.forEach((share, i) => console.log(`Share ${i + 1}:`, share));
// Reconstruct using just 2 of the 3 shares
const sharesToUse = shares.slice(0, 2);
const reconstructed = sharer.combineShares(sharesToUse);
console.log("\nReconstructed secret using 2 shares:", reconstructed);
}
export default SecretSharer;