secret-sharing-rs 0.5.1

Secret-sharing primitives (Shamir, Blakley, ramp, VSS, CRT, visual, etc.) implemented directly from the original papers with no external dependencies.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
# HOWTO — Using `secret-sharing`

Working, copy-pasteable examples for every scheme in the crate. Every
snippet compiles against `secret-sharing = { path = "..." }` with no
other dependencies.

For randomness the crate uses a ChaCha20 CSPRNG (RFC 7539), seeded
from operating-system entropy via [`OsRng`](src/csprng.rs):

```rust
use secret_sharing::{
    BigUint, ChaCha20Rng, PrimeField,
    csprng::OsRng,
    field::mersenne127,
};

fn fresh_rng() -> ChaCha20Rng {
    // Production: seed ChaCha20 from /dev/urandom via OsRng.
    let mut os = OsRng::new().expect("operating-system entropy unavailable");
    ChaCha20Rng::from_os_entropy(&mut os)
}

fn small_field() -> PrimeField {
    PrimeField::new(mersenne127())
}
```

**Tests and reproducible benches** may seed from a fixed byte array
via `ChaCha20Rng::from_seed(&[0x42u8; 32])` — the snippets below in
this document use the OS-entropy form to model real usage. If you only
have a hardware RNG or a non-`/dev/urandom` platform, implement the
[`Csprng`](src/csprng.rs) trait yourself; that trait is the boundary,
not the bundled `ChaCha20Rng`.

## Pick the right scheme

| You want | Use |
|----------|-----|
| Threshold `(k, n)` over field elements | `shamir` |
| Threshold `(k, n)` for byte strings | `bytes` |
| Geometric variant (hyperplanes) | `blakley` |
| `(k, n)` without polynomials, using CRT | `mignotte` (uniqueness) or `asmuth_bloom` (statistical secrecy) |
| Erasure coding of a file (no secrecy) | `ida` |
| Vector secret with data compression | `ramp`, `kgh`, `yamamoto`, `blakley_meadows` |
| Reed–Solomon-style robust recovery | `decode` (Berlekamp–Welch) |
| Arbitrary monotone access structure | `ito` (cumulative) or `benaloh_leichter` (formula tree) |
| Linear scheme over user-supplied matrix | `kothari`, `karchmer_wigderson`, `brickell`, `massey` |
| Verifiable shares (info-theoretic) | `vss` |
| Verifiable shares (computational, smaller) | `cgma_vss` |
| Long-lived secret refreshed periodically | `proactive` |
| Secret picture you can decode by stacking | `visual` |
| Trivial `n`-of-`n` for testing | `trivial` |

---

## `shamir` — Shamir 1979 `(k, n)` polynomial threshold

```rust
use secret_sharing::{csprng::OsRng, shamir, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

let shares = shamir::split(&field, &mut rng, &secret, /*k=*/3, /*n=*/5);
let recovered = shamir::reconstruct(&field, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);
```

Multi-secret pack (`ℓ ≤ k` secrets share the same polynomial; KGH §IV):

```rust
use secret_sharing::{csprng::OsRng, shamir, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secrets: Vec<BigUint> = (1..=3).map(|i| BigUint::from_u64(900 + i)).collect();

let shares = shamir::split_multi(&field, &mut rng, &secrets, /*k=*/4, /*n=*/7);
let got = shamir::reconstruct_multi(&field, &shares[..4], 4, secrets.len()).unwrap();
assert_eq!(got, secrets);
```

## `bytes` — byte-string Shamir

Real secrets are byte arrays (AES keys, passphrases, files). The
`bytes` module chunks a secret into field-sized blocks, runs Shamir per
block, and serialises each share with a self-describing header.

```rust
use secret_sharing::{csprng::OsRng, bytes, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let aes_key = b"32-byte AES-256 key payload!!!!!";

let shares = bytes::split(&field, &mut rng, aes_key, /*k=*/3, /*n=*/5);
let refs: Vec<&[u8]> = shares.iter().map(Vec::as_slice).collect();
let recovered = bytes::reconstruct(&field, &refs[..3], 3).unwrap();
assert_eq!(recovered, aes_key.to_vec());
```

## `blakley` — geometric `(k, n)`

