Skip to content

Commit bf1c9b2

Browse files
emberianPratyush
andauthored
feat: serde-compatible adapters (#967)
* feat: serde-compatible wrappers * clean up a bit with macros * add impl From<T> for *compressed*checked<T> * refmt * serde-encoded-bytes to base64 right now it serializes in JSON to [1, 2, 3, 4] instead of a string. this crate is efficient in both binary and text formats. * serialize: missing instances for &T/&mut T * serialize: serde_with and Vec converters * re-hide the serde module * optional feature Co-authored-by: Pratyush Mishra <pratyush795@gmail.com> * doc the new wrappers in README * move Valid impl * add simple serde_json test * README.md newline --------- Co-authored-by: Pratyush Mishra <pratyush795@gmail.com> Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
1 parent da450f9 commit bf1c9b2

File tree

8 files changed

+389
-1
lines changed

8 files changed

+389
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- [\#971](https://github.com/arkworks-rs/algebra/pull/971) (`ark-ff`) Make serial_batch_inversion_and_mul public.
77
- Consolidated logic into `bitreverse_permutation_in_place` and made it public.
88
- Remove redundant type constraints from `Pairing::G1Prepared`.
9+
- (`ark-serialize`) Add serde-compatible wrapper types `CompressedChecked<T>`, `CompressedUnchecked<T>`, `UncompressedChecked<T>`, `UncompressedUnchecked<T>`.
910

1011
### Breaking changes
1112

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ rayon = "1"
169169
serde = "1.0"
170170
serde_derive = "1.0"
171171
serde_json = "1.0"
172+
serde-encoded-bytes = "0.2"
173+
serde_with = "3.12"
172174
sha2 = { version = "0.10", default-features = false }
173175
sha3 = { version = "0.10", default-features = false }
174176
blake2 = { version = "0.10", default-features = false }

serialize/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ arrayvec.workspace = true
2525
digest.workspace = true
2626
num-bigint.workspace = true
2727
rayon = { workspace = true, optional = true }
28+
serde = { workspace = true, optional = true }
29+
serde-encoded-bytes = { workspace = true, optional = true, features = ["base64"] }
30+
serde_with = { workspace = true, optional = true, default-features = false }
2831

2932
[dev-dependencies]
3033
sha2.workspace = true
3134
sha3.workspace = true
3235
blake2.workspace = true
36+
serde_json.workspace = true
3337
ark-test-curves = { workspace = true, default-features = false, features = [
3438
"bls12_381_curve",
3539
] }
@@ -38,5 +42,7 @@ ark-test-curves = { workspace = true, default-features = false, features = [
3842
[features]
3943
default = []
4044
parallel = ["rayon"]
41-
std = ["ark-std/std"]
45+
std = ["ark-std/std", "serde_with?/std"]
4246
derive = ["ark-serialize-derive"]
47+
serde = ["dep:serde", "dep:serde-encoded-bytes", "dep:serde_with"]
48+
serde_with = ["serde", "dep:serde_with"]

serialize/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,64 @@ impl Valid for MyStruct {
126126
}
127127
}
128128
```
129+
130+
### `serde`-compatibility
131+
132+
Four wrapper types (`CompressedChecked<T>`, `UncompressedChecked<T>`, `CompressedUnchecked<T>`, `UncompressedUnchecked<T>`) exist with two features: first, a type-level configuration of the de/serialization modes, and support for the [`serde`](https://serde.rs) framework. The easiest way to use these is with the `from` and `into` annotations on a container type already implementing `Canonical*`:
133+
134+
```rust,ignore
135+
use ark_serialize::{CanonicalSerialize, CanonicalDeserialize, CompressedChecked};
136+
use ark_test_curves::bls12_381::{G1Affine, G2Affine, Fr};
137+
use serde::{Serialize, Deserialize};
138+
139+
#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
140+
pub struct Proof(pub G1Affine);
141+
142+
#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
143+
#[derive(Serialize, Deserialize)]
144+
#[serde(from = "CompressedChecked<Self>", into = "CompressedChecked<Self>")]
145+
pub struct Signature {
146+
/// Aggregated BLS signature σ' = H(m)^aSK.
147+
pub agg_sig_prime: G2Affine,
148+
/// The threshold for the signature.
149+
pub threshold: Fr,
150+
/// The SNARK proof π.
151+
pub proof: Proof,
152+
}
153+
154+
impl From<CompressedChecked<Signature>> for Signature {
155+
fn from(sig: CompressedChecked<Signature>) -> Self {
156+
sig.0
157+
}
158+
}
159+
```
160+
161+
This type can now be used with either serialization framework.
162+
163+
When the container type isn't suitable for `#[serde(from/into)]`, `serde_with` conversions can be used instead of pushing the wrapper types into the field values. This prevents the conversion structures from polluting the real datastructure (eg having to add dummy constructors and strip them out of collections), minimizing the impact of adding serde support.
164+
165+
If `serde_with` is not desired, the less powerful `vec_*` mods provide support just for the common case of sequences. Without this converter, a `CompressedChecked<Vec<T>>` gets serialized as a single blob, as opposed to one blob per element, which is probably more intuitive. The alternative, trying to store `Vec<CompressedCheck<T>>`, causes invasive API pollution.
166+
167+
```rust,ignore
168+
use ark_serialize::CompressedChecked;
169+
use serde::Serialize;
170+
use ark_test_curves::bls12_381::{G1Affine, G2Affine, Fr};
171+
172+
#[serde_with::serde_as]
173+
#[derive(Clone, Debug, Serialize)]
174+
pub struct GlobalData {
175+
#[serde_as(as = "CompressedChecked<UniversalParams<Curve>>")]
176+
pub params: UniversalParams<Curve>,
177+
pub degree_max: usize,
178+
/// Used for domain separation in lockstitch
179+
pub domain: String,
180+
#[serde_as(as = "Vec<CompressedChecked<DensePolynomial<F>>>")]
181+
pub(crate) lagrange_polynomials: Vec<DensePolynomial<F>>,
182+
#[serde(with = "ark_serialize::vec_compressed_checked")]
183+
pub(crate) lagrange_coms_g1: Vec<G1Affine>,
184+
#[serde(with = "ark_serialize::vec_compressed_checked")]
185+
pub(crate) lagrange_coms_g2: Vec<G2Affine>,
186+
#[serde(skip)]
187+
pub(crate) lockstitch: lockstitch::Protocol,
188+
}
189+
```

serialize/src/impls.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,3 +980,31 @@ where
980980
.collect()
981981
}
982982
}
983+
984+
impl<T: CanonicalSerialize> CanonicalSerialize for &T {
985+
fn serialize_with_mode<W: Write>(
986+
&self,
987+
writer: W,
988+
compress: Compress,
989+
) -> Result<(), SerializationError> {
990+
(*self).serialize_with_mode(writer, compress)
991+
}
992+
993+
fn serialized_size(&self, compress: Compress) -> usize {
994+
(*self).serialized_size(compress)
995+
}
996+
}
997+
998+
impl<T: CanonicalSerialize> CanonicalSerialize for &mut T {
999+
fn serialize_with_mode<W: Write>(
1000+
&self,
1001+
writer: W,
1002+
compress: Compress,
1003+
) -> Result<(), SerializationError> {
1004+
(**self).serialize_with_mode(writer, compress)
1005+
}
1006+
1007+
fn serialized_size(&self, compress: Compress) -> usize {
1008+
(**self).serialized_size(compress)
1009+
}
1010+
}

serialize/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ mod error;
1212
mod flags;
1313
mod impls;
1414

15+
mod serde;
16+
1517
pub use ark_std::io::{Read, Write};
1618

1719
pub use error::*;
1820
pub use flags::*;
21+
pub use serde::*;
1922

2023
#[cfg(test)]
2124
mod test;

0 commit comments

Comments
 (0)