mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Add dealer key generation crate
This commit is contained in:
36
crypto/dkg/dealer/Cargo.toml
Normal file
36
crypto/dkg/dealer/Cargo.toml
Normal file
@@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "dkg-dealer"
|
||||
version = "0.6.0"
|
||||
description = "Produce dkg::ThresholdKeys with a dealer key generation"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/dealer"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["dkg", "multisig", "threshold", "ff", "group"]
|
||||
edition = "2021"
|
||||
rust-version = "1.80"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
zeroize = { version = "^1.5", default-features = false }
|
||||
rand_core = { version = "0.6", default-features = false }
|
||||
|
||||
std-shims = { version = "0.1", path = "../../../common/std-shims", default-features = false }
|
||||
|
||||
ciphersuite = { path = "../../ciphersuite", version = "^0.4.1", default-features = false }
|
||||
dkg = { path = "../", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"zeroize/std",
|
||||
"rand_core/std",
|
||||
"std-shims/std",
|
||||
"ciphersuite/std",
|
||||
"dkg/std",
|
||||
]
|
||||
default = ["std"]
|
||||
21
crypto/dkg/dealer/LICENSE
Normal file
21
crypto/dkg/dealer/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2025 Luke Parker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
13
crypto/dkg/dealer/README.md
Normal file
13
crypto/dkg/dealer/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Distributed Key Generation - Dealer
|
||||
|
||||
This crate implements a dealer key generation protocol for the
|
||||
[`dkg`](https://docs.rs/dkg) crate's types. This provides a single point of
|
||||
failure when the key is being generated and is NOT recommended for use outside
|
||||
of tests.
|
||||
|
||||
This crate was originally part of (in some form) the `dkg` crate, which was
|
||||
[audited by Cypher Stack in March 2023](
|
||||
https://github.com/serai-dex/serai/raw/e1bb2c191b7123fd260d008e31656d090d559d21/audits/Cypher%20Stack%20crypto%20March%202023/Audit.pdf
|
||||
), culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](
|
||||
https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06
|
||||
). Any subsequent changes have not undergone auditing.
|
||||
68
crypto/dkg/dealer/src/lib.rs
Normal file
68
crypto/dkg/dealer/src/lib.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![no_std]
|
||||
|
||||
use core::ops::Deref;
|
||||
use std_shims::{vec::Vec, collections::HashMap};
|
||||
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use ciphersuite::{
|
||||
group::ff::{Field, PrimeField},
|
||||
Ciphersuite,
|
||||
};
|
||||
pub use dkg::*;
|
||||
|
||||
/// Create a key via a dealer key generation protocol.
|
||||
pub fn key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
|
||||
rng: &mut R,
|
||||
threshold: u16,
|
||||
participants: u16,
|
||||
) -> Result<HashMap<Participant, ThresholdKeys<C>>, DkgError> {
|
||||
let mut coefficients = Vec::with_capacity(usize::from(participants));
|
||||
// `.max(1)` so we always generate the 0th coefficient which we'll share
|
||||
for _ in 0 .. threshold.max(1) {
|
||||
coefficients.push(Zeroizing::new(C::F::random(&mut *rng)));
|
||||
}
|
||||
|
||||
fn polynomial<F: PrimeField + Zeroize>(
|
||||
coefficients: &[Zeroizing<F>],
|
||||
l: Participant,
|
||||
) -> Zeroizing<F> {
|
||||
let l = F::from(u64::from(u16::from(l)));
|
||||
// This should never be reached since Participant is explicitly non-zero
|
||||
assert!(l != F::ZERO, "zero participant passed to polynomial");
|
||||
let mut share = Zeroizing::new(F::ZERO);
|
||||
for (idx, coefficient) in coefficients.iter().rev().enumerate() {
|
||||
*share += coefficient.deref();
|
||||
if idx != (coefficients.len() - 1) {
|
||||
*share *= l;
|
||||
}
|
||||
}
|
||||
share
|
||||
}
|
||||
|
||||
let group_key = C::generator() * coefficients[0].deref();
|
||||
let mut secret_shares = HashMap::with_capacity(participants as usize);
|
||||
let mut verification_shares = HashMap::with_capacity(participants as usize);
|
||||
for i in 1 ..= participants {
|
||||
let i = Participant::new(i).expect("non-zero u16 wasn't a valid Participant index");
|
||||
let secret_share = polynomial(&coefficients, i);
|
||||
secret_shares.insert(i, secret_share.clone());
|
||||
verification_shares.insert(i, C::generator() * *secret_share);
|
||||
}
|
||||
|
||||
let mut res = HashMap::with_capacity(participants as usize);
|
||||
for (i, secret_share) in secret_shares {
|
||||
let keys = ThresholdKeys::new(
|
||||
ThresholdParams::new(threshold, participants, i)?,
|
||||
Interpolation::Lagrange,
|
||||
secret_share,
|
||||
verification_shares.clone(),
|
||||
)?;
|
||||
debug_assert_eq!(keys.group_key(), group_key);
|
||||
res.insert(i, keys);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
@@ -21,7 +21,7 @@ zeroize = { version = "^1.5", default-features = false }
|
||||
|
||||
thiserror = { version = "2", default-features = false }
|
||||
|
||||
ciphersuite = { path = "../../ciphersuite", version = "^0.4.1", default-features = false, features = ["alloc"] }
|
||||
ciphersuite = { path = "../../ciphersuite", version = "^0.4.1", default-features = false }
|
||||
dkg = { path = "../", default-features = false }
|
||||
|
||||
[features]
|
||||
|
||||
Reference in New Issue
Block a user