vsss_rs/
lib.rs

1/*
2    Copyright Michael Lodder. All Rights Reserved.
3    SPDX-License-Identifier: Apache-2.0
4*/
5//! Verifiable Secret Sharing Schemes are using to split secrets into
6//! multiple shares and distribute them among different entities,
7//! with the ability to verify if the shares are correct and belong
8//! to a specific set. This crate includes Shamir's secret sharing
9//! scheme which does not support verification but is more of a
10//! building block for the other schemes.
11//!
12//! This crate supports Feldman and Pedersen verifiable secret sharing
13//! schemes.
14//!
15//! Feldman and Pedersen are similar in many ways. It's hard to describe when to use
16//! one over the other. Indeed, both are used in
17//! [GennaroDKG](https://link.springer.com/article/10.1007/s00145-006-0347-3).
18//!
19//! Feldman reveals the public value of the verifier whereas Pedersen's hides it.
20//!
21//! Feldman and Pedersen are different from Shamir when splitting the secret.
22//! Combining shares back into the original secret is identical across all methods
23//! and is available for each scheme for convenience.
24//!
25//! This crate is no-standard compliant and uses const generics to specify sizes.
26//!
27//! This crate supports any number as the maximum number of shares to be requested.
28//! Anything higher than 255 is pretty ridiculous but if such a use case exists please let me know.
29//! This said, any number of shares can be requested since identifiers can be any size.
30//!
31//! Shares are represented as [`ShareElement`]s. Shares can be represented by
32//! really but is most commonly finite fields or groups
33//! depending on the use case. In the simplest case,
34//! the share identifier is the x-coordinate
35//! and the actual value of the share the y-coordinate.
36//! However, anything can be used as the identifier as long as it implements the
37//! [`ShareIdentifier`] trait.
38//!
39//! Feldman and Pedersen use the [`ShareVerifier`] trait to verify shares.
40//!
41//! In version 5, many of the required generics were removed and replaced with associated types.
42//! This simplifies the API and makes it easier to use and reduced the amount of necessary code.
43//!
44//! To split a p256 secret using Shamir
45//!
46//! ```
47//! #[cfg(any(feature = "alloc", feature = "std"))]
48//! {
49//! use vsss_rs::{*, shamir};
50//! use elliptic_curve::ff::PrimeField;
51//! use p256::{NonZeroScalar, Scalar, SecretKey};
52//!
53//! type P256Share = DefaultShare<IdentifierPrimeField<Scalar>, IdentifierPrimeField<Scalar>>;
54//!
55//! let mut osrng = rand_core::OsRng::default();
56//! let sk = SecretKey::random(&mut osrng);
57//! let nzs = sk.to_nonzero_scalar();
58//! let shared_secret = IdentifierPrimeField(*nzs.as_ref());
59//! let res = shamir::split_secret::<P256Share>(2, 3, &shared_secret, &mut osrng);
60//! assert!(res.is_ok());
61//! let shares = res.unwrap();
62//! let res = shares.combine();
63//! assert!(res.is_ok());
64//! let scalar = res.unwrap();
65//! let nzs_dup =  NonZeroScalar::from_repr(scalar.0.to_repr()).unwrap();
66//! let sk_dup = SecretKey::from(nzs_dup);
67//! assert_eq!(sk_dup.to_bytes(), sk.to_bytes());
68//! }
69//! ```
70//!
71//! To split a k256 secret using Shamir
72//!
73//! ```
74//! #[cfg(any(feature = "alloc", feature = "std"))]
75//! {
76//! use vsss_rs::{*, shamir};
77//! use elliptic_curve::ff::PrimeField;
78//! use k256::{NonZeroScalar, Scalar, ProjectivePoint, SecretKey};
79//!
80//! type K256Share = DefaultShare<IdentifierPrimeField<Scalar>, IdentifierPrimeField<Scalar>>;
81//!
82//! let mut osrng = rand_core::OsRng::default();
83//! let sk = SecretKey::random(&mut osrng);
84//! let secret = IdentifierPrimeField(*sk.to_nonzero_scalar());
85//! let res = shamir::split_secret::<K256Share>(2, 3, &secret, &mut osrng);
86//! assert!(res.is_ok());
87//! let shares = res.unwrap();
88//! let res = shares.combine();
89//! assert!(res.is_ok());
90//! let scalar = res.unwrap();
91//! let nzs_dup = NonZeroScalar::from_repr(scalar.0.to_repr()).unwrap();
92//! let sk_dup = SecretKey::from(nzs_dup);
93//! assert_eq!(sk_dup.to_bytes(), sk.to_bytes());
94//! }
95//! ```
96//!
97//! Feldman or Pedersen return extra information for verification using their respective verifiers
98//!
99//! ```
100//! #[cfg(any(feature = "alloc", feature = "std"))]
101//! {
102//! use vsss_rs::{*, feldman};
103//! use bls12_381_plus::{Scalar, G1Projective};
104//! use elliptic_curve::ff::Field;
105//!
106//! type BlsShare = DefaultShare<IdentifierPrimeField<Scalar>, IdentifierPrimeField<Scalar>>;
107//! type BlsShareVerifier = ShareVerifierGroup<G1Projective>;
108//!
109//! let mut rng = rand_core::OsRng::default();
110//! let secret = IdentifierPrimeField(Scalar::random(&mut rng));
111//! let res = feldman::split_secret::<BlsShare, BlsShareVerifier>(2, 3, &secret, None, &mut rng);
112//! assert!(res.is_ok());
113//! let (shares, verifier) = res.unwrap();
114//! for s in &shares {
115//!     assert!(verifier.verify_share(s).is_ok());
116//! }
117//! let res = shares.combine();
118//! assert!(res.is_ok());
119//! let secret_1 = res.unwrap();
120//! assert_eq!(secret, secret_1);
121//! }
122//! ```
123//!
124//! Curve25519 is not a prime field but this crate does support it using
125//! `features=["curve25519"]` which is enabled by default. This feature
126//! wraps curve25519-dalek libraries so they can be used with Shamir, Feldman, and Pedersen.
127//!
128//! Here's an example of using Ed25519 and x25519
129//!
130//! ```
131//! #[cfg(all(feature = "curve25519", any(feature = "alloc", feature = "std")))] {
132//! use curve25519_dalek::scalar::Scalar;
133//! use rand::Rng;
134//! use ed25519_dalek::SigningKey;
135//! use vsss_rs::{curve25519::WrappedScalar, *};
136//! use x25519_dalek::StaticSecret;
137//!
138//! type Ed25519Share = DefaultShare<IdentifierPrimeField<WrappedScalar>, IdentifierPrimeField<WrappedScalar>>;
139//!
140//! let mut osrng = rand::rngs::OsRng::default();
141//! let sc = Scalar::hash_from_bytes::<sha2::Sha512>(&osrng.gen::<[u8; 32]>());
142//! let sk1 = StaticSecret::from(sc.to_bytes());
143//! let ske1 = SigningKey::from_bytes(&sc.to_bytes());
144//! let secret = IdentifierPrimeField(WrappedScalar(sc));
145//! let res = shamir::split_secret::<Ed25519Share>(2, 3, &secret, &mut osrng);
146//! assert!(res.is_ok());
147//! let shares = res.unwrap();
148//! let res = shares.combine();
149//! assert!(res.is_ok());
150//! let scalar = res.unwrap();
151//! assert_eq!(scalar.0.0, sc);
152//! let sk2 = StaticSecret::from(scalar.0.0.to_bytes());
153//! let ske2 = SigningKey::from_bytes(&scalar.0.0.to_bytes());
154//! assert_eq!(sk2.to_bytes(), sk1.to_bytes());
155//! assert_eq!(ske1.to_bytes(), ske2.to_bytes());
156//! }
157//! ```
158#![deny(
159    missing_docs,
160    unused_import_braces,
161    unused_qualifications,
162    unused_parens,
163    unused_lifetimes,
164    unconditional_recursion,
165    unused_extern_crates,
166    trivial_casts,
167    trivial_numeric_casts
168)]
169#![no_std]
170#![cfg_attr(docsrs, feature(doc_cfg))]
171
172#[cfg(all(feature = "alloc", not(feature = "std")))]
173#[cfg_attr(all(feature = "alloc", not(feature = "std")), macro_use)]
174extern crate alloc;
175
176#[cfg(feature = "std")]
177#[cfg_attr(feature = "std", macro_use)]
178extern crate std;
179
180#[cfg(all(feature = "alloc", not(feature = "std")))]
181use alloc::{boxed::Box, vec::Vec};
182use core::fmt::Debug;
183#[cfg(feature = "std")]
184use std::{boxed::Box, vec::Vec};
185
186/// Macros for creating VSSS implementations
187#[macro_use]
188pub mod macros;
189#[cfg(test)]
190pub(crate) mod tests;
191
192mod element;
193mod error;
194pub mod feldman;
195mod fixed_array;
196#[allow(clippy::suspicious_arithmetic_impl)]
197#[allow(clippy::suspicious_op_assign_impl)]
198mod gf256;
199mod numbering;
200pub mod pedersen;
201mod polynomial;
202#[cfg(feature = "primitive")]
203mod primitive;
204#[cfg(feature = "bigint")]
205mod saturating;
206mod set;
207pub mod shamir;
208mod share;
209mod util;
210
211use shamir::check_params;
212use subtle::*;
213
214pub use element::*;
215pub use error::*;
216pub use feldman::Feldman;
217pub use fixed_array::*;
218pub use gf256::*;
219pub use numbering::*;
220pub use pedersen::{Pedersen, PedersenResult};
221pub use polynomial::*;
222#[cfg(feature = "primitive")]
223pub use primitive::*;
224#[cfg(feature = "bigint")]
225pub use saturating::*;
226pub use set::*;
227pub use shamir::Shamir;
228pub use share::*;
229pub use util::*;
230
231#[cfg(any(feature = "alloc", feature = "std"))]
232pub use pedersen::StdPedersenResult;
233
234#[cfg(feature = "curve25519")]
235#[cfg_attr(docsrs, doc(cfg(feature = "curve25519")))]
236pub mod curve25519;
237
238//
239#[cfg(feature = "curve25519")]
240pub use curve25519_dalek;
241pub use elliptic_curve;
242use elliptic_curve::group::GroupEncoding;
243use elliptic_curve::Group;
244
245pub use subtle;
246
247pub(crate) const USIZE_BYTES: usize = size_of::<usize>();
248pub(crate) const ISIZE_BYTES: usize = size_of::<isize>();
249
250#[cfg(any(feature = "alloc", feature = "std"))]
251/// Standard verifiable secret sharing scheme
252pub struct StdVsss<S, V>
253where
254    S: Share,
255    V: ShareVerifier<S>,
256{
257    _marker: (core::marker::PhantomData<V>, core::marker::PhantomData<S>),
258}
259
260#[cfg(any(feature = "alloc", feature = "std"))]
261impl<S, V> Shamir<S> for StdVsss<S, V>
262where
263    S: Share,
264    V: ShareVerifier<S>,
265{
266    type InnerPolynomial = Vec<S>;
267    type ShareSet = Vec<S>;
268}
269
270#[cfg(any(feature = "alloc", feature = "std"))]
271impl<S, V> Feldman<S, V> for StdVsss<S, V>
272where
273    S: Share,
274    V: ShareVerifier<S>,
275{
276    type VerifierSet = Vec<V>;
277}
278
279#[cfg(any(feature = "alloc", feature = "std"))]
280impl<S, V> Pedersen<S, V> for StdVsss<S, V>
281where
282    S: Share,
283    V: ShareVerifier<S>,
284{
285    type FeldmanVerifierSet = Vec<V>;
286    type PedersenVerifierSet = Vec<V>;
287    type PedersenResult = StdPedersenResult<S, V>;
288}