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

Commit 89e7511

Browse files
authored
ec pairing simplify (#873)
* wip testing * wip compilation * fix: ecc circuit can handle all inputs * if all pairs are zero then success == true * chore: refactor
1 parent 887f60c commit 89e7511

File tree

5 files changed

+380
-318
lines changed

5 files changed

+380
-318
lines changed

bus-mapping/src/circuit_input_builder/execution.rs

Lines changed: 48 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{
44
marker::PhantomData,
5-
ops::{Add, Mul},
5+
ops::{Add, Mul, Neg},
66
};
77

88
use crate::{
@@ -21,7 +21,11 @@ use ethers_core::k256::elliptic_curve::subtle::CtOption;
2121
use gadgets::impl_expr;
2222
use halo2_proofs::{
2323
arithmetic::{CurveAffine, Field},
24-
halo2curves::bn256::{Fq, Fq2, Fr, G1Affine, G2Affine},
24+
circuit::Value,
25+
halo2curves::{
26+
bn256::{Fq, Fq2, Fr, G1Affine, G2Affine},
27+
group::prime::PrimeCurveAffine,
28+
},
2529
plonk::Expression,
2630
};
2731

@@ -1175,6 +1179,28 @@ impl EcPairingPair {
11751179
.collect()
11761180
}
11771181

1182+
/// ...
1183+
pub fn to_g1_affine_tuple(&self) -> (Value<Fq>, Value<Fq>) {
1184+
(
1185+
Value::known(Fq::from_bytes(&self.g1_point.0.to_le_bytes()).unwrap()),
1186+
Value::known(Fq::from_bytes(&self.g1_point.1.to_le_bytes()).unwrap()),
1187+
)
1188+
}
1189+
1190+
/// ...
1191+
pub fn to_g2_affine_tuple(&self) -> (Value<Fq2>, Value<Fq2>) {
1192+
(
1193+
Value::known(Fq2 {
1194+
c0: Fq::from_bytes(&self.g2_point.1.to_le_bytes()).unwrap(),
1195+
c1: Fq::from_bytes(&self.g2_point.0.to_le_bytes()).unwrap(),
1196+
}),
1197+
Value::known(Fq2 {
1198+
c0: Fq::from_bytes(&self.g2_point.3.to_le_bytes()).unwrap(),
1199+
c1: Fq::from_bytes(&self.g2_point.2.to_le_bytes()).unwrap(),
1200+
}),
1201+
)
1202+
}
1203+
11781204
/// Returns the big-endian representation of the G2 point in the pair.
11791205
pub fn g2_bytes_be(&self) -> Vec<u8> {
11801206
std::iter::empty()
@@ -1199,69 +1225,16 @@ impl EcPairingPair {
11991225
.collect()
12001226
}
12011227

1202-
/// Padding pair for ECC circuit. The pairing check is done with a constant number
1203-
/// `N_PAIRING_PER_OP` of (G1, G2) pairs. The ECC circuit under the hood uses halo2-lib to
1204-
/// compute the multi-miller loop, which allows `(G1::Infinity, G2::Generator)` pair to skip
1205-
/// the loop for that pair. So in case the EVM inputs are less than `N_PAIRING_PER_OP` we pad
1206-
/// the ECC Circuit inputs by this pair. Any EVM input of `(G1::Infinity, G2)` or
1207-
/// `(G1, G2::Infinity)` is also transformed into `(G1::Infinity, G2::Generator)`.
1208-
pub fn ecc_padding() -> Self {
1209-
Self {
1210-
g1_point: (U256::zero(), U256::zero()),
1211-
g2_point: (
1212-
U256([
1213-
0x97e485b7aef312c2,
1214-
0xf1aa493335a9e712,
1215-
0x7260bfb731fb5d25,
1216-
0x198e9393920d483a,
1217-
]),
1218-
U256([
1219-
0x46debd5cd992f6ed,
1220-
0x674322d4f75edadd,
1221-
0x426a00665e5c4479,
1222-
0x1800deef121f1e76,
1223-
]),
1224-
U256([
1225-
0x55acdadcd122975b,
1226-
0xbc4b313370b38ef3,
1227-
0xec9e99ad690c3395,
1228-
0x090689d0585ff075,
1229-
]),
1230-
U256([
1231-
0x4ce6cc0166fa7daa,
1232-
0xe3d1e7690c43d37b,
1233-
0x4aab71808dcb408f,
1234-
0x12c85ea5db8c6deb,
1235-
]),
1236-
),
1237-
}
1238-
}
1239-
1240-
/// Padding pair for EVM circuit. The pairing check is done with a constant number
1228+
/// Padding pair for EcPairing operation. The pairing check is done with a constant number
12411229
/// `N_PAIRING_PER_OP` of (G1, G2) pairs. In case EVM inputs are less in number, we pad them
12421230
/// with `(G1::Infinity, G2::Infinity)` for simplicity.
1243-
pub fn evm_padding() -> Self {
1231+
pub fn padding_pair() -> Self {
12441232
Self {
12451233
g1_point: (U256::zero(), U256::zero()),
12461234
g2_point: (U256::zero(), U256::zero(), U256::zero(), U256::zero()),
12471235
}
12481236
}
12491237

1250-
/// Whether or not we swap the EVM pair with ECC pair. We do this iff:
1251-
/// - G1 is (0, 0)
1252-
/// - G2 is (0, 0, 0, 0)
1253-
///
1254-
/// because for the above case, we have:
1255-
/// - (G1::identity, G2::identity) as inputs from the EVM.
1256-
/// - (G1::identity, G2::generator) as inputs to ECC Circuit.
1257-
pub fn swap(&self) -> bool {
1258-
(self.g1_point.0.is_zero() && self.g1_point.1.is_zero())
1259-
&& (self.g2_point.0.is_zero()
1260-
&& self.g2_point.1.is_zero()
1261-
&& self.g2_point.2.is_zero()
1262-
&& self.g2_point.3.is_zero())
1263-
}
1264-
12651238
fn is_valid(&self) -> bool {
12661239
let fq_from_u256 = |buf: &mut [u8; 32], u256: U256| -> CtOption<Fq> {
12671240
u256.to_little_endian(buf);
@@ -1353,6 +1326,24 @@ impl EcPairingOp {
13531326
pub fn is_valid(&self) -> bool {
13541327
self.pairs.iter().all(|pair| pair.is_valid())
13551328
}
1329+
1330+
/// Dummy pairing op that satisfies the pairing check.
1331+
pub fn dummy_pairing_check_ok() -> Self {
1332+
let g1 = G1Affine::from(G1Affine::generator() * Fr::from(2));
1333+
let g1_neg = g1.neg();
1334+
let g2 = G2Affine::from(G2Affine::generator() * Fr::from(3));
1335+
let other_g1 = G1Affine::from(G1Affine::generator() * Fr::from(6));
1336+
let other_g2 = G2Affine::generator();
1337+
Self {
1338+
pairs: [
1339+
EcPairingPair::new(g1_neg, g2),
1340+
EcPairingPair::new(other_g1, other_g2),
1341+
EcPairingPair::new(G1Affine::identity(), G2Affine::generator()),
1342+
EcPairingPair::new(G1Affine::identity(), G2Affine::generator()),
1343+
],
1344+
output: 1.into(),
1345+
}
1346+
}
13561347
}
13571348

13581349
/// Event representating an exponentiation `a ^ b == d (mod m)` in precompile modexp.
Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use eth_types::U256;
2+
use itertools::Itertools;
23

34
use crate::{
45
circuit_input_builder::{
@@ -33,7 +34,7 @@ pub(crate) fn opt_data(
3334
);
3435
}
3536

36-
let (op, aux_data) = if let Some(input) = input_bytes {
37+
let op = if let Some(input) = input_bytes {
3738
if (input.len() > N_PAIRING_PER_OP * N_BYTES_PER_PAIR)
3839
|| (input.len() % N_BYTES_PER_PAIR != 0)
3940
{
@@ -49,11 +50,11 @@ pub(crate) fn opt_data(
4950
&& input.len() <= N_PAIRING_PER_OP * N_BYTES_PER_PAIR
5051
);
5152
// process input bytes.
52-
let (mut ecc_pairs, mut evm_pairs): (Vec<EcPairingPair>, Vec<EcPairingPair>) = input
53+
let mut pairs = input
5354
.chunks_exact(N_BYTES_PER_PAIR)
5455
.map(|chunk| {
5556
// process <= 192 bytes chunk at a time.
56-
let evm_circuit_pair = EcPairingPair {
57+
EcPairingPair {
5758
g1_point: (
5859
U256::from_big_endian(&chunk[0x00..0x20]),
5960
U256::from_big_endian(&chunk[0x20..0x40]),
@@ -64,47 +65,27 @@ pub(crate) fn opt_data(
6465
U256::from_big_endian(&chunk[0x80..0xA0]),
6566
U256::from_big_endian(&chunk[0xA0..0xC0]),
6667
),
67-
};
68-
// if EVM inputs were 0s.
69-
let ecc_circuit_pair = if evm_circuit_pair.swap() {
70-
EcPairingPair::ecc_padding()
71-
} else {
72-
evm_circuit_pair
73-
};
74-
(ecc_circuit_pair, evm_circuit_pair)
68+
}
7569
})
76-
.unzip();
70+
.collect_vec();
7771
// pad the pairs to make them of fixed size: N_PAIRING_PER_OP.
78-
ecc_pairs.resize(N_PAIRING_PER_OP, EcPairingPair::ecc_padding());
79-
evm_pairs.resize(N_PAIRING_PER_OP, EcPairingPair::evm_padding());
80-
(
81-
EcPairingOp {
82-
pairs: <[_; N_PAIRING_PER_OP]>::try_from(ecc_pairs).unwrap(),
83-
output: pairing_check,
84-
},
85-
EcPairingAuxData(EcPairingOp {
86-
pairs: <[_; N_PAIRING_PER_OP]>::try_from(evm_pairs).unwrap(),
87-
output: pairing_check,
88-
}),
89-
)
72+
pairs.resize(N_PAIRING_PER_OP, EcPairingPair::padding_pair());
73+
EcPairingOp {
74+
pairs: <[_; N_PAIRING_PER_OP]>::try_from(pairs).unwrap(),
75+
output: pairing_check,
76+
}
9077
} else {
91-
// if no input bytes.
92-
let ecc_pairs = [EcPairingPair::ecc_padding(); N_PAIRING_PER_OP];
93-
let evm_pairs = [EcPairingPair::evm_padding(); N_PAIRING_PER_OP];
94-
(
95-
EcPairingOp {
96-
pairs: ecc_pairs,
97-
output: pairing_check,
98-
},
99-
EcPairingAuxData(EcPairingOp {
100-
pairs: evm_pairs,
101-
output: pairing_check,
102-
}),
103-
)
78+
let pairs = [EcPairingPair::padding_pair(); N_PAIRING_PER_OP];
79+
EcPairingOp {
80+
pairs,
81+
output: pairing_check,
82+
}
10483
};
10584

10685
(
107-
Some(PrecompileEvent::EcPairing(Box::new(op))),
108-
Some(PrecompileAuxData::EcPairing(Box::new(Ok(aux_data)))),
86+
Some(PrecompileEvent::EcPairing(Box::new(op.clone()))),
87+
Some(PrecompileAuxData::EcPairing(Box::new(Ok(
88+
EcPairingAuxData(op),
89+
)))),
10990
)
11091
}

0 commit comments

Comments
 (0)