Skip to content

Commit 1a3e331

Browse files
committed
Make features requiring std optional
This commit changes some of the functionality of this crate to not use `std` or `alloc`. It also adds the following optional features to this crate: - `std` - `signing` - `dkg` All the features except `dkg` are enabled by default and may be disabled with `default-features = false` in `Cargo.toml`. The main goal of this commit is to allow `no_std` creates to consume a subset of this crate.
1 parent d2b082e commit 1a3e331

File tree

11 files changed

+701
-382
lines changed

11 files changed

+701
-382
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ jobs:
2020
save-if: false
2121
shared-key: base
2222

23-
- name: Install Cargo tools
23+
- name: Install rustfmt and clippy
2424
run: |
2525
rustup component add rustfmt clippy
2626
2727
- name: Check for license headers
2828
run: ./ci/lintHeaders.sh
2929

30-
- name: "`cargo fmt` check"
30+
- name: cargo fmt
3131
run: |
3232
cargo fmt --all -- --check
3333
34-
- name: "Clippy check on"
34+
- name: cargo clippy
3535
run: |
3636
cargo clippy --all-targets -- -D warnings
3737
@@ -47,10 +47,14 @@ jobs:
4747
save-if: false
4848
shared-key: base
4949

50+
- name: Install cargo-all-features
51+
run: |
52+
cargo install --locked cargo-all-features
53+
5054
- name: Run tests (debug mode)
5155
run: |
52-
cargo test
56+
cargo test-all-features
5357
5458
- name: Run tests (release mode)
5559
run: |
56-
cargo test --release
60+
cargo test-all-features --release

Cargo.toml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ homepage = "https://ironfish.network/"
99
repository = "https://github.com/iron-fish/ironfish-frost"
1010

1111
[dependencies]
12-
blake3 = "1.5.0"
12+
blake3 = { version = "1.5.0", optional = true }
1313
chacha20 = "0.9.1"
14-
chacha20poly1305 = { version = "0.10.1", features = ["std"] }
14+
chacha20poly1305 = "0.10.1"
1515
ed25519-dalek = { version = "2.1.0", features = ["rand_core"] }
16-
rand_chacha = "0.3.1"
16+
rand_chacha = { version = "0.3.1", optional = true }
1717
rand_core = "0.6.4"
1818
reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "311baf8865f6e21527d1f20750d8f2cf5c9e531a", features = ["frost", "frost-rerandomized"] }
19-
siphasher = "1.0.0"
19+
siphasher = { version = "1.0.0", optional = true }
2020
x25519-dalek = { version = "2.0.0", features = ["reusable_secrets", "static_secrets"] }
2121

2222
[dev-dependencies]
2323
hex-literal = "0.4.1"
2424
rand = "0.8.5"
25+
26+
[features]
27+
default = ["std", "signing"]
28+
29+
std = []
30+
signing = ["dep:blake3", "dep:rand_chacha", "dep:siphasher", "std"]
31+
dkg = ["std", "signing"]

src/dkg/group_key.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

55
use crate::multienc;
6-
use crate::multienc::MultiRecipientBlob;
76
use crate::participant::Identity;
87
use crate::participant::Secret;
98
use rand_core::CryptoRng;
@@ -70,16 +69,16 @@ impl GroupSecretKeyShard {
7069
Ok(Self { shard })
7170
}
7271

73-
pub fn export<'a, I, R>(&self, recipients: I, csrng: R) -> io::Result<Vec<u8>>
72+
pub fn export<'a, I, R>(&self, recipients: I, csrng: R) -> Vec<u8>
7473
where
7574
I: IntoIterator<Item = &'a Identity>,
75+
I::IntoIter: ExactSizeIterator,
7676
R: RngCore + CryptoRng,
7777
{
78-
multienc::encrypt(&self.shard, recipients, csrng).serialize()
78+
multienc::encrypt(&self.shard, recipients, csrng)
7979
}
8080