```rust
use secret_sharing::{csprng::OsRng, blakley, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

let shares = blakley::split(&field, &mut rng, &secret, /*k=*/3, /*n=*/5);
let recovered = blakley::reconstruct(&field, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);
```

## `mignotte` — CRT `(k, n)` with uniqueness recovery

```rust
use secret_sharing::{mignotte, BigUint};

// Bundled (3, 5) sequence over small primes; see source for the full
// validation rules.
let seq = mignotte::small_example_3_of_5();
// Secret must lie strictly inside (alpha, beta) = (437, 2431).
let secret = BigUint::from_u64(1234);
let shares = mignotte::split(&seq, &secret);
let recovered = mignotte::reconstruct(&seq, &shares[..3]).unwrap();
assert_eq!(recovered, secret);
```

To build your own sequence, use `MignotteSequence::new(moduli, k)` with
pairwise-coprime, strictly-increasing `moduli` satisfying $\alpha < \beta$.

## `asmuth_bloom` — modular CRT `(k, n)`

```rust
use secret_sharing::{csprng::OsRng, asmuth_bloom, BigUint, ChaCha20Rng};

let params = asmuth_bloom::small_example_3_of_5();
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(2); // < m_0 = 5

let shares = asmuth_bloom::split(&params, &mut rng, &secret);
let recovered = asmuth_bloom::reconstruct(&params, &shares[..3]).unwrap();
assert_eq!(recovered, secret);
```

## `ida` — Rabin Information Dispersal

Erasure coding, **not** secret sharing — per-share is `|F|/k` bytes,
any `k` shares reconstruct, but `k` of any provenance suffice.

```rust
use secret_sharing::{ida, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let data = b"the quick brown fox jumps over the lazy dog".to_vec();
let shares = ida::split(&field, &data, /*k=*/3, /*n=*/5);
let refs: Vec<&[u8]> = shares.iter().map(Vec::as_slice).collect();
let recovered = ida::reconstruct(&field, &refs[..3], 3).unwrap();
assert_eq!(recovered, data);
```

## `ramp` — McEliece–Sarwate ramp

Vector secret of `k` field elements; per-share payload is one field
element regardless of secret length.

```rust
use secret_sharing::{ramp, BigUint, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let secret: Vec<BigUint> = (0..5).map(|i| BigUint::from_u64(0x1000 + i)).collect();

let shares = ramp::split(&field, &secret, /*n=*/8);
let recovered = ramp::reconstruct(&field, &shares[..5], secret.len()).unwrap();
assert_eq!(recovered, secret);
```

## `decode` — Berlekamp–Welch errors-and-erasures recovery

```rust
use secret_sharing::decode::reconstruct_with_errors;
use secret_sharing::{csprng::OsRng, shamir, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xDECAF);

// k = 4, n = 11 — survives up to t = 3 tampered shares (m − 2t = 5 ≥ k).
let mut shares = shamir::split(&field, &mut rng, &secret, 4, 11);
shares[2].y = field.add(&shares[2].y, &BigUint::from_u64(1));
shares[5].y = BigUint::zero();
shares[9].y = field.add(&shares[9].y, &BigUint::from_u64(99));

let recovered = reconstruct_with_errors(&field, &shares, 4, 3).unwrap();
assert_eq!(recovered, secret);
```

## `kgh` — KGH §II matrix scheme for vector secrets

```rust
use secret_sharing::{csprng::OsRng, kgh, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret: Vec<BigUint> = (1..=4).map(|i| BigUint::from_u64(0x100 + i)).collect();

let shares = kgh::split(&field, &mut rng, &secret, /*k=*/3, /*n=*/6);
let recovered = kgh::reconstruct(&field, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);
```

## `yamamoto``(k, L, n)` ramp

```rust
use secret_sharing::{csprng::OsRng, yamamoto, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret: Vec<BigUint> = (1..=3).map(|i| BigUint::from_u64(0x500 + i)).collect();

// k=5, L=3, n=8: any 5 shares recover all 3 secrets; ≤ 2 reveal nothing.
let shares = yamamoto::split(&field, &mut rng, &secret, /*k=*/5, /*n=*/8);
let recovered = yamamoto::reconstruct(&field, &shares[..5], 5, secret.len()).unwrap();
assert_eq!(recovered, secret);
```

