Skip to content
This repository was archived by the owner on Dec 18, 2023. It is now read-only.

Commit 138b23f

Browse files
mmagiciankevaundrayPratyush
authored
Zcash-style serialization for BLS12-381 (#129)
Co-authored-by: kevaundray <37423678+kevaundray@users.noreply.github.com> Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
1 parent 4bcf87d commit 138b23f

File tree

11 files changed

+480
-64
lines changed

11 files changed

+480
-64
lines changed

bls12_381/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ edition = "2021"
1616
ark-ff = { version="^0.3.0", default-features = false }
1717
ark-ec = { version="^0.3.0", default-features = false }
1818
ark-std = { version="^0.3.0", default-features = false }
19+
ark-serialize = { version="^0.3.0", default-features = false }
1920

2021
[dev-dependencies]
21-
ark-serialize = { version="^0.3.0", default-features = false }
2222
ark-algebra-test-templates = { version="^0.3.0", default-features = false }
2323
ark-algebra-bench-templates = { version = "^0.3.0", default-features = false }
24+
hex = "^0.4.0"
2425

2526
[features]
2627
default = [ "curve" ]

bls12_381/src/curves/g1.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ use ark_ec::{
77
AffineRepr, Group,
88
};
99
use ark_ff::{Field, MontFp, PrimeField, Zero};
10+
use ark_serialize::{Compress, SerializationError};
1011
use ark_std::{ops::Neg, One};
12+
13+
use crate::util::{
14+
read_g1_compressed, read_g1_uncompressed, serialize_fq, EncodingFlags, G1_SERIALIZED_SIZE,
15+
};
16+
1117
pub type G1Affine = bls12::G1Affine<crate::Parameters>;
1218
pub type G1Projective = bls12::G1Projective<crate::Parameters>;
1319

@@ -70,6 +76,66 @@ impl SWCurveConfig for Parameters {
7076
let h_eff = one_minus_x().into_bigint();
7177
Parameters::mul_affine(&p, h_eff.as_ref()).into()
7278
}
79+
80+
fn deserialize_with_mode<R: ark_serialize::Read>(
81+
mut reader: R,
82+
compress: ark_serialize::Compress,
83+
validate: ark_serialize::Validate,
84+
) -> Result<Affine<Self>, ark_serialize::SerializationError> {
85+
let p = if compress == ark_serialize::Compress::Yes {
86+
read_g1_compressed(&mut reader)?
87+
} else {
88+
read_g1_uncompressed(&mut reader)?
89+
};
90+
91+
if validate == ark_serialize::Validate::Yes && !p.is_in_correct_subgroup_assuming_on_curve()
92+
{
93+
return Err(SerializationError::InvalidData);
94+
}
95+
Ok(p)
96+
}
97+
98+
fn serialize_with_mode<W: ark_serialize::Write>(
99+
item: &Affine<Self>,
100+
mut writer: W,
101+
compress: ark_serialize::Compress,
102+
) -> Result<(), SerializationError> {
103+
let encoding = EncodingFlags {
104+
is_compressed: compress == ark_serialize::Compress::Yes,
105+
is_infinity: item.is_zero(),
106+
is_lexographically_largest: item.y > -item.y,
107+
};
108+
let mut p = *item;
109+
if encoding.is_infinity {
110+
p = G1Affine::zero();
111+
}
112+
// need to access the field struct `x` directly, otherwise we get None from xy()
113+
// method
114+
let x_bytes = serialize_fq(p.x);
115+
if encoding.is_compressed {
116+
let mut bytes: [u8; G1_SERIALIZED_SIZE] = x_bytes;
117+
118+
encoding.encode_flags(&mut bytes);
119+
writer.write_all(&bytes)?;
120+
} else {
121+
let mut bytes = [0u8; 2 * G1_SERIALIZED_SIZE];
122+
bytes[0..G1_SERIALIZED_SIZE].copy_from_slice(&x_bytes[..]);
123+
bytes[G1_SERIALIZED_SIZE..].copy_from_slice(&serialize_fq(p.y)[..]);
124+
125+
encoding.encode_flags(&mut bytes);
126+
writer.write_all(&bytes)?;
127+
};
128+
129+
Ok(())
130+
}
131+
132+
fn serialized_size(compress: Compress) -> usize {
133+
if compress == Compress::Yes {
134+
G1_SERIALIZED_SIZE
135+
} else {
136+
G1_SERIALIZED_SIZE * 2
137+
}
138+
}
73139
}
74140