8181
pub fn import(secret: &Secret, exported: &[u8]) -> io::Result<Self> {
82-
let exported = MultiRecipientBlob::deserialize_from(exported)?;
8382
let bytes = multienc::decrypt(secret, &exported).map_err(io::Error::other)?;
8483

8584
if bytes.len() != GROUP_SECRET_KEY_LEN {
@@ -184,9 +183,7 @@ mod tests {
184183
let shard = GroupSecretKeyShard::random(thread_rng());
185184

186185
// Encrypt the shard with all the identities at once
187-
let exported = shard
188-
.export(&identities, thread_rng())
189-
.expect("export failed");
186+
let exported = shard.export(&identities, thread_rng());
190187

191188
// Ensure that the exported blob does not contain the shard in cleartext
192189
let shard_cleartext = shard.serialize();

src/dkg/round1.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::checksum::ChecksumHasher;
77
use crate::checksum::CHECKSUM_LEN;
88
use crate::dkg::error::Error;
99
use crate::dkg::group_key::GroupSecretKeyShard;
10-
use crate::dkg::group_key::GroupSecretKeyShardSerialization;
1110
use crate::frost;
1211
use crate::frost::keys::dkg::round1::Package;
1312
use crate::frost::keys::dkg::round1::SecretPackage;
@@ -16,7 +15,7 @@ use crate::frost::Field;
1615
use crate::frost::Identifier;
1716
use crate::frost::JubjubScalarField;
1817
use crate::multienc;
19-
use crate::multienc::MultiRecipientBlob;
18+
use crate::multienc::read_encrypted_blob;
2019
use crate::participant;
2120
use crate::participant::Identity;
2221
use crate::serde::read_u16;
@@ -143,16 +142,18 @@ pub fn export_secret_package<R: RngCore + CryptoRng>(
143142
if serializable.identifier != identity.to_frost_identifier() {
144143
return Err(io::Error::other("identity mismatch"));
145144
}
145+
146146
let mut serialized = Vec::new();
147-
serializable.serialize_into(&mut serialized)?;
148-
multienc::encrypt(&serialized, [identity], csrng).serialize()
147+
serializable
148+
.serialize_into(&mut serialized)
149+
.expect("serialization failed");
150+
Ok(multienc::encrypt(&serialized, [identity], csrng))
149151
}
150152

151153
pub fn import_secret_package(
152154
exported: &[u8],
153155
secret: &participant::Secret,
154156
) -> io::Result<SecretPackage> {
155-
let exported = MultiRecipientBlob::deserialize_from(exported)?;
156157
let serialized = multienc::decrypt(secret, &exported).map_err(io::Error::other)?;
157158
SerializableSecretPackage::deserialize_from(&serialized[..]).map(|pkg| pkg.into())
158159
}
@@ -182,8 +183,7 @@ where
182183
pub struct PublicPackage {
183184
identity: Identity,
184185
frost_package: Package,
185-
group_secret_key_shard_encrypted:
186-
MultiRecipientBlob<Vec<GroupSecretKeyShardSerialization>, Vec<u8>>,
186+
group_secret_key_shard_encrypted: Vec<u8>,
187187
checksum: Checksum,
188188
}
189189

@@ -224,9 +224,7 @@ impl PublicPackage {
224224
&self.frost_package
225225
}
226226

227-
pub fn group_secret_key_shard_encrypted(
228-
&self,
229-
) -> &MultiRecipientBlob<Vec<GroupSecretKeyShardSerialization>, Vec<u8>> {
227+
pub fn group_secret_key_shard_encrypted(&self) -> &[u8] {
230228
&self.group_secret_key_shard_encrypted
231229
}
232230

@@ -253,8 +251,7 @@ impl PublicPackage {
253251
self.identity.serialize_into(&mut writer)?;
254252
let frost_package = self.frost_package.serialize().map_err(io::Error::other)?;
255253
write_variable_length_bytes(&mut writer, &frost_package)?;
256-
self.group_secret_key_shard_encrypted
257-
.serialize_into(&mut writer)?;
254+
writer.write_all(&self.group_secret_key_shard_encrypted[..])?;
258255
writer.write_all(&self.checksum.to_le_bytes())?;
259256
Ok(())
260257
}
@@ -265,7 +262,7 @@ impl PublicPackage {
265262
let frost_package = read_variable_length_bytes(&mut reader)?;
266263
let frost_package = Package::deserialize(&frost_package).map_err(io::Error::other)?;
267264

268-
let group_secret_key_shard_encrypted = MultiRecipientBlob::deserialize_from(&mut reader)?;
265+
let group_secret_key_shard_encrypted = read_encrypted_blob(&mut reader)?;
269266

270267
let mut checksum = [0u8; CHECKSUM_LEN];
271268
reader.read_exact(&mut checksum)?;

src/dkg/round2.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::frost::Field;
1717
use crate::frost::Identifier;
1818
use crate::frost::JubjubScalarField;
1919
use crate::multienc;
20-
use crate::multienc::MultiRecipientBlob;
2120
use crate::participant;
2221
use crate::participant::Identity;
2322
use crate::serde::read_u16;
@@ -142,16 +141,18 @@ pub fn export_secret_package<R: RngCore + CryptoRng>(
142141
if serializable.identifier != identity.to_frost_identifier() {
143142
return Err(io::Error::other("identity mismatch"));
144143
}
144+
145145
let mut serialized = Vec::new();
146-
serializable.serialize_into(&mut serialized)?;
147-
multienc::encrypt(&serialized, [identity], csrng).serialize()
146+
serializable
147+
.serialize_into(&mut serialized)
148+
.expect("serialization failed");
149+
Ok(multienc::encrypt(&serialized, [identity], csrng))
148150
}
149151

150152
pub fn import_secret_package(
151153
exported: &[u8],
152154
secret: &participant::Secret,
153155
) -> io::Result<SecretPackage> {
154-
let exported = MultiRecipientBlob::deserialize_from(exported)?;
155156
let serialized = multienc::decrypt(secret, &exported).map_err(io::Error::other)?;
156157
SerializableSecretPackage::deserialize_from(&serialized[..]).map(|pkg| pkg.into())
157158
}

src/dkg/round3.rs

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,99 @@ use crate::dkg::round2;
1111
use crate::dkg::round2::import_secret_package;
1212
use crate::frost::keys::dkg::part3;
1313
use crate::frost::keys::KeyPackage;
14-
use crate::keys::PublicKeyPackage;
14+
use crate::frost::keys::PublicKeyPackage as FrostPublicKeyPackage;
15+
use crate::participant::Identity;
1516
use crate::participant::Secret;
17+
use crate::serde::read_u16;
18+
use crate::serde::read_variable_length;
19+
use crate::serde::read_variable_length_bytes;
20+
use crate::serde::write_u16;
21+
use crate::serde::write_variable_length;
22+
use crate::serde::write_variable_length_bytes;
23+
use reddsa::frost::redjubjub::VerifyingKey;
1624
use std::borrow::Borrow;
1725
use std::collections::BTreeMap;
26+
use std::io;
27+
28+
#[derive(Clone, Eq, PartialEq, Debug)]
29+
pub struct PublicKeyPackage {
30+
frost_public_key_package: FrostPublicKeyPackage,
31+
identities: Vec<Identity>,
32+
min_signers: u16,
33+
}
34+
35+
impl PublicKeyPackage {
36+
#[must_use]
37+
pub fn from_frost<I>(
38+
frost_public_key_package: FrostPublicKeyPackage,
39+
identities: I,
40+
min_signers: u16,
41+
) -> Self
42+
where
43+
I: IntoIterator<Item = Identity>,
44+
{
45+
Self {
46+
frost_public_key_package,
47+
identities: identities.into_iter().collect(),
48+
min_signers,
49+
}
50+
}
51+
52+
pub fn identities(&self) -> &[Identity] {
53+
&self.identities[..]
54+
}
55+
56+
pub fn verifying_key(&self) -> &VerifyingKey {
57+
self.frost_public_key_package.verifying_key()
58+
}
59+
60+
pub fn frost_public_key_package(&self) -> &FrostPublicKeyPackage {
61+
&self.frost_public_key_package
62+
}
63+
64+
pub fn min_signers(&self) -> u16 {
65+
self.min_signers
66+
}
67+
68+
pub fn serialize(&self) -> Vec<u8> {
69+
let mut bytes = Vec::new();
70+
self.serialize_into(&mut bytes)
71+
.expect("serialization failed");
72+
bytes
73+
}
74+
75+
#[cfg(feature = "std")]
76+
pub fn serialize_into<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
77+
let frost_public_key_package = self
78+
.frost_public_key_package
79+
.serialize()
80+
.map_err(io::Error::other)?;
81+
write_variable_length_bytes(&mut writer, &frost_public_key_package)?;
82+
write_variable_length(&mut writer, &self.identities, |writer, identity| {
83+
identity.serialize_into(writer)
84+
})?;
85+
write_u16(&mut writer, self.min_signers)?;
86+
87+
Ok(())
88+
}
89+
90+
#[cfg(feature = "std")]
91+
pub fn deserialize_from<R: io::Read>(mut reader: R) -> io::Result<Self> {
92+
let frost_public_key_package = read_variable_length_bytes(&mut reader)?;
93+
let frost_public_key_package =
94+
FrostPublicKeyPackage::deserialize(&frost_public_key_package)
95+
.map_err(io::Error::other)?;
96+
let identities =
97+
read_variable_length(&mut reader, |reader| Identity::deserialize_from(reader))?;
98+
let min_signers = read_u16(&mut reader)?;
99+
100+
Ok(PublicKeyPackage {
101+
frost_public_key_package,
102+
identities,
103+
min_signers,
104+
})
105+
}
106+
}
18107

19108
pub fn round3<'a, P, Q>(
20109
secret: &Secret,
@@ -153,10 +242,71 @@ where
153242

154243
#[cfg(test)]
155244
mod tests {
156-
use super::*;
245+
use super::round3;
246+
use super::PublicKeyPackage;
247+
use crate::dkg::error::Error;
157248
use crate::dkg::round1;
249+
use crate::dkg::round2;
158250
use crate::participant::Secret;
251+
use hex_literal::hex;
159252
use rand::thread_rng;
253+
use reddsa::frost::redjubjub::keys::split;
254+
use reddsa::frost::redjubjub::SigningKey;
255+
use reddsa::frost::redpallas::frost::keys::IdentifierList;
256+
257+
#[test]
258+
fn public_pkg_serialization_roundtrip() {
259+
let secret1 = Secret::random(thread_rng());
260+
let secret2 = Secret::random(thread_rng());
261+
let id1 = secret1.to_identity();
262+
let id2 = secret2.to_identity();
263+
264+
let mut rng = thread_rng();
265+
let signing_key = SigningKey::new(&mut rng);
266+
267+
let (_, frost_public_key_package) = split(
268+
&signing_key,
269+
2,
270+
2,
271+
IdentifierList::Custom(&[id1.to_frost_identifier(), id2.to_frost_identifier()]),
272+
&mut rng,
273+
)
274+
.expect("signing key split failed");
275+
276+
let public_key_package =
277+
PublicKeyPackage::from_frost(frost_public_key_package, [id1, id2], 2);
278+
279+
let serialized = public_key_package.serialize();
280+
281+
let deserialized = PublicKeyPackage::deserialize_from(&serialized[..])
282+
.expect("public key package deserialization failed");
283+
284+
assert_eq!(public_key_package, deserialized)
285+
}
286+
287+
#[test]
288+
fn public_pkg_deserialization_regression() {
289+
let serialization = hex!(
290+
"
291+
a600000000c3d2051e02b62709a88950f3a75eb0d03a9510123a72947eb083b5822
292+
e874793e8f40f6b0ba381109571a24f9f87421f0393f45cee913ef891bd75eb7ba7
293+
a5611858a80305cf631451a7d94604cb32d11285ebd4b6ee797eceaa464b2dfcd09
294+
7295cacf90c579265130e9e37225a23dfd51da2c4b8db499cb0e7aa6b03a15cde2d
295+
b678e99c94974b2a766f83b134c5c782803f5f5a65bc4a6392f6a81062ad8292e84
296+
4f3c00200000072cf6be086f2453ec7ce6f7b76fbb35c4dcf6fac1737dbcc2a2467
297+
b3f0c8453574ad36e9dd2b092aa0870930ed6be8d9ba40c146c5b2110fbb03f7e3b
298+
60e5d63347f47bd69c418630d0c4d3301f0a910c3d127c9d7064cedf26c0c2f0cea
299+
9486a8993eea77744ead60ea210bc43a4c56be4933762dddaba145fb215c5dbaebc
300+
a0272586e451ceb90d00fde8fa96f7eba99845066803aef4073ca39f3af9050b9f0
301+
bc63deb3652c1455090070a8dd3376128e093726a055bab2e2d2325cb5c978b62eb
302+
a97c6b42325cf4fc106321b7c8979fc123dc77a5da91ace3b3245405d680b9bcc13
303+
5828ac28415305d74abe2ca084639dd1ab7bb8c69930cf0a55a1151022020200
304+
"
305+
);
306+
let deserialized =
307+
PublicKeyPackage::deserialize_from(&serialization[..]).expect("deserialization failed");
308+
assert_eq!(&serialization[..], deserialized.serialize());
309+
}
160310

161311
#[test]
162312
fn test_round3_missing_round1_packages() {

0 commit comments

Comments
 (0)