Class: ThresholdSignature

ThresholdSignature()

new ThresholdSignature()

Threshold Signature Scheme implementation for distributed cryptography

This class implements a complete threshold signature scheme that allows any subset of participants (meeting the threshold) to collaboratively generate valid ECDSA signatures without ever reconstructing the private key. The scheme is based on Shamir's Secret Sharing and provides the following security guarantees:

Security Properties:

  • Threshold Security: Requires exactly t participants to generate signatures
  • Information-Theoretic Privacy: < t participants learn nothing about the private key
  • Robustness: Works even if some participants are unavailable (up to n-t)
  • Unforgeability: Signatures are cryptographically secure and unforgeable

Key Features:

  • Distributed key generation without trusted dealer
  • Threshold ECDSA signature generation
  • Support for linear and multiplicative operations on shared secrets
  • Compatible with standard ECDSA verification
  • Efficient polynomial-based secret sharing

Use Cases:

  • Multi-signature wallets and escrow services
  • Corporate treasury management with distributed control
  • Cryptocurrency exchanges with operator separation
  • Secure key management for high-value assets
  • Compliance requirements for multi-party authorization
Source:
Examples
// Create a 2-of-3 threshold signature scheme
const tss = new ThresholdSignature(3, 2);

// Generate a threshold signature
const signature = tss.sign("Transfer $1000 to Alice");

// Verify the signature
const isValid = ThresholdSignature.verify_threshold_signature(
  tss.public_key, 
  signature.msgHash, 
  signature.sig
);
// Corporate treasury with 3-of-5 executive approval
const corporateTSS = new ThresholdSignature(5, 3);
const executiveShares = corporateTSS.shares;

// Distribute shares to 5 executives
// Any 3 can authorize transactions
const authSignature = corporateTSS.sign("Quarterly dividend payment");
// Escrow service with dispute resolution
const escrowTSS = new ThresholdSignature(3, 2);
const [buyerShare, sellerShare, arbiterShare] = escrowTSS.shares;

// Normal case: buyer + seller release funds
// Dispute case: buyer/seller + arbiter resolve

Members

(readonly) group_size :number

Total number of participants in the threshold scheme

Type:
  • number
Source:

(readonly) polynomial_order :number

Polynomial degree (threshold - 1) for secret sharing

Type:
  • number
Source:

(readonly) threshold :number

Minimum number of participants needed for cryptographic operations

Type:
  • number
Source:

Methods

addss(a_sharesopt, b_sharesopt) → {BN}

Additive Secret Sharing (ADDSS) - combines two sets of shares additively

ADDSS enables secure addition of two shared secrets without revealing the individual secrets. Each participant adds their corresponding shares, and the result can be reconstructed to obtain the sum of the original secrets.

Mathematical Foundation:

  • If secret A is shared as (a₁, a₂, ..., aₙ)
  • And secret B is shared as (b₁, b₂, ..., bₙ)
  • Then A + B is shared as (a₁+b₁, a₂+b₂, ..., aₙ+bₙ)

Applications:

  • Combining multiple randomness sources
  • Adding constants to shared secrets
  • Building complex cryptographic protocols
  • Secure multi-party computation primitives
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

First set of secret shares

b_shares Array.<BN> <optional>
[]

Second set of secret shares

Source:
Throws:

If share arrays have different lengths

Type
Error
Returns:

The sum of the two original secrets

Type
BN
Examples
const tss = new ThresholdSignature(3, 2);

// Generate two sets of shares
const [shares1, _] = tss.jvrss();
const [shares2, __] = tss.jvrss();

// Add the shared secrets
const sum = tss.addss(shares1, shares2);

// Verify: sum should equal individual secret sum
const secret1 = tss.privite_key(shares1);
const secret2 = tss.privite_key(shares2);
const expectedSum = secret1.add(secret2).umod(N);
console.log(sum.eq(expectedSum)); // true
// Adding a constant to a shared secret
const constant = new BN(42);
const constantShares = Array(tss.group_size).fill(new BN(0));
constantShares[0] = constant; // Only first share gets the constant

const result = tss.addss(tss.shares, constantShares);
// result = original_secret + 42

invss(a_sharesopt) → {Array.<BN>}

Inverse Secret Sharing (INVSS) - computes modular inverse of shared secret

