Skip to content

Commit 64722bd

Browse files
committed
init: check invertible inputs for finexp and to_affine functions
1 parent 5aea61c commit 64722bd

File tree

4 files changed

+187
-32
lines changed

4 files changed

+187
-32
lines changed

g16ckt/src/gadgets/bn254/final_exponentiation.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
//! the structure used in the main branch.
66
77
use ark_ec::bn::BnConfig;
8-
use ark_ff::{BitIteratorBE, Field};
8+
use ark_ff::{AdditiveGroup, BitIteratorBE, Field};
99
use circuit_component_macro::component;
1010

11-
use crate::{CircuitContext, gadgets::bn254::fq12::Fq12};
11+
use crate::{
12+
CircuitContext,
13+
circuit::TRUE_WIRE,
14+
gadgets::bn254::fq12::{Fq12, ValidFq12},
15+
};
1216

1317
pub fn conjugate_native(f: ark_bn254::Fq12) -> ark_bn254::Fq12 {
1418
ark_bn254::Fq12::new(f.c0, -f.c1)
@@ -98,7 +102,16 @@ pub fn exp_by_neg_x_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) ->
98102
}
99103

100104
#[component]
101-
pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) -> Fq12 {
105+
pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) -> ValidFq12 {
106+
let is_zero = Fq12::equal_constant(circuit, f, &ark_bn254::Fq12::ZERO);
107+
let is_valid = circuit.issue_wire();
108+
circuit.add_gate(crate::Gate {
109+
wire_a: is_zero,
110+
wire_b: TRUE_WIRE,
111+
wire_c: is_valid,
112+
gate_type: crate::GateType::Xor,
113+
});
114+
102115
let f_inv = Fq12::inverse_montgomery(circuit, f);
103116
let f_conjugate = Fq12::conjugate(circuit, f);
104117
let u = Fq12::mul_montgomery(circuit, &f_inv, &f_conjugate);
@@ -127,7 +140,9 @@ pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &F
127140
let y18 = Fq12::mul_montgomery(circuit, &r2, &y11);
128141
let y19 = Fq12::frobenius_montgomery(circuit, &y18, 3);
129142

130-
Fq12::mul_montgomery(circuit, &y19, &y17)
143+
let f = Fq12::mul_montgomery(circuit, &y19, &y17);
144+
145+
ValidFq12 { f, is_valid }
131146
}
132147

133148
#[cfg(test)]
@@ -171,6 +186,7 @@ mod tests {
171186
}
172187
struct Out {
173188
value: ark_bn254::Fq12,
189+
valid: bool,
174190
}
175191
fn encode_fq6_to_wires<M: CircuitMode<WireValue = bool>>(
176192
val: &ark_bn254::Fq6,
@@ -260,7 +276,7 @@ mod tests {
260276
}
261277
}
262278
impl CircuitOutput<ExecuteMode> for Out {
263-
type WireRepr = Fq12Wires;
279+
type WireRepr = ValidFq12;
264280
fn decode(wires: Self::WireRepr, cache: &mut ExecuteMode) -> Self {
265281
fn decode_fq6_from_wires(
266282
wires: &Fq6Wires,
@@ -298,10 +314,12 @@ mod tests {
298314
ark_bn254::Fq2::new(ark_bn254::Fq::from(c2_c0), ark_bn254::Fq::from(c2_c1));
299315
ark_bn254::Fq6::new(c0, c1, c2)
300316
}
301-
let c0 = decode_fq6_from_wires(&wires.0[0], cache);
302-
let c1 = decode_fq6_from_wires(&wires.0[1], cache);
317+
let c0 = decode_fq6_from_wires(&wires.f.0[0], cache);
318+
let c1 = decode_fq6_from_wires(&wires.f.0[1], cache);
319+
let valid = cache.lookup_wire(wires.is_valid).expect("missing wire");
303320
Self {
304321
value: ark_bn254::Fq12::new(c0, c1),
322+
valid,
305323
}
306324
}
307325
}
@@ -312,6 +330,27 @@ mod tests {
312330
final_exponentiation_montgomery(ctx, &input.f)
313331
});
314332

