From 5ced638727ccad5b70d7def6c7bcddefe4767c22 Mon Sep 17 00:00:00 2001
From: cryptokat
Date: Tue, 19 Feb 2019 17:35:55 +0800
Subject: [PATCH 01/10] Util: add pre-allocated size to allow memory allocation
optmization
---
src/main/java/org/semux/util/SimpleEncoder.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/main/java/org/semux/util/SimpleEncoder.java b/src/main/java/org/semux/util/SimpleEncoder.java
index 95926f627..8b47123a2 100644
--- a/src/main/java/org/semux/util/SimpleEncoder.java
+++ b/src/main/java/org/semux/util/SimpleEncoder.java
@@ -28,6 +28,10 @@ public SimpleEncoder() {
this(Bytes.EMPTY_BYTES);
}
+ public SimpleEncoder(int size) {
+ out = new ByteArrayOutputStream(size);
+ }
+
public void writeBoolean(boolean b) {
out.write(b ? 1 : 0);
}
From a14adc1d61059d8c8a71616befa702e720c33654 Mon Sep 17 00:00:00 2001
From: cryptokat
Date: Tue, 19 Feb 2019 18:10:06 +0800
Subject: [PATCH 02/10] Native: add cross-compiling toolchain files of cmake
and ed25519 batch-verification support
1. Cross-compiling toolchain files of cmake are added to allow developers to compile the native libraries on Linux
2. Ed25519 batch-verification support is added from ed25519-donna to increase signature verification performance by 50%
---
.gitmodules | 6 +
.../java/org/semux/consensus/SemuxSync.java | 17 +-
src/main/java/org/semux/core/Block.java | 23 +-
src/main/java/org/semux/core/Transaction.java | 10 +-
src/main/java/org/semux/crypto/Key.java | 17 +
src/main/java/org/semux/crypto/Native.java | 19 +-
src/main/native/README.md | 47 +-
.../cmake/toolchain-aarch64-linux.cmake | 70 +
src/main/native/cmake/toolchain-darwin.cmake | 70 +
src/main/native/cmake/toolchain-win64.cmake | 77 +
.../native/cmake/toolchain-x86_64-linux.cmake | 70 +
src/main/native/crypto/CMakeLists.txt | 27 +-
src/main/native/crypto/cmake/Findsodium.cmake | 288 ---
src/main/native/crypto/ed25519-donna | 1 +
src/main/native/crypto/jni/jni.h | 1973 +++++++++++++++++
src/main/native/crypto/jni/jni_md.h | 56 +
src/main/native/crypto/libsodium | 1 +
.../native/crypto/org_semux_crypto_Native.cpp | 68 +-
.../native/crypto/org_semux_crypto_Native.h | 8 +
.../native/aarch64-linux/libsemuxcrypto.so | Bin 0 -> 1068144 bytes
.../resources/native/aarch64/libcrypto.so | Bin 72960 -> 0 bytes
.../resources/native/aarch64/libsodium.so.23 | Bin 315024 -> 0 bytes
.../resources/native/linux64/libcrypto.so | Bin 17176 -> 0 bytes
.../resources/native/linux64/libsodium.so.23 | Bin 1978624 -> 0 bytes
src/main/resources/native/win64/crypto.dll | Bin 12288 -> 0 bytes
.../resources/native/win64/libsemuxcrypto.dll | Bin 0 -> 2552690 bytes
src/main/resources/native/win64/libsodium.dll | Bin 278016 -> 0 bytes
.../native/x86_64-linux/libsemuxcrypto.so | Bin 0 -> 1952456 bytes
.../java/org/semux/crypto/NativeTest.java | 57 +-
29 files changed, 2574 insertions(+), 331 deletions(-)
create mode 100644 .gitmodules
create mode 100644 src/main/native/cmake/toolchain-aarch64-linux.cmake
create mode 100644 src/main/native/cmake/toolchain-darwin.cmake
create mode 100644 src/main/native/cmake/toolchain-win64.cmake
create mode 100644 src/main/native/cmake/toolchain-x86_64-linux.cmake
delete mode 100644 src/main/native/crypto/cmake/Findsodium.cmake
create mode 160000 src/main/native/crypto/ed25519-donna
create mode 100644 src/main/native/crypto/jni/jni.h
create mode 100644 src/main/native/crypto/jni/jni_md.h
create mode 160000 src/main/native/crypto/libsodium
create mode 100755 src/main/resources/native/aarch64-linux/libsemuxcrypto.so
delete mode 100755 src/main/resources/native/aarch64/libcrypto.so
delete mode 100755 src/main/resources/native/aarch64/libsodium.so.23
delete mode 100755 src/main/resources/native/linux64/libcrypto.so
delete mode 100755 src/main/resources/native/linux64/libsodium.so.23
delete mode 100644 src/main/resources/native/win64/crypto.dll
create mode 100755 src/main/resources/native/win64/libsemuxcrypto.dll
delete mode 100644 src/main/resources/native/win64/libsodium.dll
create mode 100755 src/main/resources/native/x86_64-linux/libsemuxcrypto.so
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..3654af79e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "src/main/native/crypto/libsodium"]
+ path = src/main/native/crypto/libsodium
+ url = https://github.com/jedisct1/libsodium.git
+[submodule "src/main/native/crypto/ed25519-donna"]
+ path = src/main/native/crypto/ed25519-donna
+ url = https://github.com/cryptokat/ed25519-donna.git
diff --git a/src/main/java/org/semux/consensus/SemuxSync.java b/src/main/java/org/semux/consensus/SemuxSync.java
index c983edb0b..2164bb88e 100644
--- a/src/main/java/org/semux/consensus/SemuxSync.java
+++ b/src/main/java/org/semux/consensus/SemuxSync.java
@@ -13,6 +13,7 @@
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -601,12 +602,24 @@ protected boolean validateBlockVotes(Block block) {
byte[] encoded = vote.getEncoded();
// check validity of votes
- if (!block.getVotes().stream()
- .allMatch(sig -> Key.verify(encoded, sig) && validators.contains(Hex.encode(sig.getAddress())))) {
+ if (block.getVotes().stream().anyMatch(sig -> !validators.contains(Hex.encode(sig.getAddress())))) {
logger.warn("Block votes are invalid");
return false;
}
+ if (!Key.isVerifyBatchSupported()) {
+ if (!block.getVotes().stream()
+ .allMatch(sig -> Key.verify(encoded, sig))) {
+ logger.warn("Block votes are invalid");
+ return false;
+ }
+ } else {
+ if (!Key.verifyBatch(Collections.nCopies(block.getVotes().size(), encoded), block.getVotes())) {
+ logger.warn("Block votes are invalid");
+ return false;
+ }
+ }
+
// at least two thirds voters
if (block.getVotes().stream()
.map(sig -> new ByteArray(sig.getA()))
diff --git a/src/main/java/org/semux/core/Block.java b/src/main/java/org/semux/core/Block.java
index 297798b79..32a8c0bbe 100644
--- a/src/main/java/org/semux/core/Block.java
+++ b/src/main/java/org/semux/core/Block.java
@@ -13,11 +13,13 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.semux.Network;
import org.semux.config.Config;
import org.semux.crypto.Hex;
+import org.semux.crypto.Key;
import org.semux.crypto.Key.Signature;
import org.semux.util.MerkleUtil;
import org.semux.util.SimpleDecoder;
@@ -197,10 +199,23 @@ public boolean validateTransactions(BlockHeader header, List transa
*/
public boolean validateTransactions(BlockHeader header, Collection unvalidatedTransactions,
List allTransactions, Network network) {
+
// validate transactions
- boolean valid = unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate(network));
- if (!valid) {
- return false;
+ if (!Key.isVerifyBatchSupported() || unvalidatedTransactions.size() < 3) {
+ if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate(network))) {
+ return false;
+ }
+ } else {
+ if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate(network, false))) {
+ return false;
+ }
+
+ if (!Key.verifyBatch(
+ unvalidatedTransactions.stream().map(Transaction::getHash).collect(Collectors.toUnmodifiableList()),
+ unvalidatedTransactions.stream().map(Transaction::getSignature).collect(Collectors.toUnmodifiableList())
+ )) {
+ return false;
+ }
}
// validate transactions root
@@ -447,7 +462,7 @@ public Pair> getEncodedResultsAndIndex() {
* @return
*/
public byte[] getEncodedVotes() {
- SimpleEncoder enc = new SimpleEncoder();
+ SimpleEncoder enc = new SimpleEncoder(4 + 4 + votes.size() * Signature.LENGTH);
enc.writeInt(view);
enc.writeInt(votes.size());
diff --git a/src/main/java/org/semux/core/Transaction.java b/src/main/java/org/semux/core/Transaction.java
index 9dd6370b9..83fcf8bdd 100644
--- a/src/main/java/org/semux/core/Transaction.java
+++ b/src/main/java/org/semux/core/Transaction.java
@@ -146,9 +146,11 @@ public Transaction sign(Key key) {
*
*
* @param network
+ * @param verifySignature
+ * Whether to verify the transaction signature or not. This is useful when there are multiple transaction signatures that can be verified in batch for performance reason.
* @return true if success, otherwise false
*/
- public boolean validate(Network network) {
+ public boolean validate(Network network, boolean verifySignature) {
return hash != null && hash.length == Hash.HASH_LEN
&& networkId == network.id()
&& type != null
@@ -162,7 +164,7 @@ public boolean validate(Network network) {
&& signature != null && !Arrays.equals(signature.getAddress(), EMPTY_ADDRESS)
&& Arrays.equals(Hash.h256(encoded), hash)
- && Key.verify(hash, signature)
+ && (!verifySignature || Key.verify(hash, signature))
// The coinbase key is publicly available. People can use it for transactions.
// It won't introduce any fundamental loss to the system but could potentially
@@ -172,6 +174,10 @@ public boolean validate(Network network) {
&& !Arrays.equals(to, Constants.COINBASE_ADDRESS)));
}
+ public boolean validate(Network network) {
+ return validate(network, true);
+ }
+
/**
* Returns the transaction network id.
*
diff --git a/src/main/java/org/semux/crypto/Key.java b/src/main/java/org/semux/crypto/Key.java
index b02d0f659..07f790825 100644
--- a/src/main/java/org/semux/crypto/Key.java
+++ b/src/main/java/org/semux/crypto/Key.java
@@ -14,6 +14,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
+import java.util.Collection;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -201,6 +202,22 @@ public static boolean verify(byte[] message, Signature signature) {
return false;
}
+ public static boolean isVerifyBatchSupported() {
+ return Native.isEnabled();
+ }
+
+ public static boolean verifyBatch(Collection messages, Collection signatures) {
+ if (!isVerifyBatchSupported()) {
+ throw new UnsupportedOperationException("Key#verifyBatch is only implemented in the native library.");
+ }
+
+ return Native.verifyBatch(
+ messages.toArray(new byte[messages.size()][]),
+ signatures.stream().map(Signature::getS).toArray(byte[][]::new),
+ signatures.stream().map(Signature::getA).toArray(byte[][]::new)
+ );
+ }
+
/**
* Verifies a signature.
*
diff --git a/src/main/java/org/semux/crypto/Native.java b/src/main/java/org/semux/crypto/Native.java
index 4fae9a64f..523eaa452 100644
--- a/src/main/java/org/semux/crypto/Native.java
+++ b/src/main/java/org/semux/crypto/Native.java
@@ -40,17 +40,16 @@ protected static void init() {
switch (os) {
case LINUX:
if (SystemUtil.getOsArch().equals("aarch64")) {
- enabled = loadLibrary("/native/aarch64/libsodium.so.23") && loadLibrary("/native/aarch64/libcrypto.so");
+ enabled = loadLibrary("/native/aarch64-linux/libsemuxcrypto.so");
} else {
- enabled = loadLibrary("/native/linux64/libsodium.so.23") && loadLibrary("/native/linux64/libcrypto.so");
+ enabled = loadLibrary("/native/x86_64-linux/libsemuxcrypto.so");
}
break;
case MACOS:
- enabled = loadLibrary("/native/macos64/libsodium.23.dylib")
- && loadLibrary("/native/macos64/libcrypto.dylib");
+ enabled = loadLibrary("/native/macos64/libsemuxcrypto.dylib");
break;
case WINDOWS:
- enabled = loadLibrary("/native/win64/libsodium.dll") && loadLibrary("/native/win64/crypto.dll");
+ enabled = loadLibrary("/native/win64/libsemuxcrypto.dll");
break;
default:
break;
@@ -153,4 +152,14 @@ public static void enable() {
* @return
*/
public static native boolean verify(byte[] message, byte[] signature, byte[] publicKey);
+
+ /**
+ * Batch verifies an Ed25519 signature.
+ *
+ * @param messages
+ * @param signatures
+ * @param publicKeys
+ * @return
+ */
+ public static native boolean verifyBatch(byte[][] messages, byte[][] signatures, byte[][] publicKeys);
}
diff --git a/src/main/native/README.md b/src/main/native/README.md
index 93cbb8988..2ad1cf814 100644
--- a/src/main/native/README.md
+++ b/src/main/native/README.md
@@ -1,16 +1,38 @@
# Semux Native Library
-## Build on Linux
+libsemuxcrypto is a JNI library that aims to increase the performance Semux wallet by implementing cryptography functions in C++. This library relies on thrid-parties including [libsodium](https://github.com/jedisct1/libsodium) and [ed25519-donna](https://github.com/floodyberry/ed25519-donna).
+## Build on x86_64 Linux
+
+Build on linux supports cross-compiling to the following platforms:
+
+1. aarch64-linux
+2. win64
+3. x86_64-linux
Prerequisites:
-1. Build and install libsodium 1.0.16
+1. cmake
+2. binutils-x86_64-linux-gnu
+3. binutils-aarch64-linux-gnu
+4. binutils-mingw-w64
-Build:
+Steps to build on Debian/Ubuntu based distributions:
```
+sudo apt install cmake binutils binutils-aarch64-linux-gnu binutils-mingw-w64
+
mkdir build && cd build
-cmake ..
-make
+
+cmake -vvv -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-x86_64-linux.cmake ../
+make -j$(nproc)
+cp ./native/libsemuxcrypto.so ../../resources/native/x86_64-linux/
+
+cmake -vvv -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-aarch64-linux.cmake ../
+make -j$(nproc)
+cp ./native/libsemuxcrypto.so ../../resources/native/aarch64-linux/
+
+cmake -vvv -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-w64.cmake ../
+make -j$(nproc)
+cp ./native/libsemuxcrypto.dll ../../resources/native/win64/
```
## Build on macOS
@@ -25,18 +47,3 @@ cmake ..
make
install_name_tool -change "/usr/local/lib/libsodium.23.dylib" "@loader_path/libsodium.23.dylib" crypto/libcrypto.dylib
```
-
-## Build on Windows
-
-Prerequisites:
-1. Visual Studio 2012 build tools
-2. CMake 3.8+
-3. Download and unpack libsodium 1.0.16 pre-built binaries
-4. Set `sodiumDIR` environment variable
-
-Build:
-```
-mkdir build && cd build
-cmake -G "Visual Studio 11 2012 x64" ..
-# Build the solution with Visual Studio
-```
diff --git a/src/main/native/cmake/toolchain-aarch64-linux.cmake b/src/main/native/cmake/toolchain-aarch64-linux.cmake
new file mode 100644
index 000000000..4e811d7d8
--- /dev/null
+++ b/src/main/native/cmake/toolchain-aarch64-linux.cmake
@@ -0,0 +1,70 @@
+# **********************************************************
+# Copyright (c) 2014-2017 Google, Inc. All rights reserved.
+# **********************************************************
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Google, Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+# For cross-compiling on arm64 Linux using gcc-aarch64-linux-gnu package:
+# - install AArch64 tool chain:
+# $ sudo apt-get install g++-aarch64-linux-gnu
+# - cross-compiling config
+# $ cmake -DCMAKE_TOOLCHAIN_FILE=../dynamorio/make/toolchain-arm64.cmake ../dynamorio
+# You may have to set CMAKE_FIND_ROOT_PATH to point to the target enviroment, e.g.
+# by passing -DCMAKE_FIND_ROOT_PATH=/usr/aarch64-linux-gnu on Debian-like systems.
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(TARGET_ABI "linux-gnu")
+# specify the cross compiler
+SET(CMAKE_C_COMPILER aarch64-${TARGET_ABI}-gcc)
+SET(CMAKE_CXX_COMPILER aarch64-${TARGET_ABI}-g++)
+
+# To build the tests, we need to set where the target environment containing
+# the required library is. On Debian-like systems, this is
+# /usr/aarch64-linux-gnu.
+SET(CMAKE_FIND_ROOT_PATH "/usr/aarch64-${TARGET_ABI}")
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Set additional variables.
+# If we don't set some of these, CMake will end up using the host version.
+# We want the full path, however, so we can pass EXISTS and other checks in
+# the our CMake code.
+find_program(GCC_FULL_PATH aarch64-${TARGET_ABI}-gcc)
+if (NOT GCC_FULL_PATH)
+ message(FATAL_ERROR "Cross-compiler aarch64-${TARGET_ABI}-gcc not found")
+endif ()
+get_filename_component(GCC_DIR ${GCC_FULL_PATH} PATH)
+SET(CMAKE_LINKER ${GCC_DIR}/aarch64-${TARGET_ABI}-ld CACHE FILEPATH "linker")
+SET(CMAKE_ASM_COMPILER ${GCC_DIR}/aarch64-${TARGET_ABI}-as CACHE FILEPATH "assembler")
+SET(CMAKE_OBJCOPY ${GCC_DIR}/aarch64-${TARGET_ABI}-objcopy CACHE FILEPATH "objcopy")
+SET(CMAKE_STRIP ${GCC_DIR}/aarch64-${TARGET_ABI}-strip CACHE FILEPATH "strip")
+SET(CMAKE_CPP ${GCC_DIR}/aarch64-${TARGET_ABI}-cpp CACHE FILEPATH "cpp")
+
+set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections -Wl,--no-undefined")
\ No newline at end of file
diff --git a/src/main/native/cmake/toolchain-darwin.cmake b/src/main/native/cmake/toolchain-darwin.cmake
new file mode 100644
index 000000000..f383ccd3e
--- /dev/null
+++ b/src/main/native/cmake/toolchain-darwin.cmake
@@ -0,0 +1,70 @@
+# **********************************************************
+# Copyright (c) 2014-2017 Google, Inc. All rights reserved.
+# **********************************************************
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Google, Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+# For cross-compiling on arm64 Linux using gcc-x86_64-linux-gnu package:
+# - install x86_64 tool chain:
+# $ sudo apt-get install g++-x86_64-linux-gnu
+# - cross-compiling config
+# $ cmake -DCMAKE_TOOLCHAIN_FILE=../dynamorio/make/toolchain-arm64.cmake ../dynamorio
+# You may have to set CMAKE_FIND_ROOT_PATH to point to the target enviroment, e.g.
+# by passing -DCMAKE_FIND_ROOT_PATH=/usr/x86_64-linux-gnu on Debian-like systems.
+set(CMAKE_SYSTEM_NAME Darwin)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+set(TARGET_ABI "linux-gnu")
+# specify the cross compiler
+SET(CMAKE_C_COMPILER clang)
+SET(CMAKE_CXX_COMPILER clang++)
+
+# To build the tests, we need to set where the target environment containing
+# the required library is. On Debian-like systems, this is
+# /usr/x86_64-linux-gnu.
+SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-${TARGET_ABI}")
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Set additional variables.
+# If we don't set some of these, CMake will end up using the host version.
+# We want the full path, however, so we can pass EXISTS and other checks in
+# the our CMake code.
+find_program(GCC_FULL_PATH x86_64-${TARGET_ABI}-gcc)
+if (NOT GCC_FULL_PATH)
+ message(FATAL_ERROR "Cross-compiler x86_64-${TARGET_ABI}-gcc not found")
+endif ()
+get_filename_component(GCC_DIR ${GCC_FULL_PATH} PATH)
+SET(CMAKE_LINKER ${GCC_DIR}/x86_64-${TARGET_ABI}-ld CACHE FILEPATH "linker")
+SET(CMAKE_ASM_COMPILER ${GCC_DIR}/x86_64-${TARGET_ABI}-as CACHE FILEPATH "assembler")
+SET(CMAKE_OBJCOPY ${GCC_DIR}/x86_64-${TARGET_ABI}-objcopy CACHE FILEPATH "objcopy")
+SET(CMAKE_STRIP ${GCC_DIR}/x86_64-${TARGET_ABI}-strip CACHE FILEPATH "strip")
+SET(CMAKE_CPP ${GCC_DIR}/x86_64-${TARGET_ABI}-cpp CACHE FILEPATH "cpp")
+
+set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections -Wl,--no-undefined")
\ No newline at end of file
diff --git a/src/main/native/cmake/toolchain-win64.cmake b/src/main/native/cmake/toolchain-win64.cmake
new file mode 100644
index 000000000..34288a8d6
--- /dev/null
+++ b/src/main/native/cmake/toolchain-win64.cmake
@@ -0,0 +1,77 @@
+
+# **********************************************************
+# Copyright (c) 2014-2017 Google, Inc. All rights reserved.
+# **********************************************************
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Google, Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+# For cross-compiling on arm64 Linux using gcc-x86_64-linux-gnu package:
+# - install x86_64 tool chain:
+# $ sudo apt-get install g++-x86_64-linux-gnu
+# - cross-compiling config
+# $ cmake -DCMAKE_TOOLCHAIN_FILE=../dynamorio/make/toolchain-arm64.cmake ../dynamorio
+# You may have to set CMAKE_FIND_ROOT_PATH to point to the target enviroment, e.g.
+# by passing -DCMAKE_FIND_ROOT_PATH=/usr/x86_64-linux-gnu on Debian-like systems.
+set(STATIC 1)
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+set(TARGET_ABI "w64-mingw32")
+# specify the cross compiler
+SET(CMAKE_C_COMPILER x86_64-${TARGET_ABI}-gcc)
+SET(CMAKE_CXX_COMPILER x86_64-${TARGET_ABI}-g++)
+
+# To build the tests, we need to set where the target environment containing
+# the required library is. On Debian-like systems, this is
+# /usr/x86_64-linux-gnu.
+SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-${TARGET_ABI}")
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Set additional variables.
+# If we don't set some of these, CMake will end up using the host version.
+# We want the full path, however, so we can pass EXISTS and other checks in
+# the our CMake code.
+find_program(GCC_FULL_PATH x86_64-${TARGET_ABI}-gcc)
+if (NOT GCC_FULL_PATH)
+ message(FATAL_ERROR "Cross-compiler x86_64-${TARGET_ABI}-gcc not found")
+endif ()
+get_filename_component(GCC_DIR ${GCC_FULL_PATH} PATH)
+SET(CMAKE_LINKER ${GCC_DIR}/x86_64-${TARGET_ABI}-ld CACHE FILEPATH "linker")
+SET(CMAKE_ASM_COMPILER ${GCC_DIR}/x86_64-${TARGET_ABI}-as CACHE FILEPATH "assembler")
+SET(CMAKE_OBJCOPY ${GCC_DIR}/x86_64-${TARGET_ABI}-objcopy CACHE FILEPATH "objcopy")
+SET(CMAKE_STRIP ${GCC_DIR}/x86_64-${TARGET_ABI}-strip CACHE FILEPATH "strip")
+SET(CMAKE_CPP ${GCC_DIR}/x86_64-${TARGET_ABI}-cpp CACHE FILEPATH "cpp")
+
+# avoid gcc dependency
+SET(CMAKE_SHARED_LINKER_FLAGS
+ "-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static" CACHE STRING "" FORCE)
+SET(CMAKE_EXE_LINKER_FLAGS
+ "-fdata-sections -ffunction-sections -Wl,--enable-stdcall-fixup -static-libgcc -static" CACHE STRING "" FORCE)
+link_libraries(-static-libgcc -static-libstdc++)
\ No newline at end of file
diff --git a/src/main/native/cmake/toolchain-x86_64-linux.cmake b/src/main/native/cmake/toolchain-x86_64-linux.cmake
new file mode 100644
index 000000000..425f89822
--- /dev/null
+++ b/src/main/native/cmake/toolchain-x86_64-linux.cmake
@@ -0,0 +1,70 @@
+# **********************************************************
+# Copyright (c) 2014-2017 Google, Inc. All rights reserved.
+# **********************************************************
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of Google, Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+# For cross-compiling on arm64 Linux using gcc-x86_64-linux-gnu package:
+# - install x86_64 tool chain:
+# $ sudo apt-get install g++-x86_64-linux-gnu
+# - cross-compiling config
+# $ cmake -DCMAKE_TOOLCHAIN_FILE=../dynamorio/make/toolchain-arm64.cmake ../dynamorio
+# You may have to set CMAKE_FIND_ROOT_PATH to point to the target enviroment, e.g.
+# by passing -DCMAKE_FIND_ROOT_PATH=/usr/x86_64-linux-gnu on Debian-like systems.
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+set(TARGET_ABI "linux-gnu")
+# specify the cross compiler
+SET(CMAKE_C_COMPILER x86_64-${TARGET_ABI}-gcc)
+SET(CMAKE_CXX_COMPILER x86_64-${TARGET_ABI}-g++)
+
+# To build the tests, we need to set where the target environment containing
+# the required library is. On Debian-like systems, this is
+# /usr/x86_64-linux-gnu.
+SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-${TARGET_ABI}")
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Set additional variables.
+# If we don't set some of these, CMake will end up using the host version.
+# We want the full path, however, so we can pass EXISTS and other checks in
+# the our CMake code.
+find_program(GCC_FULL_PATH x86_64-${TARGET_ABI}-gcc)
+if (NOT GCC_FULL_PATH)
+ message(FATAL_ERROR "Cross-compiler x86_64-${TARGET_ABI}-gcc not found")
+endif ()
+get_filename_component(GCC_DIR ${GCC_FULL_PATH} PATH)
+SET(CMAKE_LINKER ${GCC_DIR}/x86_64-${TARGET_ABI}-ld CACHE FILEPATH "linker")
+SET(CMAKE_ASM_COMPILER ${GCC_DIR}/x86_64-${TARGET_ABI}-as CACHE FILEPATH "assembler")
+SET(CMAKE_OBJCOPY ${GCC_DIR}/x86_64-${TARGET_ABI}-objcopy CACHE FILEPATH "objcopy")
+SET(CMAKE_STRIP ${GCC_DIR}/x86_64-${TARGET_ABI}-strip CACHE FILEPATH "strip")
+SET(CMAKE_CPP ${GCC_DIR}/x86_64-${TARGET_ABI}-cpp CACHE FILEPATH "cpp")
+
+set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections -Wl,--no-undefined")
\ No newline at end of file
diff --git a/src/main/native/crypto/CMakeLists.txt b/src/main/native/crypto/CMakeLists.txt
index 25a2c4e51..05cab9aad 100644
--- a/src/main/native/crypto/CMakeLists.txt
+++ b/src/main/native/crypto/CMakeLists.txt
@@ -3,19 +3,32 @@ cmake_minimum_required(VERSION 3.5)
project(crypto)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+set(CMAKE_CXX_FLAGS_RELEASE "-Os -fdata-sections -ffunction-sections -fstack-protector")
+add_definitions(-DED25519_CUSTOMHASH -DED25519_CUSTOMRANDOM)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
# Java JNI
-find_package(JNI REQUIRED)
-include_directories(${JNI_INCLUDE_DIRS})
+include_directories("./jni")
# libsodium library
-find_package(sodium REQUIRED)
-include_directories(${sodium_INCLUDE_DIR})
+include_directories("./libsodium/src/libsodium/include")
+add_custom_target(
+ sodium
+ COMMAND make clean
+ COMMAND ./autogen.sh
+ COMMAND ./configure --enable-shared=no --enable-minimal=yes --disable-pie --host=${CMAKE_SYSTEM_PROCESSOR}-${TARGET_ABI}
+ COMMAND make -j${nproc}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/libsodium"
+)
# source files
-set(SOURCE_FILES org_semux_crypto_Native.cpp ripemd160.c)
+set(SOURCE_FILES org_semux_crypto_Native.cpp ripemd160.c ed25519-donna/ed25519.c)
# build
-add_library(crypto SHARED ${SOURCE_FILES})
-target_link_libraries(crypto sodium)
\ No newline at end of file
+add_library(semuxcrypto SHARED ${SOURCE_FILES})
+add_dependencies(semuxcrypto sodium)
+target_link_libraries(
+ semuxcrypto
+ "-Wl,--whole-archive ${CMAKE_CURRENT_LIST_DIR}/libsodium/src/libsodium/.libs/libsodium.a -Wl,--no-whole-archive"
+)
\ No newline at end of file
diff --git a/src/main/native/crypto/cmake/Findsodium.cmake b/src/main/native/crypto/cmake/Findsodium.cmake
deleted file mode 100644
index 30e6f5c1d..000000000
--- a/src/main/native/crypto/cmake/Findsodium.cmake
+++ /dev/null
@@ -1,288 +0,0 @@
-# Written in 2016 by Henrik Steffen Gaßmann
-#
-# To the extent possible under law, the author(s) have dedicated all
-# copyright and related and neighboring rights to this software to the
-# public domain worldwide. This software is distributed without any warranty.
-#
-# You should have received a copy of the CC0 Public Domain Dedication
-# along with this software. If not, see
-#
-# http://creativecommons.org/publicdomain/zero/1.0/
-#
-########################################################################
-# Tries to find the local libsodium installation.
-#
-# On Windows the sodium_DIR environment variable is used as a default
-# hint which can be overridden by setting the corresponding cmake variable.
-#
-# Once done the following variables will be defined:
-#
-# sodium_FOUND
-# sodium_INCLUDE_DIR
-# sodium_LIBRARY_DEBUG
-# sodium_LIBRARY_RELEASE
-#
-#
-# Furthermore an imported "sodium" target is created.
-#
-
-if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
- OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
- set(_GCC_COMPATIBLE 1)
-endif()
-
-# static library option
-if (NOT DEFINED sodium_USE_STATIC_LIBS)
- option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF)
-endif()
-if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST))
- unset(sodium_LIBRARY CACHE)
- unset(sodium_LIBRARY_DEBUG CACHE)
- unset(sodium_LIBRARY_RELEASE CACHE)
- unset(sodium_DLL_DEBUG CACHE)
- unset(sodium_DLL_RELEASE CACHE)
- set(sodium_USE_STATIC_LIBS_LAST ${sodium_USE_STATIC_LIBS} CACHE INTERNAL "internal change tracking variable")
-endif()
-
-
-########################################################################
-# UNIX
-if (UNIX)
- # import pkg-config
- find_package(PkgConfig QUIET)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(sodium_PKG QUIET libsodium)
- endif()
-
- if(sodium_USE_STATIC_LIBS)
- foreach(_libname ${sodium_PKG_STATIC_LIBRARIES})
- if (NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending with .a
- list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a")
- endif()
- endforeach()
- list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES)
-
- # if pkgconfig for libsodium doesn't provide
- # static lib info, then override PKG_STATIC here..
- if (sodium_PKG_STATIC_LIBRARIES STREQUAL "")
- set(sodium_PKG_STATIC_LIBRARIES libsodium.a)
- endif()
-
- set(XPREFIX sodium_PKG_STATIC)
- else()
- if (sodium_PKG_LIBRARIES STREQUAL "")
- set(sodium_PKG_LIBRARIES sodium)
- endif()
-
- set(XPREFIX sodium_PKG)
- endif()
-
- find_path(sodium_INCLUDE_DIR sodium.h
- HINTS ${${XPREFIX}_INCLUDE_DIRS}
- )
- find_library(sodium_LIBRARY_DEBUG NAMES ${${XPREFIX}_LIBRARIES}
- HINTS ${${XPREFIX}_LIBRARY_DIRS}
- )
- find_library(sodium_LIBRARY_RELEASE NAMES ${${XPREFIX}_LIBRARIES}
- HINTS ${${XPREFIX}_LIBRARY_DIRS}
- )
-
-
-########################################################################
-# Windows
-elseif (WIN32)
- set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory")
- mark_as_advanced(sodium_DIR)
-
- find_path(sodium_INCLUDE_DIR sodium.h
- HINTS ${sodium_DIR}
- PATH_SUFFIXES include
- )
-
- if (MSVC)
- # detect target architecture
- file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.c" [=[
- #if defined _M_IX86
- #error ARCH_VALUE x86_32
- #elif defined _M_X64
- #error ARCH_VALUE x86_64
- #endif
- #error ARCH_VALUE unknown
- ]=])
- try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/arch.c"
- OUTPUT_VARIABLE _COMPILATION_LOG
- )
- string(REGEX REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*" "\\1" _TARGET_ARCH "${_COMPILATION_LOG}")
-
- # construct library path
- if (_TARGET_ARCH STREQUAL "x86_32")
- string(APPEND _PLATFORM_PATH "Win32")
- elseif(_TARGET_ARCH STREQUAL "x86_64")
- string(APPEND _PLATFORM_PATH "x64")
- else()
- message(FATAL_ERROR "the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake.")
- endif()
- string(APPEND _PLATFORM_PATH "/$$CONFIG$$")
-
- if (MSVC_VERSION LESS 1900)
- math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60")
- else()
- math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50")
- endif()
- string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}")
-
- if (sodium_USE_STATIC_LIBS)
- string(APPEND _PLATFORM_PATH "/static")
- else()
- string(APPEND _PLATFORM_PATH "/dynamic")
- endif()
-
- string(REPLACE "$$CONFIG$$" "Debug" _DEBUG_PATH_SUFFIX "${_PLATFORM_PATH}")
- string(REPLACE "$$CONFIG$$" "Release" _RELEASE_PATH_SUFFIX "${_PLATFORM_PATH}")
-
- find_library(sodium_LIBRARY_DEBUG libsodium.lib
- HINTS ${sodium_DIR}
- PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}
- )
- find_library(sodium_LIBRARY_RELEASE libsodium.lib
- HINTS ${sodium_DIR}
- PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}
- )
- if (NOT sodium_USE_STATIC_LIBS)
- set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES})
- set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll")
- find_library(sodium_DLL_DEBUG libsodium
- HINTS ${sodium_DIR}
- PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}
- )
- find_library(sodium_DLL_RELEASE libsodium
- HINTS ${sodium_DIR}
- PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}
- )
- set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK})
- endif()
-
- elseif(_GCC_COMPATIBLE)
- if (sodium_USE_STATIC_LIBS)
- find_library(sodium_LIBRARY_DEBUG libsodium.a
- HINTS ${sodium_DIR}
- PATH_SUFFIXES lib
- )
- find_library(sodium_LIBRARY_RELEASE libsodium.a
- HINTS ${sodium_DIR}
- PATH_SUFFIXES lib
- )
- else()
- find_library(sodium_LIBRARY_DEBUG libsodium.dll.a
- HINTS ${sodium_DIR}
- PATH_SUFFIXES lib
- )
- find_library(sodium_LIBRARY_RELEASE libsodium.dll.a
- HINTS ${sodium_DIR}
- PATH_SUFFIXES lib
- )
-
- file(GLOB _DLL
- LIST_DIRECTORIES false
- RELATIVE "${sodium_DIR}/bin"
- "${sodium_DIR}/bin/libsodium*.dll"
- )
- find_library(sodium_DLL_DEBUG ${_DLL} libsodium
- HINTS ${sodium_DIR}
- PATH_SUFFIXES bin
- )
- find_library(sodium_DLL_RELEASE ${_DLL} libsodium
- HINTS ${sodium_DIR}
- PATH_SUFFIXES bin
- )
- endif()
- else()
- message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
- endif()
-
-
-########################################################################
-# unsupported
-else()
- message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
-endif()
-
-
-########################################################################
-# common stuff
-
-# extract sodium version
-if (sodium_INCLUDE_DIR)
- set(_VERSION_HEADER "${_INCLUDE_DIR}/sodium/version.h")
- if (EXISTS _VERSION_HEADER)
- file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT)
- string(REGEX REPLACE ".*#[ \t]*define[ \t]*SODIUM_VERSION_STRING[ \t]*\"([^\n]*)\".*" "\\1"
- sodium_VERSION "${_VERSION_HEADER_CONTENT}")
- set(sodium_VERSION "${sodium_VERSION}" PARENT_SCOPE)
- endif()
-endif()
-
-# communicate results
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(sodium
- REQUIRED_VARS
- sodium_LIBRARY_RELEASE
- sodium_LIBRARY_DEBUG
- sodium_INCLUDE_DIR
- VERSION_VAR
- sodium_VERSION
-)
-
-# mark file paths as advanced
-mark_as_advanced(sodium_INCLUDE_DIR)
-mark_as_advanced(sodium_LIBRARY_DEBUG)
-mark_as_advanced(sodium_LIBRARY_RELEASE)
-if (WIN32)
- mark_as_advanced(sodium_DLL_DEBUG)
- mark_as_advanced(sodium_DLL_RELEASE)
-endif()
-
-# create imported target
-if(sodium_USE_STATIC_LIBS)
- set(_LIB_TYPE STATIC)
-else()
- set(_LIB_TYPE SHARED)
-endif()
-add_library(sodium ${_LIB_TYPE} IMPORTED)
-
-set_target_properties(sodium PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${sodium_INCLUDE_DIR}"
- IMPORTED_LINK_INTERFACE_LANGUAGES "C"
-)
-
-if (sodium_USE_STATIC_LIBS)
- set_target_properties(sodium PROPERTIES
- INTERFACE_COMPILE_DEFINITIONS "SODIUM_STATIC"
- IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}"
- IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}"
- )
-else()
- if (UNIX)
- set_target_properties(sodium PROPERTIES
- IMPORTED_LOCATION "${sodium_LIBRARY_RELEASE}"
- IMPORTED_LOCATION_DEBUG "${sodium_LIBRARY_DEBUG}"
- )
- elseif (WIN32)
- set_target_properties(sodium PROPERTIES
- IMPORTED_IMPLIB "${sodium_LIBRARY_RELEASE}"
- IMPORTED_IMPLIB_DEBUG "${sodium_LIBRARY_DEBUG}"
- )
- if (NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND"))
- set_target_properties(sodium PROPERTIES
- IMPORTED_LOCATION_DEBUG "${sodium_DLL_DEBUG}"
- )
- endif()
- if (NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND"))
- set_target_properties(sodium PROPERTIES
- IMPORTED_LOCATION_RELWITHDEBINFO "${sodium_DLL_RELEASE}"
- IMPORTED_LOCATION_MINSIZEREL "${sodium_DLL_RELEASE}"
- IMPORTED_LOCATION_RELEASE "${sodium_DLL_RELEASE}"
- )
- endif()
- endif()
-endif()
diff --git a/src/main/native/crypto/ed25519-donna b/src/main/native/crypto/ed25519-donna
new file mode 160000
index 000000000..e52e48d48
--- /dev/null
+++ b/src/main/native/crypto/ed25519-donna
@@ -0,0 +1 @@
+Subproject commit e52e48d48615c2c95ce70d5dccbeb6f7a1caedf7
diff --git a/src/main/native/crypto/jni/jni.h b/src/main/native/crypto/jni/jni.h
new file mode 100644
index 000000000..e15503f4d
--- /dev/null
+++ b/src/main/native/crypto/jni/jni.h
@@ -0,0 +1,1973 @@
+/*
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * We used part of Netscape's Java Runtime Interface (JRI) as the starting
+ * point of our design and implementation.
+ */
+
+/******************************************************************************
+ * Java Runtime Interface
+ * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved.
+ *****************************************************************************/
+
+#ifndef _JAVASOFT_JNI_H_
+#define _JAVASOFT_JNI_H_
+
+#include
+#include
+
+/* jni_md.h contains the machine-dependent typedefs for jbyte, jint
+ and jlong */
+
+#include "jni_md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * JNI Types
+ */
+
+#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H
+
+typedef unsigned char jboolean;
+typedef unsigned short jchar;
+typedef short jshort;
+typedef float jfloat;
+typedef double jdouble;
+
+typedef jint jsize;
+
+#ifdef __cplusplus
+
+class _jobject {};
+class _jclass : public _jobject {};
+class _jthrowable : public _jobject {};
+class _jstring : public _jobject {};
+class _jarray : public _jobject {};
+class _jbooleanArray : public _jarray {};
+class _jbyteArray : public _jarray {};
+class _jcharArray : public _jarray {};
+class _jshortArray : public _jarray {};
+class _jintArray : public _jarray {};
+class _jlongArray : public _jarray {};
+class _jfloatArray : public _jarray {};
+class _jdoubleArray : public _jarray {};
+class _jobjectArray : public _jarray {};
+
+typedef _jobject *jobject;
+typedef _jclass *jclass;
+typedef _jthrowable *jthrowable;
+typedef _jstring *jstring;
+typedef _jarray *jarray;
+typedef _jbooleanArray *jbooleanArray;
+typedef _jbyteArray *jbyteArray;
+typedef _jcharArray *jcharArray;
+typedef _jshortArray *jshortArray;
+typedef _jintArray *jintArray;
+typedef _jlongArray *jlongArray;
+typedef _jfloatArray *jfloatArray;
+typedef _jdoubleArray *jdoubleArray;
+typedef _jobjectArray *jobjectArray;
+
+#else
+
+struct _jobject;
+
+typedef struct _jobject *jobject;
+typedef jobject jclass;
+typedef jobject jthrowable;
+typedef jobject jstring;
+typedef jobject jarray;
+typedef jarray jbooleanArray;
+typedef jarray jbyteArray;
+typedef jarray jcharArray;
+typedef jarray jshortArray;
+typedef jarray jintArray;
+typedef jarray jlongArray;
+typedef jarray jfloatArray;
+typedef jarray jdoubleArray;
+typedef jarray jobjectArray;
+
+#endif
+
+typedef jobject jweak;
+
+typedef union jvalue {
+ jboolean z;
+ jbyte b;
+ jchar c;
+ jshort s;
+ jint i;
+ jlong j;
+ jfloat f;
+ jdouble d;
+ jobject l;
+} jvalue;
+
+struct _jfieldID;
+typedef struct _jfieldID *jfieldID;
+
+struct _jmethodID;
+typedef struct _jmethodID *jmethodID;
+
+/* Return values from jobjectRefType */
+typedef enum _jobjectType {
+ JNIInvalidRefType = 0,
+ JNILocalRefType = 1,
+ JNIGlobalRefType = 2,
+ JNIWeakGlobalRefType = 3
+} jobjectRefType;
+
+
+#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */
+
+/*
+ * jboolean constants
+ */
+
+#define JNI_FALSE 0
+#define JNI_TRUE 1
+
+/*
+ * possible return values for JNI functions.
+ */
+
+#define JNI_OK 0 /* success */
+#define JNI_ERR (-1) /* unknown error */
+#define JNI_EDETACHED (-2) /* thread detached from the VM */
+#define JNI_EVERSION (-3) /* JNI version error */
+#define JNI_ENOMEM (-4) /* not enough memory */
+#define JNI_EEXIST (-5) /* VM already created */
+#define JNI_EINVAL (-6) /* invalid arguments */
+
+/*
+ * used in ReleaseScalarArrayElements
+ */
+
+#define JNI_COMMIT 1
+#define JNI_ABORT 2
+
+/*
+ * used in RegisterNatives to describe native method name, signature,
+ * and function pointer.
+ */
+
+typedef struct {
+ char *name;
+ char *signature;
+ void *fnPtr;
+} JNINativeMethod;
+
+/*
+ * JNI Native Method Interface.
+ */
+
+struct JNINativeInterface_;
+
+struct JNIEnv_;
+
+#ifdef __cplusplus
+typedef JNIEnv_ JNIEnv;
+#else
+typedef const struct JNINativeInterface_ *JNIEnv;
+#endif
+
+/*
+ * JNI Invocation Interface.
+ */
+
+struct JNIInvokeInterface_;
+
+struct JavaVM_;
+
+#ifdef __cplusplus
+typedef JavaVM_ JavaVM;
+#else
+typedef const struct JNIInvokeInterface_ *JavaVM;
+#endif
+
+struct JNINativeInterface_ {
+ void *reserved0;
+ void *reserved1;
+ void *reserved2;
+
+ void *reserved3;
+ jint (JNICALL *GetVersion)(JNIEnv *env);
+
+ jclass (JNICALL *DefineClass)
+ (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
+ jsize len);
+ jclass (JNICALL *FindClass)
+ (JNIEnv *env, const char *name);
+
+ jmethodID (JNICALL *FromReflectedMethod)
+ (JNIEnv *env, jobject method);
+ jfieldID (JNICALL *FromReflectedField)
+ (JNIEnv *env, jobject field);
+
+ jobject (JNICALL *ToReflectedMethod)
+ (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
+
+ jclass (JNICALL *GetSuperclass)
+ (JNIEnv *env, jclass sub);
+ jboolean (JNICALL *IsAssignableFrom)
+ (JNIEnv *env, jclass sub, jclass sup);
+
+ jobject (JNICALL *ToReflectedField)
+ (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
+
+ jint (JNICALL *Throw)
+ (JNIEnv *env, jthrowable obj);
+ jint (JNICALL *ThrowNew)
+ (JNIEnv *env, jclass clazz, const char *msg);
+ jthrowable (JNICALL *ExceptionOccurred)
+ (JNIEnv *env);
+ void (JNICALL *ExceptionDescribe)
+ (JNIEnv *env);
+ void (JNICALL *ExceptionClear)
+ (JNIEnv *env);
+ void (JNICALL *FatalError)
+ (JNIEnv *env, const char *msg);
+
+ jint (JNICALL *PushLocalFrame)
+ (JNIEnv *env, jint capacity);
+ jobject (JNICALL *PopLocalFrame)
+ (JNIEnv *env, jobject result);
+
+ jobject (JNICALL *NewGlobalRef)
+ (JNIEnv *env, jobject lobj);
+ void (JNICALL *DeleteGlobalRef)
+ (JNIEnv *env, jobject gref);
+ void (JNICALL *DeleteLocalRef)
+ (JNIEnv *env, jobject obj);
+ jboolean (JNICALL *IsSameObject)
+ (JNIEnv *env, jobject obj1, jobject obj2);
+ jobject (JNICALL *NewLocalRef)
+ (JNIEnv *env, jobject ref);
+ jint (JNICALL *EnsureLocalCapacity)
+ (JNIEnv *env, jint capacity);
+
+ jobject (JNICALL *AllocObject)
+ (JNIEnv *env, jclass clazz);
+ jobject (JNICALL *NewObject)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jobject (JNICALL *NewObjectV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jobject (JNICALL *NewObjectA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jclass (JNICALL *GetObjectClass)
+ (JNIEnv *env, jobject obj);
+ jboolean (JNICALL *IsInstanceOf)
+ (JNIEnv *env, jobject obj, jclass clazz);
+
+ jmethodID (JNICALL *GetMethodID)
+ (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+ jobject (JNICALL *CallObjectMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jobject (JNICALL *CallObjectMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jobject (JNICALL *CallObjectMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+ jboolean (JNICALL *CallBooleanMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jboolean (JNICALL *CallBooleanMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jboolean (JNICALL *CallBooleanMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+ jbyte (JNICALL *CallByteMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jbyte (JNICALL *CallByteMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jbyte (JNICALL *CallByteMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jchar (JNICALL *CallCharMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jchar (JNICALL *CallCharMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jchar (JNICALL *CallCharMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jshort (JNICALL *CallShortMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jshort (JNICALL *CallShortMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jshort (JNICALL *CallShortMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jint (JNICALL *CallIntMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jint (JNICALL *CallIntMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jint (JNICALL *CallIntMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jlong (JNICALL *CallLongMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jlong (JNICALL *CallLongMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jlong (JNICALL *CallLongMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jfloat (JNICALL *CallFloatMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jfloat (JNICALL *CallFloatMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jfloat (JNICALL *CallFloatMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ jdouble (JNICALL *CallDoubleMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ jdouble (JNICALL *CallDoubleMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ jdouble (JNICALL *CallDoubleMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+ void (JNICALL *CallVoidMethod)
+ (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+ void (JNICALL *CallVoidMethodV)
+ (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+ void (JNICALL *CallVoidMethodA)
+ (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+ jobject (JNICALL *CallNonvirtualObjectMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jobject (JNICALL *CallNonvirtualObjectMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jobject (JNICALL *CallNonvirtualObjectMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue * args);
+
+ jboolean (JNICALL *CallNonvirtualBooleanMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jboolean (JNICALL *CallNonvirtualBooleanMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jboolean (JNICALL *CallNonvirtualBooleanMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue * args);
+
+ jbyte (JNICALL *CallNonvirtualByteMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jbyte (JNICALL *CallNonvirtualByteMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jbyte (JNICALL *CallNonvirtualByteMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jchar (JNICALL *CallNonvirtualCharMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jchar (JNICALL *CallNonvirtualCharMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jchar (JNICALL *CallNonvirtualCharMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jshort (JNICALL *CallNonvirtualShortMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jshort (JNICALL *CallNonvirtualShortMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jshort (JNICALL *CallNonvirtualShortMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jint (JNICALL *CallNonvirtualIntMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jint (JNICALL *CallNonvirtualIntMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jint (JNICALL *CallNonvirtualIntMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jlong (JNICALL *CallNonvirtualLongMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jlong (JNICALL *CallNonvirtualLongMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jlong (JNICALL *CallNonvirtualLongMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jfloat (JNICALL *CallNonvirtualFloatMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jfloat (JNICALL *CallNonvirtualFloatMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jfloat (JNICALL *CallNonvirtualFloatMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ jdouble (JNICALL *CallNonvirtualDoubleMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ jdouble (JNICALL *CallNonvirtualDoubleMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ jdouble (JNICALL *CallNonvirtualDoubleMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue *args);
+
+ void (JNICALL *CallNonvirtualVoidMethod)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+ void (JNICALL *CallNonvirtualVoidMethodV)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ va_list args);
+ void (JNICALL *CallNonvirtualVoidMethodA)
+ (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+ const jvalue * args);
+
+ jfieldID (JNICALL *GetFieldID)
+ (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+ jobject (JNICALL *GetObjectField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jboolean (JNICALL *GetBooleanField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jbyte (JNICALL *GetByteField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jchar (JNICALL *GetCharField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jshort (JNICALL *GetShortField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jint (JNICALL *GetIntField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jlong (JNICALL *GetLongField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jfloat (JNICALL *GetFloatField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+ jdouble (JNICALL *GetDoubleField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID);
+
+ void (JNICALL *SetObjectField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
+ void (JNICALL *SetBooleanField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
+ void (JNICALL *SetByteField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
+ void (JNICALL *SetCharField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
+ void (JNICALL *SetShortField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
+ void (JNICALL *SetIntField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
+ void (JNICALL *SetLongField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
+ void (JNICALL *SetFloatField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
+ void (JNICALL *SetDoubleField)
+ (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
+
+ jmethodID (JNICALL *GetStaticMethodID)
+ (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+ jobject (JNICALL *CallStaticObjectMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jobject (JNICALL *CallStaticObjectMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jobject (JNICALL *CallStaticObjectMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jboolean (JNICALL *CallStaticBooleanMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jboolean (JNICALL *CallStaticBooleanMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jboolean (JNICALL *CallStaticBooleanMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jbyte (JNICALL *CallStaticByteMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jbyte (JNICALL *CallStaticByteMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jbyte (JNICALL *CallStaticByteMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jchar (JNICALL *CallStaticCharMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jchar (JNICALL *CallStaticCharMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jchar (JNICALL *CallStaticCharMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jshort (JNICALL *CallStaticShortMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jshort (JNICALL *CallStaticShortMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jshort (JNICALL *CallStaticShortMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jint (JNICALL *CallStaticIntMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jint (JNICALL *CallStaticIntMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jint (JNICALL *CallStaticIntMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jlong (JNICALL *CallStaticLongMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jlong (JNICALL *CallStaticLongMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jlong (JNICALL *CallStaticLongMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jfloat (JNICALL *CallStaticFloatMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jfloat (JNICALL *CallStaticFloatMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jfloat (JNICALL *CallStaticFloatMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ jdouble (JNICALL *CallStaticDoubleMethod)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+ jdouble (JNICALL *CallStaticDoubleMethodV)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+ jdouble (JNICALL *CallStaticDoubleMethodA)
+ (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+ void (JNICALL *CallStaticVoidMethod)
+ (JNIEnv *env, jclass cls, jmethodID methodID, ...);
+ void (JNICALL *CallStaticVoidMethodV)
+ (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
+ void (JNICALL *CallStaticVoidMethodA)
+ (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args);
+
+ jfieldID (JNICALL *GetStaticFieldID)
+ (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+ jobject (JNICALL *GetStaticObjectField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jboolean (JNICALL *GetStaticBooleanField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jbyte (JNICALL *GetStaticByteField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jchar (JNICALL *GetStaticCharField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jshort (JNICALL *GetStaticShortField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jint (JNICALL *GetStaticIntField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jlong (JNICALL *GetStaticLongField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jfloat (JNICALL *GetStaticFloatField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+ jdouble (JNICALL *GetStaticDoubleField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID);
+
+ void (JNICALL *SetStaticObjectField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
+ void (JNICALL *SetStaticBooleanField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
+ void (JNICALL *SetStaticByteField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
+ void (JNICALL *SetStaticCharField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
+ void (JNICALL *SetStaticShortField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
+ void (JNICALL *SetStaticIntField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
+ void (JNICALL *SetStaticLongField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
+ void (JNICALL *SetStaticFloatField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
+ void (JNICALL *SetStaticDoubleField)
+ (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);
+
+ jstring (JNICALL *NewString)
+ (JNIEnv *env, const jchar *unicode, jsize len);
+ jsize (JNICALL *GetStringLength)
+ (JNIEnv *env, jstring str);
+ const jchar *(JNICALL *GetStringChars)
+ (JNIEnv *env, jstring str, jboolean *isCopy);
+ void (JNICALL *ReleaseStringChars)
+ (JNIEnv *env, jstring str, const jchar *chars);
+
+ jstring (JNICALL *NewStringUTF)
+ (JNIEnv *env, const char *utf);
+ jsize (JNICALL *GetStringUTFLength)
+ (JNIEnv *env, jstring str);
+ const char* (JNICALL *GetStringUTFChars)
+ (JNIEnv *env, jstring str, jboolean *isCopy);
+ void (JNICALL *ReleaseStringUTFChars)
+ (JNIEnv *env, jstring str, const char* chars);
+
+
+ jsize (JNICALL *GetArrayLength)
+ (JNIEnv *env, jarray array);
+
+ jobjectArray (JNICALL *NewObjectArray)
+ (JNIEnv *env, jsize len, jclass clazz, jobject init);
+ jobject (JNICALL *GetObjectArrayElement)
+ (JNIEnv *env, jobjectArray array, jsize index);
+ void (JNICALL *SetObjectArrayElement)
+ (JNIEnv *env, jobjectArray array, jsize index, jobject val);
+
+ jbooleanArray (JNICALL *NewBooleanArray)
+ (JNIEnv *env, jsize len);
+ jbyteArray (JNICALL *NewByteArray)
+ (JNIEnv *env, jsize len);
+ jcharArray (JNICALL *NewCharArray)
+ (JNIEnv *env, jsize len);
+ jshortArray (JNICALL *NewShortArray)
+ (JNIEnv *env, jsize len);
+ jintArray (JNICALL *NewIntArray)
+ (JNIEnv *env, jsize len);
+ jlongArray (JNICALL *NewLongArray)
+ (JNIEnv *env, jsize len);
+ jfloatArray (JNICALL *NewFloatArray)
+ (JNIEnv *env, jsize len);
+ jdoubleArray (JNICALL *NewDoubleArray)
+ (JNIEnv *env, jsize len);
+
+ jboolean * (JNICALL *GetBooleanArrayElements)
+ (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
+ jbyte * (JNICALL *GetByteArrayElements)
+ (JNIEnv *env, jbyteArray array, jboolean *isCopy);
+ jchar * (JNICALL *GetCharArrayElements)
+ (JNIEnv *env, jcharArray array, jboolean *isCopy);
+ jshort * (JNICALL *GetShortArrayElements)
+ (JNIEnv *env, jshortArray array, jboolean *isCopy);
+ jint * (JNICALL *GetIntArrayElements)
+ (JNIEnv *env, jintArray array, jboolean *isCopy);
+ jlong * (JNICALL *GetLongArrayElements)
+ (JNIEnv *env, jlongArray array, jboolean *isCopy);
+ jfloat * (JNICALL *GetFloatArrayElements)
+ (JNIEnv *env, jfloatArray array, jboolean *isCopy);
+ jdouble * (JNICALL *GetDoubleArrayElements)
+ (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
+
+ void (JNICALL *ReleaseBooleanArrayElements)
+ (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
+ void (JNICALL *ReleaseByteArrayElements)
+ (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
+ void (JNICALL *ReleaseCharArrayElements)
+ (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
+ void (JNICALL *ReleaseShortArrayElements)
+ (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
+ void (JNICALL *ReleaseIntArrayElements)
+ (JNIEnv *env, jintArray array, jint *elems, jint mode);
+ void (JNICALL *ReleaseLongArrayElements)
+ (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
+ void (JNICALL *ReleaseFloatArrayElements)
+ (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
+ void (JNICALL *ReleaseDoubleArrayElements)
+ (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
+
+ void (JNICALL *GetBooleanArrayRegion)
+ (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
+ void (JNICALL *GetByteArrayRegion)
+ (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
+ void (JNICALL *GetCharArrayRegion)
+ (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
+ void (JNICALL *GetShortArrayRegion)
+ (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
+ void (JNICALL *GetIntArrayRegion)
+ (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
+ void (JNICALL *GetLongArrayRegion)
+ (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
+ void (JNICALL *GetFloatArrayRegion)
+ (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
+ void (JNICALL *GetDoubleArrayRegion)
+ (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+ void (JNICALL *SetBooleanArrayRegion)
+ (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf);
+ void (JNICALL *SetByteArrayRegion)
+ (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
+ void (JNICALL *SetCharArrayRegion)
+ (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
+ void (JNICALL *SetShortArrayRegion)
+ (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
+ void (JNICALL *SetIntArrayRegion)
+ (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
+ void (JNICALL *SetLongArrayRegion)
+ (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf);
+ void (JNICALL *SetFloatArrayRegion)
+ (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
+ void (JNICALL *SetDoubleArrayRegion)
+ (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);
+
+ jint (JNICALL *RegisterNatives)
+ (JNIEnv *env, jclass clazz, const JNINativeMethod *methods,
+ jint nMethods);
+ jint (JNICALL *UnregisterNatives)
+ (JNIEnv *env, jclass clazz);
+
+ jint (JNICALL *MonitorEnter)
+ (JNIEnv *env, jobject obj);
+ jint (JNICALL *MonitorExit)
+ (JNIEnv *env, jobject obj);
+
+ jint (JNICALL *GetJavaVM)
+ (JNIEnv *env, JavaVM **vm);
+
+ void (JNICALL *GetStringRegion)
+ (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
+ void (JNICALL *GetStringUTFRegion)
+ (JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
+
+ void * (JNICALL *GetPrimitiveArrayCritical)
+ (JNIEnv *env, jarray array, jboolean *isCopy);
+ void (JNICALL *ReleasePrimitiveArrayCritical)
+ (JNIEnv *env, jarray array, void *carray, jint mode);
+
+ const jchar * (JNICALL *GetStringCritical)
+ (JNIEnv *env, jstring string, jboolean *isCopy);
+ void (JNICALL *ReleaseStringCritical)
+ (JNIEnv *env, jstring string, const jchar *cstring);
+
+ jweak (JNICALL *NewWeakGlobalRef)
+ (JNIEnv *env, jobject obj);
+ void (JNICALL *DeleteWeakGlobalRef)
+ (JNIEnv *env, jweak ref);
+
+ jboolean (JNICALL *ExceptionCheck)
+ (JNIEnv *env);
+
+ jobject (JNICALL *NewDirectByteBuffer)
+ (JNIEnv* env, void* address, jlong capacity);
+ void* (JNICALL *GetDirectBufferAddress)
+ (JNIEnv* env, jobject buf);
+ jlong (JNICALL *GetDirectBufferCapacity)
+ (JNIEnv* env, jobject buf);
+
+ /* New JNI 1.6 Features */
+
+ jobjectRefType (JNICALL *GetObjectRefType)
+ (JNIEnv* env, jobject obj);
+
+ /* Module Features */
+
+ jobject (JNICALL *GetModule)
+ (JNIEnv* env, jclass clazz);
+};
+
+/*
+ * We use inlined functions for C++ so that programmers can write:
+ *
+ * env->FindClass("java/lang/String")
+ *
+ * in C++ rather than:
+ *
+ * (*env)->FindClass(env, "java/lang/String")
+ *
+ * in C.
+ */
+
+struct JNIEnv_ {
+ const struct JNINativeInterface_ *functions;
+#ifdef __cplusplus
+
+ jint GetVersion() {
+ return functions->GetVersion(this);
+ }
+ jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
+ jsize len) {
+ return functions->DefineClass(this, name, loader, buf, len);
+ }
+ jclass FindClass(const char *name) {
+ return functions->FindClass(this, name);
+ }
+ jmethodID FromReflectedMethod(jobject method) {
+ return functions->FromReflectedMethod(this,method);
+ }
+ jfieldID FromReflectedField(jobject field) {
+ return functions->FromReflectedField(this,field);
+ }
+
+ jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) {
+ return functions->ToReflectedMethod(this, cls, methodID, isStatic);
+ }
+
+ jclass GetSuperclass(jclass sub) {
+ return functions->GetSuperclass(this, sub);
+ }
+ jboolean IsAssignableFrom(jclass sub, jclass sup) {
+ return functions->IsAssignableFrom(this, sub, sup);
+ }
+
+ jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) {
+ return functions->ToReflectedField(this,cls,fieldID,isStatic);
+ }
+
+ jint Throw(jthrowable obj) {
+ return functions->Throw(this, obj);
+ }
+ jint ThrowNew(jclass clazz, const char *msg) {
+ return functions->ThrowNew(this, clazz, msg);
+ }
+ jthrowable ExceptionOccurred() {
+ return functions->ExceptionOccurred(this);
+ }
+ void ExceptionDescribe() {
+ functions->ExceptionDescribe(this);
+ }
+ void ExceptionClear() {
+ functions->ExceptionClear(this);
+ }
+ void FatalError(const char *msg) {
+ functions->FatalError(this, msg);
+ }
+
+ jint PushLocalFrame(jint capacity) {
+ return functions->PushLocalFrame(this,capacity);
+ }
+ jobject PopLocalFrame(jobject result) {
+ return functions->PopLocalFrame(this,result);
+ }
+
+ jobject NewGlobalRef(jobject lobj) {
+ return functions->NewGlobalRef(this,lobj);
+ }
+ void DeleteGlobalRef(jobject gref) {
+ functions->DeleteGlobalRef(this,gref);
+ }
+ void DeleteLocalRef(jobject obj) {
+ functions->DeleteLocalRef(this, obj);
+ }
+
+ jboolean IsSameObject(jobject obj1, jobject obj2) {
+ return functions->IsSameObject(this,obj1,obj2);
+ }
+
+ jobject NewLocalRef(jobject ref) {
+ return functions->NewLocalRef(this,ref);
+ }
+ jint EnsureLocalCapacity(jint capacity) {
+ return functions->EnsureLocalCapacity(this,capacity);
+ }
+
+ jobject AllocObject(jclass clazz) {
+ return functions->AllocObject(this,clazz);
+ }
+ jobject NewObject(jclass clazz, jmethodID methodID, ...) {
+ va_list args;
+ jobject result;
+ va_start(args, methodID);
+ result = functions->NewObjectV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jobject NewObjectV(jclass clazz, jmethodID methodID,
+ va_list args) {
+ return functions->NewObjectV(this,clazz,methodID,args);
+ }
+ jobject NewObjectA(jclass clazz, jmethodID methodID,
+ const jvalue *args) {
+ return functions->NewObjectA(this,clazz,methodID,args);
+ }
+
+ jclass GetObjectClass(jobject obj) {
+ return functions->GetObjectClass(this,obj);
+ }
+ jboolean IsInstanceOf(jobject obj, jclass clazz) {
+ return functions->IsInstanceOf(this,obj,clazz);
+ }
+
+ jmethodID GetMethodID(jclass clazz, const char *name,
+ const char *sig) {
+ return functions->GetMethodID(this,clazz,name,sig);
+ }
+
+ jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jobject result;
+ va_start(args,methodID);
+ result = functions->CallObjectMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jobject CallObjectMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallObjectMethodV(this,obj,methodID,args);
+ }
+ jobject CallObjectMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallObjectMethodA(this,obj,methodID,args);
+ }
+
+ jboolean CallBooleanMethod(jobject obj,
+ jmethodID methodID, ...) {
+ va_list args;
+ jboolean result;
+ va_start(args,methodID);
+ result = functions->CallBooleanMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jboolean CallBooleanMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallBooleanMethodV(this,obj,methodID,args);
+ }
+ jboolean CallBooleanMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallBooleanMethodA(this,obj,methodID, args);
+ }
+
+ jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jbyte result;
+ va_start(args,methodID);
+ result = functions->CallByteMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jbyte CallByteMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallByteMethodV(this,obj,methodID,args);
+ }
+ jbyte CallByteMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallByteMethodA(this,obj,methodID,args);
+ }
+
+ jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jchar result;
+ va_start(args,methodID);
+ result = functions->CallCharMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jchar CallCharMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallCharMethodV(this,obj,methodID,args);
+ }
+ jchar CallCharMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallCharMethodA(this,obj,methodID,args);
+ }
+
+ jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jshort result;
+ va_start(args,methodID);
+ result = functions->CallShortMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jshort CallShortMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallShortMethodV(this,obj,methodID,args);
+ }
+ jshort CallShortMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallShortMethodA(this,obj,methodID,args);
+ }
+
+ jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jint result;
+ va_start(args,methodID);
+ result = functions->CallIntMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jint CallIntMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallIntMethodV(this,obj,methodID,args);
+ }
+ jint CallIntMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallIntMethodA(this,obj,methodID,args);
+ }
+
+ jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jlong result;
+ va_start(args,methodID);
+ result = functions->CallLongMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jlong CallLongMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallLongMethodV(this,obj,methodID,args);
+ }
+ jlong CallLongMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallLongMethodA(this,obj,methodID,args);
+ }
+
+ jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jfloat result;
+ va_start(args,methodID);
+ result = functions->CallFloatMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jfloat CallFloatMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallFloatMethodV(this,obj,methodID,args);
+ }
+ jfloat CallFloatMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallFloatMethodA(this,obj,methodID,args);
+ }
+
+ jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ jdouble result;
+ va_start(args,methodID);
+ result = functions->CallDoubleMethodV(this,obj,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jdouble CallDoubleMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ return functions->CallDoubleMethodV(this,obj,methodID,args);
+ }
+ jdouble CallDoubleMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallDoubleMethodA(this,obj,methodID,args);
+ }
+
+ void CallVoidMethod(jobject obj, jmethodID methodID, ...) {
+ va_list args;
+ va_start(args,methodID);
+ functions->CallVoidMethodV(this,obj,methodID,args);
+ va_end(args);
+ }
+ void CallVoidMethodV(jobject obj, jmethodID methodID,
+ va_list args) {
+ functions->CallVoidMethodV(this,obj,methodID,args);
+ }
+ void CallVoidMethodA(jobject obj, jmethodID methodID,
+ const jvalue * args) {
+ functions->CallVoidMethodA(this,obj,methodID,args);
+ }
+
+ jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jobject result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualObjectMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jboolean result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualBooleanMethodA(this,obj,clazz,
+ methodID, args);
+ }
+
+ jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jbyte result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualByteMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualByteMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualByteMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jchar CallNonvirtualCharMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jchar result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualCharMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualCharMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualCharMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jshort CallNonvirtualShortMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jshort result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualShortMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualShortMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualShortMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jint CallNonvirtualIntMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jint result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualIntMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jint CallNonvirtualIntMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualIntMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jint CallNonvirtualIntMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualIntMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jlong CallNonvirtualLongMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jlong result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualLongMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallNonvirtualLongMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz,
+ jmethodID methodID, const jvalue * args) {
+ return functions->CallNonvirtualLongMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jfloat result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz,
+ jmethodID methodID,
+ va_list args) {
+ return functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz,
+ jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallNonvirtualFloatMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jdouble result;
+ va_start(args,methodID);
+ result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+ methodID,args);
+ va_end(args);
+ return result;
+ }
+ jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz,
+ jmethodID methodID,
+ va_list args) {
+ return functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+ methodID,args);
+ }
+ jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz,
+ jmethodID methodID,
+ const jvalue * args) {
+ return functions->CallNonvirtualDoubleMethodA(this,obj,clazz,
+ methodID,args);
+ }
+
+ void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ va_start(args,methodID);
+ functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+ va_end(args);
+ }
+ void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,
+ jmethodID methodID,
+ va_list args) {
+ functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+ }
+ void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,
+ jmethodID methodID,
+ const jvalue * args) {
+ functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args);
+ }
+
+ jfieldID GetFieldID(jclass clazz, const char *name,
+ const char *sig) {
+ return functions->GetFieldID(this,clazz,name,sig);
+ }
+
+ jobject GetObjectField(jobject obj, jfieldID fieldID) {
+ return functions->GetObjectField(this,obj,fieldID);
+ }
+ jboolean GetBooleanField(jobject obj, jfieldID fieldID) {
+ return functions->GetBooleanField(this,obj,fieldID);
+ }
+ jbyte GetByteField(jobject obj, jfieldID fieldID) {
+ return functions->GetByteField(this,obj,fieldID);
+ }
+ jchar GetCharField(jobject obj, jfieldID fieldID) {
+ return functions->GetCharField(this,obj,fieldID);
+ }
+ jshort GetShortField(jobject obj, jfieldID fieldID) {
+ return functions->GetShortField(this,obj,fieldID);
+ }
+ jint GetIntField(jobject obj, jfieldID fieldID) {
+ return functions->GetIntField(this,obj,fieldID);
+ }
+ jlong GetLongField(jobject obj, jfieldID fieldID) {
+ return functions->GetLongField(this,obj,fieldID);
+ }
+ jfloat GetFloatField(jobject obj, jfieldID fieldID) {
+ return functions->GetFloatField(this,obj,fieldID);
+ }
+ jdouble GetDoubleField(jobject obj, jfieldID fieldID) {
+ return functions->GetDoubleField(this,obj,fieldID);
+ }
+
+ void SetObjectField(jobject obj, jfieldID fieldID, jobject val) {
+ functions->SetObjectField(this,obj,fieldID,val);
+ }
+ void SetBooleanField(jobject obj, jfieldID fieldID,
+ jboolean val) {
+ functions->SetBooleanField(this,obj,fieldID,val);
+ }
+ void SetByteField(jobject obj, jfieldID fieldID,
+ jbyte val) {
+ functions->SetByteField(this,obj,fieldID,val);
+ }
+ void SetCharField(jobject obj, jfieldID fieldID,
+ jchar val) {
+ functions->SetCharField(this,obj,fieldID,val);
+ }
+ void SetShortField(jobject obj, jfieldID fieldID,
+ jshort val) {
+ functions->SetShortField(this,obj,fieldID,val);
+ }
+ void SetIntField(jobject obj, jfieldID fieldID,
+ jint val) {
+ functions->SetIntField(this,obj,fieldID,val);
+ }
+ void SetLongField(jobject obj, jfieldID fieldID,
+ jlong val) {
+ functions->SetLongField(this,obj,fieldID,val);
+ }
+ void SetFloatField(jobject obj, jfieldID fieldID,
+ jfloat val) {
+ functions->SetFloatField(this,obj,fieldID,val);
+ }
+ void SetDoubleField(jobject obj, jfieldID fieldID,
+ jdouble val) {
+ functions->SetDoubleField(this,obj,fieldID,val);
+ }
+
+ jmethodID GetStaticMethodID(jclass clazz, const char *name,
+ const char *sig) {
+ return functions->GetStaticMethodID(this,clazz,name,sig);
+ }
+
+ jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID,
+ ...) {
+ va_list args;
+ jobject result;
+ va_start(args,methodID);
+ result = functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID,
+ va_list args) {
+ return functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+ }
+ jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID,
+ const jvalue *args) {
+ return functions->CallStaticObjectMethodA(this,clazz,methodID,args);
+ }
+
+ jboolean CallStaticBooleanMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jboolean result;
+ va_start(args,methodID);
+ result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jboolean CallStaticBooleanMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+ }
+ jboolean CallStaticBooleanMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticBooleanMethodA(this,clazz,methodID,args);
+ }
+
+ jbyte CallStaticByteMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jbyte result;
+ va_start(args,methodID);
+ result = functions->CallStaticByteMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jbyte CallStaticByteMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticByteMethodV(this,clazz,methodID,args);
+ }
+ jbyte CallStaticByteMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticByteMethodA(this,clazz,methodID,args);
+ }
+
+ jchar CallStaticCharMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jchar result;
+ va_start(args,methodID);
+ result = functions->CallStaticCharMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jchar CallStaticCharMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticCharMethodV(this,clazz,methodID,args);
+ }
+ jchar CallStaticCharMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticCharMethodA(this,clazz,methodID,args);
+ }
+
+ jshort CallStaticShortMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jshort result;
+ va_start(args,methodID);
+ result = functions->CallStaticShortMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jshort CallStaticShortMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticShortMethodV(this,clazz,methodID,args);
+ }
+ jshort CallStaticShortMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticShortMethodA(this,clazz,methodID,args);
+ }
+
+ jint CallStaticIntMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jint result;
+ va_start(args,methodID);
+ result = functions->CallStaticIntMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jint CallStaticIntMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticIntMethodV(this,clazz,methodID,args);
+ }
+ jint CallStaticIntMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticIntMethodA(this,clazz,methodID,args);
+ }
+
+ jlong CallStaticLongMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jlong result;
+ va_start(args,methodID);
+ result = functions->CallStaticLongMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jlong CallStaticLongMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticLongMethodV(this,clazz,methodID,args);
+ }
+ jlong CallStaticLongMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticLongMethodA(this,clazz,methodID,args);
+ }
+
+ jfloat CallStaticFloatMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jfloat result;
+ va_start(args,methodID);
+ result = functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jfloat CallStaticFloatMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+ }
+ jfloat CallStaticFloatMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticFloatMethodA(this,clazz,methodID,args);
+ }
+
+ jdouble CallStaticDoubleMethod(jclass clazz,
+ jmethodID methodID, ...) {
+ va_list args;
+ jdouble result;
+ va_start(args,methodID);
+ result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+ va_end(args);
+ return result;
+ }
+ jdouble CallStaticDoubleMethodV(jclass clazz,
+ jmethodID methodID, va_list args) {
+ return functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+ }
+ jdouble CallStaticDoubleMethodA(jclass clazz,
+ jmethodID methodID, const jvalue *args) {
+ return functions->CallStaticDoubleMethodA(this,clazz,methodID,args);
+ }
+
+ void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) {
+ va_list args;
+ va_start(args,methodID);
+ functions->CallStaticVoidMethodV(this,cls,methodID,args);
+ va_end(args);
+ }
+ void CallStaticVoidMethodV(jclass cls, jmethodID methodID,
+ va_list args) {
+ functions->CallStaticVoidMethodV(this,cls,methodID,args);
+ }
+ void CallStaticVoidMethodA(jclass cls, jmethodID methodID,
+ const jvalue * args) {
+ functions->CallStaticVoidMethodA(this,cls,methodID,args);
+ }
+
+ jfieldID GetStaticFieldID(jclass clazz, const char *name,
+ const char *sig) {
+ return functions->GetStaticFieldID(this,clazz,name,sig);
+ }
+ jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticObjectField(this,clazz,fieldID);
+ }
+ jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticBooleanField(this,clazz,fieldID);
+ }
+ jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticByteField(this,clazz,fieldID);
+ }
+ jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticCharField(this,clazz,fieldID);
+ }
+ jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticShortField(this,clazz,fieldID);
+ }
+ jint GetStaticIntField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticIntField(this,clazz,fieldID);
+ }
+ jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticLongField(this,clazz,fieldID);
+ }
+ jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticFloatField(this,clazz,fieldID);
+ }
+ jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {
+ return functions->GetStaticDoubleField(this,clazz,fieldID);
+ }
+
+ void SetStaticObjectField(jclass clazz, jfieldID fieldID,
+ jobject value) {
+ functions->SetStaticObjectField(this,clazz,fieldID,value);
+ }
+ void SetStaticBooleanField(jclass clazz, jfieldID fieldID,
+ jboolean value) {
+ functions->SetStaticBooleanField(this,clazz,fieldID,value);
+ }
+ void SetStaticByteField(jclass clazz, jfieldID fieldID,
+ jbyte value) {
+ functions->SetStaticByteField(this,clazz,fieldID,value);
+ }
+ void SetStaticCharField(jclass clazz, jfieldID fieldID,
+ jchar value) {
+ functions->SetStaticCharField(this,clazz,fieldID,value);
+ }
+ void SetStaticShortField(jclass clazz, jfieldID fieldID,
+ jshort value) {
+ functions->SetStaticShortField(this,clazz,fieldID,value);
+ }
+ void SetStaticIntField(jclass clazz, jfieldID fieldID,
+ jint value) {
+ functions->SetStaticIntField(this,clazz,fieldID,value);
+ }
+ void SetStaticLongField(jclass clazz, jfieldID fieldID,
+ jlong value) {
+ functions->SetStaticLongField(this,clazz,fieldID,value);
+ }
+ void SetStaticFloatField(jclass clazz, jfieldID fieldID,
+ jfloat value) {
+ functions->SetStaticFloatField(this,clazz,fieldID,value);
+ }
+ void SetStaticDoubleField(jclass clazz, jfieldID fieldID,
+ jdouble value) {
+ functions->SetStaticDoubleField(this,clazz,fieldID,value);
+ }
+
+ jstring NewString(const jchar *unicode, jsize len) {
+ return functions->NewString(this,unicode,len);
+ }
+ jsize GetStringLength(jstring str) {
+ return functions->GetStringLength(this,str);
+ }
+ const jchar *GetStringChars(jstring str, jboolean *isCopy) {
+ return functions->GetStringChars(this,str,isCopy);
+ }
+ void ReleaseStringChars(jstring str, const jchar *chars) {
+ functions->ReleaseStringChars(this,str,chars);
+ }
+
+ jstring NewStringUTF(const char *utf) {
+ return functions->NewStringUTF(this,utf);
+ }
+ jsize GetStringUTFLength(jstring str) {
+ return functions->GetStringUTFLength(this,str);
+ }
+ const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
+ return functions->GetStringUTFChars(this,str,isCopy);
+ }
+ void ReleaseStringUTFChars(jstring str, const char* chars) {
+ functions->ReleaseStringUTFChars(this,str,chars);
+ }
+
+ jsize GetArrayLength(jarray array) {
+ return functions->GetArrayLength(this,array);
+ }
+
+ jobjectArray NewObjectArray(jsize len, jclass clazz,
+ jobject init) {
+ return functions->NewObjectArray(this,len,clazz,init);
+ }
+ jobject GetObjectArrayElement(jobjectArray array, jsize index) {
+ return functions->GetObjectArrayElement(this,array,index);
+ }
+ void SetObjectArrayElement(jobjectArray array, jsize index,
+ jobject val) {
+ functions->SetObjectArrayElement(this,array,index,val);
+ }
+
+ jbooleanArray NewBooleanArray(jsize len) {
+ return functions->NewBooleanArray(this,len);
+ }
+ jbyteArray NewByteArray(jsize len) {
+ return functions->NewByteArray(this,len);
+ }
+ jcharArray NewCharArray(jsize len) {
+ return functions->NewCharArray(this,len);
+ }
+ jshortArray NewShortArray(jsize len) {
+ return functions->NewShortArray(this,len);
+ }
+ jintArray NewIntArray(jsize len) {
+ return functions->NewIntArray(this,len);
+ }
+ jlongArray NewLongArray(jsize len) {
+ return functions->NewLongArray(this,len);
+ }
+ jfloatArray NewFloatArray(jsize len) {
+ return functions->NewFloatArray(this,len);
+ }
+ jdoubleArray NewDoubleArray(jsize len) {
+ return functions->NewDoubleArray(this,len);
+ }
+
+ jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) {
+ return functions->GetBooleanArrayElements(this,array,isCopy);
+ }
+ jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) {
+ return functions->GetByteArrayElements(this,array,isCopy);
+ }
+ jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) {
+ return functions->GetCharArrayElements(this,array,isCopy);
+ }
+ jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) {
+ return functions->GetShortArrayElements(this,array,isCopy);
+ }
+ jint * GetIntArrayElements(jintArray array, jboolean *isCopy) {
+ return functions->GetIntArrayElements(this,array,isCopy);
+ }
+ jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) {
+ return functions->GetLongArrayElements(this,array,isCopy);
+ }
+ jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) {
+ return functions->GetFloatArrayElements(this,array,isCopy);
+ }
+ jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) {
+ return functions->GetDoubleArrayElements(this,array,isCopy);
+ }
+
+ void ReleaseBooleanArrayElements(jbooleanArray array,
+ jboolean *elems,
+ jint mode) {
+ functions->ReleaseBooleanArrayElements(this,array,elems,mode);
+ }
+ void ReleaseByteArrayElements(jbyteArray array,
+ jbyte *elems,
+ jint mode) {
+ functions->ReleaseByteArrayElements(this,array,elems,mode);
+ }
+ void ReleaseCharArrayElements(jcharArray array,
+ jchar *elems,
+ jint mode) {
+ functions->ReleaseCharArrayElements(this,array,elems,mode);
+ }
+ void ReleaseShortArrayElements(jshortArray array,
+ jshort *elems,
+ jint mode) {
+ functions->ReleaseShortArrayElements(this,array,elems,mode);
+ }
+ void ReleaseIntArrayElements(jintArray array,
+ jint *elems,
+ jint mode) {
+ functions->ReleaseIntArrayElements(this,array,elems,mode);
+ }
+ void ReleaseLongArrayElements(jlongArray array,
+ jlong *elems,
+ jint mode) {
+ functions->ReleaseLongArrayElements(this,array,elems,mode);
+ }
+ void ReleaseFloatArrayElements(jfloatArray array,
+ jfloat *elems,
+ jint mode) {
+ functions->ReleaseFloatArrayElements(this,array,elems,mode);
+ }
+ void ReleaseDoubleArrayElements(jdoubleArray array,
+ jdouble *elems,
+ jint mode) {
+ functions->ReleaseDoubleArrayElements(this,array,elems,mode);
+ }
+
+ void GetBooleanArrayRegion(jbooleanArray array,
+ jsize start, jsize len, jboolean *buf) {
+ functions->GetBooleanArrayRegion(this,array,start,len,buf);
+ }
+ void GetByteArrayRegion(jbyteArray array,
+ jsize start, jsize len, jbyte *buf) {
+ functions->GetByteArrayRegion(this,array,start,len,buf);
+ }
+ void GetCharArrayRegion(jcharArray array,
+ jsize start, jsize len, jchar *buf) {
+ functions->GetCharArrayRegion(this,array,start,len,buf);
+ }
+ void GetShortArrayRegion(jshortArray array,
+ jsize start, jsize len, jshort *buf) {
+ functions->GetShortArrayRegion(this,array,start,len,buf);
+ }
+ void GetIntArrayRegion(jintArray array,
+ jsize start, jsize len, jint *buf) {
+ functions->GetIntArrayRegion(this,array,start,len,buf);
+ }
+ void GetLongArrayRegion(jlongArray array,
+ jsize start, jsize len, jlong *buf) {
+ functions->GetLongArrayRegion(this,array,start,len,buf);
+ }
+ void GetFloatArrayRegion(jfloatArray array,
+ jsize start, jsize len, jfloat *buf) {
+ functions->GetFloatArrayRegion(this,array,start,len,buf);
+ }
+ void GetDoubleArrayRegion(jdoubleArray array,
+ jsize start, jsize len, jdouble *buf) {
+ functions->GetDoubleArrayRegion(this,array,start,len,buf);
+ }
+
+ void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
+ const jboolean *buf) {
+ functions->SetBooleanArrayRegion(this,array,start,len,buf);
+ }
+ void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+ const jbyte *buf) {
+ functions->SetByteArrayRegion(this,array,start,len,buf);
+ }
+ void SetCharArrayRegion(jcharArray array, jsize start, jsize len,
+ const jchar *buf) {
+ functions->SetCharArrayRegion(this,array,start,len,buf);
+ }
+ void SetShortArrayRegion(jshortArray array, jsize start, jsize len,
+ const jshort *buf) {
+ functions->SetShortArrayRegion(this,array,start,len,buf);
+ }
+ void SetIntArrayRegion(jintArray array, jsize start, jsize len,
+ const jint *buf) {
+ functions->SetIntArrayRegion(this,array,start,len,buf);
+ }
+ void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
+ const jlong *buf) {
+ functions->SetLongArrayRegion(this,array,start,len,buf);
+ }
+ void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
+ const jfloat *buf) {
+ functions->SetFloatArrayRegion(this,array,start,len,buf);
+ }
+ void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+ const jdouble *buf) {
+ functions->SetDoubleArrayRegion(this,array,start,len,buf);
+ }
+
+ jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
+ jint nMethods) {
+ return functions->RegisterNatives(this,clazz,methods,nMethods);
+ }
+ jint UnregisterNatives(jclass clazz) {
+ return functions->UnregisterNatives(this,clazz);
+ }
+
+ jint MonitorEnter(jobject obj) {
+ return functions->MonitorEnter(this,obj);
+ }
+ jint MonitorExit(jobject obj) {
+ return functions->MonitorExit(this,obj);
+ }
+
+ jint GetJavaVM(JavaVM **vm) {
+ return functions->GetJavaVM(this,vm);
+ }
+
+ void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
+ functions->GetStringRegion(this,str,start,len,buf);
+ }
+ void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
+ functions->GetStringUTFRegion(this,str,start,len,buf);
+ }
+
+ void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
+ return functions->GetPrimitiveArrayCritical(this,array,isCopy);
+ }
+ void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {
+ functions->ReleasePrimitiveArrayCritical(this,array,carray,mode);
+ }
+
+ const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
+ return functions->GetStringCritical(this,string,isCopy);
+ }
+ void ReleaseStringCritical(jstring string, const jchar *cstring) {
+ functions->ReleaseStringCritical(this,string,cstring);
+ }
+
+ jweak NewWeakGlobalRef(jobject obj) {
+ return functions->NewWeakGlobalRef(this,obj);
+ }
+ void DeleteWeakGlobalRef(jweak ref) {
+ functions->DeleteWeakGlobalRef(this,ref);
+ }
+
+ jboolean ExceptionCheck() {
+ return functions->ExceptionCheck(this);
+ }
+
+ jobject NewDirectByteBuffer(void* address, jlong capacity) {
+ return functions->NewDirectByteBuffer(this, address, capacity);
+ }
+ void* GetDirectBufferAddress(jobject buf) {
+ return functions->GetDirectBufferAddress(this, buf);
+ }
+ jlong GetDirectBufferCapacity(jobject buf) {
+ return functions->GetDirectBufferCapacity(this, buf);
+ }
+ jobjectRefType GetObjectRefType(jobject obj) {
+ return functions->GetObjectRefType(this, obj);
+ }
+
+ /* Module Features */
+
+ jobject GetModule(jclass clazz) {
+ return functions->GetModule(this, clazz);
+ }
+
+#endif /* __cplusplus */
+};
+
+typedef struct JavaVMOption {
+ char *optionString;
+ void *extraInfo;
+} JavaVMOption;
+
+typedef struct JavaVMInitArgs {
+ jint version;
+
+ jint nOptions;
+ JavaVMOption *options;
+ jboolean ignoreUnrecognized;
+} JavaVMInitArgs;
+
+typedef struct JavaVMAttachArgs {
+ jint version;
+
+ char *name;
+ jobject group;
+} JavaVMAttachArgs;
+
+/* These will be VM-specific. */
+
+#define JDK1_2
+#define JDK1_4
+
+/* End VM-specific. */
+
+struct JNIInvokeInterface_ {
+ void *reserved0;
+ void *reserved1;
+ void *reserved2;
+
+ jint (JNICALL *DestroyJavaVM)(JavaVM *vm);
+
+ jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args);
+
+ jint (JNICALL *DetachCurrentThread)(JavaVM *vm);
+
+ jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
+
+ jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args);
+};
+
+struct JavaVM_ {
+ const struct JNIInvokeInterface_ *functions;
+#ifdef __cplusplus
+
+ jint DestroyJavaVM() {
+ return functions->DestroyJavaVM(this);
+ }
+ jint AttachCurrentThread(void **penv, void *args) {
+ return functions->AttachCurrentThread(this, penv, args);
+ }
+ jint DetachCurrentThread() {
+ return functions->DetachCurrentThread(this);
+ }
+
+ jint GetEnv(void **penv, jint version) {
+ return functions->GetEnv(this, penv, version);
+ }
+ jint AttachCurrentThreadAsDaemon(void **penv, void *args) {
+ return functions->AttachCurrentThreadAsDaemon(this, penv, args);
+ }
+#endif
+};
+
+#ifdef _JNI_IMPLEMENTATION_
+#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT
+#else
+#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT
+#endif
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetDefaultJavaVMInitArgs(void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
+
+/* Defined by native libraries. */
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved);
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved);
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+#define JNI_VERSION_1_6 0x00010006
+#define JNI_VERSION_1_8 0x00010008
+#define JNI_VERSION_9 0x00090000
+#define JNI_VERSION_10 0x000a0000
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* !_JAVASOFT_JNI_H_ */
diff --git a/src/main/native/crypto/jni/jni_md.h b/src/main/native/crypto/jni/jni_md.h
new file mode 100644
index 000000000..6e352038f
--- /dev/null
+++ b/src/main/native/crypto/jni/jni_md.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef _JAVASOFT_JNI_MD_H_
+#define _JAVASOFT_JNI_MD_H_
+
+#ifndef __has_attribute
+ #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
+ #ifdef ARM
+ #define JNIEXPORT __attribute__((externally_visible,visibility("default")))
+ #define JNIIMPORT __attribute__((externally_visible,visibility("default")))
+ #else
+ #define JNIEXPORT __attribute__((visibility("default")))
+ #define JNIIMPORT __attribute__((visibility("default")))
+ #endif
+#else
+ #define JNIEXPORT
+ #define JNIIMPORT
+#endif
+
+#define JNICALL
+
+typedef int jint;
+#ifdef _LP64
+typedef long jlong;
+#else
+typedef long long jlong;
+#endif
+
+typedef signed char jbyte;
+
+#endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/src/main/native/crypto/libsodium b/src/main/native/crypto/libsodium
new file mode 160000
index 000000000..b732443c4
--- /dev/null
+++ b/src/main/native/crypto/libsodium
@@ -0,0 +1 @@
+Subproject commit b732443c442239c2e0184820e9b23cca0de0828c
diff --git a/src/main/native/crypto/org_semux_crypto_Native.cpp b/src/main/native/crypto/org_semux_crypto_Native.cpp
index d39f36cf4..3948190a5 100644
--- a/src/main/native/crypto/org_semux_crypto_Native.cpp
+++ b/src/main/native/crypto/org_semux_crypto_Native.cpp
@@ -1,6 +1,7 @@
#include "org_semux_crypto_Native.h"
#include "ripemd160.h"
#include
+#include "ed25519-donna/ed25519.h"
JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_h256
(JNIEnv *env, jclass cls, jbyteArray msg)
@@ -107,13 +108,76 @@ JNIEXPORT jboolean JNICALL Java_org_semux_crypto_Native_verify
env->GetByteArrayRegion(pk, 0, crypto_sign_ed25519_PUBLICKEYBYTES, pk_buf);
// verify ed25519 signature
- jboolean result = crypto_sign_ed25519_verify_detached((const unsigned char *)sig_buf,
- (const unsigned char *)msg_buf, msg_size, (const unsigned char *)pk_buf) == 0;
+ jboolean result = ed25519_sign_open(
+ (const unsigned char *)msg_buf,
+ msg_size,
+ (const unsigned char *)pk_buf,
+ (const unsigned char *)sig_buf) == 0;
// release buffer
free(pk_buf);
free(sig_buf);
free(msg_buf);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_semux_crypto_Native_verifyBatch
+(JNIEnv *env, jclass cls, jobjectArray msgs, jobjectArray sigs, jobjectArray pks)
+{
+ // check null inputs
+ if (msgs == NULL || sigs == NULL || pks == NULL) {
+ return false;
+ }
+
+ // check array lengths
+ const jsize msgs_size = env->GetArrayLength(msgs);
+ const jsize sigs_size = env->GetArrayLength(sigs);
+ const jsize pks_size = env->GetArrayLength(pks);
+ if (msgs_size != sigs_size || sigs_size != pks_size) {
+ env->ThrowNew(env->FindClass("org/semux/crypto/CryptoException"), "Input arrays must have an identical length");
+ return false;
+ }
+
+ // read byte arrays into c buffers
+ auto msg_bufs = new jbyte*[msgs_size];
+ auto msg_lens = new size_t[msgs_size];
+ auto sig_bufs = new jbyte*[sigs_size];
+ auto pk_bufs = new jbyte*[pks_size];
+ for (int i = 0;i < msgs_size;i++) {
+ jbyteArray msg = (jbyteArray) env->GetObjectArrayElement(msgs, i);
+ jbyteArray sig = (jbyteArray) env->GetObjectArrayElement(sigs, i);
+ jbyteArray pk = (jbyteArray) env->GetObjectArrayElement(pks, i);
+ if (msg == NULL || sig == NULL || env->GetArrayLength(sig) != crypto_sign_ed25519_BYTES
+ || pk == NULL || env->GetArrayLength(pk) != crypto_sign_ed25519_PUBLICKEYBYTES) {
+ return false;
+ }
+
+ const jsize msg_size = env->GetArrayLength(msg);
+ msg_lens[i] = (size_t) msg_size;
+ msg_bufs[i] = new jbyte[msg_size];
+ env->GetByteArrayRegion(msg, 0, msg_size, msg_bufs[i]);
+ sig_bufs[i] = new jbyte[crypto_sign_ed25519_BYTES];
+ env->GetByteArrayRegion(sig, 0, crypto_sign_ed25519_BYTES, sig_bufs[i]);
+ pk_bufs[i] = new jbyte[crypto_sign_ed25519_PUBLICKEYBYTES];
+ env->GetByteArrayRegion(pk, 0, crypto_sign_ed25519_PUBLICKEYBYTES, pk_bufs[i]);
+ }
+
+ // verify ed25519 signature
+ int *valid = new int[msgs_size];
+ jboolean result = ed25519_sign_open_batch((const unsigned char **)msg_bufs, msg_lens, (const unsigned char **)pk_bufs, (const unsigned char **)sig_bufs, msgs_size, valid) == 0;
+
+ // release buffers
+ for (int i = 0;i < msgs_size;i++) {
+ delete[] msg_bufs[i];
+ delete[] sig_bufs[i];
+ delete[] pk_bufs[i];
+ }
+ delete[] msg_bufs;
+ delete[] msg_lens;
+ delete[] sig_bufs;
+ delete[] pk_bufs;
+ delete[] valid;
+
return result;
}
\ No newline at end of file
diff --git a/src/main/native/crypto/org_semux_crypto_Native.h b/src/main/native/crypto/org_semux_crypto_Native.h
index c77278429..97a278db8 100644
--- a/src/main/native/crypto/org_semux_crypto_Native.h
+++ b/src/main/native/crypto/org_semux_crypto_Native.h
@@ -39,6 +39,14 @@ JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_sign
JNIEXPORT jboolean JNICALL Java_org_semux_crypto_Native_verify
(JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray);
+/*
+ * Class: org_semux_crypto_Native
+ * Method: verifyBatch
+ * Signature: ([[B[[B[[B)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_semux_crypto_Native_verifyBatch
+ (JNIEnv *, jclass, jobjectArray, jobjectArray, jobjectArray);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/main/resources/native/aarch64-linux/libsemuxcrypto.so b/src/main/resources/native/aarch64-linux/libsemuxcrypto.so
new file mode 100755
index 0000000000000000000000000000000000000000..9c8f06eb571c1107b617ed2c098d6fc35b480217
GIT binary patch
literal 1068144
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