INVSS computes the modular inverse of a shared secret without revealing the secret. This is crucial for threshold ECDSA signatures where we need to compute k⁻¹ (inverse of the nonce) as part of the signature generation process.

Algorithm:

  1. Generate a fresh random secret b using JVRSS
  2. Compute c = a × b using PROSS (where a is the input secret)
  3. Reconstruct c (this reveals c but not a or b individually)
  4. Compute c⁻¹ using standard modular inverse
  5. Multiply b shares by c⁻¹ to get shares of a⁻¹

Security:

  • The intermediate value c is revealed but provides no information about a
  • The randomness b masks the original secret a
  • Final result is properly shared according to the threshold scheme
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

Shares of the secret to invert

Source:
Returns:

Shares of the modular inverse of the original secret

Type
Array.<BN>
Examples
const tss = new ThresholdSignature(5, 3);

// Compute inverse of shared secret
const inverseShares = tss.invss(tss.shares);

// Verify: secret × inverse = 1 (mod N)
const product = tss.pross(tss.shares, inverseShares);
console.log(product.eq(new BN(1))); // true
// Use in threshold signature (simplified)
const message = Buffer.from("Hello World!");
const msgHash = new BN(createHash('sha256').update(message).digest());

// Generate nonce shares
const [kShares, kPubKey] = tss.jvrss();

// Compute inverse of nonce
const kInvShares = tss.invss(kShares);

// This would be used in signature computation
// s = k⁻¹(hash + r × private_key)

jvrss() → {Array|Array.<BN>|Object}

Joint Verifiable Random Secret Sharing (JVRSS) protocol implementation

JVRSS is the core protocol for distributed key generation without a trusted dealer. It combines multiple random polynomials from all participants to create a shared secret that no single party knows or can control.

Protocol Steps:

  1. Polynomial Generation: Each participant conceptually generates a random polynomial
  2. Share Distribution: Each polynomial contributes to every participant's final share
  3. Linear Combination: Shares are combined additively to create the final distribution
  4. Public Key Derivation: The aggregate public key is computed from polynomial constants

Security Properties:

  • No single participant controls the final secret
  • The secret is uniformly random over the field
  • Shares are properly distributed according to Shamir's scheme
  • Public key is verifiable and corresponds to the shared secret
Source:
Returns:
  • Tuple containing shares array and aggregate public key

    Type
    Array
  • returns.0 - Array of secret shares for each participant

    Type
    Array.<BN>
  • returns.1 - Aggregate elliptic curve public key point

    Type
    Object
Examples
const tss = new ThresholdSignature(5, 3);
const [shares, publicKey] = tss.jvrss();

console.log(shares.length);        // 5 shares
console.log(publicKey.constructor.name); // ProjectivePoint

// Shares are properly distributed
const points = tss.shares_to_points(shares);
const secret = Polynomial.interpolate_evaluate(points, 0);
const derivedPubKey = secp256k1.ProjectivePoint.fromPrivateKey(secret.toBuffer());

// Public keys should match
console.log(publicKey.equals(derivedPubKey)); // true
// Manual JVRSS execution for understanding
const groupSize = 3, threshold = 2;
const polynomials = Array(groupSize).fill(null)
  .map(() => Polynomial.fromRandom(threshold - 1));

// Each participant's share is sum of evaluations
let manualShares = Array(groupSize).fill(new BN(0));
for (let i = 0; i < groupSize; i++) {
  for (let j = 0; j < groupSize; j++) {
    manualShares[j] = manualShares[j].add(polynomials[i].evaluate(j + 1));
  }
}

// This produces the same result as jvrss()

privite_key(a_sharesopt) → {BN}

Reconstructs the private key from secret shares using polynomial interpolation

This method recovers the original private key from the distributed shares. It should be used with caution as it reconstructs the full private key, defeating the purpose of the threshold scheme. Typically used only for specific operations like computing WIF format or for emergency recovery.

Security Warning:

  • Reconstructing the private key centralizes control
  • Should only be done when absolutely necessary
  • Consider using threshold operations instead when possible
  • Ensure secure deletion of reconstructed key after use
Parameters:
Name Type Attributes Description
a_shares Array.<BN> <optional>

Secret shares to reconstruct from (defaults to this.shares)

Source:
Returns:

The reconstructed private key as a BigNumber

Type
BN
Examples
const tss = new ThresholdSignature(3, 2);

