Skip to content

Commit 0627041

Browse files
authored
Merge pull request #21 from JuI3s/torus-compression
Torus compression
2 parents 89de836 + 003bfa5 commit 0627041

File tree

25 files changed

+1834
-130
lines changed

25 files changed

+1834
-130
lines changed

curves/bn254/src/constraints/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
//! One can perform standard algebraic operations on `FBaseVar`:
1111
//!
1212
//! ```
13-
//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
13+
//! # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
1414
//! use ark_std::UniformRand;
15-
//! use ark_relations::r1cs::*;
15+
//! use ark_relations::gr1cs::*;
1616
//! use ark_r1cs_std::prelude::*;
1717
//! use ark_bn254::{*, constraints::*};
1818
//!
@@ -59,9 +59,9 @@
5959
//! One can also perform standard algebraic operations on `GVar`:
6060
//!
6161
//! ```
62-
//! # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
62+
//! # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
6363
//! # use ark_std::UniformRand;
64-
//! # use ark_relations::r1cs::*;
64+
//! # use ark_relations::gr1cs::*;
6565
//! # use ark_r1cs_std::prelude::*;
6666
//! # use ark_bn254::{*, constraints::*};
6767
//!

curves/bn254/src/curves/g2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ impl SWCurveConfig for Config {
3737
const COEFF_A: Fq2 = Fq2::ZERO;
3838

3939
/// COEFF_B = 3/(u+9)
40-
/// (19485874751759354771024239261021720505790618469301721065564631296452457478373, 266929791119991161246907387137283842545076965332900288569378510910307636690)
40+
/// (19485874751759354771024239261021720505790618469301721065564631296452457478373,
41+
/// 266929791119991161246907387137283842545076965332900288569378510910307636690)
4142
const COEFF_B: Fq2 = Fq2::new(
4243
MontFp!("19485874751759354771024239261021720505790618469301721065564631296452457478373"),
4344
MontFp!("266929791119991161246907387137283842545076965332900288569378510910307636690"),

curves/bn254/src/curves/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ impl BnConfig for Config {
3939
type Fp12Config = Fq12Config;
4040
type G1Config = g1::Config;
4141
type G2Config = g2::Config;
42+
43+
type CompressedFp12Config = CompressedFq12;
4244
}
4345

4446
pub type Bn254 = Bn<Config>;

curves/bn254/src/curves/tests.rs

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,227 @@ test_group!(pairing_output; ark_ec::pairing::PairingOutput<Bn254>; msm);
99
test_pairing!(pairing; crate::Bn254);
1010
test_group!(g1_glv; G1Projective; glv);
1111
test_group!(g2_glv; G2Projective; glv);
12+
13+
// Test compressed pairing.
14+
#[cfg(test)]
15+
mod test {
16+
use ark_ec::pairing::{CompressedPairing, Pairing};
17+
use ark_ff::{AdditiveGroup, CyclotomicMultSubgroup, Field, UniformRand};
18+
use ark_std::{test_rng, vec::Vec};
19+
20+
use crate::{
21+
compressible_fq12_to_fq12, fq12_to_compressible_fq12, torus_compress_fq6,
22+
torus_compress_psi_6_pow_to_two_fq2, torus_decompress_fq6, Bn254, CompressibleFq12, Fq12,
23+
Fq2, Fq6, G1Projective, G2Projective,
24+
};
25+
26+
const PSI_6: [u64; 32] = [
27+
0x72ab9d4cf9110b20,
28+
0x973cd2a37a1b4236,
29+
0x1ba98b1bc336a6d5,
30+
0x2dfcbbaca5d60846,
31+
0xd5439cc568e9448a,
32+
0xe1db0edd8549f5a5,
33+
0x6f93e1753d4af731,
34+
0x49c8a9c36c6fee88,
35+
0x15f3f80815d4b9fa,
36+
0x1ba650a506fe3ed0,
37+
0xaefe7d8fff4f3dff,
38+
0x6ac0657132447def,
39+
0xf1f3ac284dd0152c,
40+
0x37018c9976be9e50,
41+
0x22c60855715fb2d0,
42+
0x208847a342f135b0,
43+
0x3ee1e2cb94f42a1d,
44+
0x3c4a7ccbcfffdab3,
45+
0xad8c7c82ecaf3f33,
46+
0x6ca3fffc37db0759,
47+
0x37cd075497b1b668,
48+
0xea10af7b063fb6d2,
49+
0x4c05f030809f6505,
50+
0x2a2ce31f8f0d0104,
51+
0x8cabad13097c3c76,
52+
0x4d2a25ff065eb903,
53+
0xa3df56ffaff05a83,
54+
0x2d5b0867d19408a1,
55+
0x223eaadf9b381c71,
56+
0xe8809c2c51000097,
57+
0x0e97a02f2739dcf3,
58+
0x1b59e685800b,
59+
];
60+
61+
#[test]
62+
fn test_compression() {
63+
let q2: [u64; 8] = [
64+
0x3b5458a2275d69b1,
65+
0xa602072d09eac101,
66+
0x4a50189c6d96cadc,
67+
0x04689e957a1242c8,
68+
0x26edfa5c34c6b38d,
69+
0xb00b855116375606,
70+
0x599a6f7c0348d21c,
71+
0x925c4b8763cbf9c,
72+
];
73+
74+
let num_trials = 5;
75+
let mut rng = test_rng();
76+
77+
// Step by step testing of the compression algorithm described in
78+
// https://eprint.iacr.org/2007/429.pdf Proposition 1
79+
for _ in 0..num_trials {
80+
let fq12_ele = CompressibleFq12::rand(&mut rng);
81+
let c1 = fq12_ele.torus_compress_base_order_minus_one_pow();
82+
let c1_pow = -c1.pow(q2);
83+
let compressed_prod = CompressibleFq12::mul_torus_compressed_elements(c1_pow, c1);
84+
85+
assert_eq!(
86+
CompressibleFq12::torus_decompress(compressed_prod),
87+
fq12_ele.pow(PSI_6)
88+
);
89+
let compressed_fq6 = torus_compress_fq6(compressed_prod);
90+
let decompressed_fq6 = torus_decompress_fq6(compressed_fq6);
91+
assert_eq!(compressed_prod, decompressed_fq6);
92+
}
93+
94+
// Test that the compression does not work with Fq12 as expected because the generator of
95+
// the quadratic extension inside Fq12 is not of degree 2 over Fq2.
96+
for _ in 0..num_trials {
97+
let fq12_ele = Fq12::rand(&mut rng);
98+
let c1 = fq12_ele.torus_compress_base_order_minus_one_pow();
99+
let c1_pow = -c1.pow(q2);
100+
let compressed_prod = Fq12::mul_torus_compressed_elements(c1_pow, c1);
101+
102+
assert_ne!(Fq12::torus_decompress(compressed_prod), fq12_ele.pow(PSI_6));
103+
}
104+
105+
// Test compression of an CompressibleFq12 element e2e.
106+
for _ in 0..num_trials {
107+
let compressible_fq12 = CompressibleFq12::rand(&mut rng);
108+
let compressed_fq12 = torus_compress_psi_6_pow_to_two_fq2(compressible_fq12);
109+
let decompressed_fq12 = compressed_fq12.decompress();
110+
assert_eq!(compressible_fq12.pow(PSI_6), decompressed_fq12);
111+
}
112+
}
113+
114+
#[test]
115+
fn test_compressible_fq12_to_fq12_conversion() {
116+
let num_trials = 100;
117+
let mut rng = test_rng();
118+
119+
let x = Fq6 {
120+
c0: Fq2::ZERO,
121+
c1: Fq2::ONE,
122+
c2: Fq2::ZERO,
123+
};
124+
125+
for _ in 0..num_trials {
126+
// a = c0 + c1 * residue^(1/2)
127+
let a = CompressibleFq12::rand(&mut rng);
128+
// a_prime = c0 + c1 * x * residue^(1/6), where x = residue^(1/3)
129+
let a_prime = compressible_fq12_to_fq12(a);
130+
assert_eq!(a_prime.c1, x * a.c1);
131+
}
132+
133+
for _ in 0..num_trials {
134+
// a = c0 + c1 * residue^(1/6)
135+
let a = Fq12::rand(&mut rng);
136+
// a_prime = c0 + c1 / x * residue^(1/2), where x = residue^(1/3)
137+
let a_prime = fq12_to_compressible_fq12(a);
138+
assert_eq!(a_prime.c1, x.inverse().unwrap() * a.c1);
139+
}
140+
141+
// Check inverses
142+
for _ in 0..num_trials {
143+
let fq12_ele = Fq12::rand(&mut rng);
144+
let compressible_fq12 = fq12_to_compressible_fq12(fq12_ele);
145+
let fq12_back = compressible_fq12_to_fq12(compressible_fq12);
146+
assert_eq!(fq12_ele, fq12_back);
147+
148+
let compressible_fq12 = CompressibleFq12::rand(&mut rng);
149+
let fq12_ele = compressible_fq12_to_fq12(compressible_fq12);
150+
let compressible_fq12_back = fq12_to_compressible_fq12(fq12_ele);
151+
assert_eq!(compressible_fq12, compressible_fq12_back);
152+
}
153+
154+
// Homomorphic property
155+
for _ in 0..num_trials {
156+
let a = CompressibleFq12::rand(&mut rng);
157+
let b = CompressibleFq12::rand(&mut rng);
158+
let c = a * b;
159+
let a_prime = compressible_fq12_to_fq12(a);
160+
let b_prime = compressible_fq12_to_fq12(b);
161+
let c_prime = compressible_fq12_to_fq12(c);
162+
assert_eq!(a_prime * b_prime, c_prime);
163+
164+
let a = Fq12::rand(&mut rng);
165+
let b = Fq12::rand(&mut rng);
166+
let c = a * b;
167+
let a_prime = fq12_to_compressible_fq12(a);
168+
let b_prime = fq12_to_compressible_fq12(b);
169+
let c_prime = fq12_to_compressible_fq12(c);
170+
assert_eq!(a_prime * b_prime, c_prime);
171+
}
172+
173+
// Check that converting an Fq12 element to a CompressibleFq12 element before compressing
174+
// its psi_6 power works, where decompressing is simply converting back to an Fq12 element.
175+
for _ in 0..num_trials {
176+
let a = Fq12::rand(&mut rng);
177+
let a_prime = fq12_to_compressible_fq12(a);
178+
let compressed = torus_compress_psi_6_pow_to_two_fq2(a_prime);
179+
180+
let decompressed = compressed.decompress();
181+
let decompressed_fq12 = compressible_fq12_to_fq12(decompressed);
182+
assert_eq!(a.pow(PSI_6), decompressed_fq12);
183+
}
184+
}
185+
186+
#[test]
187+
fn test_compressed_pairing() {
188+
let num_trials = 10;
189+
let mut rng = test_rng();
190+
191+
// Test pairing e2e.
192+
for _ in 0..num_trials {
193+
let g1 = G1Projective::rand(&mut rng);
194+
let g2 = G2Projective::rand(&mut rng);
195+
let pairing_value = Bn254::pairing(g1, g2).0;
196+
let compressed_pairing_value = Bn254::compressed_pairing(g1, g2);
197+
assert_eq!(pairing_value, compressed_pairing_value.decompress_to_fq12());
198+
}
199+
200+
// Test multi-pairing e2e.
201+
let num_pairs = 10;
202+
for _ in 0..num_trials {
203+
let g1 = (0..num_pairs)
204+
.map(|_| G1Projective::rand(&mut rng))
205+
.collect::<Vec<_>>();
206+
let g2 = (0..num_pairs)
207+
.map(|_| G2Projective::rand(&mut rng))
208+
.collect::<Vec<_>>();
209+
let pairing_value = Bn254::multi_pairing(g1.iter().cloned(), g2.iter().cloned()).0;
210+
let compressed_pairing_value =
211+
Bn254::compressed_multi_pairing(g1.iter().cloned(), g2.iter().cloned());
212+
assert_eq!(pairing_value, compressed_pairing_value.decompress_to_fq12());
213+
}
214+
215+
// This is more for documentation purposes. For the compressed pairing calculation, we swap
216+
// the order of computing exponentiation by \Psi_6(q^2) and \Phi_6(q^2) (see documentation
217+
// for their definitions). The Miller loop output is not in the cyclotomic subgroup of the
218+
// right order where the optimization (defined in the CyclotomicMultSubgroup trait) can be
219+
// applied.
220+
for _ in 0..num_trials {
221+
let g1 = G1Projective::rand(&mut rng);
222+
let g2 = G2Projective::rand(&mut rng);
223+
224+
let miller_loop_output = Bn254::multi_miller_loop([g1], [g2]).0;
225+
assert_ne!(
226+
miller_loop_output.cyclotomic_inverse(),
227+
miller_loop_output.inverse()
228+
);
229+
assert_ne!(
230+
miller_loop_output.cyclotomic_exp(PSI_6),
231+
miller_loop_output.pow(PSI_6)
232+
);
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)