75141
fn one_minus_x() -> Fr {

bls12_381/src/curves/g2.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ use ark_ec::{
88
AffineRepr, CurveGroup, Group,
99
};
1010
use ark_ff::{Field, MontFp, Zero};
11+
use ark_serialize::{Compress, SerializationError};
1112

12-
use crate::*;
13+
use super::util::{serialize_fq, EncodingFlags, G2_SERIALIZED_SIZE};
14+
use crate::{
15+
util::{read_g2_compressed, read_g2_uncompressed},
16+
*,
17+
};
1318

1419
pub type G2Affine = bls12::G2Affine<crate::Parameters>;
1520
pub type G2Projective = bls12::G2Projective<crate::Parameters>;
@@ -105,6 +110,75 @@ impl SWCurveConfig for Parameters {
105110
psi2_p2 += &-psi_p;
106111
(psi2_p2 - p_projective).into_affine()
107112
}
113+
114+
fn deserialize_with_mode<R: ark_serialize::Read>(
115+
mut reader: R,
116+
compress: ark_serialize::Compress,
117+
validate: ark_serialize::Validate,
118+
) -> Result<Affine<Self>, ark_serialize::SerializationError> {
119+
let p = if compress == ark_serialize::Compress::Yes {
120+
read_g2_compressed(&mut reader)?
121+
} else {
122+
read_g2_uncompressed(&mut reader)?
123+
};
124+
125+
if validate == ark_serialize::Validate::Yes && !p.is_in_correct_subgroup_assuming_on_curve()
126+
{
127+
return Err(SerializationError::InvalidData);
128+
}
129+
Ok(p)
130+
}
131+
132+
fn serialize_with_mode<W: ark_serialize::Write>(
133+
item: &Affine<Self>,
134+
mut writer: W,
135+
compress: ark_serialize::Compress,
136+
) -> Result<(), SerializationError> {
137+
let encoding = EncodingFlags {
138+
is_compressed: compress == ark_serialize::Compress::Yes,
139+
is_infinity: item.is_zero(),
140+
is_lexographically_largest: item.y > -item.y,
141+
};
142+
let mut p = *item;
143+
if encoding.is_infinity {
144+
p = G2Affine::zero();
145+
}
146+
147+
let mut x_bytes = [0u8; G2_SERIALIZED_SIZE];
148+
let c1_bytes = serialize_fq(p.x.c1);
149+
let c0_bytes = serialize_fq(p.x.c0);
150+
x_bytes[0..48].copy_from_slice(&c1_bytes[..]);
151+
x_bytes[48..96].copy_from_slice(&c0_bytes[..]);
152+
if encoding.is_compressed {
153+
let mut bytes: [u8; G2_SERIALIZED_SIZE] = x_bytes;
154+
155+
encoding.encode_flags(&mut bytes);
156+
writer.write_all(&bytes)?;
157+
} else {
158+
let mut bytes = [0u8; 2 * G2_SERIALIZED_SIZE];
159+
160+
let mut y_bytes = [0u8; G2_SERIALIZED_SIZE];
161+
let c1_bytes = serialize_fq(p.y.c1);
162+
let c0_bytes = serialize_fq(p.y.c0);
163+
y_bytes[0..48].copy_from_slice(&c1_bytes[..]);
164+
y_bytes[48..96].copy_from_slice(&c0_bytes[..]);
165+
bytes[0..G2_SERIALIZED_SIZE].copy_from_slice(&x_bytes);
166+
bytes[G2_SERIALIZED_SIZE..].copy_from_slice(&y_bytes);
167+
168+
encoding.encode_flags(&mut bytes);
169+
writer.write_all(&bytes)?;
170+
};
171+
172+
Ok(())
173+
}
174+
175+
fn serialized_size(compress: ark_serialize::Compress) -> usize {
176+
if compress == Compress::Yes {
177+
G2_SERIALIZED_SIZE
178+
} else {
179+
2 * G2_SERIALIZED_SIZE
180+
}
181+
}
108182
}
109183

110184
pub const G2_GENERATOR_X: Fq2 = Fq2::new(G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);

bls12_381/src/curves/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{Fq, Fq12Config, Fq2Config, Fq6Config};
44

55
pub mod g1;
66
pub mod g2;
7+
pub(crate) mod util;
78

89
#[cfg(test)]
910
mod tests;

bls12_381/src/curves/tests.rs

Lines changed: 0 additions & 62 deletions
This file was deleted.
46.9 KB
Binary file not shown.
Binary file not shown.
93.8 KB
Binary file not shown.
Binary file not shown.