// Reconstruct private key (use with caution!)
const privateKey = tss.privite_key();

// Verify it corresponds to the public key
const derivedPubKey = secp256k1.ProjectivePoint.fromPrivateKey(privateKey.toBuffer());
console.log(derivedPubKey.equals(tss.public_key)); // true
// Partial reconstruction with threshold shares only
const thresholdShares = tss.shares.slice(0, tss.threshold);
const partialKey = tss.privite_key(thresholdShares);

// Should equal full reconstruction
const fullKey = tss.privite_key();
console.log(partialKey.eq(fullKey)); // true
// Emergency recovery scenario
function emergencyRecovery(shareHolders) {
  if (shareHolders.length < tss.threshold) {
    throw new Error("Insufficient shares for recovery");
  }
  
  const recoveredKey = tss.privite_key(shareHolders.slice(0, tss.threshold));
  
  // Use recovered key for emergency operations
  // ... perform emergency actions ...
  
  // Securely delete the key
  recoveredKey.fill(0);
}

pross(a_sharesopt, b_sharesopt) → {BN}

Polynomial Reconstruction Secret Sharing (PROSS) - computes product of shared secrets

PROSS enables secure multiplication of two shared secrets. This is more complex than addition because the product of two degree-t polynomials yields a degree-2t polynomial, requiring more shares for reconstruction.

Mathematical Foundation:

  • Product of degree-t polynomials has degree 2t
  • Requires 2t+1 shares for reconstruction (vs t+1 for addition)
  • Uses polynomial interpolation on the product values
  • Result is the product of the original secrets

Security Note:

  • Requires more participants for security than addition
  • Product shares reveal more information than additive shares
  • Should be used carefully in cryptographic protocols

Applications:

  • Computing multiplicative inverses (used in INVSS)
  • Secure polynomial evaluation
  • Advanced threshold cryptographic protocols
  • Zero-knowledge proof systems
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

First set of secret shares

b_shares Array.<BN> <optional>
[]

Second set of secret shares

Source:
Returns:

The product of the two original secrets

Type
BN
Examples
const tss = new ThresholdSignature(5, 2); // Need larger group for PROSS

// Generate two secrets
const [shares1, _] = tss.jvrss();
const [shares2, __] = tss.jvrss();

// Compute product
const product = tss.pross(shares1, shares2);

// Verify result
const secret1 = tss.privite_key(shares1);
const secret2 = tss.privite_key(shares2);
const expectedProduct = secret1.mul(secret2).umod(N);
console.log(product.eq(expectedProduct)); // true
// Squaring a shared secret
const squared = tss.pross(tss.shares, tss.shares);
const originalSecret = tss.privite_key();
const expectedSquare = originalSecret.mul(originalSecret).umod(N);
console.log(squared.eq(expectedSquare)); // true

shares_to_points(sharesopt) → {SharePoints}

Converts share values to coordinate points for polynomial interpolation

Transforms an array of share values into the coordinate format required for Lagrange interpolation. Each share at index i becomes a point (i+1, share) since polynomial evaluation uses 1-based indexing (x=0 is reserved for secrets).

Parameters:
Name Type Attributes Default Description
shares Array.<BN> <optional>
[]

Array of BigNumber share values to convert

Source:
Returns:

Array of [x, y] coordinate pairs for interpolation

Type
SharePoints
Examples
const tss = new ThresholdSignature(3, 2);
const points = tss.shares_to_points(tss.shares);
console.log(points);
// [[1, share1_value], [2, share2_value], [3, share3_value]]

// Use for secret reconstruction
const secret = Polynomial.interpolate_evaluate(points, 0);
// Partial reconstruction with threshold shares
const partialShares = tss.shares.slice(0, tss.threshold);
const thresholdPoints = tss.shares_to_points(partialShares);
const reconstructed = Polynomial.interpolate_evaluate(thresholdPoints, 0);

sign(message) → {ThresholdSignatureResult}

Generates a threshold signature for a given message

This is the core method that produces threshold ECDSA signatures. The signature is generated collaboratively using the threshold scheme without reconstructing the private key. The process follows the threshold ECDSA protocol:

Threshold ECDSA Algorithm:

  1. Nonce Generation: Create shared random nonce k using JVRSS
  2. R Value Computation: Compute R = k×G and extract r = R.x mod n
  3. Inverse Computation: Compute k⁻¹ using INVSS without revealing k
  4. Signature Shares: Each party computes their share of s = k⁻¹(hash + r×private)
  5. Reconstruction: Combine shares to get final signature (r, s)
  6. Validation: Ensure signature is valid and non-zero

Security Properties:

  • Private key never reconstructed during signing
  • Nonce is generated distributively and remains secret
  • Resulting signature is indistinguishable from single-party ECDSA
  • Compatible with standard ECDSA verification
Parameters:
Name Type Description
message string

Message to sign (will be SHA256 hashed)

Source:
Returns:

Complete signature with metadata

Type
ThresholdSignatureResult
Examples
const tss = new ThresholdSignature(3, 2);

// Generate threshold signature
const signature = tss.sign("Transfer $1000 to Alice");

console.log(signature.sig.r);           // BigInt r value
console.log(signature.sig.s);           // BigInt s value  
console.log(signature.serialized_sig);  // Base64 compact format
console.log(signature.recovery_id);     // 0-3 for public key recovery

// Verify signature
const isValid = ThresholdSignature.verify_threshold_signature(
  tss.public_key,
  signature.msgHash,
  signature.sig
);
console.log(isValid); // true
// Corporate authorization workflow
const corporateTSS = new ThresholdSignature(5, 3);

const authMessage = JSON.stringify({
  action: "wire_transfer",
  amount: 1000000,
  recipient: "operations_account",
  timestamp: Date.now()
});

const authorization = corporateTSS.sign(authMessage);
console.log("Authorization signature:", authorization.serialized_sig);
// Escrow release with buyer + seller
const escrowTSS = new ThresholdSignature(3, 2);

const releaseMessage = "Release escrow funds to seller";
const escrowSignature = escrowTSS.sign(releaseMessage);

// This signature can be verified by anyone
const verified = ThresholdSignature.verify_threshold_signature(
  escrowTSS.public_key,
  escrowSignature.msgHash,
  escrowSignature.sig
);

(static) verify_threshold_signature(public_key, msgHash, sig) → {boolean}

Verifies a threshold signature against a public key and message hash

This static method verifies threshold signatures using standard ECDSA verification. Threshold signatures are indistinguishable from regular ECDSA signatures, so standard verification algorithms work without modification.

Verification Algorithm:

  1. Input Validation: Ensure signature components r and s are valid
  2. Hash Processing: Use the provided message hash (already computed)
  3. Inverse Computation: Compute w = s⁻¹ mod n
  4. Point Calculation: Compute u₁ = w×hash and u₂ = w×r
  5. Point Addition: Compute point = u₁×G + u₂×PublicKey
  6. Verification: Check if point.x ≡ r (mod n)

Compatibility:

  • Works with any ECDSA signature, threshold or single-party
  • Uses standard secp256k1 curve parameters
  • Compatible with Bitcoin and Ethereum signature formats
  • Can be used by third parties without threshold scheme knowledge
Parameters:
Name Type Description
public_key Object

Elliptic curve public key point

msgHash Buffer

SHA256 hash of the original message

sig Object

Signature object with r and s components

Properties
Name Type Description
r bigint

Signature r value

s bigint

Signature s value

Source:
Returns:

True if signature is valid, false otherwise

Type
boolean
Examples
// Verify a threshold signature
const tss = new ThresholdSignature(3, 2);
const signature = tss.sign("Hello World!");

const isValid = ThresholdSignature.verify_threshold_signature(
  tss.public_key,
  signature.msgHash,
  signature.sig
);
console.log(isValid); // true
// Third-party verification (doesn't need threshold scheme)
function verifyTransaction(publicKey, messageHash, signature) {
  return ThresholdSignature.verify_threshold_signature(
    publicKey,
    messageHash,
    signature
  );
}

// Works with any ECDSA signature
const valid = verifyTransaction(
  somePublicKey,
  someMessageHash,
  someSignature
);
// Batch verification for multiple signatures
function verifyBatch(signatures) {
  return signatures.every(({ publicKey, msgHash, sig }) =>
    ThresholdSignature.verify_threshold_signature(publicKey, msgHash, sig)
  );
}
// Integration with Bitcoin transaction verification
function verifyBitcoinTransaction(transaction, publicKey) {
  const messageHash = computeTransactionHash(transaction);
  const signature = extractSignature(transaction);
  
  return ThresholdSignature.verify_threshold_signature(
    publicKey,
    messageHash,
    signature
  );
}