315-
assert_eq!(result.output_value.value, expected_m);
333+
assert!(
334+
result.output_value.valid,
335+
"final_exponentiation_montgomery input should be valid"
336+
);
337+
assert_eq!(
338+
result.output_value.value, expected_m,
339+
"final_exponentiation_montgomery output should be valid"
340+
);
341+
342+
// Test for non-invertible element
343+
let input = In {
344+
f: ark_bn254::Fq12::ZERO,
345+
};
346+
let result: StreamingResult<_, _, Out> =
347+
CircuitBuilder::streaming_execute(input, 10_000, |ctx, input| {
348+
final_exponentiation_montgomery(ctx, &input.f)
349+
});
350+
351+
assert!(
352+
!result.output_value.valid,
353+
"final_exponentiation_montgomery input should be invalid"
354+
);
316355
}
317356
}

g16ckt/src/gadgets/bn254/fq12.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rand::Rng;
55
use super::fq6::Fq6Components;
66
use crate::{
77
CircuitContext, Gate, WireId,
8-
circuit::{FromWires, WiresObject},
8+
circuit::{FromWires, WiresArity, WiresObject},
99
gadgets::bn254::{fq::Fq, fq2::Fq2, fq6::Fq6},
1010
};
1111

@@ -447,6 +447,58 @@ impl Fq12 {
447447
}
448448
}
449449

