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
pub use crypto_box::aead::Error;
use crypto_box::aead::{generic_array::GenericArray, Aead};
pub use crypto_box::{Box, PublicKey, SecretKey};
pub use dark_crystal_secret_sharing_rust::{combine_authenticated, share_authenticated};
use rand::Rng;
use std::convert::TryInto;
use zeroize::Zeroize;
#[derive(Debug)]
pub struct EncryptedShareSet {
pub ciphertext: Vec<u8>,
pub encrypted_shares: Vec<Vec<u8>>,
pub eph_public_key: PublicKey,
}
pub fn share_and_encrypt(
public_keys: Vec<[u8; 32]>,
secret: Vec<u8>,
threshold: u8,
) -> Result<EncryptedShareSet, Error> {
let num_shares = public_keys.len().try_into().unwrap();
let (shares, ciphertext) = share_authenticated(&secret, num_shares, threshold);
let mut encrypted_shares: Vec<Vec<u8>> = Vec::new();
let mut rng = crypto_box::rand_core::OsRng;
let eph_secret_key = SecretKey::generate(&mut rng);
let eph_public_key = eph_secret_key.public_key();
let mut eph_secret_key_bytes = eph_secret_key.as_bytes().clone();
for share_index in 0..public_keys.len() {
let share = &shares[share_index];
let pk = PublicKey::from(public_keys[share_index]);
let esk = SecretKey::from(eph_secret_key_bytes);
encrypted_shares.push(encrypt(esk, pk, share.to_vec())?);
}
eph_secret_key_bytes.zeroize();
Ok(EncryptedShareSet {
encrypted_shares,
ciphertext,
eph_public_key,
})
}
pub fn encrypt(
secret_key: SecretKey,
public_key: PublicKey,
plaintext: Vec<u8>,
) -> Result<Vec<u8>, Error> {
let alice_box = Box::new(&public_key, &secret_key);
let mut rng = crypto_box::rand_core::OsRng;
let nonce_bytes = rng.gen::<[u8; 24]>();
let nonce = GenericArray::from_slice(&nonce_bytes);
let mut ciphertext_with_nonce = nonce_bytes.to_vec();
let ciphertext = alice_box.encrypt(&nonce, &plaintext[..])?;
ciphertext_with_nonce.extend(ciphertext);
Ok(ciphertext_with_nonce)
}
pub fn decrypt(
secret_key: SecretKey,
public_key: &PublicKey,
ciphertext_with_nonce: &Vec<u8>,
) -> Result<Vec<u8>, Error> {
let ciphertext = &ciphertext_with_nonce[24..];
let nonce = GenericArray::from_slice(&ciphertext_with_nonce[..24]);
let bob_box = Box::new(public_key, &secret_key);
bob_box.decrypt(&nonce, &ciphertext[..])
}
#[cfg(test)]
mod tests {
use super::*;
use dark_crystal_secret_sharing_rust::combine_authenticated;
#[test]
fn encryption() {
let mut rng = crypto_box::rand_core::OsRng;
let alice_secret_key = SecretKey::generate(&mut rng);
let alice_public_key = alice_secret_key.public_key();
let bob_secret_key = SecretKey::generate(&mut rng);
let bob_public_key = bob_secret_key.public_key();
let plaintext = b"hello";
let ciphertext = encrypt(alice_secret_key, bob_public_key, plaintext.to_vec()).unwrap();
let decrypted_plaintext = decrypt(bob_secret_key, &alice_public_key, &ciphertext).unwrap();
assert_eq!(&plaintext[..], &decrypted_plaintext[..]);
}
#[test]
fn test_share_and_encrypt() {
let mut rng = crypto_box::rand_core::OsRng;
let alice_secret_key = SecretKey::generate(&mut rng);
let alice_public_key = alice_secret_key.public_key();
let bob_secret_key = SecretKey::generate(&mut rng);
let bob_public_key = bob_secret_key.public_key();
let mut public_keys: Vec<[u8; 32]> = Vec::new();
public_keys.push(*bob_public_key.as_bytes());
public_keys.push(*alice_public_key.as_bytes());
let original_secret = b"hello";
let encrypted_share_set =
share_and_encrypt(public_keys, original_secret[..].to_vec(), 2).unwrap();
assert_eq!(encrypted_share_set.encrypted_shares.len(), 2);
let mut decrypted_shares: Vec<Vec<u8>> = Vec::new();
decrypted_shares.push(
decrypt(
alice_secret_key,
&encrypted_share_set.eph_public_key,
&encrypted_share_set.encrypted_shares[1],
)
.unwrap(),
);
decrypted_shares.push(
decrypt(
bob_secret_key,
&encrypted_share_set.eph_public_key,
&encrypted_share_set.encrypted_shares[0],
)
.unwrap(),
);
let recovered_secret =
combine_authenticated(decrypted_shares, encrypted_share_set.ciphertext).unwrap();
assert_eq!(recovered_secret, b"hello");
}
}