ThresholdSignature(group_sizeopt, thresholdopt)

new ThresholdSignature(group_sizeopt, thresholdopt)

Creates a new threshold signature scheme instance

Initializes the threshold cryptographic system with specified parameters and generates the initial shared secret distribution. The constructor performs the following operations:

  1. Parameter Validation: Ensures threshold constraints are met
  2. JVRSS Execution: Runs Joint Verifiable Random Secret Sharing
  3. Key Generation: Creates distributed private key shares
  4. Public Key Derivation: Computes the corresponding public key

Threshold Constraints:

  • threshold ≥ 2 (minimum for meaningful security)
  • threshold ≤ group_size (cannot exceed total participants)
  • group_size ≥ 2 (minimum for distribution)
Parameters:
Name Type Attributes Default Description
group_size number <optional>
3

Total number of participants in the scheme

threshold number <optional>
2

Minimum number of participants needed for operations

Source:
Throws:

"Threshold is too high or low" if constraints are violated

Type
Error
Examples
// Create a 2-of-3 threshold scheme
const tss = new ThresholdSignature(3, 2);
console.log(tss.group_size);    // 3
console.log(tss.threshold);     // 2
console.log(tss.shares.length); // 3 shares generated
// Create a 5-of-7 corporate scheme
const corporateTSS = new ThresholdSignature(7, 5);
console.log(corporateTSS.polynomial_order); // 4 (threshold - 1)
// Error cases
try {
  new ThresholdSignature(3, 5); // threshold > group_size
} catch (error) {
  console.log(error.message); // "Threshold is too high or low"
}

try {
  new ThresholdSignature(3, 1); // threshold < 2
} catch (error) {
  console.log(error.message); // "Threshold is too high or low"
}

Members

(readonly) group_size :number

Total number of participants in the threshold scheme

Type:
  • number
Source:

(readonly) polynomial_order :number

Polynomial degree (threshold - 1) for secret sharing

Type:
  • number
Source:

(readonly) threshold :number

Minimum number of participants needed for cryptographic operations

Type:
  • number
Source:

Methods

addss(a_sharesopt, b_sharesopt) → {BN}

Additive Secret Sharing (ADDSS) - combines two sets of shares additively

ADDSS enables secure addition of two shared secrets without revealing the individual secrets. Each participant adds their corresponding shares, and the result can be reconstructed to obtain the sum of the original secrets.

Mathematical Foundation:

  • If secret A is shared as (a₁, a₂, ..., aₙ)
  • And secret B is shared as (b₁, b₂, ..., bₙ)
  • Then A + B is shared as (a₁+b₁, a₂+b₂, ..., aₙ+bₙ)

Applications:

  • Combining multiple randomness sources
  • Adding constants to shared secrets
  • Building complex cryptographic protocols
  • Secure multi-party computation primitives
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

First set of secret shares

b_shares Array.<BN> <optional>
[]

Second set of secret shares

Source:
Throws:

If share arrays have different lengths

Type
Error
Returns:

The sum of the two original secrets

Type
BN
Examples
const tss = new ThresholdSignature(3, 2);

// Generate two sets of shares
const [shares1, _] = tss.jvrss();
const [shares2, __] = tss.jvrss();

// Add the shared secrets
const sum = tss.addss(shares1, shares2);

// Verify: sum should equal individual secret sum
const secret1 = tss.privite_key(shares1);
const secret2 = tss.privite_key(shares2);
const expectedSum = secret1.add(secret2).umod(N);
console.log(sum.eq(expectedSum)); // true
// Adding a constant to a shared secret
const constant = new BN(42);
const constantShares = Array(tss.group_size).fill(new BN(0));
constantShares[0] = constant; // Only first share gets the constant

const result = tss.addss(tss.shares, constantShares);
// result = original_secret + 42

invss(a_sharesopt) → {Array.<BN>}

Inverse Secret Sharing (INVSS) - computes modular inverse of shared secret

INVSS computes the modular inverse of a shared secret without revealing the secret. This is crucial for threshold ECDSA signatures where we need to compute k⁻¹ (inverse of the nonce) as part of the signature generation process.