450+
/// Analogous to Option<Fq12> where `is_valid` carries `false` if variable is None
451+
#[derive(Clone, Debug)]
452+
pub struct ValidFq12 {
453+
pub f: Fq12,
454+
pub is_valid: WireId,
455+
}
456+
457+
impl WiresObject for ValidFq12 {
458+
fn to_wires_vec(&self) -> Vec<WireId> {
459+
let mut wires: Vec<WireId> = self.f.0[0]
460+
.to_wires_vec()
461+
.into_iter()
462+
.chain(self.f.0[1].to_wires_vec())
463+
.collect();
464+
wires.push(self.is_valid);
465+
wires
466+
}
467+
468+
fn clone_from(&self, mut wire_gen: &mut impl FnMut() -> WireId) -> Self {
469+
ValidFq12 {
470+
f: Fq12([
471+
self.f.0[0].clone_from(&mut wire_gen),
472+
self.f.0[1].clone_from(&mut wire_gen),
473+
]),
474+
is_valid: wire_gen(),
475+
}
476+
}
477+
}
478+
479+
impl FromWires for ValidFq12 {
480+
fn from_wires(wires: &[WireId]) -> Option<Self> {
481+
if wires.len() == ValidFq12::ARITY {
482+
let mid = Fq6::N_BITS;
483+
let fq6_1 = Fq6::from_wires(&wires[..mid])?;
484+
let fq6_2 = Fq6::from_wires(&wires[mid..2 * mid])?;
485+
let is_valid_wires = &wires[2 * mid..];
486+
assert_eq!(is_valid_wires.len(), 1); // single is valid wire
487+
let res = ValidFq12 {
488+
f: Fq12([fq6_1, fq6_2]),
489+
is_valid: is_valid_wires[0],
490+
};
491+
Some(res)
492+
} else {
493+
None
494+
}
495+
}
496+
}
497+
498+
impl WiresArity for ValidFq12 {
499+
const ARITY: usize = Fq12::N_BITS + 1;
500+
}
501+
450502
#[cfg(test)]
451503
mod tests {
452504
use std::{array, str::FromStr};

g16ckt/src/gadgets/bn254/pairing.rs

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ use crate::{
2222
CircuitContext, Fp254Impl,
2323
circuit::{FromWires, OffCircuitParam, WiresArity, WiresObject},
2424
gadgets::bn254::{
25-
final_exponentiation::final_exponentiation_montgomery, fq::Fq, fq2::Fq2, fq6::Fq6,
26-
fq12::Fq12, g1::G1Projective, g2::G2Projective,
25+
final_exponentiation::final_exponentiation_montgomery,
26+
fq::Fq,
27+
fq2::Fq2,
28+
fq6::Fq6,
29+
fq12::{Fq12, ValidFq12},
30+
g1::G1Projective,
31+
g2::G2Projective,
2732
},
2833
};
2934

@@ -883,7 +888,7 @@ pub fn pairing_const_q<C: CircuitContext>(
883888
circuit: &mut C,
884889
p: &G1Projective,
885890
q: &ark_bn254::G2Affine,
886-
) -> Fq12 {
891+
) -> ValidFq12 {
887892
let f = miller_loop_const_q(circuit, p, q);
888893
final_exponentiation_montgomery(circuit, &f)
889894
}
@@ -894,7 +899,7 @@ pub fn multi_pairing_const_q<C: CircuitContext>(
894899
circuit: &mut C,
895900
ps: &[G1Projective],
896901
qs: &[ark_bn254::G2Affine],
897-
) -> Fq12 {
902+
) -> ValidFq12 {
898903
let f = multi_miller_loop_const_q(circuit, ps, qs);
899904
final_exponentiation_montgomery(circuit, &f)
900905
}
@@ -1146,7 +1151,10 @@ mod tests {
11461151
};
11471152
let result =
11481153
CircuitBuilder::streaming_execute::<_, _, Fq12Output>(input, 10_000, |ctx, w| {
1149-
ell_montgomery(ctx, &w.f, &w.c, &w.p)
1154+
ValidFq12 {
1155+
f: ell_montgomery(ctx, &w.f, &w.c, &w.p),
1156+
is_valid: TRUE_WIRE,
1157+
}
11501158
});
11511159

11521160
assert_eq!(result.output_value.value, expected_m);
@@ -1720,6 +1728,7 @@ mod tests {
17201728

17211729
struct FinalExpOutput {
17221730
value: ark_bn254::Fq12,
1731+
is_valid: bool,
17231732
}
17241733
impl CircuitInput for FEInput {
17251734
type WireRepr = FEWires;
@@ -1740,7 +1749,7 @@ mod tests {
17401749
}
17411750
}
17421751
impl CircuitOutput<ExecuteMode> for FinalExpOutput {
1743-
type WireRepr = Fq12;
1752+
type WireRepr = ValidFq12;
17441753
fn decode(wires: Self::WireRepr, cache: &mut ExecuteMode) -> Self {
17451754
// Reuse local decoder helpers
17461755
fn decode_fq6_from_wires(
@@ -1779,10 +1788,14 @@ mod tests {
17791788
ark_bn254::Fq2::new(ark_bn254::Fq::from(c2_c0), ark_bn254::Fq::from(c2_c1));
17801789
ark_bn254::Fq6::new(c0, c1, c2)
17811790
}
1782-
let c0 = decode_fq6_from_wires(&wires.0[0], cache);
1783-
let c1 = decode_fq6_from_wires(&wires.0[1], cache);
1791+
let c0 = decode_fq6_from_wires(&wires.f.0[0], cache);
1792+
let c1 = decode_fq6_from_wires(&wires.f.0[1], cache);
1793+
let is_valid = cache
1794+
.lookup_wire(wires.is_valid)
1795+
.expect("missing wire value");
17841796
Self {
17851797
value: ark_bn254::Fq12::new(c0, c1),
1798+
is_valid,
17861799
}
17871800
}
17881801
}
@@ -1794,7 +1807,14 @@ mod tests {
17941807
|ctx, input| final_exponentiation_montgomery(ctx, &input.f),
17951808
);
17961809

1797-
assert_eq!(result.output_value.value, expected_m);
1810+
assert_eq!(
1811+
result.output_value.value, expected_m,
1812+
"final_exponentiation_montgomery output should be valid"
1813+
);
1814+
assert!(
1815+
result.output_value.is_valid,
1816+
"final_exponentiation_montgomery input should be valid"
1817+
);
17981818
}
17991819

18001820
#[test]
@@ -1914,14 +1934,19 @@ mod tests {
19141934

19151935
struct Fq12Output {
19161936
value: ark_bn254::Fq12,
1937+
valid: bool,
19171938
}
19181939
impl CircuitOutput<ExecuteMode> for Fq12Output {
1919-
type WireRepr = Fq12;
1940+
type WireRepr = ValidFq12;
19201941
fn decode(wires: Self::WireRepr, cache: &mut ExecuteMode) -> Self {
1921-
let c0 = decode_fq6_from_wires(&wires.0[0], cache);
1922-
let c1 = decode_fq6_from_wires(&wires.0[1], cache);
1942+
let c0 = decode_fq6_from_wires(&wires.f.0[0], cache);
1943+
let c1 = decode_fq6_from_wires(&wires.f.0[1], cache);
1944+
let is_valid = cache
1945+
.lookup_wire(wires.is_valid)
1946+
.expect("missing wire value");
19231947
Self {
19241948
value: ark_bn254::Fq12::new(c0, c1),
1949+
valid: is_valid,
19251950
}
19261951
}
19271952
}
@@ -2018,7 +2043,10 @@ mod tests {
20182043
};
20192044
let result =
20202045
CircuitBuilder::streaming_execute::<_, _, Fq12Output>(input, 10_000, |ctx, input| {
2021-
ell_eval_const(ctx, &input.f, &coeff, &input.p)
2046+
ValidFq12 {
2047+
f: ell_eval_const(ctx, &input.f, &coeff, &input.p),
2048+
is_valid: TRUE_WIRE,
2049+
}
20222050
});
20232051

20242052
assert_eq!(result.output_value.value, expected_m);
@@ -2095,7 +2123,10 @@ mod tests {
20952123
let result = CircuitBuilder::streaming_execute::<_, _, Fq12Output>(
20962124
In { p },
20972125
10_000,
2098-
|ctx, input| miller_loop_const_q(ctx, &input.p, &q),
2126+
|ctx, input| ValidFq12 {
2127+
f: miller_loop_const_q(ctx, &input.p, &q),
2128+
is_valid: TRUE_WIRE,
2129+
},
20992130
);
21002131

21012132
assert_eq!(result.output_value.value, expected_m);
@@ -2175,7 +2206,8 @@ mod tests {
21752206
|ctx, input| pairing_const_q(ctx, &input.p, &q),
21762207
);
21772208

2178-
assert_eq!(result.output_value.value, expected_m);
2209+
assert!(result.output_value.valid, "input should be valid");
2210+
assert_eq!(result.output_value.value, expected_m, "output should match");
21792211
}
21802212

21812213
#[test]
@@ -2511,7 +2543,10 @@ mod tests {
25112543
let result = CircuitBuilder::streaming_execute::<_, _, Fq12Output>(
25122544
input,
25132545
40_000,
2514-
|circuit, wires| multi_miller_loop_montgomery_fast(circuit, &wires.ps, &wires.qs),
2546+
|circuit, wires| ValidFq12 {
2547+
f: multi_miller_loop_montgomery_fast(circuit, &wires.ps, &wires.qs),
2548+
is_valid: TRUE_WIRE,
2549+
},
25152550
);
25162551

25172552
assert_eq!(result.output_value.value, expected_m);
@@ -2730,9 +2765,12 @@ mod tests {
27302765
let input = In { p1, p2, p3, q3 };
27312766
let result =
27322767
CircuitBuilder::streaming_execute::<_, _, Fq12Output>(input, 80_000, |ctx, w| {
2733-
multi_miller_loop_groth16_evaluate_montgomery_fast(
2734-
ctx, &w.p1, &w.p2, &w.p3, q1, q2, &w.q3,
2735-
)
2768+
ValidFq12 {
2769+
f: multi_miller_loop_groth16_evaluate_montgomery_fast(
2770+
ctx, &w.p1, &w.p2, &w.p3, q1, q2, &w.q3,
2771+
),
2772+
is_valid: TRUE_WIRE,
2773+
}
27362774
});
27372775

27382776
assert_eq!(

0 commit comments

Comments
 (0)