Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit 0768ce3

Browse files
authored
Merge pull request #5307 from paritytech/eip-212
EIP-212 (bn128 curve pairing)
2 parents 70c82c0 + 7a1db08 commit 0768ce3

File tree

3 files changed

+182
-4
lines changed

3 files changed

+182
-4
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ethcore/res/ethereum/foundation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x7fffffffffffff", "pricing": { "modexp": { "divisor": 20 } } } },
194194
"0000000000000000000000000000000000000006": { "builtin": { "name": "bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
195195
"0000000000000000000000000000000000000007": { "builtin": { "name": "bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
196+
"0000000000000000000000000000000000000008": { "builtin": { "name": "bn128_pairing", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
196197
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
197198
"balance": "1337000000000000000000"
198199
},

ethcore/src/builtin.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ fn ethereum_builtin(name: &str) -> Box<Impl> {
158158
"modexp" => Box::new(ModexpImpl) as Box<Impl>,
159159
"bn128_add" => Box::new(Bn128AddImpl) as Box<Impl>,
160160
"bn128_mul" => Box::new(Bn128MulImpl) as Box<Impl>,
161+
"bn128_pairing" => Box::new(Bn128PairingImpl) as Box<Impl>,
161162
_ => panic!("invalid builtin name: {}", name),
162163
}
163164
}
@@ -191,6 +192,9 @@ struct Bn128AddImpl;
191192
#[derive(Debug)]
192193
struct Bn128MulImpl;
193194

195+
#[derive(Debug)]
196+
struct Bn128PairingImpl;
197+
194198
impl Impl for Identity {
195199
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
196200
output.write(0, input);
@@ -393,11 +397,109 @@ impl Impl for Bn128MulImpl {
393397
}
394398
}
395399

400+
mod bn128_gen {
401+
use bn::{AffineG1, AffineG2, Fq, Fq2, G1, G2, Gt, pairing};
402+
403+
lazy_static! {
404+
pub static ref P1: G1 = G1::from(AffineG1::new(
405+
Fq::from_str("1").expect("1 is a valid field element"),
406+
Fq::from_str("2").expect("2 is a valid field element"),
407+
).expect("Generator P1(1, 2) is a valid curve point"));
408+
}
409+
410+
lazy_static! {
411+
pub static ref P2: G2 = G2::from(AffineG2::new(
412+
Fq2::new(
413+
Fq::from_str("10857046999023057135944570762232829481370756359578518086990519993285655852781")
414+
.expect("a valid field element"),
415+
Fq::from_str("11559732032986387107991004021392285783925812861821192530917403151452391805634")
416+
.expect("a valid field element"),
417+
),
418+
Fq2::new(
419+
Fq::from_str("8495653923123431417604973247489272438418190587263600148770280649306958101930")
420+
.expect("a valid field element"),
421+
Fq::from_str("4082367875863433681332203403145435568316851327593401208105741076214120093531")
422+
.expect("a valid field element"),
423+
),
424+
).expect("the generator P2(10857046999023057135944570762232829481370756359578518086990519993285655852781 + 11559732032986387107991004021392285783925812861821192530917403151452391805634i, 8495653923123431417604973247489272438418190587263600148770280649306958101930 + 4082367875863433681332203403145435568316851327593401208105741076214120093531i) is a valid curve point"));
425+
}
426+
427+
lazy_static! {
428+
pub static ref P1_P2_PAIRING: Gt = pairing(P1.clone(), P2.clone());
429+
}
430+
}
431+
432+
impl Impl for Bn128PairingImpl {
433+
/// Can fail if:
434+
/// - input length is not a multiple of 192
435+
/// - any of odd points does not belong to bn128 curve
436+
/// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1)
437+
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
438+
use bn::{AffineG1, AffineG2, Fq, Fq2, pairing, G1, G2, Gt};
439+
440+
let elements = input.len() / 192; // (a, b_a, b_b - each 64-byte affine coordinates)
441+
if input.len() % 192 != 0 {
442+
return Err("Invalid input length, must be multiple of 192 (3 * (32*2))".into())
443+
}
444+
let ret_val = if input.len() == 0 {
445+
U256::one()
446+
} else {
447+
let mut vals = Vec::new();
448+
for idx in 0..elements {
449+
let a_x = Fq::from_slice(&input[idx*192..idx*192+32])
450+
.map_err(|_| Error::from("Invalid a argument x coordinate"))?;
451+
452+
let a_y = Fq::from_slice(&input[idx*192+32..idx*192+64])
453+
.map_err(|_| Error::from("Invalid a argument y coordinate"))?;
454+
455+
let b_b_x = Fq::from_slice(&input[idx*192+64..idx*192+96])
456+
.map_err(|_| Error::from("Invalid b argument imaginary coeff x coordinate"))?;
457+
458+
let b_b_y = Fq::from_slice(&input[idx*192+96..idx*192+128])
459+
.map_err(|_| Error::from("Invalid b argument imaginary coeff y coordinate"))?;
460+
461+
let b_a_x = Fq::from_slice(&input[idx*192+128..idx*192+160])
462+
.map_err(|_| Error::from("Invalid b argument real coeff x coordinate"))?;
463+
464+
let b_a_y = Fq::from_slice(&input[idx*192+160..idx*192+192])
465+
.map_err(|_| Error::from("Invalid b argument real coeff y coordinate"))?;
466+
467+
vals.push((
468+
G1::from(
469+
AffineG1::new(a_x, a_y).map_err(|_| Error::from("Invalid a argument - not on curve"))?
470+
),
471+
G2::from(
472+
AffineG2::new(
473+
Fq2::new(b_a_x, b_a_y),
474+
Fq2::new(b_b_x, b_b_y),
475+
).map_err(|_| Error::from("Invalid b argument - not on curve"))?
476+
),
477+
));
478+
};
479+
480+
let mul = vals.into_iter().fold(Gt::one(), |s, (a, b)| s * pairing(a, b));
481+
482+
if mul == *bn128_gen::P1_P2_PAIRING {
483+
U256::one()
484+
} else {
485+
U256::zero()
486+
}
487+
};
488+
489+
let mut buf = [0u8; 32];
490+
ret_val.to_big_endian(&mut buf);
491+
output.write(0, &buf);
492+
493+
Ok(())
494+
}
495+
}
496+
396497
#[cfg(test)]
397498
mod tests {
398499
use super::{Builtin, Linear, ethereum_builtin, Pricer, Modexp};
399500
use ethjson;
400501
use util::{U256, BytesRef};
502+
use rustc_serialize::hex::FromHex;
401503

402504
#[test]
403505
fn identity() {
@@ -713,7 +815,82 @@ mod tests {
713815
assert!(res.is_err(), "There should be built-in error here");
714816
}
715817
}
818+
819+
fn builtin_pairing() -> Builtin {
820+
Builtin {
821+
pricer: Box::new(Linear { base: 0, word: 0 }),
822+
native: ethereum_builtin("bn128_pairing"),
823+
activate_at: 0,
824+
}
825+
}
826+
827+
fn empty_test(f: Builtin, expected: Vec<u8>) {
828+
let mut empty = [0u8; 0];
829+
let input = BytesRef::Fixed(&mut empty);
830+
831+
let mut output = vec![0u8; expected.len()];
832+
833+
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
834+
assert_eq!(output, expected);
835+
}
836+
837+
fn error_test(f: Builtin, input: &[u8], msg_contains: Option<&str>) {
838+
let mut output = vec![0u8; 64];
839+
let res = f.execute(input, &mut BytesRef::Fixed(&mut output[..]));
840+
if let Some(msg) = msg_contains {
841+
if let Err(e) = res {
842+
if !e.0.contains(msg) {
843+
panic!("There should be error containing '{}' here, but got: '{}'", msg, e.0);
844+
}
845+
}
846+
} else {
847+
assert!(res.is_err(), "There should be built-in error here");
848+
}
849+
}
850+
851+
fn bytes(s: &'static str) -> Vec<u8> {
852+
FromHex::from_hex(s).expect("static str should contain valid hex bytes")
853+
}
716854

855+
#[test]
856+
fn bn128_pairing_empty() {
857+
// should not fail, because empty input is a valid input of 0 elements
858+
empty_test(
859+
builtin_pairing(),
860+
bytes("0000000000000000000000000000000000000000000000000000000000000001"),
861+
);
862+
}
863+
864+
#[test]
865+
fn bn128_pairing_notcurve() {
866+
// should fail - point not on curve
867+
error_test(
868+
builtin_pairing(),
869+
&bytes("\
870+
1111111111111111111111111111111111111111111111111111111111111111\
871+
1111111111111111111111111111111111111111111111111111111111111111\
872+
1111111111111111111111111111111111111111111111111111111111111111\
873+
1111111111111111111111111111111111111111111111111111111111111111\
874+
1111111111111111111111111111111111111111111111111111111111111111\
875+
1111111111111111111111111111111111111111111111111111111111111111"
876+
),
877+
Some("not on curve"),
878+
);
879+
}
880+
881+
#[test]
882+
fn bn128_pairing_fragmented() {
883+
// should fail - input length is invalid
884+
error_test(
885+
builtin_pairing(),
886+
&bytes("\
887+
1111111111111111111111111111111111111111111111111111111111111111\
888+
1111111111111111111111111111111111111111111111111111111111111111\
889+
111111111111111111111111111111"
890+
),
891+
Some("Invalid input length"),
892+
);
893+
}
717894

718895
#[test]
719896
#[should_panic]

0 commit comments

Comments
 (0)