diff --git a/Cargo.lock b/Cargo.lock index 42d6054e6..b92cbaed9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,7 +178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bn" version = "0.4.2" -source = "git+https://github.com/paritytech/bn#78cf02fd7b35e4a2398fedd96f68c92953badea7" +source = "git+https://github.com/paritytech/bn#7e513a84330f02603759e370f22af90c99e3e717" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 7de9409a0..112afbd97 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -112,7 +112,7 @@ impl Builtin { /// Simple forwarder for execute. pub fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - self.native.execute(input, output); + self.native.execute(input, output)?; Ok(()) } @@ -157,6 +157,8 @@ fn ethereum_builtin(name: &str) -> Box { "sha256" => Box::new(Sha256) as Box, "ripemd160" => Box::new(Ripemd160) as Box, "modexp" => Box::new(ModexpImpl) as Box, + "alt_bn128_add" => Box::new(Bn128AddImpl) as Box, + "alt_bn128_mul" => Box::new(Bn128MulImpl) as Box, _ => panic!("invalid builtin name: {}", name), } } @@ -326,25 +328,39 @@ impl Impl for ModexpImpl { impl Impl for Bn128AddImpl { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - use bn::{Fq, AffineG1, G1}; + use bn::{Fq, AffineG1, G1, Group}; let mut buf = [0u8; 32]; let mut next_coord = |reader: &mut io::Chain<&[u8], io::Repeat>| { reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - Fq::from_slice(&input[0..32]) + Fq::from_slice(&buf[0..32]) }; let mut padded_input = input.chain(io::repeat(0)); - let p1x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; - let p1y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; - let p1: G1 = AffineG1::new(p1x, p1y).into(); + let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; + let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; + let p1: G1 = if px == Fq::zero() && py == Fq::zero() { + G1::zero() + } else { + AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() + }; - let p2x = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 x coordinate"))?; - let p2y = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p2 y coordinate"))?; - let p2: G1 = AffineG1::new(p2x, p2y).into(); + let px = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 x coordinate"))?; + let py = next_coord(&mut padded_input).map_err(|_| Error::from("Invalid p1 y coordinate"))?; + let p2: G1 = if px == Fq::zero() && py == Fq::zero() { + G1::zero() + } else { + AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() + }; - let sum = AffineG1::from_jacobian(p1 + p2).expect("Sum of two valid points is a valid point also; qed"); + let mut write_buf = [0u8; 64]; + if let Some(sum) = AffineG1::from_jacobian(p1 + p2) { + // point not at infinity + sum.x().to_big_endian(&mut write_buf[0..32]); + sum.y().to_big_endian(&mut write_buf[32..64]); + } + output.write(0, &write_buf); Ok(()) } @@ -572,6 +588,51 @@ mod tests { } } + #[test] + fn alt_bn128_add() { + use rustc_serialize::hex::FromHex; + + let f = Builtin { + pricer: Box::new(Linear { base: 0, word: 0 }), + native: ethereum_builtin("alt_bn128_add"), + activate_at: 0, + }; + + // zero-points additions + { + let input = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + let mut output = vec![0u8; 64]; + let expected = FromHex::from_hex("\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ).unwrap(); + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail"); + assert_eq!(output, expected); + } + + // should fail - point not on curve + { + let input = FromHex::from_hex("\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111" + ).unwrap(); + + let mut output = vec![0u8; 64]; + + let res = f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])); + assert!(res.is_err(), "There should be built-in error here"); + } + } + #[test] #[should_panic] fn from_unknown_linear() {