For the complete documentation index, see llms.txt. This page is also available as Markdown.

Threshold Key Sharing and Backup via Shamir's Secret Sharing Scheme

Deggen (d.kellenschwiler@bsvassociation.org)

Abstract

This standard defines a method for splitting a secp256k1 private key into m shares such that any n of those shares (where 2 ≤ n ≤ m) can reconstruct the original key, while any fewer than n shares reveal nothing about it. The scheme is an application of Shamir's Secret Sharing over the secp256k1 prime field, augmented with a cryptographically secure, non-deterministic share-coordinate generation procedure and a short integrity tag. A canonical textual ("backup") serialization is specified so that individual shares can be written down, stored offline, and later recombined. This codifies the toKeyShares / fromKeyShares and toBackupShares / fromBackupShares methods of the PrivateKey class in the BSV TypeScript SDK.

Motivation

A single private key is a single point of failure: lose it and funds or identity are gone; leak it and they are stolen. Common mitigations — full copies in multiple locations — multiply the leak surface for every copy made. Threshold secret sharing breaks this trade-off: a key is distributed across m custodians or locations, a quorum of n is required to recover it, and a minority of compromised or lost shares neither reveals the key nor prevents recovery.

This standard targets the backup and recovery use case (e.g. toBackupShares(2, 3): split into three shares, any two recover the key). It specifies the field arithmetic, the share-coordinate generation, the integrity tag, and the textual serialization precisely enough that an independent implementation can produce shares recoverable by, and recover keys from, the reference implementation.

This scheme covers storage and reconstruction of a key. It is not a threshold-signature scheme: the key is fully reassembled in one place at recovery time, and the dealer (the party performing the split) sees the whole key. It does not provide verifiable secret sharing (a malicious dealer is not provably constrained beyond the integrity tag), nor does it protect the key while reassembled.

Specification

Field

All share arithmetic is performed in the prime field 𝔽p, where p is the secp256k1 field prime:

p = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F

Note. p is the curve's coordinate-field prime, not the group order n. A private key is a scalar in [1, n-1] and n < p, so every valid private key is also a valid element of 𝔽p. The secret is treated purely as an integer; no elliptic-curve point operations are involved in the sharing itself.

Secret encoding

Let k be the private key interpreted as a big-endian unsigned integer. k is the secret and is defined as the value of the sharing polynomial at x = 0:

Polynomial

To support a threshold of n, the dealer defines a polynomial of degree n − 1 over 𝔽p. The reference implementation represents this polynomial implicitly by n points rather than by explicit coefficients:

  • Point 0 is (0, k) — the secret.

  • Points 1 … n−1 are (xᵢ, yᵢ) where each xᵢ and yᵢ is a fresh 32-byte random value reduced mod p.

These n points uniquely determine a degree (n − 1) polynomial. The polynomial is evaluated at an arbitrary coordinate x by Lagrange interpolation through its defining points:

All additions, subtractions, multiplications, and the modular inverse (·)⁻¹ are performed mod p.

Share-coordinate generation

For each of the m shares the dealer must choose a distinct, non-zero x-coordinate at which to evaluate f. Coordinates MUST be generated as follows so that a split is non-deterministic and remains safe even if the system RNG is partially compromised:

  1. Draw a single 64-byte master seed from a CSPRNG, used as the HMAC key for the whole split.

  2. For share index i (0 ≤ i < m), starting at attempt = 0: a. Build the message counter = [ i, attempt, r₀ … r₃₁ ] where r₀ … r₃₁ are 32 fresh CSPRNG bytes drawn for this attempt. b. Compute x = HMAC-SHA-512(seed, counter) mod p. c. If x = 0 or x was already used by an earlier share, increment attempt and retry from (a). d. Abort with an error if a share's coordinate is not resolved within 5 attempts.

  3. Record x, then compute y = f(x). The share is the point (x, y).