Algorithm:

  1. Generate a fresh random secret b using JVRSS
  2. Compute c = a × b using PROSS (where a is the input secret)
  3. Reconstruct c (this reveals c but not a or b individually)
  4. Compute c⁻¹ using standard modular inverse
  5. Multiply b shares by c⁻¹ to get shares of a⁻¹

Security:

  • The intermediate value c is revealed but provides no information about a
  • The randomness b masks the original secret a
  • Final result is properly shared according to the threshold scheme
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

Shares of the secret to invert

Source:
Returns:

Shares of the modular inverse of the original secret

Type
Array.<BN>
Examples
const tss = new ThresholdSignature(5, 3);

// Compute inverse of shared secret
const inverseShares = tss.invss(tss.shares);

// Verify: secret × inverse = 1 (mod N)
const product = tss.pross(tss.shares, inverseShares);
console.log(product.eq(new BN(1))); // true
// Use in threshold signature (simplified)
const message = Buffer.from("Hello World!");
const msgHash = new BN(createHash('sha256').update(message).digest());

// Generate nonce shares
const [kShares, kPubKey] = tss.jvrss();

// Compute inverse of nonce
const kInvShares = tss.invss(kShares);

// This would be used in signature computation
// s = k⁻¹(hash + r × private_key)

jvrss() → {Array|Array.<BN>|Object}

Joint Verifiable Random Secret Sharing (JVRSS) protocol implementation

JVRSS is the core protocol for distributed key generation without a trusted dealer. It combines multiple random polynomials from all participants to create a shared secret that no single party knows or can control.

Protocol Steps:

  1. Polynomial Generation: Each participant conceptually generates a random polynomial
  2. Share Distribution: Each polynomial contributes to every participant's final share
  3. Linear Combination: Shares are combined additively to create the final distribution
  4. Public Key Derivation: The aggregate public key is computed from polynomial constants

Security Properties:

  • No single participant controls the final secret
  • The secret is uniformly random over the field
  • Shares are properly distributed according to Shamir's scheme
  • Public key is verifiable and corresponds to the shared secret
Source:
Returns:
  • Tuple containing shares array and aggregate public key

    Type
    Array
  • returns.0 - Array of secret shares for each participant

    Type
    Array.<BN>
  • returns.1 - Aggregate elliptic curve public key point

    Type
    Object
Examples
const tss = new ThresholdSignature(5, 3);
const [shares, publicKey] = tss.jvrss();

console.log(shares.length);        // 5 shares
console.log(publicKey.constructor.name); // ProjectivePoint

// Shares are properly distributed
const points = tss.shares_to_points(shares);
const secret = Polynomial.interpolate_evaluate(points, 0);
const derivedPubKey = secp256k1.ProjectivePoint.fromPrivateKey(secret.toBuffer());

// Public keys should match
console.log(publicKey.equals(derivedPubKey)); // true
// Manual JVRSS execution for understanding
const groupSize = 3, threshold = 2;
const polynomials = Array(groupSize).fill(null)
  .map(() => Polynomial.fromRandom(threshold - 1));

// Each participant's share is sum of evaluations
let manualShares = Array(groupSize).fill(new BN(0));
for (let i = 0; i < groupSize; i++) {
  for (let j = 0; j < groupSize; j++) {
    manualShares[j] = manualShares[j].add(polynomials[i].evaluate(j + 1));
  }
}

// This produces the same result as jvrss()

privite_key(a_sharesopt) → {BN}

Reconstructs the private key from secret shares using polynomial interpolation

This method recovers the original private key from the distributed shares. It should be used with caution as it reconstructs the full private key, defeating the purpose of the threshold scheme. Typically used only for specific operations like computing WIF format or for emergency recovery.

Security Warning:

  • Reconstructing the private key centralizes control
  • Should only be done when absolutely necessary
  • Consider using threshold operations instead when possible
  • Ensure secure deletion of reconstructed key after use
Parameters:
Name Type Attributes Description
a_shares Array.<BN> <optional>

Secret shares to reconstruct from (defaults to this.shares)

Source:
Returns:

The reconstructed private key as a BigNumber

Type
BN
Examples
const tss = new ThresholdSignature(3, 2);

// Reconstruct private key (use with caution!)
const privateKey = tss.privite_key();

