Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
223 changes: 204 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,218 @@
# libzksnark
a zksnark jni library
# zksnark-java-sdk

# Pull source
A Java JNI wrapper for ZK-SNARK cryptographic functions, providing Sapling protocol support for the TRON blockchain.

## Overview

This library enables Java applications to perform ZK-SNARK operations including:
- Sapling spend and output proof generation
- Proof verification
- ZIP32 hierarchical key derivation
- Note encryption/decryption using ChaCha20-Poly1305
- Blake2b hashing with salt and personalization

## Requirements

| Tool | Version | Notes |
|------|---------|-------|
| cmake | >= 3.10.2 | CMake 3.x recommended |
| Rust (cargo) | >= 1.50.0 | Rust 2018 edition |
| libtool | >= 2.4.0 | GNU libtool |
| automake | >= 1.13 | GNU automake |
| Maven | >= 3.5.0 | Apache Maven |
| JDK | 8+ | JAVA_HOME must be set |
| Xcode Command Line Tools | Latest | macOS only |

## Installation

### Clone the Repository

```bash
# Clone with submodules
git clone git@github.com:tronprotocol/zksnark-java-sdk.git --recursive

# Or initialize submodules after cloning
git clone git@github.com:tronprotocol/zksnark-java-sdk.git
cd zksnark-java-sdk
git submodule update --init --recursive
```
$ git clone git@github.com:tronprotocol/zksnark-java-sdk.git --recursive

### Build the Native Library

**Linux / macOS (Intel):**

```bash
cd cpp && mkdir build && cd build
cmake ..
make -j4
make install
```
OR

**macOS (M1/Apple Silicon):**

```bash
cd cpp && mkdir build && cd build
CC=cc cmake -DCMAKE_OSX_ARCHITECTURES=arm64 ..
make -j4
make install
```
$ git clone git@github.com:tronprotocol/zksnark-java-sdk.git
$ git submodule update --init --recursive

### Build the Java Package

Run this from the project root directory:

```bash
mvn clean package
```

# Required
This creates a JAR file with the native libraries bundled for the current platform.

cmake (version >= 3.10.2)
## Clean and Rebuild

cargo
### Clean Build Artifacts

libtool
```bash
# Clean CMake build
rm -rf cpp/build

automake
# Clean Rust build
rm -rf rust/librustzcash/target

# Clean Java build
mvn clean
```

mvn
## Usage

jdk8(need JAVA_HOME set)
### Initialize ZK-SNARK Parameters

# for m1
```shell
cd cpp && mkdir build && cd build
CC=cc cmake ..
make
Before using any ZK-SNARK functions, initialize the Sapling parameters:

```java
import org.tron.common.zksnark.LibrustzcashWrapper;
import org.tron.common.util.Utils;

LibrustzcashWrapper.getInstance().librustzcashInitZksnarkParams(
Utils.getParamsFile("sapling-spend.params"),
"8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
Utils.getParamsFile("sapling-output.params"),
"657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028"
);
```

### Key Derivation (ZIP32)

```java
import org.tron.common.zksnark.LibrustzcashWrapper;

// Derive master xsk from seed
byte[] seed = new byte[32]; // your seed
byte[] xskMaster = new byte[160];
LibrustzcashWrapper.getInstance().librustzcashZip32XskMaster(seed, seed.length, xskMaster);

// Derive child xsk at index i
byte[] xskChild = new byte[160];
LibrustzcashWrapper.getInstance().librustzcashZip32XskDerive(xskMaster, i, xskChild);

// Derive address from xfvk
byte[] xfvk = new byte[160];
byte[] index = new byte[11];
byte[] jRet = new byte[11];
byte[] addr = new byte[43];
boolean success = LibrustzcashWrapper.getInstance()
.librustzcashZip32XfvkAddress(xfvk, index, jRet, addr);
```

### Generate Sapling Spend Proof

```java
import org.tron.common.zksnark.LibrustzcashWrapper;

