Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement arkworks wrapper #1

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
cmake_minimum_required(VERSION 3.10.2)

project(zksnark-java-sdk)

# This flag allows linking both 'libarkworks' and 'librustzcash' within the same project.
# It should be safe as long as the same version of the Rust toolchain is used to build both libraries.
set(LINK_FLAGS "-Wl,--allow-multiple-definition")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_BUILD_TYPE Release)
Expand All @@ -24,8 +26,10 @@ link_directories(lib)

set(zksnark_jni_include org_tron_common_zksnark_Librustzcash_LibrustzcashJNI.h)
set(sodium_jni_include org_tron_common_zksnark_Libsodium_LibsodiumJNI.h)
set(arkworks_jni_include org_tron_common_zksnark_Libarkworks_LibarkworksJNI.h)
set(zksnark_jni_src LibrustzcashJNIImpl.cpp)
set(sodium_jni_src LibsodiumJNIImpl.cpp)
set(arkworks_jni_src LibarkworksJNIImpl.cpp)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src zksnark_srcs)

file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include)
Expand All @@ -35,6 +39,7 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
include_directories("${CMAKE_BINARY_DIR}")
include_directories("${CMAKE_BINARY_DIR}/include")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/librustzcash/include")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../rust/libarkworks/include")

add_custom_command(
OUTPUT "${zksnark_jni_include}"
Expand All @@ -54,10 +59,22 @@ add_custom_command(
DEPENDS ${sodium_jni_include}
)

add_custom_command(
OUTPUT "${arkworks_jni_include}"
COMMAND ${Java_JAVAC_EXECUTABLE} -verbose
-h ${CMAKE_BINARY_DIR}/include
-d ${CMAKE_BINARY_DIR}/tmp
"${CMAKE_CURRENT_SOURCE_DIR}/../src/main/java/org/tron/common/zksnark/Libarkworks.java"
DEPENDS ${arkworks_jni_include}
)

set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/rust)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/target
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
${CMAKE_CURRENT_SOURCE_DIR}/../rust/libarkworks/target
)

