import { RawShare } from '@noy-db/shamir'; export { RawShare, ShareJSON, combineSecret, decodeShareBase32, decodeShareBytes, decodeShareJSON, encodeShareBase32, encodeShareBytes, encodeShareJSON, gfAdd, gfDiv, gfInv, gfMul, gfPolyEval, lagrangeInterpolateAtZero, splitSecret } from '@noy-db/shamir'; import { NoydbShamir } from '@noy-db/hub/on'; export { NoydbShamir } from '@noy-db/hub/on'; /** * **@noy-db/on-shamir** — k-of-n Shamir Secret Sharing of the vault KEK. * * Any K of N enrolled shares recombines the original KEK; fewer than * K leaks zero bits. Unlike naive multi-secret schemes, each * share can be protected by ANY other `@noy-db/on-*` method — share * 1 under a WebAuthn passkey, share 2 under an OIDC login, share 3 * on paper in a safe. This composability is the defining feature. * * Part of the `@noy-db/on-*` authentication family. * * ## Math * * Shamir Secret Sharing over GF(2^8), byte-wise. For each byte of the * secret, construct a random polynomial of degree k-1 with the byte * as the constant term. Each share is a value of that polynomial at * a distinct x-coordinate. Lagrange interpolation at x=0 recovers * the byte. * * The math and the share codecs live in **`@noy-db/shamir`** — a * zero-dependency primitive with no hub contract — and are re-exported * here unchanged, so this package's published surface is unaltered by * the split. Import from `@noy-db/shamir` directly when composing * threshold sharing into something that is not a noy-db unlock method. * * ## Threat model * * Protects against: * - Up to K-1 colluding share holders (mathematically — fewer than K shares reveals zero bits) * - Loss of up to N-K shares * * Does NOT protect against: * - K colluding share holders (by design — that's the threshold contract) * - Device compromise of the combining machine during reconstruction * * ## Usage * * ```ts * import { * splitKEK, * combineKEK, * encodeShareBase32, * decodeShareBase32, * } from '@noy-db/on-shamir' * * // ENROLL — user has unlocked the vault with secret; now create a 2-of-3 split * const shares = await splitKEK(currentKEK, { k: 2, n: 3 }) * const shareStrings = shares.map(encodeShareBase32) * // Distribute each shareString to a different holder via any on-* method * * // UNLOCK — collect 2 of the 3 shares and combine * const collected = [decodeShareBase32(shareA), decodeShareBase32(shareB)] * const kek = await combineKEK(collected) * // kek is now a non-extractable CryptoKey usable as the vault's KEK * ``` * * @packageDocumentation */ interface SplitKEKOptions { /** Threshold — minimum shares needed to reconstruct. Must be >= 2. */ readonly k: number; /** Total shares. Must satisfy k <= n <= 255. */ readonly n: number; } /** * Split the given KEK into N Shamir shares. * * The KEK must be extractable (so the raw bytes can be read for the * split operation). The returned `RawShare[]` contains the raw share * material — serialise each via `encodeShareBase32` / `encodeShareJSON` * before distributing. * * The caller is responsible for: * 1. Distributing the shares to their holders. * 2. Writing an audit-ledger entry recording the enrollment (including * the `k`, `n`, and share x-coordinates — not the share material). * 3. Securely zeroing any in-memory share/secret material after * serialisation. */ declare function splitKEK(kek: CryptoKey, options: SplitKEKOptions): Promise; declare function shamirRecoveryProvider(): NoydbShamir; /** * Reconstruct the KEK from K or more shares. * * Returns a non-extractable `CryptoKey` ready to use as the vault's * KEK. Internal secret bytes are zeroed after the CryptoKey is * imported. * * Throws: * - if fewer than K shares are provided * - if shares have mismatched lengths (likely indicating shares from * different enrollments were mixed) * - if duplicate x-coordinates are detected */ declare function combineKEK(shares: readonly RawShare[]): Promise; export { type SplitKEKOptions, combineKEK, shamirRecoveryProvider, splitKEK };