Shamir's Secret Sharing

repository·main·Indexed 42 days ago

https://github.com/privy-io/shamir-secret-sharing

A zero-dependency, independently audited TypeScript implementation of Shamir's Secret Sharing algorithm using GF(2^8). Version 0.0.4 provides split() and combine() functions to divide Uint8Array secrets into multiple shares and reconstruct them based on a minimum threshold, compatible with Node.js and browser environments.

Tokens
1.4K
Snippets
5
Records
6
Agent score
5%

What's inside shamir-secret-sharing

  1. Security considerations for Shamir's Secret Sharing

    main

    When using this library, be aware of the following security constraints:

    1. Reconstruction integrity: The library does not verify if the reconstructed secret is correct. If shares are corrupted or incorrect, combine will produce an incorrect value. You must independently verify the integrity of the reconstructed secret.
    2. Side-channel attacks: Because JavaScript is garbage-collected and JIT-compiled, true constant-time execution cannot be guaranteed, though algorithmic constant-time is targeted where possible.
    3. Secret entropy: Secrets should be uniformly random. If your secret is not high-entropy, it is recommended to encrypt the value first and split the encryption key instead.
    4. Input validation: The library assumes inputs are correctly formed. Callers are responsible for validating that inputs to split and combine come from trusted or validated sources.
  2. Example: Splitting and combining a symmetric key

    main

    This example demonstrates how to export a Web Crypto API key as a Uint8Array, split it into shares, and reconstruct it.

    import {split, combine} from 'shamir-secret-sharing';
    
    // 1. Generate a symmetric key
    const key = await crypto.subtle.generateKey(
      {
        name: "AES-GCM",
        length: 256
      },
      true,
      ["encrypt", "decrypt"]
    );
    
    // 2. Export the key to a Uint8Array
    const exportedKeyBuffer = await crypto.subtle.exportKey('raw', key);
    const exportedKey = new Uint8Array(exportedKeyBuffer);
    
    // 3. Split the key into 3 shares, requiring 2 to reconstruct
    const [share1, share2, share3] = await split(exportedKey, 3, 2);
    
    // 4. Reconstruct using a subset of shares
    const reconstructed = await combine([share2, share1]);
    
    // 5. Verify
    console.log(btoa(reconstructed) === btoa(exportedKey)); // true
  3. Reconstruct a secret from shares using combine()

    main

    The combine function takes a subset of shares and reconstructs the original secret.

    Parameters:

    • shares: An array of Uint8Array shares. The array must contain at least 2 and at most 255 shares.

    Returns: A Promise that resolves to the reconstructed Uint8Array secret.

    import {combine} from 'shamir-secret-sharing';
    
    // Assuming shares were generated via split()
    const reconstructed = await combine([share1, share2]);
  4. Split a secret into shares using split()

    main

    The split function divides a Uint8Array secret into a specified number of shares. To reconstruct the secret, a minimum number of these shares (the threshold) must be provided.

    Parameters:

    • secret: The Uint8Array value to split.
    • shares: The total number of shares to generate. Must be between 2 and 255.
    • threshold: The minimum number of shares required for reconstruction. Must be between 2 and 255.

    Returns: A Promise that resolves to an array of Uint8Array shares.

    import {split} from 'shamir-secret-sharing';
    
    const secret = new Uint8Array([1, 2, 3, 4]);
    const shares = await split(secret, 3, 2);
    // shares is Uint8Array[]
  5. Reconstruct a secret from shares

    main

    Use the combine function to reconstruct the original Uint8Array secret from a collection of shares.

    Constraints:

    • shares: Must be an array of Uint8Array objects.
    • The array must contain between 2 and 255 shares.
    • All shares must have the same byte length.
    • Each share must be at least 2 bytes long.
    • Each share must contain a unique X-coordinate (the last byte of the share).

    If the provided shares are fewer than the threshold used during the split process, the reconstruction will fail to produce the original secret.

    import { combine } from 'shamir-secret-sharing';
    
    // Assuming 'shares' was generated by split()
    const secret = await combine(shares.slice(0, 3));
    // secret will be the original Uint8Array
  6. Split a secret into multiple shares

    main

    Use the split function to divide a Uint8Array secret into a specified number of shares. You must also define a threshold, which is the minimum number of shares required to reconstruct the original secret.

    Constraints:

    • secret: Must be a non-empty Uint8Array.
    • shares: Must be an integer between 2 and 255.
    • threshold: Must be an integer between 2 and 255, and cannot be greater than shares.

    Each resulting share is a Uint8Array where the last byte represents the unique X-coordinate of that share.

    import { split } from 'shamir-secret-sharing';
    
    const secret = new Uint8Array([42, 123, 255]);
    const shares = await split(secret, 5, 3);
    // shares is an array of 5 Uint8Arrays, requiring any 3 to reconstruct