## `blakley_meadows``(k, L, n)` Blakley ramp

```rust
use secret_sharing::{csprng::OsRng, blakley_meadows, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret: Vec<BigUint> = (1..=3).map(|i| BigUint::from_u64(0x100 + i)).collect();

// k=5, L=3, n=8: same threshold structure as yamamoto, geometric form.
let shares = blakley_meadows::split(&field, &mut rng, &secret, /*k=*/5, /*n=*/8);
let recovered = blakley_meadows::reconstruct(&field, &shares[..5], 5, secret.len()).unwrap();
assert_eq!(recovered, secret);
```

## `ito` — Ito–Saito–Nishizeki cumulative array

Realises any monotone access structure described by its maximal
forbidden coalitions.

```rust
use secret_sharing::{csprng::OsRng, ito, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64(65_537));
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());

// Custom access structure: {1,2}, {3,4}, {1,3} qualify.
// Maximal forbidden coalitions: {1,4}, {2,3}, {2,4}.
let structure = ito::AccessStructure::new(
    /*n=*/4,
    vec![vec![1, 4], vec![2, 3], vec![2, 4]],
).unwrap();

let secret = BigUint::from_u64(0xC0DE);
let shares = ito::split(&field, &mut rng, &secret, &structure);

// {1, 2} qualifies and recovers.
let coalition: Vec<_> = shares.iter()
    .filter(|s| matches!(s.player, 1 | 2))
    .cloned()
    .collect();
let recovered = ito::reconstruct(&field, &structure, &coalition).unwrap();
assert_eq!(recovered, secret);
```

For an `(k, n)` threshold rendered as ISN, use the helper:

```rust
use secret_sharing::ito::threshold_access_structure;
let structure = threshold_access_structure(/*n=*/5, /*k=*/3);
```

## `benaloh_leichter` — monotone formula tree

```rust
use secret_sharing::{csprng::OsRng, benaloh_leichter as bl, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64(65_537));
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());

// T = (P1 AND P2) OR (P1 AND P3) OR (P2 AND P3) — a 2-of-3 threshold.
let formula = bl::Formula::or(vec![
    bl::Formula::and(vec![bl::Formula::party(1), bl::Formula::party(2)]),
    bl::Formula::and(vec![bl::Formula::party(1), bl::Formula::party(3)]),
    bl::Formula::and(vec![bl::Formula::party(2), bl::Formula::party(3)]),
]);

let secret = BigUint::from_u64(0xBEEF);
let shares = bl::split(&field, &mut rng, &secret, &formula);

let pair: Vec<_> = shares.iter()
    .filter(|s| matches!(s.player, 1 | 2))
    .cloned()
    .collect();
let recovered = bl::reconstruct(&field, &formula, &pair).unwrap();
assert_eq!(recovered, secret);
```

## `kothari` — generalised linear `(k, n)`

User-supplied public matrix. Vandermonde convenience matches Shamir.

```rust
use secret_sharing::{csprng::OsRng, kothari, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64((1u64 << 61) - 1));
let scheme = kothari::vandermonde(field, /*k=*/3, /*n=*/5);
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xCAFE);

let shares = kothari::split(&scheme, &mut rng, &secret);
let pairs: Vec<_> = (0..3).map(|c| (c, shares[c].clone())).collect();
let recovered = kothari::reconstruct(&scheme, &pairs).unwrap();
assert_eq!(recovered, secret);
```

## `karchmer_wigderson` — monotone span programs

The most general linear-SSS framework. Threshold convenience:

```rust
use secret_sharing::{csprng::OsRng, karchmer_wigderson as kw, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64((1u64 << 61) - 1));
let prog = kw::threshold_msp(field, /*k=*/3, /*n=*/5);
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

let shares = kw::split(&prog, &mut rng, &secret);
let coalition: Vec<_> = shares.iter()
    .filter(|s| matches!(s.player, 1 | 2 | 3))
    .cloned()
    .collect();
let recovered = kw::reconstruct(&prog, &coalition).unwrap();
assert_eq!(recovered, secret);
```

For a custom MSP, hand-build the `(rows, labels)` so that the row-set
of every qualified coalition spans the canonical target `e_1`.

