Skip to content

Commit 13dcbdf

Browse files
committed
merge issue 1 and 3 and combine validation gates
2 parents 9d8db07 + 64722bd commit 13dcbdf

File tree

4 files changed

+193
-115
lines changed

4 files changed

+193
-115
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};

0 commit comments

Comments
 (0)