// Initialize proving context
long ctx = LibrustzcashWrapper.getInstance().librustzcashSaplingProvingCtxInit();

// Generate spend proof
byte[] ak = new byte[32];
byte[] nsk = new byte[32];
byte[] diversifier = new byte[11];
byte[] rcm = new byte[32];
byte[] ar = new byte[32];
long value = 1000000L;
byte[] anchor = new byte[32];
byte[] witness = new byte[1065]; // Merkle path
byte[] cv = new byte[32];
byte[] rk = new byte[32];
byte[] zkproof = new byte[192];

boolean result = LibrustzcashWrapper.getInstance().librustzcashSaplingSpendProof(
ctx, ak, nsk, diversifier, rcm, ar, value, anchor, witness, cv, rk, zkproof
);

// Clean up
LibrustzcashWrapper.getInstance().librustzcashSaplingProvingCtxFree(ctx);
```

### Verify Sapling Proofs

```java
import org.tron.common.zksnark.LibrustzcashWrapper;

// Initialize verification context
long ctx = LibrustzcashWrapper.getInstance().librustzcashSaplingVerificationCtxInit();

// Verify spend
boolean spendValid = LibrustzcashWrapper.getInstance().librustzcashSaplingCheckSpend(
ctx, cv, anchor, nullifier, rk, zkproof, spendAuthSig, sighashValue
);

// Verify output
boolean outputValid = LibrustzcashWrapper.getInstance().librustzcashSaplingCheckOutput(
ctx, cv, cm, ephemeralKey, zkproof
);

// Final binding check
boolean valid = LibrustzcashWrapper.getInstance().librustzcashSaplingFinalCheck(
ctx, valueBalance, bindingSig, sighashValue
);

