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
use crate::{secret_key_share::SECRET_KEY_SHARE_BYTES, SecretKeyShare};
use bls12_381_plus::Scalar;
use core::mem::MaybeUninit;
use hkdf::HkdfExtract;
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use subtle::CtOption;
use vsss_rs::{Error, Shamir, Share};
use zeroize::Zeroize;
#[derive(Clone, Debug, Eq, PartialEq, Zeroize)]
#[zeroize(drop)]
pub struct SecretKey(pub Scalar);
impl Default for SecretKey {
fn default() -> Self {
Self(Scalar::zero())
}
}
impl From<SecretKey> for [u8; SecretKey::BYTES] {
fn from(sk: SecretKey) -> [u8; SecretKey::BYTES] {
sk.to_bytes()
}
}
impl<'a> From<&'a SecretKey> for [u8; SecretKey::BYTES] {
fn from(sk: &'a SecretKey) -> [u8; SecretKey::BYTES] {
sk.to_bytes()
}
}
impl Serialize for SecretKey {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(s)
}
}
impl<'de> Deserialize<'de> for SecretKey {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let scalar = Scalar::deserialize(d)?;
Ok(Self(scalar))
}
}
impl SecretKey {
pub const BYTES: usize = 32;
pub fn hash<B: AsRef<[u8]>>(data: B) -> Option<Self> {
generate_secret_key(data.as_ref())
}
pub fn random(mut rng: impl RngCore + CryptoRng) -> Option<Self> {
let mut data = [0u8; Self::BYTES];
rng.fill_bytes(&mut data);
generate_secret_key(&data)
}
pub fn to_bytes(&self) -> [u8; Self::BYTES] {
let mut bytes = self.0.to_bytes();
bytes.reverse();
bytes
}
pub fn from_bytes(bytes: &[u8; Self::BYTES]) -> CtOption<Self> {
let mut t = [0u8; Self::BYTES];
t.copy_from_slice(bytes);
t.reverse();
Scalar::from_bytes(&t).map(SecretKey)
}
pub fn split<R: RngCore + CryptoRng, const T: usize, const N: usize>(
&self,
rng: &mut R,
) -> Result<[SecretKeyShare; N], Error> {
let shares =
Shamir::<T, N>::split_secret::<Scalar, R, SECRET_KEY_SHARE_BYTES>(self.0, rng)?;
let mut secrets: MaybeUninit<[SecretKeyShare; N]> = MaybeUninit::uninit();
for (i, s) in shares.iter().enumerate() {
let p = (secrets.as_mut_ptr() as *mut SecretKeyShare).wrapping_add(i);
unsafe { core::ptr::write(p, SecretKeyShare(*s)) };
}
Ok(unsafe { secrets.assume_init() })
}
pub fn combine<const T: usize, const N: usize>(
shares: &[SecretKeyShare],
) -> Result<SecretKey, Error> {
if T > shares.len() {
return Err(Error::SharingLimitLessThanThreshold);
}
let mut ss = [Share::<SECRET_KEY_SHARE_BYTES>::default(); T];
for i in 0..T {
ss[i] = shares[i].0;
}
let scalar = Shamir::<T, N>::combine_shares::<Scalar, SECRET_KEY_SHARE_BYTES>(&ss)?;
Ok(SecretKey(scalar))
}
}
fn generate_secret_key(ikm: &[u8]) -> Option<SecretKey> {
const SALT: &[u8] = b"BLS-SIG-KEYGEN-SALT-";
const INFO: [u8; 2] = [0u8, 48u8];
let mut extracter = HkdfExtract::<sha2::Sha256>::new(Some(SALT));
extracter.input_ikm(ikm);
extracter.input_ikm(&[0u8]);
let (_, h) = extracter.finalize();
let mut output = [0u8; 48];
if h.expand(&INFO, &mut output).is_err() {
None
} else {
Some(SecretKey(Scalar::from_okm(&output)))
}
}