From d01e48b8009c90ee0c15842d5f52e217abc86ffd Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 1 Aug 2016 20:55:36 -0600 Subject: [PATCH] Foundations of libsnark interaction and BN curve operation wrappers. --- .gitmodules | 3 + Cargo.lock | 20 +++++ Cargo.toml | 7 ++ libsnark | 1 + src/bnwrap.cpp | 62 +++++++++++++++ src/build.rs | 31 ++++++++ src/curve/g1.rs | 61 ++++++++++++++ src/curve/mod.rs | 201 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 10 ++- 9 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 160000 libsnark create mode 100644 src/bnwrap.cpp create mode 100644 src/build.rs create mode 100644 src/curve/g1.rs create mode 100644 src/curve/mod.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1a33193 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libsnark"] + path = libsnark + url = https://github.com/zcash/libsnark.git diff --git a/Cargo.lock b/Cargo.lock index d4cde19..c00b781 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,4 +1,24 @@ [root] name = "mpc" version = "0.0.1" +dependencies = [ + "gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 90eb071..2a6360f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,11 @@ authors = [ license = "MIT OR Apache-2.0" readme = "README.md" +build = "src/build.rs" + +[build-dependencies] +gcc = "0.3.*" + [dependencies] +libc = "0.2.*" +lazy_static = "0.1.*" diff --git a/libsnark b/libsnark new file mode 160000 index 0000000..a703148 --- /dev/null +++ b/libsnark @@ -0,0 +1 @@ +Subproject commit a7031481fd8d2360337321401fe8e24f0359317a diff --git a/src/bnwrap.cpp b/src/bnwrap.cpp new file mode 100644 index 0000000..a571e1e --- /dev/null +++ b/src/bnwrap.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" +#include +#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" +#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" +#include "algebra/curves/public_params.hpp" +#include "relations/arithmetic_programs/qap/qap.hpp" +#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" + +using namespace std; +using namespace libsnark; + +typedef Fr FieldT; + +extern "C" void bnwrap_init() { + assert(sodium_init() != -1); + init_alt_bn128_params(); +} + +extern "C" alt_bn128_G1 bnwrap_G1_zero() { + return alt_bn128_G1::zero(); +} + +extern "C" alt_bn128_G1 bnwrap_G1_one() { + return alt_bn128_G1::one(); +} + +extern "C" alt_bn128_G1 bnwrap_G1_random() { + return alt_bn128_G1::random_element(); +} + +extern "C" bool bnwrap_G1_is_zero(alt_bn128_G1 *p) { + return p->is_zero(); +} + +extern "C" bool bnwrap_G1_is_equal(alt_bn128_G1 *p, alt_bn128_G1 *q) { + return *p == *q; +} + +extern "C" alt_bn128_G1 bnwrap_G1_add(alt_bn128_G1 *p, alt_bn128_G1 *q) { + return *p + *q; +} + +extern "C" alt_bn128_G1 bnwrap_G1_sub(alt_bn128_G1 *p, alt_bn128_G1 *q) { + return *p - *q; +} + +extern "C" alt_bn128_G1 bnwrap_G1_neg(alt_bn128_G1 *p) { + return -(*p); +} + +extern "C" alt_bn128_G1 bnwrap_G1_scalarmul(alt_bn128_G1 *p, FieldT *q) { + return (*q) * (*p); +} + +extern "C" FieldT bnwrap_fr_from(const char *a) { + return FieldT(a); +} diff --git a/src/build.rs b/src/build.rs new file mode 100644 index 0000000..058af45 --- /dev/null +++ b/src/build.rs @@ -0,0 +1,31 @@ +extern crate gcc; + +fn main() { + println!("cargo:rustc-link-lib=gmp"); + println!("cargo:rustc-link-lib=gmpxx"); + println!("cargo:rustc-link-lib=sodium"); + + let mut cfg = gcc::Config::new(); + + cfg.cpp(true) + .define("NO_PROCPS", None) + .define("STATIC", None) + .define("CURVE_ALT_BN128", None) + .define("MONTGOMERY_OUTPUT", None) + .define("USE_ASM", None) + .define("NO_PT_COMPRESSION", None) + .define("BINARY_OUTPUT", None) + .flag("-std=c++11") + .include("libsnark/src") + .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp") + .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp") + .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp") + .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp") + .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp") + .file("libsnark/src/common/utils.cpp") + .file("libsnark/src/common/profiling.cpp") + .file("src/bnwrap.cpp") + ; + + cfg.compile("libbnwrap.a"); +} diff --git a/src/curve/g1.rs b/src/curve/g1.rs new file mode 100644 index 0000000..7dc3198 --- /dev/null +++ b/src/curve/g1.rs @@ -0,0 +1,61 @@ +use super::{Fr,GroupElement}; + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct G1 { + x: [u64; 4], + y: [u64; 4], + z: [u64; 4] +} + +extern "C" { + fn bnwrap_G1_zero() -> G1; + fn bnwrap_G1_one() -> G1; + fn bnwrap_G1_random() -> G1; + + fn bnwrap_G1_is_zero(p: *const G1) -> bool; + fn bnwrap_G1_is_equal(p: *const G1, q: *const G1) -> bool; + + fn bnwrap_G1_add(p: *const G1, q: *const G1) -> G1; + fn bnwrap_G1_sub(p: *const G1, q: *const G1) -> G1; + fn bnwrap_G1_neg(p: *const G1) -> G1; + fn bnwrap_G1_scalarmul(p: *const G1, s: *const Fr) -> G1; +} + +impl GroupElement for G1 { + fn zero() -> G1 { + unsafe { bnwrap_G1_zero() } + } + + fn one() -> G1 { + unsafe { bnwrap_G1_one() } + } + + fn is_equal(&self, other: &Self) -> bool { + unsafe { bnwrap_G1_is_equal(self, other) } + } + + fn random() -> G1 { + unsafe { bnwrap_G1_random() } + } + + fn is_zero(&self) -> bool { + unsafe { bnwrap_G1_is_zero(self) } + } + + fn arith_neg(&self) -> Self { + unsafe { bnwrap_G1_neg(self) } + } + + fn arith_add(&self, other: &Self) -> Self { + unsafe { bnwrap_G1_add(self, other) } + } + + fn arith_sub(&self, other: &Self) -> Self { + unsafe { bnwrap_G1_sub(self, other) } + } + + fn arith_mul(&self, other: &Fr) -> Self { + unsafe { bnwrap_G1_scalarmul(self, other) } + } +} diff --git a/src/curve/mod.rs b/src/curve/mod.rs new file mode 100644 index 0000000..1959312 --- /dev/null +++ b/src/curve/mod.rs @@ -0,0 +1,201 @@ +use std::ops::{Add,Sub,Mul,Neg}; +use std::sync::Mutex; +use libc::c_char; +use std::ffi::CString; + +mod g1; + +pub type G1 = G; + +extern "C" { + fn bnwrap_init(); +} + +lazy_static! { + static ref INIT_LOCK: Mutex = Mutex::new(false); +} + +/// This must be called before anything in this module is used. +pub fn initialize() { + let mut l = INIT_LOCK.lock().unwrap(); + + if !*l { + unsafe { bnwrap_init(); } + *l = true; + } +} + +/// The scalar field for the curve construction we use. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct Fr([u64; 4]); + +extern "C" { + fn bnwrap_fr_from(s: *const c_char) -> Fr; +} + +impl Fr { + pub fn from_str(s: &'static str) -> Self { + for c in s.chars() { + if c != '0' && + c != '1' && + c != '2' && + c != '3' && + c != '4' && + c != '5' && + c != '6' && + c != '7' && + c != '8' && + c != '9' { + panic!("character out of range") + } + } + + let s = CString::new(s).unwrap(); + + unsafe { bnwrap_fr_from(s.as_ptr()) } + } +} + +pub trait GroupElement: Sized + Copy + Clone { + fn zero() -> Self; + fn one() -> Self; + fn random() -> Self; + + fn is_equal(&self, other: &Self) -> bool; + fn is_zero(&self) -> bool; + + fn arith_neg(&self) -> Self; + fn arith_add(&self, other: &Self) -> Self; + fn arith_sub(&self, other: &Self) -> Self; + fn arith_mul(&self, other: &Fr) -> Self; +} + +#[derive(Copy, Clone)] +pub struct G(T); + +impl G { + pub fn zero() -> Self { + G(T::zero()) + } + + pub fn one() -> Self { + G(T::one()) + } + + pub fn random() -> Self { + G(T::random()) + } + + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +impl PartialEq for G { + fn eq(&self, other: &Self) -> bool { + self.0.is_equal(&other.0) + } +} + +impl<'a, T: GroupElement> Neg for &'a G { + type Output = G; + + fn neg(self) -> G { + G(self.0.arith_neg()) + } +} + +impl<'a, 'b, T: GroupElement> Add<&'a G> for &'b G { + type Output = G; + + fn add(self, other: &G) -> G { + G(self.0.arith_add(&other.0)) + } +} + +impl<'a, 'b, T: GroupElement> Sub<&'a G> for &'b G { + type Output = G; + + fn sub(self, other: &G) -> G { + G(self.0.arith_sub(&other.0)) + } +} + +impl<'a, 'b, T: GroupElement> Mul<&'a Fr> for &'b G { + type Output = G; + + fn mul(self, other: &Fr) -> G { + G(self.0.arith_mul(other)) + } +} + +mod test { + use super::{G, Fr, g1, initialize, GroupElement}; + + fn test_associative() { + for _ in 0..50 { + let a = G::::random(); + let b = G::::random(); + let c = G::::random(); + + let x = &(&a + &b) + &c; + let y = &(&a + &c) + &b; + + assert!(x == y); + } + } + + fn test_scalar_mul() { + let r = G::::random(); + let res = &r * &Fr::from_str("16"); + + let mut acc = G::::zero(); + + for _ in 0..16 { + acc = &acc + &r; + } + + assert!(acc == res); + } + + fn test_addition() { + { + let a = G::::random(); + let b = -(&a); + let c = &a + &b; + + assert!(c.is_zero()); + } + { + let a = G::::random(); + let b = -(&a); + let c = &a - &b; + let d = &a * &Fr::from_str("2"); + + assert!(c == d); + } + } + + fn test_primitives() { + let a = G::::zero(); + let b = G::::one(); + + assert_eq!(a.is_zero(), true); + assert_eq!(b.is_zero(), false); + } + + fn test_group_ops() { + test_associative::(); + test_primitives::(); + test_scalar_mul::(); + test_addition::(); + } + + #[test] + fn test_g1() { + initialize(); + + test_group_ops::(); + } +} diff --git a/src/main.rs b/src/main.rs index 58dfaaa..68f91f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,11 @@ +extern crate libc; +#[macro_use] +extern crate lazy_static; + +mod curve; + +use curve::*; + fn main() { - + initialize(); }