Stateless · ANARKey ePrint 2025/551

Bottom-Up Secret Sharing

Guardians choose their own shares from their existing keys — the owner collects them, publishes a short auxiliary value φ, and guardians can recover the secret on demand without ever having stored anything extra.

📄
IO Research · ePrint 2025/551
ANARKey: A New Approach to (Socially) Recover Keys
Aniket Kate · Pratyay Mukherjee · Hamza Saleem · Pratik Sarkar · Bhaskar Roberts

The Bottom-Up Secret Sharing (BUSS) scheme used here is formalised in §5.1. ANARKey introduces a community-based social key recovery model where each member acts as guardian for others using only their existing secret key — no additional storage required. The scheme is proven secure against malicious and adaptive corruption of up to t parties.

Overview

Bottom-Up Secret Sharing inverts the classical trust model of Shamir SSS. In traditional schemes, the dealer chooses all shares and distributes them to guardians — who must store them securely forever. In BUSS, each guardian independently derives their own share from their existing secret key: σⱼ = H(owner_id ‖ skⱼ). The owner collects these guardian-chosen shares, builds the unique polynomial of degree n through (0, secret) and all guardian points, then publishes a short auxiliary value φ to a public bulletin board. When recovery is needed, any t+1 guardians recompute their share on demand — the same hash call, no stored state.

The key insight: a single guardian key serves as guardian for many key-owners. Each distinct owner_id yields an independent, uncorrelated share — so a guardian protecting their own hardware wallet key automatically becomes a potential guardian for any friend who registers them.

Inverted trust model: in traditional SSS the dealer chooses and distributes all shares to guardians. In BUSS, guardians choose their own shares proactively — the dealer only learns them in order to build φ. This inverts the trust model and lets guardians recover on-demand from their own key, with no extra storage.

Protocol

BUSS operates in two phases. During backup, each guardian derives their share from their own secret key and the owner's identifier. The owner collects all guardian shares, builds a unique degree-(n−1) polynomial through (0, secret) and the n−1 guardian points, then publishes a short auxiliary value φ to a public bulletin board.

01

Guardian Share Derivation

Guardian j computes σⱼ = H(owner_id ‖ skⱼ) deterministically from their own secret key and the owner's public identifier. No extra storage, no round-trip coordination — the same call always yields the same σⱼ.

02

Owner Interpolates and Publishes φ

The owner builds the unique degree-(n−1) polynomial f through (0, s), (1, σ₁), …, (n−1, σ_{n−1}), then evaluates at the negative integers to produce φ = (f(−1), …, f(−(n−t−1))) — just n−t−1 field elements posted publicly (e.g., on-chain).

03

Recovery

Any t+1 guardians recompute their σ on-demand (same hash call as step 01). Combined with the n−t−1 public φ points, they have exactly n evaluations of f — enough to recover s = f(0) via Lagrange interpolation.

Why φ has exactly n−t−1 entries: the t+1 guardian shares plus n−t−1 public points sum to n — the degree of f plus one, the minimum needed to uniquely determine f and hence s = f(0).
Protocol overview (n = 4, t = 1 · threshold = 2 · |φ| = 2) Guardians Owner P₁ Bulletin Board ───────────────────── ──────────────────── ──────────────── P₂: σ₁,₂ = H(pk₁, sk₂) ─▶ │ P₃: σ₁,₃ = H(pk₁, sk₃) ─▶ │ build f of degree 3 P₄: σ₁,₄ = H(pk₁, sk₄) ─▶ │ f(0)=sk₁, f(j)=σ₁,ⱼ φ₁ = (f(−1), f(−2)) ──▶ ✓ Recovery (any 2 of 3 guardians) Uses: ──────────────────────────────── t+1 = 2 recomputed guardian shares P₂ recomputes σ₁,₂ + n−t−1 = 2 public φ points P₃ recomputes σ₁,₃ = 4 points on f → Lagrange → sk₁ ✓

Stateless Guardian Shares

The guardian_share function is the primitive that enables stateless recovery. It hashes owner_id ‖ guardian_sk using a 64-byte hash function and reduces the output to a field element via FromUniformBytes<64> — bias < 2⁻¹²⁸ for 256-bit fields.

BUSS — full protocol (t=2, n=5)
use arc_pleiades::{BottomUpSSS, guardian_share};
use arc_pleiades::bottom_up::BottumUpSS;
use arc_pleiades::bottom_up::buss::Share;
use midnight_curves::Fq as Scalar;
use sha2::Sha512;
use rand::thread_rng;

let owner_id = b"alice@example.com";
let secret   = Scalar::random(&mut thread_rng());

// ── Backup: each guardian independently derives σ from their own key ──
let g_keys: Vec<Scalar> = (0..4).map(|_| Scalar::random(&mut thread_rng())).collect();
let sigma_b: Vec<Share<Scalar>> = g_keys.iter().enumerate()
    .map(|(i, &sk)| Share {
        x: Scalar::from((i + 1) as u64),
        y: guardian_share::<Scalar, Sha512>(owner_id, sk),
    })
    .collect();

// ── Owner collects all σ, builds f, publishes φ (2 field elements) ──
let buss = BottomUpSSS::new(2, 5)?; // t=2, n=5 → 4 shares, threshold 3
let phi = buss.split(secret, &sigma_b)?;
// Publish phi to a bulletin board (n−t−1 = 2 field elements)

// ── Recovery: any 3 guardians recompute σ on-demand — no stored state ──
let sigma_r = vec![
    Share { x: Scalar::from(1u64), y: guardian_share::<Scalar, Sha512>(owner_id, g_keys[0]) },
    Share { x: Scalar::from(3u64), y: guardian_share::<Scalar, Sha512>(owner_id, g_keys[2]) },
    Share { x: Scalar::from(4u64), y: guardian_share::<Scalar, Sha512>(owner_id, g_keys[3]) },
];
let recovered = buss.reconstruct(&phi, &sigma_r)?;
assert_eq!(secret, recovered);
Ideal use case: BUSS shines when guardians are existing key-holders — hardware wallet owners, multi-sig participants, community members — who cannot be asked to manage additional data. A guardian recovering a friend's key uses the same secret key they already protect. Nothing new to store, nothing new to lose.