The combination of a per-split master seed, the per-share index, the retry counter, and fresh per-attempt randomness ensures non-determinism, uniqueness, and resistance to RNG bias.

Integrity tag

Each share carries an 8-character integrity tag binding it to its key. The tag is the first 8 hexadecimal characters (4 bytes) of the HASH160 (RIPEMD-160(SHA-256(·))) of the compressed public key corresponding to the private key:

All shares of one key carry the same tag. The tag lets a recovery implementation reject shares that belong to different keys and confirm that a reconstructed key matches the original. It is a non-secret checksum, not an authentication mechanism: 4 bytes is enough to catch accidental mismatch but MUST NOT be relied upon to prove key ownership.

Backup serialization

A share is serialized to text as four .-separated fields:

Field
Encoding

x

Base58 of the big-endian byte array of the x-coordinate (no checksum)

y

Base58 of the big-endian byte array of the y-coordinate (no checksum)

threshold

The threshold n, as a base-10 integer

integrity

The 8-character hex integrity tag

x and y together form the point; the leading <x>.<y> substring is the point serialization. Example shares for a (3, 5) split (threshold 3, integrity 2f804d43):

A parser MUST reject any share that does not split into exactly four fields, and MUST reject a set of shares whose threshold fields or integrity fields are not all equal.

Reconstruction

Given a set S of distinct shares with common threshold n:

  1. Verify |S| ≥ n. (Additional shares beyond n are permitted; the first n are used.)

  2. Verify that no two of the shares used share the same x-coordinate; reject duplicates with an error.

  3. Reconstruct the polynomial from the n points and evaluate it at x = 0 by Lagrange interpolation:

  4. Derive the public key from k, compute its integrity tag as above, and compare against the shares' tag. If they differ, abort with an integrity-mismatch error.

  5. Return k as the recovered private key.

Parameter constraints

  • threshold (n) and totalShares (m) MUST be integers.

  • n ≥ 2.

  • m ≥ 2.

  • n ≤ m.

A threshold of 1 is disallowed: it would make any single share equal to the key.

Security considerations

  • Dealer trust. The party that splits the key sees the whole key and, at recovery, the key is fully reassembled in one place. This scheme protects keys at rest across distributed shares; it does not provide threshold signing or guard the key while in use.

  • Information-theoretic secrecy below threshold. Fewer than n shares reveal no information about k, because the remaining coefficient(s) of the degree (n − 1) polynomial are uniformly random over 𝔽p.

  • Integrity tag is not authentication. The 4-byte tag detects accidental share mismatch and confirms a correct reconstruction. It is short and public; it does not prevent a motivated adversary who controls share distribution from substituting a different key, and it MUST NOT be treated as proof of ownership.

  • Coordinate generation. Implementations MUST use the HMAC-based, per-attempt-randomized coordinate generation so that repeated splits of the same key produce different shares and a biased or partially compromised RNG does not yield colliding or predictable coordinates.

  • Share storage. Each serialized share is sufficient, in quorum, to recover spending authority. Shares SHOULD be stored with the same care as the key fragments they are, in mutually independent locations.

Implementations

The scheme is implemented in the BSV TypeScript SDK (@bsv/sdk) on the PrivateKey primitive:

Relevant methods:

  • PrivateKey.toKeyShares(threshold, totalShares): KeyShares — split into a structured KeyShares object.

  • PrivateKey.toBackupShares(threshold, totalShares): string[] — split and serialize to backup strings.

  • PrivateKey.fromKeyShares(keyShares): PrivateKey — reconstruct from a KeyShares object.

  • PrivateKey.fromBackupShares(shares): PrivateKey — parse backup strings and reconstruct.

  • The KeyShares class (points, threshold, integrity) with toBackupFormat() / fromBackupFormat().

  • The Polynomial and PointInFiniteField primitives implementing the field arithmetic and Lagrange interpolation.

References

Last updated

Was this helpful?