// Verify it corresponds to the public key
const derivedPubKey = secp256k1.ProjectivePoint.fromPrivateKey(privateKey.toBuffer());
console.log(derivedPubKey.equals(tss.public_key)); // true
// Partial reconstruction with threshold shares only
const thresholdShares = tss.shares.slice(0, tss.threshold);
const partialKey = tss.privite_key(thresholdShares);

// Should equal full reconstruction
const fullKey = tss.privite_key();
console.log(partialKey.eq(fullKey)); // true
// Emergency recovery scenario
function emergencyRecovery(shareHolders) {
  if (shareHolders.length < tss.threshold) {
    throw new Error("Insufficient shares for recovery");
  }
  
  const recoveredKey = tss.privite_key(shareHolders.slice(0, tss.threshold));
  
  // Use recovered key for emergency operations
  // ... perform emergency actions ...
  
  // Securely delete the key
  recoveredKey.fill(0);
}

pross(a_sharesopt, b_sharesopt) → {BN}

Polynomial Reconstruction Secret Sharing (PROSS) - computes product of shared secrets

PROSS enables secure multiplication of two shared secrets. This is more complex than addition because the product of two degree-t polynomials yields a degree-2t polynomial, requiring more shares for reconstruction.

Mathematical Foundation:

  • Product of degree-t polynomials has degree 2t
  • Requires 2t+1 shares for reconstruction (vs t+1 for addition)
  • Uses polynomial interpolation on the product values
  • Result is the product of the original secrets

Security Note:

  • Requires more participants for security than addition
  • Product shares reveal more information than additive shares
  • Should be used carefully in cryptographic protocols

Applications:

  • Computing multiplicative inverses (used in INVSS)
  • Secure polynomial evaluation
  • Advanced threshold cryptographic protocols
  • Zero-knowledge proof systems
Parameters:
Name Type Attributes Default Description
a_shares Array.<BN> <optional>
[]

First set of secret shares

b_shares Array.<BN> <optional>
[]

Second set of secret shares

Source:
Returns:

The product of the two original secrets

Type
BN
Examples
const tss = new ThresholdSignature(5, 2); // Need larger group for PROSS

// Generate two secrets
const [shares1, _] = tss.jvrss();
const [shares2, __] = tss.jvrss();

// Compute product
const product = tss.pross(shares1, shares2);

// Verify result
const secret1 = tss.privite_key(shares1);
const secret2 = tss.privite_key(shares2);
const expectedProduct = secret1.mul(secret2).umod(N);
console.log(product.eq(expectedProduct)); // true
// Squaring a shared secret
const squared = tss.pross(tss.shares, tss.shares);
const originalSecret = tss.privite_key();
const expectedSquare = originalSecret.mul(originalSecret).umod(N);
console.log(squared.eq(expectedSquare)); // true

shares_to_points(sharesopt) → {SharePoints}

Converts share values to coordinate points for polynomial interpolation

Transforms an array of share values into the coordinate format required for Lagrange interpolation. Each share at index i becomes a point (i+1, share) since polynomial evaluation uses 1-based indexing (x=0 is reserved for secrets).

Parameters:
Name Type Attributes Default Description
shares Array.<BN> <optional>
[]

Array of BigNumber share values to convert

Source:
Returns:

Array of [x, y] coordinate pairs for interpolation

Type
SharePoints
Examples
const tss = new ThresholdSignature(3, 2);
const points = tss.shares_to_points(tss.shares);
console.log(points);
// [[1, share1_value], [2, share2_value], [3, share3_value]]

// Use for secret reconstruction
const secret = Polynomial.interpolate_evaluate(points, 0);
// Partial reconstruction with threshold shares
const partialShares = tss.shares.slice(0, tss.threshold);
const thresholdPoints = tss.shares_to_points(partialShares);
const reconstructed = Polynomial.interpolate_evaluate(thresholdPoints, 0);

sign(message) → {ThresholdSignatureResult}

Generates a threshold signature for a given message

This is the core method that produces threshold ECDSA signatures. The signature is generated collaboratively using the threshold scheme without reconstructing the private key. The process follows the threshold ECDSA protocol:

Threshold ECDSA Algorithm:

  1. Nonce Generation: Create shared random nonce k using JVRSS
  2. R Value Computation: Compute R = k×G and extract r = R.x mod n
  3. Inverse Computation: Compute k⁻¹ using INVSS without revealing k
  4. Signature Shares: Each party computes their share of s = k⁻¹(hash + r×private)
  5. Reconstruction: Combine shares to get final signature (r, s)
  6. Validation: Ensure signature is valid and non-zero