## `brickell` — ideal vector-space SSS

One vector per player; per-player share is a single field element.

```rust
use secret_sharing::{csprng::OsRng, brickell, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64((1u64 << 61) - 1));
// Brickell's flagship example: realises an access structure where
// {1} qualifies alone, {2,3} qualifies, but {2} and {3} do not.
let v = vec![
    vec![BigUint::one(),  BigUint::zero()],     // v_1 = (1, 0)
    vec![BigUint::one(),  BigUint::one()],      // v_2 = (1, 1)
    vec![BigUint::one(),  BigUint::from_u64(2)],// v_3 = (1, 2)
    vec![BigUint::zero(), BigUint::one()],      // v_4 = (0, 1)
];
let scheme = brickell::Scheme::new(field, v);
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(33);

let shares = brickell::split(&scheme, &mut rng, &secret);
let solo_p1: Vec<_> = shares.iter()
    .filter(|s| s.player == 1)
    .cloned()
    .collect();
let recovered = brickell::reconstruct(&scheme, &solo_p1).unwrap();
assert_eq!(recovered, secret);
```

## `massey` — linear-code SSS via minimal codewords

```rust
use secret_sharing::{csprng::OsRng, massey, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64((1u64 << 61) - 1));
// Reed–Solomon-style (2, 3) Shamir as a Massey code:
// G is 2 × 4, column 0 is the secret slot, columns 1..3 are players.
let g = vec![
    vec![BigUint::one(),  BigUint::one(),  BigUint::one(),  BigUint::one()],
    vec![BigUint::zero(), BigUint::one(),  BigUint::from_u64(2), BigUint::from_u64(3)],
];
let scheme = massey::CodeScheme::new(field, g);
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

let shares = massey::split(&scheme, &mut rng, &secret);
let pair: Vec<_> = shares.iter()
    .filter(|s| matches!(s.player, 1 | 2))
    .cloned()
    .collect();
let recovered = massey::reconstruct(&scheme, &pair).unwrap();
assert_eq!(recovered, secret);
```

## `vss` — Rabin–Ben-Or bivariate VSS (information-theoretic)

```rust
use secret_sharing::{csprng::OsRng, vss, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64((1u64 << 61) - 1));
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

// Honest-majority: 2(k − 1) < n. Helper:
assert!(vss::is_honest_majority(/*k=*/3, /*n=*/5));

let shares = vss::deal(&field, &mut rng, &secret, 3, 5);

// Pairwise cross-checks must pass before any share is used.
assert!(vss::verify_consistent(&field, &shares));

let recovered = vss::reconstruct(&field, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);
```

## `cgma_vss` — Chor-GMA computational VSS (Feldman commitments)

```rust
use secret_sharing::{csprng::OsRng, cgma_vss, BigUint, ChaCha20Rng};

// RFC 5114 §2.3 — 2048-bit p, 256-bit prime-order subgroup, generator
// g of that subgroup. Validated cryptographer-grade Schnorr group.
let group = cgma_vss::rfc5114_modp_2048_256();
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0x1234_5678_9abc_def0); // < q (256-bit)

let (shares, commits) = cgma_vss::deal(&group, &mut rng, &secret, /*k=*/3, /*n=*/5);

// Each receiver must verify before using their share.
for s in &shares {
    assert!(cgma_vss::verify_share(&group, &commits, s), "share {} valid", s.player);
}

let recovered = cgma_vss::reconstruct(&group, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);
```

## `proactive` — Herzberg et al. share refresh

Refresh a Shamir share set without changing the underlying secret.
Old shares are no longer compatible with new shares — discard them.

```rust
use secret_sharing::{csprng::OsRng, proactive, shamir, BigUint, ChaCha20Rng, PrimeField};
use secret_sharing::field::mersenne127;

let field = PrimeField::new(mersenne127());
let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());
let secret = BigUint::from_u64(0xC0FFEE);

let mut shares = shamir::split(&field, &mut rng, &secret, /*k=*/3, /*n=*/5);

// Epoch boundary: refresh.
shares = proactive::refresh(&field, &mut rng, &shares, 3);

// Same secret, different polynomial.
let recovered = shamir::reconstruct(&field, &shares[..3], 3).unwrap();
assert_eq!(recovered, secret);

// Lost-share recovery: simulate losing player 3's share.
let lost_x = shares[2].x.clone();
let live = vec![shares[0].clone(), shares[1].clone(), shares[3].clone()];
let recovered_share = proactive::recover_share(&field, &live, 3, &lost_x).unwrap();
assert_eq!(recovered_share, shares[2]);
```

