Skip to content

Commit 76832b8

Browse files
authored
Merge pull request #24 from ethereumjs/ethbn
Rewrite using ethereum-bn128.rs
2 parents 0a4a831 + 981a4a5 commit 76832b8

File tree

4 files changed

+47
-221
lines changed

4 files changed

+47
-221
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ authors = ["holgerd77 <[email protected]>",
77
publish = false
88

99
[dependencies]
10-
bn = { git = "https://github.com/paritytech/bn", default-features = false }
10+
ethereum-bn128 = { git = "https://github.com/ewasm/ethereum-bn128.rs" }
11+
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
1112
rustc-hex = "1.0"

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
[![Build Status](https://img.shields.io/travis/ethereumjs/rustbn.js.svg?branch=master&style=flat-square)](https://travis-ci.org/ethereumjs/rustbn.js)
33
[![Gitter](https://img.shields.io/gitter/room/ethereum/ethereumjs-lib.svg?style=flat-square)](https://gitter.im/ethereum/ethereumjs-lib) or #ethereumjs on freenode
44

5-
Rust to Javascript compile of the [Parity fork](https://github.com/paritytech/bn) of the [Zcash bn
5+
Rust to Javascript/Webassembly compilation of [ethereum-bn128.rs](https://github.com/ewasm/ethereum-bn128.rs).
6+
7+
Internally it uses the [Parity fork](https://github.com/paritytech/bn) of the [Zcash bn
68
pairing cryptography library](https://github.com/zcash/bn), implementing an efficient bilinear pairing on the Barreto-Naehrig (BN) curve.
79

810
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).

lib/index.asm.js

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

src/main.rs

Lines changed: 35 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,255 +1,78 @@
1-
extern crate bn;
1+
extern crate ethereum_bn128;
2+
extern crate parity_bytes as bytes;
23
extern crate rustc_hex;
34

45
use std::os::raw::c_char;
56
use std::ffi::CStr;
67

78
use rustc_hex::FromHex;
89
use rustc_hex::ToHex;
9-
use std::io::{self, Read};
1010

11-
#[derive(Debug)]
12-
pub struct Error(pub &'static str);
13-
14-
impl From<&'static str> for Error {
15-
fn from(val: &'static str) -> Self {
16-
Error(val)
17-
}
18-
}
19-
20-
fn read_fr(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::Fr, Error> {
21-
use bn::Fr;
22-
let mut buf = [0u8; 32];
23-
reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed");
24-
Fr::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid field element"))
25-
}
26-
27-
28-
fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Error> {
29-
use bn::{Fq, AffineG1, G1, Group};
30-
31-
let mut buf = [0u8; 32];
32-
33-
reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed");
34-
let px = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point x coordinate"))?;
35-
36-
reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed");
37-
let py = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point y coordinate"))?;
38-
39-
Ok(
40-
if px == Fq::zero() && py == Fq::zero() {
41-
G1::zero()
42-
} else {
43-
AffineG1::new(px, py).map_err(|_| Error::from("Invalid curve point"))?.into()
44-
}
45-
)
46-
}
11+
use bytes::BytesRef;
4712

4813
#[no_mangle]
4914
pub fn ec_mul(input_hex_ptr: *const c_char) -> *const c_char {
50-
use bn::AffineG1;
51-
5215
let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) };
5316
let input_str: &str = input_hex.to_str().unwrap();
5417
let input_parsed = FromHex::from_hex(input_str).unwrap();
55-
let mut padded_input = input_parsed.chain(io::repeat(0));
5618

57-
let p1;
58-
match read_point(&mut padded_input) {
59-
Ok(p) => { p1 = p; },
60-
Err(_) => { return "\0".as_ptr() as *const c_char }
61-
}
62-
63-
let fr;
64-
match read_fr(&mut padded_input) {
65-
Ok(f) => { fr = f; },
66-
Err(_) => { return "\0".as_ptr() as *const c_char }
67-
}
68-
69-
let mut ecmul_output_buf = [0u8; 64];
70-
if let Some(sum) = AffineG1::from_jacobian(p1 * fr) {
71-
// point not at infinity
72-
sum.x().to_big_endian(&mut ecmul_output_buf[0..32]).expect("Cannot fail since 0..32 is 32-byte length");
73-
sum.y().to_big_endian(&mut ecmul_output_buf[32..64]).expect("Cannot fail since 32..64 is 32-byte length");;
19+
let mut output = vec![0u8; 64];
20+
match ethereum_bn128::bn128_mul(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) {
21+
Ok(_) => {
22+
let mut output_hex = output.to_hex();
23+
output_hex.push_str("\0");
24+
return output_hex.as_ptr() as *const c_char
25+
}
26+
Err(_) => {
27+
return "\0".as_ptr() as *const c_char
28+
}
7429
}
75-
76-
let mut ec_mul_output_str = ecmul_output_buf.to_hex();
77-
ec_mul_output_str.push_str("\0");
78-
return ec_mul_output_str.as_ptr() as *const c_char
7930
}
8031

81-
8232
#[no_mangle]
8333
pub fn ec_add(input_hex_ptr: *const c_char) -> *const c_char {
84-
use bn::AffineG1;
85-
8634
let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) };
8735
let input_str: &str = input_hex.to_str().unwrap();
8836
let input_parsed = FromHex::from_hex(input_str).unwrap();
89-
let mut padded_input = input_parsed.chain(io::repeat(0));
90-
91-
let mut padded_buf = [0u8; 128];
92-
padded_input.read_exact(&mut padded_buf[..]).expect("reading from zero-extended memory cannot fail; qed");
93-
94-
let point1 = &padded_buf[0..64];
95-
let point2 = &padded_buf[64..128];
96-
97-
let mut point1_padded = point1.chain(io::repeat(0));
98-
let mut point2_padded = point2.chain(io::repeat(0));
99-
100-
let p1;
101-
match read_point(&mut point1_padded) {
102-
Ok(p) => {
103-
p1 = p;
104-
},
105-
Err(_) => { return "\0".as_ptr() as *const c_char }
106-
}
107-
108-
match read_point(&mut point2_padded) {
109-
Ok(p) => {
110-
let p2 = p;
111-
let mut ecadd_output_buf = [0u8; 64];
112-
if let Some(sum) = AffineG1:: from_jacobian(p1 + p2) {
113-
sum.x().to_big_endian(&mut ecadd_output_buf[0..32]).expect("Cannot fail since 0..32 is 32-byte length");
114-
sum.y().to_big_endian(&mut ecadd_output_buf[32..64]).expect("Cannot fail since 32..64 is 32-byte length");;
115-
}
116-
let mut ec_add_output_str = ecadd_output_buf.to_hex();
117-
ec_add_output_str.push_str("\0");
118-
return ec_add_output_str.as_ptr() as *const c_char
119-
},
120-
Err(_) => { return "\0".as_ptr() as *const c_char }
121-
}
12237

38+
let mut output = vec![0u8; 64];
39+
match ethereum_bn128::bn128_add(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) {
40+
Ok(_) => {
41+
let mut output_hex = output.to_hex();
42+
output_hex.push_str("\0");
43+
return output_hex.as_ptr() as *const c_char
44+
}
45+
Err(_) => {
46+
return "\0".as_ptr() as *const c_char
47+
}
48+
}
12349
}
12450

12551
#[no_mangle]
12652
pub fn ec_pairing(input_hex_ptr: *const c_char) -> *const c_char {
127-
use bn::{Fq, Fq2, G1, G2, Gt, AffineG1, AffineG2, Group, pairing};
128-
12953
let input_hex = unsafe { CStr::from_ptr(input_hex_ptr) };
13054
let input_str: &str = input_hex.to_str().unwrap();
131-
let input = FromHex::from_hex(input_str).unwrap();
132-
//println!("input: {:?}", input);
133-
134-
let elements = input.len() / 192;
135-
136-
if input.len() % 192 != 0 {
137-
return "\0".as_ptr() as *const c_char;
138-
}
139-
140-
let ret_val = if input.len() == 0 {
141-
bn::arith::U256::one()
142-
} else {
143-
let mut vals = Vec::new();
144-
145-
for idx in 0..elements {
146-
let x_1;
147-
match Fq::from_slice(&input[idx*192..idx*192+32]) {
148-
Ok(fq) => { x_1 = fq },
149-
Err(_) => { return "\0".as_ptr() as *const c_char }
150-
}
151-
152-
let y_1;
153-
match Fq::from_slice(&input[idx*192+32..idx*192+64]) {
154-
Ok(fq) => { y_1 = fq },
155-
Err(_) => { return "\0".as_ptr() as *const c_char }
156-
}
157-
158-
let x2_i;
159-
match Fq::from_slice(&input[idx*192+64..idx*192+96]) {
160-
Ok(fq) => { x2_i = fq },
161-
Err(_) => { return "\0".as_ptr() as *const c_char }
162-
}
163-
164-
let x2_r;
165-
match Fq::from_slice(&input[idx*192+96..idx*192+128]) {
166-
Ok(fq) => { x2_r = fq },
167-
Err(_) => { return "\0".as_ptr() as *const c_char }
168-
}
169-
170-
let y2_i;
171-
match Fq::from_slice(&input[idx*192+128..idx*192+160]) {
172-
Ok(fq) => { y2_i = fq },
173-
Err(_) => { return "\0".as_ptr() as *const c_char }
174-
}
175-
176-
let y2_r;
177-
match Fq::from_slice(&input[idx*192+160..idx*192+192]) {
178-
Ok(fq) => { y2_r = fq },
179-
Err(_) => { return "\0".as_ptr() as *const c_char }
180-
}
181-
182-
//println!("creating g1_point with x1 and y1...");
183-
//println!("x1: {:?} y1: {:?}", x_1, y_1);
184-
185-
let g1_point;
186-
if x_1 == Fq::zero() && y_1 == Fq::zero() {
187-
g1_point = G1::zero();
188-
} else {
189-
match AffineG1::new(x_1, y_1) {
190-
Ok(ap) => {
191-
let g1_affine_point = ap;
192-
g1_point = G1::from(g1_affine_point);
193-
},
194-
Err(_) => { return "\0".as_ptr() as *const c_char }
195-
}
196-
}
197-
198-
/*
199-
let mut g1_point_x_buf = [0u8; 32];
200-
let mut g1_point_y_buf = [0u8; 32];
201-
g1_point.x().to_big_endian(&mut g1_point_x_buf[0..32]);
202-
println!("g1_point.x(): {:?}", g1_point_x_buf.to_hex());
203-
g1_point.y().to_big_endian(&mut g1_point_y_buf[0..32]);
204-
println!("g1_point.y(): {:?}", g1_point_y_buf.to_hex());
205-
*/
206-
207-
let fq2_x = Fq2::new(x2_r, x2_i);
208-
let fq2_y = Fq2::new(y2_r, y2_i);
209-
210-
let g2_point;
211-
if x2_r.is_zero() && x2_i.is_zero() && y2_r.is_zero() && y2_i.is_zero() {
212-
g2_point = G2::zero();
213-
} else {
214-
match AffineG2::new(fq2_x, fq2_y) {
215-
Ok (ap) => {
216-
let g2_affine_point = ap;
217-
g2_point = G2::from(g2_affine_point);
218-
},
219-
Err(_) => { return "\0".as_ptr() as *const c_char }
220-
}
221-
}
222-
223-
vals.push((g1_point, g2_point));
224-
};
55+
let input_parsed = FromHex::from_hex(input_str).unwrap();
22556

226-
let mul = vals.into_iter().fold(Gt::one(), |s, (a, b)| s * pairing(a, b));
227-
if mul == Gt::one() {
228-
bn::arith::U256::one()
229-
} else {
230-
bn::arith::U256::zero()
57+
let mut output = vec![0u8; 32];
58+
match ethereum_bn128::bn128_pairing(&input_parsed[..], &mut BytesRef::Fixed(&mut output[..])) {
59+
Ok(_) => {
60+
let mut output_hex = output.to_hex();
61+
output_hex.push_str("\0");
62+
return output_hex.as_ptr() as *const c_char
23163
}
232-
};
233-
234-
let mut ec_pairing_output_buf = [0u8; 32];
235-
ret_val.to_big_endian(&mut ec_pairing_output_buf).expect("Cannot fail since buf is 32-byte length");
236-
let mut ec_pairing_output_str = ec_pairing_output_buf.to_hex();
237-
//println!("ec_pairing_output_str: {:?}", ec_pairing_output_str);
238-
239-
ec_pairing_output_str.push_str("\0");
240-
return ec_pairing_output_str.as_ptr() as *const c_char
64+
Err(_) => {
65+
return "\0".as_ptr() as *const c_char
66+
}
67+
}
24168
}
24269

243-
244-
24570
extern {
24671
fn emscripten_exit_with_live_runtime();
24772
}
24873

249-
25074
fn main() {
25175
unsafe {
25276
emscripten_exit_with_live_runtime();
25377
}
254-
25578
}

0 commit comments

Comments
 (0)