Security Properties:

  • Private key never reconstructed during signing
  • Nonce is generated distributively and remains secret
  • Resulting signature is indistinguishable from single-party ECDSA
  • Compatible with standard ECDSA verification
Parameters:
Name Type Description
message string

Message to sign (will be SHA256 hashed)

Source:
Returns:

Complete signature with metadata

Type
ThresholdSignatureResult
Examples
const tss = new ThresholdSignature(3, 2);

// Generate threshold signature
const signature = tss.sign("Transfer $1000 to Alice");

console.log(signature.sig.r);           // BigInt r value
console.log(signature.sig.s);           // BigInt s value  
console.log(signature.serialized_sig);  // Base64 compact format
console.log(signature.recovery_id);     // 0-3 for public key recovery

// Verify signature
const isValid = ThresholdSignature.verify_threshold_signature(
  tss.public_key,
  signature.msgHash,
  signature.sig
);
console.log(isValid); // true
// Corporate authorization workflow
const corporateTSS = new ThresholdSignature(5, 3);

const authMessage = JSON.stringify({
  action: "wire_transfer",
  amount: 1000000,
  recipient: "operations_account",
  timestamp: Date.now()
});

const authorization = corporateTSS.sign(authMessage);
console.log("Authorization signature:", authorization.serialized_sig);
// Escrow release with buyer + seller
const escrowTSS = new ThresholdSignature(3, 2);

const releaseMessage = "Release escrow funds to seller";
const escrowSignature = escrowTSS.sign(releaseMessage);

// This signature can be verified by anyone
const verified = ThresholdSignature.verify_threshold_signature(
  escrowTSS.public_key,
  escrowSignature.msgHash,
  escrowSignature.sig
);

(static) verify_threshold_signature(public_key, msgHash, sig) → {boolean}

Verifies a threshold signature against a public key and message hash

This static method verifies threshold signatures using standard ECDSA verification. Threshold signatures are indistinguishable from regular ECDSA signatures, so standard verification algorithms work without modification.

Verification Algorithm:

  1. Input Validation: Ensure signature components r and s are valid
  2. Hash Processing: Use the provided message hash (already computed)
  3. Inverse Computation: Compute w = s⁻¹ mod n
  4. Point Calculation: Compute u₁ = w×hash and u₂ = w×r
  5. Point Addition: Compute point = u₁×G + u₂×PublicKey
  6. Verification: Check if point.x ≡ r (mod n)

Compatibility:

  • Works with any ECDSA signature, threshold or single-party
  • Uses standard secp256k1 curve parameters
  • Compatible with Bitcoin and Ethereum signature formats
  • Can be used by third parties without threshold scheme knowledge
Parameters:
Name Type Description
public_key Object

Elliptic curve public key point

msgHash Buffer

SHA256 hash of the original message

sig Object

Signature object with r and s components

Properties
Name Type Description
r bigint

Signature r value

s bigint

Signature s value

Source:
Returns:

True if signature is valid, false otherwise

Type
boolean
Examples
// Verify a threshold signature
const tss = new ThresholdSignature(3, 2);
const signature = tss.sign("Hello World!");

const isValid = ThresholdSignature.verify_threshold_signature(
  tss.public_key,
  signature.msgHash,
  signature.sig
);
console.log(isValid); // true
// Third-party verification (doesn't need threshold scheme)
function verifyTransaction(publicKey, messageHash, signature) {
  return ThresholdSignature.verify_threshold_signature(
    publicKey,
    messageHash,
    signature
  );
}

// Works with any ECDSA signature
const valid = verifyTransaction(
  somePublicKey,
  someMessageHash,
  someSignature
);
// Batch verification for multiple signatures
function verifyBatch(signatures) {
  return signatures.every(({ publicKey, msgHash, sig }) =>
    ThresholdSignature.verify_threshold_signature(publicKey, msgHash, sig)
  );
}
// Integration with Bitcoin transaction verification
function verifyBitcoinTransaction(transaction, publicKey) {
  const messageHash = computeTransactionHash(transaction);
  const signature = extractSignature(transaction);
  
  return ThresholdSignature.verify_threshold_signature(
    publicKey,
    messageHash,
    signature
  );
}