ExternalProject_Add(
librustzcash
Expand All @@ -71,7 +88,22 @@ ExternalProject_Add(
INSTALL_COMMAND ""
LOG_BUILD OFF)

add_custom_target(rust ALL DEPENDS librustzcash)
add_custom_target(rustzcash ALL DEPENDS librustzcash)

# libarkworks
ExternalProject_Add(
libarkworks
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND cargo build
# COMMAND cargo build
--package libarkworks
--release
BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../rust/libarkworks"
INSTALL_COMMAND ""
LOG_BUILD OFF)

add_custom_target(rustarkworks ALL DEPENDS libarkworks)


# libsodium
Expand All @@ -93,20 +125,24 @@ ADD_LIBRARY(zksnarkjni
SHARED
${CMAKE_CURRENT_SOURCE_DIR}/src/${zksnark_jni_src}
${CMAKE_CURRENT_SOURCE_DIR}/src/${sodium_jni_src}
${CMAKE_CURRENT_SOURCE_DIR}/src/${arkworks_jni_src}
${zksnark_src_dependencies}
${zksnark_jni_include}
${sodium_jni_include}
${arkworks_jni_include}
${zksnark_srcs}
)

target_link_libraries(zksnarkjni
${CMAKE_THREAD_LIBS_INIT}
"${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/target/release/librustzcash.a"
"${CMAKE_CURRENT_SOURCE_DIR}/../rust/libarkworks/target/release/libarkworks.a"
${NACL_DIR}/src/libsodium/src/libsodium/.libs/libsodium.a
)

add_dependencies(zksnarkjni rust)
add_dependencies(zksnarkjni rustzcash)
add_dependencies(zksnarkjni libsodium)
add_dependencies(zksnarkjni rustarkworks)

if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET_TARGET_PROPERTIES( zksnarkjni PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,--wrap=memcpy" )
Expand Down
146 changes: 146 additions & 0 deletions cpp/src/LibarkworksJNIImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#include "org_tron_common_zksnark_Libarkworks_LibarkworksJNI.h"
#include "libarkworks.h"
#include <iostream>

jboolean bool2jboolean(bool b) {
if (b) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksG1IsValid
* Signature: ([B[B)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksG1IsValid
(JNIEnv * env, jobject, jbyteArray x, jbyteArray y) {
unsigned char * x_p = (unsigned char *) env->GetByteArrayElements(x, nullptr);
unsigned char * y_p = (unsigned char *) env->GetByteArrayElements(y, nullptr);
if (x_p == NULL || y_p == NULL) {
return JNI_FALSE;
}

bool result = libarkworks_g1_is_valid(x_p, y_p);
env->ReleaseByteArrayElements(x, (jbyte*) x_p, 0);
env->ReleaseByteArrayElements(y, (jbyte*) y_p, 0);
return bool2jboolean(result);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksG2IsValid
* Signature: ([B[B[B[B)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksG2IsValid
(JNIEnv * env, jobject, jbyteArray a, jbyteArray b, jbyteArray c, jbyteArray d) {
unsigned char * a_p = (unsigned char *) env->GetByteArrayElements(a, nullptr);
unsigned char * b_p = (unsigned char *) env->GetByteArrayElements(b, nullptr);
unsigned char * c_p = (unsigned char *) env->GetByteArrayElements(c, nullptr);
unsigned char * d_p = (unsigned char *) env->GetByteArrayElements(d, nullptr);
if (a_p == NULL || b_p == NULL || c_p == NULL || d_p == NULL) {
return JNI_FALSE;
}

bool result = libarkworks_g2_is_valid(a_p, b_p, c_p, d_p);
env->ReleaseByteArrayElements(a, (jbyte*) a_p, 0);
env->ReleaseByteArrayElements(b, (jbyte*) b_p, 0);
env->ReleaseByteArrayElements(c, (jbyte*) c_p, 0);
env->ReleaseByteArrayElements(d, (jbyte*) d_p, 0);
return bool2jboolean(result);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksAddG1
* Signature: ([B[B[B)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksAddG1
(JNIEnv * env, jobject, jbyteArray a, jbyteArray b, jbyteArray result) {
unsigned char * a_p = (unsigned char *) env->GetByteArrayElements(a, nullptr);
unsigned char * b_p = (unsigned char *) env->GetByteArrayElements(b, nullptr);
unsigned char * result_p = (unsigned char *) env->GetByteArrayElements(result, nullptr);
if (a_p == NULL || b_p == NULL || result_p == NULL) {
return JNI_FALSE;
}

bool success = libarkworks_add_g1(a_p, b_p, result_p);
env->ReleaseByteArrayElements(a, (jbyte*) a_p, 0);
env->ReleaseByteArrayElements(b, (jbyte*) b_p, 0);
env->ReleaseByteArrayElements(result, (jbyte*) result_p, 0);
return bool2jboolean(success);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksMulG1
* Signature: ([B[B[B)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksMulG1
(JNIEnv * env, jobject, jbyteArray p, jbyteArray s, jbyteArray result) {
unsigned char * p_p = (unsigned char *) env->GetByteArrayElements(p, nullptr);
unsigned char * s_p = (unsigned char *) env->GetByteArrayElements(s, nullptr);
unsigned char * result_p = (unsigned char *) env->GetByteArrayElements(result, nullptr);
if (p_p == NULL || s_p == NULL || result_p == NULL) {
return JNI_FALSE;
}

bool success = libarkworks_mul_g1(p_p, s_p, result_p);
env->ReleaseByteArrayElements(p, (jbyte*) p_p, 0);
env->ReleaseByteArrayElements(s, (jbyte*) s_p, 0);
env->ReleaseByteArrayElements(result, (jbyte*) result_p, 0);
return bool2jboolean(success);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksPairingCheck
* Signature: ([B[BI)Z
*/
JNIEXPORT jboolean JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksPairingCheck
(JNIEnv * env, jobject, jbyteArray g1s, jbyteArray g2s, jint pairs) {
unsigned char * g1s_p = (unsigned char *) env->GetByteArrayElements(g1s, nullptr);
unsigned char * g2s_p = (unsigned char *) env->GetByteArrayElements(g2s, nullptr);
if (g1s_p == NULL || g2s_p == NULL) {
return JNI_FALSE;
}

bool success = libarkworks_pairing_check(g1s_p, g2s_p, pairs);
env->ReleaseByteArrayElements(g1s, (jbyte*) g1s_p, 0);
env->ReleaseByteArrayElements(g2s, (jbyte*) g2s_p, 0);
return bool2jboolean(success);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksRandomG1
* Signature: ([B)V
*/
JNIEXPORT void JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksRandomG1
(JNIEnv * env, jobject, jbyteArray g1) {
unsigned char * g1_p = (unsigned char *) env->GetByteArrayElements(g1, nullptr);
if (g1_p == NULL) {
return;
}

libarkworks_random_g1(g1_p);
env->ReleaseByteArrayElements(g1, (jbyte*) g1_p, 0);
}

/*
* Class: org_tron_common_zksnark_Libarkworks_LibarkworksJNI
* Method: libarkworksRandomG2
* Signature: ([B)V
*/
JNIEXPORT void JNICALL Java_org_tron_common_zksnark_Libarkworks_00024LibarkworksJNI_libarkworksRandomG2
(JNIEnv * env, jobject, jbyteArray g2) {
unsigned char * g2_p = (unsigned char *) env->GetByteArrayElements(g2, nullptr);
if (g2_p == NULL) {
return;
}

libarkworks_random_g2(g2_p);
env->ReleaseByteArrayElements(g2, (jbyte*)g2_p, 0);
}
2 changes: 2 additions & 0 deletions rust/libarkworks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
/Cargo.lock
22 changes: 22 additions & 0 deletions rust/libarkworks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "libarkworks"
version = "0.1.0"
edition = "2021"

[lib]
name = "arkworks"
path = "src/lib.rs"
crate-type = ["staticlib", "cdylib"]

[dependencies]
libc = "0.2"
rand = "0.8.5"
ark-bn254 = "0.4.0"
ark-ff = "0.4.2"
ark-serialize = "0.4.2"
ark-ec = "0.4.2"

[profile.release]
AllFi marked this conversation as resolved.
Show resolved Hide resolved
lto = true
panic = 'abort'
codegen-units = 1
52 changes: 52 additions & 0 deletions rust/libarkworks/include/libarkworks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifndef LIBARKWORKS_INCLUDE_H_
#define LIBARKWORKS_INCLUDE_H_

#include <stdint.h>

extern "C" {
#ifdef WIN32
typedef uint16_t codeunit;
#else
typedef uint8_t codeunit;
#endif

bool libarkworks_g1_is_valid(
const unsigned char *x,
const unsigned char *y
);

bool libarkworks_g2_is_valid(
const unsigned char *a,
const unsigned char *b,
const unsigned char *c,
const unsigned char *d
);

bool libarkworks_add_g1(
const unsigned char *a,
const unsigned char *b,
unsigned char *result
);

bool libarkworks_mul_g1(
const unsigned char *p,
const unsigned char *s,
unsigned char *result
);

bool libarkworks_pairing_check(
const unsigned char *g1s,
const unsigned char *g2s,
const uint32_t pairs
);

void libarkworks_random_g1(
unsigned char *g1
);

void libarkworks_random_g2(
unsigned char *g2
);
}

#endif // LIBARKWORKS_INCLUDE_H_
66 changes: 66 additions & 0 deletions rust/libarkworks/src/bn254.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use ark_bn254::{Bn254, G1Affine, G2Affine};
use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
use ark_ff::{BigInteger256, Field, Fp12, UniformRand};
use ark_serialize::SerializationError;

use crate::{serialize::EthSerializeDeserialize, G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE};

pub fn random_g1() -> Vec<u8> {
let mut rng = rand::thread_rng();
G1Affine::rand(&mut rng)
.eth_serialize()
.expect("failed to serialize random point")
}

pub fn random_g2() -> Vec<u8> {
let mut rng = rand::thread_rng();
G2Affine::rand(&mut rng)
.eth_serialize()
.expect("failed to serialize random point")
}

pub fn g1_is_valid(serialized: Vec<u8>) -> bool {
// We probably can safely bypass is_in_correct_subgroup_assuming_on_curve check
// since there is only one subgroup and we can't fail this check
let g1 = G1Affine::eth_deserialize_unchecked(&serialized);
match g1 {
Ok(g1) => g1.is_on_curve(),
Err(_) => false,
}
}

pub fn g2_is_valid(serialized: Vec<u8>) -> bool {
G2Affine::eth_deserialize(&serialized).is_ok()
}

pub fn add_g1(a_serialized: &[u8], b_serialized: &[u8]) -> Result<Vec<u8>, SerializationError> {
let a = G1Affine::eth_deserialize_unchecked(a_serialized)?;
let b = G1Affine::eth_deserialize_unchecked(b_serialized)?;
(a + b).into_affine().eth_serialize()
}

pub fn mul_g1(a_serialized: &[u8], s_serialized: &[u8]) -> Result<Vec<u8>, SerializationError> {
let p = G1Affine::eth_deserialize_unchecked(a_serialized)?;
let s = BigInteger256::eth_deserialize(s_serialized)?;
p.mul_bigint(s).into_affine().eth_serialize()
}

pub fn pairing_check(
g1s_serialized: &[u8],
g2s_serialized: &[u8],
pairs: usize,
) -> Result<bool, SerializationError> {
let mut g1s = vec![];
let mut g2s = vec![];
for i in 0..pairs {
g1s.push(G1Affine::eth_deserialize_unchecked(
&g1s_serialized[i * G1_SERIALIZED_SIZE..(i + 1) * G1_SERIALIZED_SIZE],
)?);
g2s.push(G2Affine::eth_deserialize_unchecked(
&g2s_serialized[i * G2_SERIALIZED_SIZE..(i + 1) * G2_SERIALIZED_SIZE],
)?);
}

let result = Bn254::multi_pairing(g1s, g2s);
Ok(result.0 == Fp12::ONE)
}
Loading