## `visual` — Naor–Shamir visual cryptography (n, n)

Black-and-white image as `Vec<Vec<bool>>`; reconstruction by stacking
(bitwise OR) all `n` shares. Per-pixel expansion is $2^{n-1}$.

```rust
use secret_sharing::{csprng::OsRng, visual, ChaCha20Rng};

let mut rng = ChaCha20Rng::from_os_entropy(&mut OsRng::new().unwrap());

// 4×4 checkerboard.
let secret: Vec<Vec<bool>> = (0..4)
    .map(|y| (0..4).map(|x| (x + y) % 2 == 0).collect())
    .collect();

let shares = visual::split_n_of_n(&mut rng, &secret, /*n=*/2);
// Stack — physically, lay the transparencies on top of each other.
let stacked = visual::stack(&shares).unwrap();
let decoded = visual::decode(&stacked, /*n=*/2).unwrap();
assert_eq!(decoded, secret);
```

`n` is not stored alongside the shares — caller must persist it.

## `trivial``n`-of-`n` additive split

```rust
use secret_sharing::{csprng::OsRng, trivial, BigUint, ChaCha20Rng, PrimeField};

let field = PrimeField::new(BigUint::from_u64(65_537));
let mut rng = ChaCha20Rng::from_seed(&[7u8; 32]);
let secret = BigUint::from_u64(12_345);

let shares = trivial::split(&field, &mut rng, &secret, /*n=*/3);
let recovered = trivial::reconstruct(&field, &shares);
assert_eq!(recovered, secret);

// Byte-XOR variant (q = 2 special case):
let xor_shares = trivial::split_xor(&mut rng, b"my super secret payload", 3);
let recovered = trivial::reconstruct_xor(&xor_shares);
assert_eq!(recovered, b"my super secret payload".to_vec());
```

---

## Failure modes that return `None`

Every reconstruction function in this crate uses `Option<...>` rather
than panicking on caller-supplied bad input. A `None` means **one of**:

- fewer than `k` shares,
- duplicate / out-of-range share index or player,
- malformed wire bytes (for `bytes` and `ida`),
- extra shares (beyond the first `k`) inconsistent with the
  polynomial or matrix fitted to the first `k`,
- (CRT schemes) recovered value outside the legal secret range,
- (`vss`) any pairwise cross-check fails,
- (`cgma_vss`) commitment fails the discrete-log verification or lies
  outside the order-`q` subgroup.

Static contract violations (e.g. `k < 2`, `n < k`, secret ≥ field
modulus) panic via `assert!` — those are programmer errors, not
runtime failures.

## Picking a field

| Helper | Modulus | Plaintext block | Share-element width |
|--------|---------|-----------------|---------------------|
| `field::mersenne127()` | $2^{127} - 1$ | 15 bytes | 16 bytes |
| `field::mersenne521()` | $2^{521} - 1$ | 65 bytes | 66 bytes |

Any user-supplied prime works — `PrimeField::new(p)` accepts an
arbitrary `BigUint`. The caller is responsible for choosing a value
that is genuinely prime and large enough to comfortably exceed `n`.

## Threat model recap

- **Variable-time arithmetic.** `BigUint` is documented as variable-
  time; do not deploy in side-channel-exposed environments.
- **Honest dealer.** Most schemes (everything except `vss` and
  `cgma_vss`) trust the dealer. Use a VSS module if dealer integrity
  is in scope.
- **Tampering.** Naive Lagrange / linear-system reconstruction returns
  a wrong-but-plausible secret if exactly `k` shares are supplied and
  one is corrupted. Provide extras (`shares.len() > k`) so the
  validator can cross-check, or use `decode` for Reed–Solomon error
  correction up to `(m − k) / 2` shares.
- **Zeroization.** `BigUint` zeroes its limb buffer on `Drop`. Other
  intermediate `Vec`s and byte buffers are not scrubbed beyond that.