// Clean up
LibrustzcashWrapper.getInstance().librustzcashSaplingVerificationCtxFree(ctx);
```

## Running Tests

Run this from the project root directory:

```bash
mvn test
```

Tests cover:
- Key derivation (ask→ak, nsk→nk, ivk derivation)
- Proof generation and verification
- Note encryption/decryption
- Merkle tree operations

## Project Structure

```text
zksnark-java-sdk/
├── src/main/java/ # Java JNI wrappers
│ └── org/tron/common/
│ ├── zksnark/ # Librustzcash, Libsodium, Wrapper classes
│ └── util/ # Utils (library loading)
├── src/main/resources/
│ └── META-INF/native/ # Native libraries (osx64/, linux64/)
├── cpp/ # C++ JNI implementation
├── rust/librustzcash/ # Rust ZK-SNARK library (submodule)
└── pom.xml # Maven build configuration
```

## License

Apache License 2.0

## Resources

- [Zcash Sapling Protocol](https://zips.z.cash/protocol/protocol.pdf)
- [ZIP32 - Hierarchical Key Derivation](https://zips.z.cash/zip-0032)
91 changes: 79 additions & 12 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_BUILD_TYPE Release)
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -DNDEBUG")

# macOS specific: Add libc++ include path for Clang
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE CMAKE_OSX_SYSROOT OUTPUT_STRIP_TRAILING_WHITESPACE)
include_directories("${CMAKE_OSX_SYSROOT}/usr/include/c++/v1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++")
endif()

find_package( Threads )
find_package(Java REQUIRED)
# find_package(JNI REQUIRED)
Expand Down Expand Up @@ -36,6 +45,44 @@ include_directories("${CMAKE_BINARY_DIR}")
include_directories("${CMAKE_BINARY_DIR}/include")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/librustzcash/include")

set(RUST_BUILD_TARGET "$ENV{RUST_BUILD_TARGET}")
if(NOT RUST_BUILD_TARGET)
if(APPLE)
if(CMAKE_OSX_ARCHITECTURES)
set(RUST_TARGET_ARCH "${CMAKE_OSX_ARCHITECTURES}")
else()
set(RUST_TARGET_ARCH "${CMAKE_SYSTEM_PROCESSOR}")
endif()

if(RUST_TARGET_ARCH MATCHES ";")
message(FATAL_ERROR "Universal macOS builds are not supported. Set CMAKE_OSX_ARCHITECTURES to a single architecture or provide RUST_BUILD_TARGET.")
endif()

if(RUST_TARGET_ARCH STREQUAL "arm64" OR RUST_TARGET_ARCH STREQUAL "aarch64")
set(RUST_BUILD_TARGET "aarch64-apple-darwin")
elseif(RUST_TARGET_ARCH STREQUAL "x86_64")
set(RUST_BUILD_TARGET "x86_64-apple-darwin")
else()
message(FATAL_ERROR "Unsupported macOS architecture '${RUST_TARGET_ARCH}'. Set RUST_BUILD_TARGET explicitly.")
endif()
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
set(RUST_BUILD_TARGET "aarch64-unknown-linux-gnu")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64)$")
set(RUST_BUILD_TARGET "x86_64-unknown-linux-gnu")
endif()
endif()
endif()

set(RUST_BUILD_COMMAND cargo build --package librustzcash --release)
set(RUST_LIBRARY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/target/release/librustzcash.a")
if(RUST_BUILD_TARGET)
list(APPEND RUST_BUILD_COMMAND --target ${RUST_BUILD_TARGET})
set(RUST_LIBRARY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash/target/${RUST_BUILD_TARGET}/release/librustzcash.a")
endif()

message(STATUS "Using Rust target: ${RUST_BUILD_TARGET}")

add_custom_command(
OUTPUT "${zksnark_jni_include}"
COMMAND ${Java_JAVAC_EXECUTABLE} -verbose
Expand Down Expand Up @@ -63,10 +110,7 @@ ExternalProject_Add(
librustzcash
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND cargo build
# COMMAND cargo build
--package librustzcash
--release
BUILD_COMMAND ${RUST_BUILD_COMMAND}
BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../rust/librustzcash"
INSTALL_COMMAND ""
LOG_BUILD OFF)
Expand Down Expand Up @@ -101,19 +145,42 @@ ADD_LIBRARY(zksnarkjni

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

add_dependencies(zksnarkjni rust)
add_dependencies(zksnarkjni libsodium)

if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET_TARGET_PROPERTIES( zksnarkjni PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,--wrap=memcpy" )
endif()

if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
INSTALL(TARGETS zksnarkjni LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/native-package/linux)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
SET_TARGET_PROPERTIES( zksnarkjni PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,--wrap=memcpy -s" )
# Linux: support both x86_64 and aarch64
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
INSTALL(TARGETS zksnarkjni LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/META-INF/native/linux64/aarch64)
else()
INSTALL(TARGETS zksnarkjni LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/META-INF/native/linux64)
endif()
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
# macOS: support both x86_64 and arm64
SET_TARGET_PROPERTIES(zksnarkjni PROPERTIES SUFFIX ".jnilib")

# Create architecture-specific directories
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
set(MACOS_NATIVE_DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/META-INF/native/osx64/aarch64")
else()
set(MACOS_NATIVE_DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/META-INF/native/osx64")
endif()

INSTALL(TARGETS zksnarkjni LIBRARY DESTINATION ${MACOS_NATIVE_DESTINATION})
INSTALL(CODE
"execute_process(
COMMAND /usr/bin/codesign --force --sign - \"${MACOS_NATIVE_DESTINATION}/libzksnarkjni.jnilib\"
RESULT_VARIABLE codesign_result
)
if(NOT codesign_result EQUAL 0)
message(FATAL_ERROR \"codesign failed with exit code \${codesign_result}: ${MACOS_NATIVE_DESTINATION}/libzksnarkjni.jnilib\")
endif()"
)
else()
INSTALL(TARGETS zksnarkjni LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/resources/native-package/macos)
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}. Only Linux and macOS are supported.")
endif()
Loading