From 0b8b52cb4116bd28452427c9fa584b3957241618 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 25 Dec 2015 00:30:10 -0700 Subject: [PATCH] Add basic field arithmetic. --- tinysnark/Cargo.toml | 17 +++++--- tinysnark/README.md | 1 + tinysnark/src/arith.rs | 94 +++++++++++++++++++++++++++++++++++++++++ tinysnark/src/lib.rs | 80 +++++++++++++++++++++++++++++++++-- tinysnark/tinysnark.cpp | 40 +++++++++++++++++- 5 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 tinysnark/README.md create mode 100644 tinysnark/src/arith.rs diff --git a/tinysnark/Cargo.toml b/tinysnark/Cargo.toml index 40af785..57dc0d0 100644 --- a/tinysnark/Cargo.toml +++ b/tinysnark/Cargo.toml @@ -1,13 +1,16 @@ [package] -name = "tinysnark" -homepage = "https://github.com/ebfull/bellman" -repository = "https://github.com/ebfull/bellman" -documentation = "https://github.com/ebfull/bellman" -license = "MIT" -description = "Tiny libsnark bindings" -version = "0.0.1" authors = ["Sean Bowe "] build = "build.rs" +description = "Tiny libsnark bindings" +documentation = "https://github.com/ebfull/bellman" +homepage = "https://github.com/ebfull/bellman" +license = "MIT" +name = "tinysnark" +repository = "https://github.com/ebfull/bellman" +version = "0.0.1" [build-dependencies] gcc = "0.3" + +[dependencies] +libc = "0.2.4" diff --git a/tinysnark/README.md b/tinysnark/README.md new file mode 100644 index 0000000..6e311a5 --- /dev/null +++ b/tinysnark/README.md @@ -0,0 +1 @@ +This is a tiny wrapper around libsnark's r1cs_ppzksnark on ALT_BN128. \ No newline at end of file diff --git a/tinysnark/src/arith.rs b/tinysnark/src/arith.rs new file mode 100644 index 0000000..bf106af --- /dev/null +++ b/tinysnark/src/arith.rs @@ -0,0 +1,94 @@ +use libc::{c_ulong, c_long}; +use std::ops::{Neg, Add, Mul}; + +extern "C" { + fn tinysnark_fieldt_zero() -> FieldT; + fn tinysnark_fieldt_one() -> FieldT; + fn tinysnark_fieldt_neg(val: FieldT) -> FieldT; + fn tinysnark_fieldt_inverse(val: FieldT) -> FieldT; + fn tinysnark_fieldt_from_long(val: c_long) -> FieldT; + fn tinysnark_long_from_fieldt(val: FieldT) -> c_ulong; + fn tinysnark_fieldt_mul(a: FieldT, b: FieldT) -> FieldT; + fn tinysnark_fieldt_add(a: FieldT, b: FieldT) -> FieldT; +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct FieldT([u8; 32]); + +impl FieldT { + #[inline(always)] + pub fn one() -> FieldT { + unsafe { tinysnark_fieldt_one() } + } + + #[inline(always)] + pub fn zero() -> FieldT { + unsafe { tinysnark_fieldt_zero() } + } + + #[inline(always)] + pub fn inverse(self) -> FieldT { + unsafe { tinysnark_fieldt_inverse(self) } + } + + #[cfg(test)] + pub fn debug_equal(&self, is: [u8; 32]) -> bool { + &FieldT(is) == self + } +} + +impl From for FieldT { + #[inline(always)] + fn from(num: i64) -> FieldT { + unsafe { tinysnark_fieldt_from_long(num) } + } +} + +impl From for u64 { + #[inline(always)] + fn from(num: FieldT) -> u64 { + unsafe { tinysnark_long_from_fieldt(num) } + } +} + +impl Neg for FieldT { + type Output = FieldT; + + #[inline(always)] + fn neg(self) -> FieldT { + unsafe { tinysnark_fieldt_neg(self) } + } +} + +impl Add for FieldT { + type Output = FieldT; + + #[inline(always)] + fn add(self, other: FieldT) -> FieldT { + unsafe { tinysnark_fieldt_add(self, other) } + } +} + +impl Mul for FieldT { + type Output = FieldT; + + #[inline(always)] + fn mul(self, other: FieldT) -> FieldT { + unsafe { tinysnark_fieldt_mul(self, other) } + } +} + +impl PartialEq for FieldT { + fn eq(&self, other: &FieldT) -> bool { + for i in 0..32 { + if (self.0)[i] != (other.0)[i] { + return false; + } + } + + true + } +} + +impl Eq for FieldT { } diff --git a/tinysnark/src/lib.rs b/tinysnark/src/lib.rs index c2e8bda..6d87cbd 100644 --- a/tinysnark/src/lib.rs +++ b/tinysnark/src/lib.rs @@ -1,9 +1,81 @@ +#![feature(box_syntax, test)] +extern crate libc; + +mod arith; + +pub use self::arith::*; + +use std::sync::{Once, ONCE_INIT}; + +static START: Once = ONCE_INIT; +static mut INITIALIZED: bool = false; + extern "C" { - fn tinysnark_init_public_params(); - fn tinysnark_test(); + fn tinysnark_init_public_params(); + fn tinysnark_test(); +} + +pub fn init() { + START.call_once(|| { + unsafe { tinysnark_init_public_params(); } + unsafe { INITIALIZED = true; } + }); +} + +pub fn is_initialized() -> bool { + unsafe { INITIALIZED } } pub fn test() { - unsafe { tinysnark_init_public_params(); } - unsafe { tinysnark_test(); } + unsafe { tinysnark_test(); } +} + +#[cfg(test)] +mod tests { + extern crate test; + use super::{init, FieldT}; + use self::test::Bencher; + + #[test] + fn test_one() { + init(); + let one = FieldT::one(); + let negone = -one; + let newone = -negone; + + assert!(one == newone); + assert!(one != negone); + assert!(newone != negone); + + assert_eq!(one, 1.into()); + assert_eq!(negone, (-1).into()); + + assert!(one.debug_equal([251, 255, 255, 79, 28, 52, 150, 172, 41, 205, 96, 159, 149, 118, 252, 54, 46, 70, 121, 120, 111, 163, 110, 102, 47, 223, 7, 154, 193, 119, 10, 14])); + assert!(negone.debug_equal([6, 0, 0, 160, 119, 193, 75, 151, 103, 163, 88, 218, 178, 113, 55, 241, 46, 18, 8, 9, 71, 162, 225, 81, 250, 192, 41, 71, 177, 214, 89, 34])); + } + + #[test] + fn test_math() { + init(); + + assert_eq!(FieldT::one() + 10.into(), 11.into()); + assert_eq!(FieldT::from(2) + 2.into(), FieldT::from(2) * 2.into()); + assert_eq!(FieldT::from(2), FieldT::from(-1) + FieldT::one() * 3.into()); + + assert_eq!(FieldT::one(), FieldT::from(100) * FieldT::from(100).inverse()); + } + + #[test] + fn test_conversions() { + init(); + + for i in 0..10000 { + let num: FieldT = i.into(); + let back: u64 = num.into(); + + assert_eq!(i, back as i64); + } + + assert_eq!(u64::from(FieldT::from(-1)), 4891460686036598784); + } } \ No newline at end of file diff --git a/tinysnark/tinysnark.cpp b/tinysnark/tinysnark.cpp index 9976826..f716777 100644 --- a/tinysnark/tinysnark.cpp +++ b/tinysnark/tinysnark.cpp @@ -11,13 +11,49 @@ zk-SNARK support using the ALT_BN128 curve. using namespace libsnark; using namespace std; +typedef Fr FieldT; + +extern "C" FieldT tinysnark_fieldt_mul(FieldT a, FieldT b) { + return a * b; +} + +extern "C" FieldT tinysnark_fieldt_add(FieldT a, FieldT b) { + return a + b; +} + +extern "C" unsigned long tinysnark_long_from_fieldt(FieldT num) { + return num.as_bigint().as_ulong(); +} + +extern "C" FieldT tinysnark_fieldt_from_long(long num) { + return FieldT(num); +} + +extern "C" FieldT tinysnark_fieldt_one() { + return FieldT::one(); +} + +extern "C" FieldT tinysnark_fieldt_zero() { + return FieldT::zero(); +} + +extern "C" FieldT tinysnark_fieldt_neg(FieldT val) { + return -val; +} + +extern "C" FieldT tinysnark_fieldt_inverse(FieldT val) { + return val.inverse(); +} + extern "C" void tinysnark_init_public_params() { default_r1cs_ppzksnark_pp::init_public_params(); + { + auto p = FieldT::one(); + assert(sizeof(p) == 32); + } } extern "C" void tinysnark_test() { - typedef Fr FieldT; - protoboard pb; linear_combination sum;