Skip to content

Commit 9205ecf

Browse files
committed
add field bounds check on input proof
1 parent 6e4bb3c commit 9205ecf

File tree

3 files changed

+128
-37
lines changed

3 files changed

+128
-37
lines changed

g16ckt/src/gadgets/bn254/g1.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::{cmp::min, collections::HashMap, iter};
22

33
use ark_ec::short_weierstrass::SWCurveConfig;
4-
use ark_ff::{Field, Zero};
4+
use ark_ff::{Field, PrimeField, Zero};
55
use circuit_component_macro::component;
6+
use num_bigint::BigUint;
67

78
use crate::{
89
CircuitContext, WireId,
@@ -435,14 +436,17 @@ impl G1Projective {
435436
circuit: &mut C,
436437
serialized_bits: [WireId; 32 * 8],
437438
) -> DecompressedG1Wires {
438-
let (x_m, flag) = {
439+
let (x_m, is_x_m_valid, flag) = {
439440
let (num, flag) = serialized_bits.split_at(Fq::N_BITS);
440-
let a = Fq(BigIntWires { bits: num.to_vec() });
441+
let a = BigIntWires { bits: num.to_vec() };
442+
// check BigUint is a valid fq
443+
let r: BigUint = ark_bn254::Fq::MODULUS.into();
444+
let valid_fq = bigint::less_than_constant(circuit, &a, &r);
441445
// convert input field element in standard form into montgomery form
442446
let r = Fq::as_montgomery(ark_bn254::Fq::ONE);
443-
let a_mont = Fq::mul_by_constant_montgomery(circuit, &a, &r.square());
447+
let a_mont = Fq::mul_by_constant_montgomery(circuit, &Fq(a), &r.square());
444448
// flag_0 is lsb, flag 1 is msb
445-
(a_mont, [flag[0], flag[1]])
449+
(a_mont, valid_fq, [flag[0], flag[1]])
446450
};
447451

448452
// Part 1: Extract Flags
@@ -532,13 +536,20 @@ impl G1Projective {
532536
// Input is invalid if input is not a valid point in the curve or deserialization error
533537
// valid only if both crieterion is met
534538
let tmp0 = circuit.issue_wire();
539+
let tmp1 = circuit.issue_wire();
535540
circuit.add_gate(crate::Gate {
536541
wire_a: rhs_is_qr,
537542
wire_b: flags_is_valid,
538543
wire_c: tmp0,
539544
gate_type: crate::GateType::And,
540545
});
541-
tmp0
546+
circuit.add_gate(crate::Gate {
547+
wire_a: tmp0,
548+
wire_b: is_x_m_valid,
549+
wire_c: tmp1,
550+
gate_type: crate::GateType::And,
551+
});
552+
tmp1
542553
};
543554

544555
DecompressedG1Wires {

g16ckt/src/gadgets/bn254/g2.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::{cmp::min, collections::HashMap, iter::zip};
22

33
use ark_ec::short_weierstrass::SWCurveConfig;
4-
use ark_ff::{AdditiveGroup, Field, Zero};
4+
use ark_ff::{AdditiveGroup, Field, PrimeField, Zero};
55
use circuit_component_macro::component;
6+
use num_bigint::BigUint;
67

78
use crate::{
89
CircuitContext, WireId,
@@ -564,29 +565,40 @@ impl G2Projective {
564565
circuit: &mut C,
565566
serialized_bits: [WireId; 64 * 8],
566567
) -> DecompressedG2Wires {
567-
let (x, flag) = {
568+
let (x, is_x_valid, flag) = {
568569
let (num1, num2, flag) = (
569570
&serialized_bits[0..Fq::N_BITS],
570571
&serialized_bits[32 * 8..32 * 8 + Fq::N_BITS],
571572
&serialized_bits[32 * 8 + Fq::N_BITS..],
572573
);
573-
let a = Fq2([
574-
Fq(BigIntWires {
575-
bits: num1.to_vec(),
576-
}),
577-
Fq(BigIntWires {
578-
bits: num2.to_vec(),
579-
}),
580-
]);
574+
let a0 = BigIntWires {
575+
bits: num1.to_vec(),
576+
};
577+
let a1 = BigIntWires {
578+
bits: num2.to_vec(),
579+
};
580+
let r: BigUint = ark_bn254::Fq::MODULUS.into();
581+
let valid_fq = {
582+
let valid_a0 = bigint::less_than_constant(circuit, &a0, &r);
583+
let valid_a1 = bigint::less_than_constant(circuit, &a1, &r);
584+
let valid_fq = circuit.issue_wire();
585+
circuit.add_gate(crate::Gate {
586+
wire_a: valid_a0,
587+
wire_b: valid_a1,
588+
wire_c: valid_fq,
589+
gate_type: crate::GateType::And,
590+
});
591+
valid_fq
592+
};
581593

582594
// convert input field element in standard form into montgomery form
583595
let r = Fq::as_montgomery(ark_bn254::Fq::ONE);
584-
let a_mont_x = Fq::mul_by_constant_montgomery(circuit, a.c0(), &r.square());
596+
let a_mont_x = Fq::mul_by_constant_montgomery(circuit, &Fq(a0), &r.square());
585597
let r = Fq::as_montgomery(ark_bn254::Fq::ONE);
586-
let a_mont_y = Fq::mul_by_constant_montgomery(circuit, a.c1(), &r.square());
598+
let a_mont_y = Fq::mul_by_constant_montgomery(circuit, &Fq(a1), &r.square());
587599

588600
// flag_0 is lsb, flag 1 is msb
589-
(Fq2([a_mont_x, a_mont_y]), [flag[0], flag[1]])
601+
(Fq2([a_mont_x, a_mont_y]), valid_fq, [flag[0], flag[1]])
590602
};
591603

592604
// Part 1: Extract Flags
@@ -696,13 +708,20 @@ impl G2Projective {
696708
// Input is invalid if input is not a valid point in the curve or deserialization error
697709
// valid only if both crieterion is met
698710
let tmp0 = circuit.issue_wire();
711+
let tmp1 = circuit.issue_wire();
699712
circuit.add_gate(crate::Gate {
700713
wire_a: rhs_is_qr,
701714
wire_b: flags_is_valid,
702715
wire_c: tmp0,
703716
gate_type: crate::GateType::And,
704717
});
705-
tmp0
718+
circuit.add_gate(crate::Gate {
719+
wire_a: tmp0,
720+
wire_b: is_x_valid,
721+
wire_c: tmp1,
722+
gate_type: crate::GateType::And,
723+
});
724+
tmp1
706725
};
707726

708727
DecompressedG2Wires {

g16ckt/src/gadgets/groth16.rs

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
77
use ark_bn254::Bn254;
88
use ark_ec::{AffineRepr, pairing::Pairing};
9-
use ark_ff::Field;
9+
use ark_ff::{Field, PrimeField};
1010
use ark_groth16::VerifyingKey;
1111
use ark_serialize::CanonicalSerialize;
1212
use circuit_component_macro::component;
1313
use num_bigint::BigUint;
1414

1515
use crate::{
1616
CircuitContext, WireId,
17-
circuit::{CircuitInput, CircuitMode, EncodeInput, WiresObject},
17+
circuit::{CircuitInput, CircuitMode, EncodeInput, TRUE_WIRE, WiresObject},
1818
gadgets::{
19-
bigint::BigIntWires,
19+
bigint::{self, BigIntWires},
2020
bn254::{
2121
G2Projective, final_exponentiation::final_exponentiation_montgomery, fq::Fq,
2222
fq12::Fq12, fr::Fr, g1::G1Projective,
@@ -68,26 +68,87 @@ pub fn groth16_verify<C: CircuitContext>(
6868
vk,
6969
} = input;
7070

71-
let proof_is_on_curve = {
72-
let a_is_on_curve = G1Projective::is_on_curve(circuit, a);
73-
let b_is_on_curve = G2Projective::is_on_curve(circuit, b);
74-
let c_is_on_curve = G1Projective::is_on_curve(circuit, c);
71+
let is_valid_field_and_group = {
72+
let is_valid_fr = {
73+
let mut and_all_wires = TRUE_WIRE;
74+
public.iter().for_each(|pubinp| {
75+
let r: BigUint = ark_bn254::Fr::MODULUS.into();
76+
let valid_pubinp = bigint::less_than_constant(circuit, pubinp, &r);
77+
let new_wire = circuit.issue_wire();
78+
circuit.add_gate(crate::Gate {
79+
wire_a: and_all_wires,
80+
wire_b: valid_pubinp,
81+
wire_c: new_wire,
82+
gate_type: crate::GateType::And,
83+
});
84+
and_all_wires = new_wire;
85+
});
86+
and_all_wires
87+
};
88+
89+
// Verify that all group elements of input proof include valid base field elements
90+
let is_valid_fq = {
91+
let elems = [
92+
&a.x, &a.y, &a.z, &b.x.0[0], &b.x.0[1], &b.y.0[0], &b.y.0[1], &b.z.0[0], &b.z.0[1],
93+
&c.x, &c.y, &c.z,
94+
];
95+
let mut and_all_wires = TRUE_WIRE;
96+
elems.iter().for_each(|pubinp| {
97+
let r: BigUint = ark_bn254::Fq::MODULUS.into();
98+
let valid_fq = bigint::less_than_constant(circuit, pubinp, &r);
99+
let new_wire = circuit.issue_wire();
100+
circuit.add_gate(crate::Gate {
101+
wire_a: and_all_wires,
102+
wire_b: valid_fq,
103+
wire_c: new_wire,
104+
gate_type: crate::GateType::And,
105+
});
106+
and_all_wires = new_wire;
107+
});
108+
and_all_wires
109+
};
75110

76-
let tmp0 = circuit.issue_wire();
77-
let tmp1 = circuit.issue_wire();
111+
let is_on_curve = {
112+
let a_is_on_curve = G1Projective::is_on_curve(circuit, a);
113+
let b_is_on_curve = G2Projective::is_on_curve(circuit, b);
114+
let c_is_on_curve = G1Projective::is_on_curve(circuit, c);
115+
116+
// valid group check
117+
let tmp0 = circuit.issue_wire();
118+
let is_on_curve = circuit.issue_wire();
119+
circuit.add_gate(crate::Gate {
120+
wire_a: a_is_on_curve,
121+
wire_b: b_is_on_curve,
122+
wire_c: tmp0,
123+
gate_type: crate::GateType::And,
124+
});
125+
circuit.add_gate(crate::Gate {
126+
wire_a: tmp0,
127+
wire_b: c_is_on_curve,
128+
wire_c: is_on_curve,
129+
gate_type: crate::GateType::And,
130+
});
131+
is_on_curve
132+
};
133+
134+
// valid fq and fr
135+
let is_valid_field = circuit.issue_wire();
78136
circuit.add_gate(crate::Gate {
79-
wire_a: a_is_on_curve,
80-
wire_b: b_is_on_curve,
81-
wire_c: tmp0,
137+
wire_a: is_valid_fr,
138+
wire_b: is_valid_fq,
139+
wire_c: is_valid_field,
82140
gate_type: crate::GateType::And,
83141
});
142+
143+
// valid field and group check
144+
let is_valid_field_and_group = circuit.issue_wire();
84145
circuit.add_gate(crate::Gate {
85-
wire_a: tmp0,
86-
wire_b: c_is_on_curve,
87-
wire_c: tmp1,
146+
wire_a: is_valid_field,
147+
wire_b: is_on_curve,
148+
wire_c: is_valid_field_and_group,
88149
gate_type: crate::GateType::And,
89150
});
90-
tmp1
151+
is_valid_field_and_group
91152
};
92153

93154
// Standard verification with public inputs
@@ -135,7 +196,7 @@ pub fn groth16_verify<C: CircuitContext>(
135196
let valid = circuit.issue_wire();
136197
circuit.add_gate(crate::Gate {
137198
wire_a: finexp_match,
138-
wire_b: proof_is_on_curve,
199+
wire_b: is_valid_field_and_group,
139200
wire_c: valid,
140201
gate_type: crate::GateType::And,
141202
});

0 commit comments

Comments
 (0)