diff --git a/Cargo.toml b/Cargo.toml index 1265b90..ee00e9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,6 @@ authors = ["holgerd77 ", publish = false [dependencies] -bn = { git = "https://github.com/cdetrio/bn", branch = "mont-repr-fix" } +ethereum-bn128 = { git = "https://github.com/ewasm/ethereum-bn128.rs" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } rustc-hex = "1.0" diff --git a/README.md b/README.md index 2708ddc..f120735 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ [![Build Status](https://img.shields.io/travis/ethereumjs/rustbn.js.svg?branch=master&style=flat-square)](https://travis-ci.org/ethereumjs/rustbn.js) [![Gitter](https://img.shields.io/gitter/room/ethereum/ethereumjs-lib.svg?style=flat-square)](https://gitter.im/ethereum/ethereumjs-lib) or #ethereumjs on freenode -Rust to Javascript compile of the [Parity fork](https://github.com/paritytech/bn) of the [Zcash bn +Rust to Javascript/Webassembly compilation of [ethereum-bn128.rs](https://github.com/ewasm/ethereum-bn128.rs). + +Internally it uses the [Parity fork](https://github.com/paritytech/bn) of the [Zcash bn pairing cryptography library](https://github.com/zcash/bn), implementing an efficient bilinear pairing on the Barreto-Naehrig (BN) curve. It implements helpers to support the functionality defined in [EIP-196](https://eips.ethereum.org/EIPS/eip-196) and [EIP-197](https://eips.ethereum.org/EIPS/eip-197). diff --git a/src/main.rs b/src/main.rs index 1273f94..1cc55c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -extern crate bn; +extern crate ethereum_bn128; +extern crate parity_bytes as bytes; extern crate rustc_hex; use std::os::raw::c_char; @@ -6,250 +7,72 @@ use std::ffi::CStr; use rustc_hex::FromHex; use rustc_hex::ToHex; -use std::io::{self, Read}; -#[derive(Debug)] -pub struct Error(pub &'static str); - -impl From<&'static str> for Error { - fn from(val: &'static str) -> Self { - Error(val) - } -} - -fn read_fr(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::Fr, Error> { - use bn::Fr; - let mut buf = [0u8; 32]; - reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - Fr::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid field element")) -} - - -fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Error> { - use bn::{Fq, AffineG1, G1, Group}; - - let mut buf = [0u8; 32]; - - reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - let px = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point x coordinate"))?; - - reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - let py = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point y coordinate"))?; - - Ok( - if px == Fq::zero() && py == Fq::zero() { - G1::zero() - } else { - AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into() - } - ) -} +use bytes::BytesRef; #[no_mangle] pub fn ec_mul(input_hex_ptr: *const c_char) -> *const c_char { - use bn::AffineG1; - let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) }; let input_str: &str = input_hex.to_str().unwrap(); let input_parsed = FromHex::from_hex(input_str).unwrap(); - let mut padded_input = input_parsed.chain(io::repeat(0)); - let p1; - match read_point(&mut padded_input) { - Ok(p) => { p1 = p; }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let fr; - match read_fr(&mut padded_input) { - Ok(f) => { fr = f; }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let mut ecmul_output_buf = [0u8; 64]; - if let Some(sum) = AffineG1::from_jacobian(p1 * fr) { - // point not at infinity - sum.x().to_big_endian(&mut ecmul_output_buf[0..32]).expect("Cannot fail since 0..32 is 32-byte length"); - sum.y().to_big_endian(&mut ecmul_output_buf[32..64]).expect("Cannot fail since 32..64 is 32-byte length");; + let mut output = vec![0u8; 64]; + match ethereum_bn128::bn128_mul(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) { + Ok(_) => { + let mut output_hex = output.to_hex(); + output_hex.push_str("\0"); + return output_hex.as_ptr() as *const c_char + } + Err(_) => { + return "\0".as_ptr() as *const c_char + } } - - let mut ec_mul_output_str = ecmul_output_buf.to_hex(); - ec_mul_output_str.push_str("\0"); - return ec_mul_output_str.as_ptr() as *const c_char } - #[no_mangle] pub fn ec_add(input_hex_ptr: *const c_char) -> *const c_char { - use bn::AffineG1; - let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) }; let input_str: &str = input_hex.to_str().unwrap(); let input_parsed = FromHex::from_hex(input_str).unwrap(); - let mut padded_input = input_parsed.chain(io::repeat(0)); - - let mut padded_buf = [0u8; 128]; - padded_input.read_exact(&mut padded_buf[..]).expect("reading from zero-extended memory cannot fail; qed"); - - let point1 = &padded_buf[0..64]; - let point2 = &padded_buf[64..128]; - - let mut point1_padded = point1.chain(io::repeat(0)); - let mut point2_padded = point2.chain(io::repeat(0)); - - let p1; - match read_point(&mut point1_padded) { - Ok(p) => { - p1 = p; - }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - match read_point(&mut point2_padded) { - Ok(p) => { - let p2 = p; - let mut ecadd_output_buf = [0u8; 64]; - if let Some(sum) = AffineG1:: from_jacobian(p1 + p2) { - sum.x().to_big_endian(&mut ecadd_output_buf[0..32]).expect("Cannot fail since 0..32 is 32-byte length"); - sum.y().to_big_endian(&mut ecadd_output_buf[32..64]).expect("Cannot fail since 32..64 is 32-byte length");; - } - let mut ec_add_output_str = ecadd_output_buf.to_hex(); - ec_add_output_str.push_str("\0"); - return ec_add_output_str.as_ptr() as *const c_char - }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } + let mut output = vec![0u8; 64]; + match ethereum_bn128::bn128_add(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) { + Ok(_) => { + let mut output_hex = output.to_hex(); + output_hex.push_str("\0"); + return output_hex.as_ptr() as *const c_char + } + Err(_) => { + return "\0".as_ptr() as *const c_char + } + } } #[no_mangle] pub fn ec_pairing(input_hex_ptr: *const c_char) -> *const c_char { - use bn::{Fq, Fq2, G1, G2, Gt, AffineG1, AffineG2, Group, pairing}; - let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) }; let input_str: &str = input_hex.to_str().unwrap(); - let input = FromHex::from_hex(input_str).unwrap(); - //println!("input: {:?}", input); - - let elements = input.len() / 192; - - if input.len() % 192 != 0 { - return "\0".as_ptr() as *const c_char; - } - - let ret_val = if input.len() == 0 { - bn::arith::U256::one() - } else { - let mut vals = Vec::new(); - - for idx in 0..elements { - let x_1; - match Fq::from_slice(&input[idx*192..idx*192+32]) { - Ok(fq) => { x_1 = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let y_1; - match Fq::from_slice(&input[idx*192+32..idx*192+64]) { - Ok(fq) => { y_1 = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let x2_i; - match Fq::from_slice(&input[idx*192+64..idx*192+96]) { - Ok(fq) => { x2_i = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let x2_r; - match Fq::from_slice(&input[idx*192+96..idx*192+128]) { - Ok(fq) => { x2_r = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let y2_i; - match Fq::from_slice(&input[idx*192+128..idx*192+160]) { - Ok(fq) => { y2_i = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - let y2_r; - match Fq::from_slice(&input[idx*192+160..idx*192+192]) { - Ok(fq) => { y2_r = fq }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - - //println!("creating g1_point with x1 and y1..."); - //println!("x1: {:?} y1: {:?}", x_1, y_1); - - let g1_point; - if x_1 == Fq::zero() && y_1 == Fq::zero() { - g1_point = G1::zero(); - } else { - match AffineG1::new(x_1, y_1) { - Ok(ap) => { - let g1_affine_point = ap; - g1_point = G1::from(g1_affine_point); - }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - } - - /* - let mut g1_point_x_buf = [0u8; 32]; - let mut g1_point_y_buf = [0u8; 32]; - g1_point.x().to_big_endian(&mut g1_point_x_buf[0..32]); - println!("g1_point.x(): {:?}", g1_point_x_buf.to_hex()); - g1_point.y().to_big_endian(&mut g1_point_y_buf[0..32]); - println!("g1_point.y(): {:?}", g1_point_y_buf.to_hex()); - */ - - let fq2_x = Fq2::new(x2_r, x2_i); - let fq2_y = Fq2::new(y2_r, y2_i); - - let g2_point; - if x2_r.is_zero() && x2_i.is_zero() && y2_r.is_zero() && y2_i.is_zero() { - g2_point = G2::zero(); - } else { - match AffineG2::new(fq2_x, fq2_y) { - Ok (ap) => { - let g2_affine_point = ap; - g2_point = G2::from(g2_affine_point); - }, - Err(_) => { return "\0".as_ptr() as *const c_char } - } - } - - vals.push((g1_point, g2_point)); - }; + let input_parsed = FromHex::from_hex(input_str).unwrap(); - let mul = vals.into_iter().fold(Gt::one(), |s, (a, b)| s * pairing(a, b)); - if mul == Gt::one() { - bn::arith::U256::one() - } else { - bn::arith::U256::zero() + let mut output = vec![0u8; 32]; + match ethereum_bn128::bn128_pairing(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) { + Ok(_) => { + let mut output_hex = output.to_hex(); + output_hex.push_str("\0"); + return output_hex.as_ptr() as *const c_char } - }; - - let mut ec_pairing_output_buf = [0u8; 32]; - ret_val.to_big_endian(&mut ec_pairing_output_buf).expect("Cannot fail since buf is 32-byte length"); - let mut ec_pairing_output_str = ec_pairing_output_buf.to_hex(); - //println!("ec_pairing_output_str: {:?}", ec_pairing_output_str); - - ec_pairing_output_str.push_str("\0"); - return ec_pairing_output_str.as_ptr() as *const c_char + Err(_) => { + return "\0".as_ptr() as *const c_char + } + } } - - extern { fn emscripten_exit_with_live_runtime(); } - fn main() { unsafe { emscripten_exit_with_live_runtime(); } - }