bls12_381/src/curves/tests/mod.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use ark_algebra_test_templates::*;
2+
use ark_ec::{AffineRepr, CurveGroup, Group};
3+
use ark_ff::{fields::Field, One, UniformRand, Zero};
4+
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
5+
use ark_std::{rand::Rng, test_rng, vec};
6+
7+
use crate::{Bls12_381, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective};
8+
9+
test_group!(g1; G1Projective; sw);
10+
test_group!(g2; G2Projective; sw);
11+
test_group!(pairing_output; ark_ec::pairing::PairingOutput<Bls12_381>; msm);
12+
test_pairing!(pairing; crate::Bls12_381);
13+
14+
#[test]
15+
fn test_g1_endomorphism_beta() {
16+
assert!(crate::g1::BETA.pow(&[3u64]).is_one());
17+
}
18+
19+
#[test]
20+
fn test_g1_subgroup_membership_via_endomorphism() {
21+
let mut rng = test_rng();
22+
let generator = G1Projective::rand(&mut rng).into_affine();
23+
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
24+
}
25+
26+
#[test]
27+
fn test_g1_subgroup_non_membership_via_endomorphism() {
28+
let mut rng = test_rng();
29+
loop {
30+
let x = Fq::rand(&mut rng);
31+
let greatest = rng.gen();
32+
33+
if let Some(p) = G1Affine::get_point_from_x_unchecked(x, greatest) {
34+
if !p.mul_bigint(Fr::characteristic()).is_zero() {
35+
assert!(!p.is_in_correct_subgroup_assuming_on_curve());
36+
return;
37+
}
38+
}
39+
}
40+
}
41+
42+
#[test]
43+
fn test_g2_subgroup_membership_via_endomorphism() {
44+
let mut rng = test_rng();
45+
let generator = G2Projective::rand(&mut rng).into_affine();
46+
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
47+
}
48+
49+
#[test]
50+
fn test_g2_subgroup_non_membership_via_endomorphism() {
51+
let mut rng = test_rng();
52+
loop {
53+
let x = Fq2::rand(&mut rng);
54+
let greatest = rng.gen();
55+
56+
if let Some(p) = G2Affine::get_point_from_x_unchecked(x, greatest) {
57+
if !p.mul_bigint(Fr::characteristic()).is_zero() {
58+
assert!(!p.is_in_correct_subgroup_assuming_on_curve());
59+
return;
60+
}
61+
}
62+
}
63+
}
64+
65+
// Test vectors and macro adapted from https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/tests/mod.rs
66+
macro_rules! test_vectors {
67+
($projective:ident, $affine:ident, $compress:expr, $expected:ident) => {
68+
let mut e = $projective::zero();
69+
70+
let mut v = vec![];
71+
{
72+
let mut expected = $expected;
73+
for _ in 0..1000 {
74+
let e_affine = $affine::from(e);
75+
let mut serialized = vec![0u8; e.serialized_size($compress)];
76+
e_affine
77+
.serialize_with_mode(serialized.as_mut_slice(), $compress)
78+
.unwrap();
79+
v.extend_from_slice(&serialized[..]);
80+
81+
let mut decoded = serialized;
82+
let len_of_encoding = decoded.len();
83+
(&mut decoded[..]).copy_from_slice(&expected[0..len_of_encoding]);
84+
expected = &expected[len_of_encoding..];
85+
let decoded =
86+
$affine::deserialize_with_mode(&decoded[..], $compress, Validate::Yes).unwrap();
87+
assert_eq!(e_affine, decoded);
88+
89+
e += &$projective::generator();
90+
}
91+
}
92+
93+
assert_eq!(&v[..], $expected);
94+
};
95+
}
96+
97+
#[test]
98+
fn g1_compressed_valid_test_vectors() {
99+
let bytes: &'static [u8] = include_bytes!("g1_compressed_valid_test_vectors.dat");
100+
test_vectors!(G1Projective, G1Affine, Compress::Yes, bytes);
101+
}
102+
103+
#[test]
104+
fn g1_uncompressed_valid_test_vectors() {
105+
let bytes: &'static [u8] = include_bytes!("g1_uncompressed_valid_test_vectors.dat");
106+
test_vectors!(G1Projective, G1Affine, Compress::No, bytes);
107+
}
108+
109+
#[test]
110+
fn g2_compressed_valid_test_vectors() {
111+
let bytes: &'static [u8] = include_bytes!("g2_compressed_valid_test_vectors.dat");
112+
test_vectors!(G2Projective, G2Affine, Compress::Yes, bytes);
113+
}
114+
115+
#[test]
116+
fn g2_uncompressed_valid_test_vectors() {
117+
let bytes: &'static [u8] = include_bytes!("g2_uncompressed_valid_test_vectors.dat");
118+
test_vectors!(G2Projective, G2Affine, Compress::No, bytes);
119+
}

0 commit comments

Comments
 (0)