Skip to content

Commit bd75503

Browse files
authored
Merge pull request #93 from dfns/fix-serde
Fix serde issue
2 parents 3a176e4 + b7bc11a commit bd75503

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+800
-14
lines changed

Cargo.lock

+61-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ members = [
66
"key-share",
77
"tests",
88
]
9-

key-share/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
# Changelog
22

33
## v0.2.1
4+
* Fix key share (de)serialization issue [#93]
45
* Add a notice about the serialization to key share docs [#91]
56

67
[#91]: https://github.com/dfns/cggmp21/pull/91
8+
[#93]: https://github.com/dfns/cggmp21/pull/93
79

810
## v0.2.0
11+
**YANKED**: this release is yanked because it had an issue with key share (de)serialization
12+
that was addressed in v0.2.1
13+
914
* Add support of HD wallets compatible with BIP-32 and SLIP-10 [#68],
1015
[#74], [#75]
1116
* Prohibit key shares with zero secret share or secret key [#82]
@@ -16,5 +21,7 @@
1621
[#82]: https://github.com/dfns/cggmp21/pull/82
1722

1823
## v0.1.0
24+
**YANKED**: this release is yanked because it had an issue with key share (de)serialization
25+
that was addressed in v0.2.1
1926

2027
Initial release

key-share/src/lib.rs

+68-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use core::ops;
2121
use generic_ec::{serde::CurveName, Curve, NonZero, Point, Scalar, SecretScalar};
2222
use generic_ec_zkp::polynomial::lagrange_coefficient;
2323

24+
#[cfg(feature = "serde")]
25+
mod serde_fix;
2426
#[cfg(feature = "spof")]
2527
pub mod trusted_dealer;
2628
mod utils;
@@ -107,19 +109,81 @@ use serde_with::As;
107109
/// If you need the smallest size of serialized key share, we advise implementing serialization manually (all fields of
108110
/// the key share are public!).
109111
#[derive(Clone)]
110-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
111-
#[cfg_attr(feature = "serde", serde(bound = ""))]
112112
pub struct DirtyCoreKeyShare<E: Curve> {
113113
/// Index of local party in key generation protocol
114114
pub i: u16,
115115
/// Public key info
116-
#[cfg_attr(feature = "serde", serde(flatten))]
117116
pub key_info: DirtyKeyInfo<E>,
118117
/// Secret share $x_i$
119-
#[cfg_attr(feature = "serde", serde(with = "As::<generic_ec::serde::Compact>"))]
120118
pub x: NonZero<SecretScalar<E>>,
121119
}
122120

121+
#[cfg(feature = "serde")]
122+
impl<E: Curve> serde::Serialize for DirtyCoreKeyShare<E> {
123+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
124+
where
125+
S: serde::Serializer,
126+
{
127+
// See [`crate::serde_fix`] module docs
128+
let Self {
129+
i,
130+
key_info:
131+
DirtyKeyInfo {
132+
curve,
133+
shared_public_key,
134+
public_shares,
135+
vss_setup,
136+
#[cfg(feature = "hd-wallets")]
137+
chain_code,
138+
},
139+
x,
140+
} = &self;
141+
serde_fix::ser::CoreKeyShare {
142+
i,
143+
curve,
144+
shared_public_key,
145+
public_shares,
146+
vss_setup,
147+
x,
148+
#[cfg(feature = "hd-wallets")]
149+
chain_code,
150+
}
151+
.serialize(serializer)
152+
}
153+
}
154+
155+
#[cfg(feature = "serde")]
156+
impl<'de, E: Curve> serde::Deserialize<'de> for DirtyCoreKeyShare<E> {
157+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
158+
where
159+
D: serde::Deserializer<'de>,
160+
{
161+
// See [`crate::serde_fix`] module docs
162+
let serde_fix::de::CoreKeyShare {
163+
curve,
164+
i,
165+
shared_public_key,
166+
public_shares,
167+
vss_setup,
168+
x,
169+
#[cfg(feature = "hd-wallets")]
170+
chain_code,
171+
} = serde::Deserialize::deserialize(deserializer)?;
172+
Ok(Self {
173+
i,
174+
key_info: DirtyKeyInfo {
175+
curve,
176+
shared_public_key,
177+
public_shares,
178+
vss_setup,
179+
#[cfg(feature = "hd-wallets")]
180+
chain_code,
181+
},
182+
x,
183+
})
184+
}
185+
}
186+
123187
/// Public Key Info
124188
///
125189
/// Contains public information about the TSS key, including shared public key, commitments to

key-share/src/serde_fix.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! Fixes serde serialization of the key share
2+
//!
3+
//! This module contains structs that help us implementing `serde::{Serialize, Deserialize}`
4+
//! for [`crate::DirtyCoreKeyShare`].
5+
//!
6+
//! Context: we used to have key share struct flatten, with all DirtyKeyInfo fields being
7+
//! right in the key share. However, at some point, we've decided to move all public common
8+
//! fields into a separate structure. In order to keep serialization format compatible,
9+
//! we used `#[serde(flatten)]` attribute, to make on-wire data appear like all the fields
10+
//! are still in the same struct. It turned out, that `#[serde(flatten)]` is buggy, and,
11+
//! specifically, it does not preserve `is_human_readable` flag, which broke (de)serialization
12+
//! code and compatibility with old key shares.
13+
//!
14+
//! See the issue for more details on the `serde` problem: <https://github.com/serde-rs/serde/issues/2704>
15+
//!
16+
//! Until the issue in `serde` crate is addressed, we have to use a workaround in this module.
17+
//! We basically reimplement `flatten` attribute manually at the cost of extra allocations.
18+
19+
use generic_ec::{serde::CurveName, Curve, NonZero, Point, SecretScalar};
20+
use serde_with::As;
21+
22+
macro_rules! core_key_share {
23+
($($(#[$attr:meta])*pub $field:ident: $ty:ty),+$(,)?) => {
24+
pub mod ser {
25+
use super::*;
26+
27+
#[derive(serde::Serialize)]
28+
#[serde(bound = "")]
29+
pub struct CoreKeyShare<'a, E: Curve> {$(
30+
$(#[$attr])*
31+
pub $field: &'a $ty,
32+
)+}
33+
}
34+
pub mod de {
35+
use super::*;
36+
37+
#[derive(serde::Deserialize)]
38+
#[serde(bound = "")]
39+
pub struct CoreKeyShare<E: Curve> {$(
40+
$(#[$attr])*
41+
pub $field: $ty,
42+
)+}
43+
}
44+
};
45+
}
46+
47+
core_key_share! {
48+
pub curve: CurveName<E>,
49+
pub i: u16,
50+
#[serde(with = "As::<generic_ec::serde::Compact>")]
51+
pub shared_public_key: NonZero<Point<E>>,
52+
#[serde(with = "As::<Vec<generic_ec::serde::Compact>>")]
53+
pub public_shares: Vec<NonZero<Point<E>>>,
54+
pub vss_setup: Option<crate::VssSetup<E>>,
55+
#[cfg(feature = "hd-wallets")]
56+
#[cfg_attr(
57+
feature = "serde",
58+
serde(default),
59+
serde(with = "As::<Option<crate::utils::HexOrBin>>")
60+
)]
61+
pub chain_code: Option<slip_10::ChainCode>,
62+
#[serde(with = "As::<generic_ec::serde::Compact>")]
63+
pub x: NonZero<SecretScalar<E>>,
64+
}

test-data/old-shares/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This folder contains core key shares (aka `cggmp21::IncompleteKeyShare` or `key_share::CoreKeyShare`)
2+
generated at different version of the library. We use them to make sure that newer versions of the
3+
`key_share` crate are able to deserialize older key shares.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"curve": "secp256k1",
3+
"i": 0,
4+
"shared_public_key": "03ea3bac8aa37f22a9a6862fd78c05f13bfc8ce32ff86b745949a3fb9ea1d41b8c",
5+
"public_shares": [
6+
"0297b263571c7f0556d8fffc5476ca0eedd81753f8db773f8099cd441a130cac80",
7+
"0217fbd8dac7a60a53b6958e0de0844c73d72bba7d897981b33be39a70f629b85f",
8+
"034c7e81b999a5b0d63b64c3b02ed1f500230875d2a0f3841516293db5291a83bc",
9+
"0377c80d50ed8e71c06a8348fd09c10ce3fbaa7c93b029aac4b60980134f972b51",
10+
"03a19446e07ca07b04c1bbe0e1381854246b943ef3d7a3422e8c3b8b22aae3ab76"
11+
],
12+
"vss_setup": null,
13+
"x": "b1903373aadd5c3c509814552606ddabe77fd0fdba4f589a56866f7b88e4ac4d"
14+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"curve": "secp256k1",
3+
"i": 0,
4+
"shared_public_key": "02078005f22cb615d85097d9a825aac2c4f0a6a4417873abf1fe2b4fda4bda99e2",
5+
"public_shares": [
6+
"03915d143b9cf4b8f6e95ea9425777c70056a4f3c694539f10595b8e2ef2cf9df9",
7+
"03903e8903d49697991198cf2fc5890f5ce55ae955d5615b326b9782b773bca581",
8+
"027b4f4c8a43c93c29279e3c0a2ef54f0fd63bf3b394105319378a243bce31d207",
9+
"026a9d37cfc5d70b94c35274e3cf15aa6141ad77c76ab7cfb029d7f69405eae839",
10+
"03b1c4a488c4cd6be65a2b1b805f7e63da18ee8ce8ae3dd8a459f995f2717cc602"
11+
],
12+
"vss_setup": {
13+
"min_signers": 3,
14+
"I": [
15+
{
16+
"curve": "secp256k1",
17+
"scalar": "0000000000000000000000000000000000000000000000000000000000000001"
18+
},
19+
{
20+
"curve": "secp256k1",
21+
"scalar": "0000000000000000000000000000000000000000000000000000000000000002"
22+
},
23+
{
24+
"curve": "secp256k1",
25+
"scalar": "0000000000000000000000000000000000000000000000000000000000000003"
26+
},
27+
{
28+
"curve": "secp256k1",
29+
"scalar": "0000000000000000000000000000000000000000000000000000000000000004"
30+
},
31+
{
32+
"curve": "secp256k1",
33+
"scalar": "0000000000000000000000000000000000000000000000000000000000000005"
34+
}
35+
]
36+
},
37+
"x": "49a7c9da6f3815a0c52352c3e44f325dd1d2d9f506b2f5e840f75ba66e93ff22"
38+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"curve": "secp256r1",
3+
"i": 0,
4+
"shared_public_key": "02714f76bc665803b80d6cd7f1d651bbfb2fd29f504f11deecd5111665ec8e5336",
5+
"public_shares": [
6+
"02905d81b11fd9af73900ab8b5bc70dd5f9c81a7afb7a0d0168f027f2998c3e4d2",
7+
"026bdfffccb9a446a69e9efaf7f4d5208c9b264b1b6a1ac5e878083442287dad55",
8+
"0326481d4aaa11b1654d8fd193fd9f4a39d47af8fc3532d281593676fcdd2e92bf",
9+
"02085baeef45ce5c1daf216a5c34e39f6e4c08d3b5f85b60194b5c6244ec7e8ba5",
10+
"0301b710133950ea505556a0e9dba5becbb59551b3519a8701bf8df9a8734fbbbd"
11+
],
12+
"vss_setup": null,
13+
"x": "27b3c8fcc99e566514d507db7a377c9948062dde1559b514ddea31d58732e2f9"
14+
}
Binary file not shown.

0 commit comments

Comments
 (0)