diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..3c32d25 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8794d04 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,155 @@ +name: Publish artifacts to Sonatype Repo + +on: + push: + branches: + - master + - version-[0-9].[0-9]+.x + tags: + - v[0-9].[0-9]+.[0-9]+ + pull_request: + +env: + NATIVE_DIR: zwaves_jni/javalib/src/main/resources/META-INF/native + GRADLE_EXTRA_ARGS: --console=plain -Ppr=${{ github.event.number }} -PrefName=${{ github.head_ref }} + # GITHUB_CONTEXT: ${{ toJson(github) }} # For debugging purposes + +jobs: + build-native: + name: ${{ matrix.platform }}/${{ matrix.arch }} library + runs-on: ${{ matrix.os }} + env: + # Where a library should be + target-path: ${{ matrix.jni-platform }}/${{ matrix.arch }} + + # Rust build target + build-target: ${{ matrix.build-arch }}-${{ matrix.build-platform }} + + # Rust target directory + TARGET_DIR: ./target + + # Emit backtraces on panics. + RUST_BACKTRACE: 1 + strategy: + matrix: +# platform: [ linux, osx, windows ] +# arch: [ aarch64, amd64, x86 ] + platform: [ linux ] + arch: [ amd64 ] + exclude: + - platform: osx + arch: x86 + - platform: windows + arch: aarch64 + + include: + - platform: linux + os: ubuntu-20.04 + build-platform: unknown-linux-gnu + artifact: libzwaves_jni.so + jni-platform: linux64 + +# - platform: linux +# arch: aarch64 +# extra-packages: gcc-aarch64-linux-gnu +# +# - platform: linux +# arch: x86 +# extra-packages: gcc-multilib +# jni-platform: linux32 +# +# - platform: osx +# os: macos-latest +# build-platform: apple-darwin +# artifact: libzwaves_jni.dylib +# jni-platform: osx64 +# +# - platform: windows +# os: windows-2019 +# build-platform: pc-windows-msvc # x86 and gcc lead to "undefined reference to _Unwind_Resume" +# artifact: zwaves_jni.dll +# jni-platform: windows64 +# +# - platform: windows +# arch: x86 +# jni-platform: windows32 +# +# - arch: aarch64 +# build-arch: aarch64 + + - arch: amd64 + build-arch: x86_64 + +# - arch: x86 +# build-arch: i686 + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Print debug information + run: | + echo "Build target: ${{ env.build-target }}" + echo "Target path: ${{ env.target-path }}" + + - name: Install build tools + if: ${{ matrix.extra-packages }} + run: | + sudo apt-get update + sudo apt-get install -y ${{ matrix.extra-packages }} + + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + target: ${{ env.build-target }} + + - name: Enable Rust dependencies caching + uses: Swatinem/rust-cache@v2 + + - name: Run Rust tests + # Architecture is always x86-64: https://stackoverflow.com/a/71220337 + if: matrix.arch == 'amd64' + run: | + cd zwaves_jni + cargo test --lib --target ${{ env.build-target }} + + - name: Build native libraries + run: | + cd zwaves_jni + cargo build --release --target ${{ env.build-target }} + cd .. + + cp target/${{ env.build-target }}/release/${{ matrix.artifact }} ${{ env.NATIVE_DIR }}/${{ env.target-path }} + + - name: Upload result + uses: actions/upload-artifact@v3 + with: + name: native-libraries + path: ${{ env.NATIVE_DIR }}/**/* + + build-jni: + name: Build JNI library + runs-on: ubuntu-20.04 + needs: build-native + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-java@v3 + with: + java-version: 8 + distribution: temurin + cache: gradle + + - uses: actions/download-artifact@v3 + with: + name: native-libraries + path: ${{ env.NATIVE_DIR }} + + - name: Publish version + run: | + cd zwaves_jni/javalib + ./gradlew ${GRADLE_EXTRA_ARGS} publishToSonatype \ + -PsonatypeUsername='${{ secrets.OSSRH_USERNAME }}' \ + -PsonatypePassword='${{ secrets.OSSRH_PASSWORD }}' \ + -PgpgKey='${{ secrets.OSSRH_GPG_KEY_ASCII }}' \ + -PgpgPassphrase='${{ secrets.OSSRH_GPG_PASSPHRASE }}' diff --git a/.gitignore b/.gitignore index 18f8e7e..1aedb3d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ bin/ pkg/ wasm-pack.log .vscode +.idea +!zwaves_jni/src/bn256/bin !zwaves_setup/src/bin diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..bb26182 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +edition = "2018" + +max_width = 120 +hard_tabs = false +newline_style = "Unix" + +imports_granularity = "Crate" diff --git a/zwaves_jni/.cargo/config b/zwaves_jni/.cargo/config deleted file mode 100644 index f550e2a..0000000 --- a/zwaves_jni/.cargo/config +++ /dev/null @@ -1,13 +0,0 @@ -[target.x86_64-apple-darwin] -linker = "x86_64-apple-darwin14-clang" -ar = "x86_64-apple-darwin14-ar" - -[target.x86_64-pc-windows-gnu] -linker = "x86_64-w64-mingw32-gcc" -ar = "x86_64-w64-mingw32-gcc-ar" - -[target.i686-pc-windows-gnu] -linker = "i686-w64-mingw32-gcc" -ar = "i686-w64-mingw32-gcc-ar" - - diff --git a/zwaves_jni/Cargo.toml b/zwaves_jni/Cargo.toml index 862b957..b98b326 100644 --- a/zwaves_jni/Cargo.toml +++ b/zwaves_jni/Cargo.toml @@ -1,21 +1,35 @@ [package] name = "zwaves_jni" -version = "0.1.0" +version = "0.2.0" authors = ["Igor Gulamov "] edition = "2018" [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] name = "zwaves_jni" +[[bin]] +path = "src/bn256/bin/show_test_vectors.rs" +name="show_test_vectors" + [dependencies] bellman = { version = "0.1.0" } zwaves_primitives = { path = "../zwaves_primitives"} sapling-crypto = { path = "../sapling-crypto" } pairing = "0.14" +pairing_ce = "0.18" # for bn256 num = "0.2" serde = { version = "1.0", features = ["derive"] } base64 = "0.11.0" jni = "0.14.0" byteorder = "1" rand = "0.4" + +# for bn256 +[dependencies.ff] +version = "=0.7" +features = ["derive"] +package = "ff_ce" + +[dev-dependencies] +test-case = "3.2.1" diff --git a/zwaves_jni/build_all.sh b/zwaves_jni/build_all.sh index 93b1393..4bbf7cc 100644 --- a/zwaves_jni/build_all.sh +++ b/zwaves_jni/build_all.sh @@ -1,12 +1,3 @@ -if [ ! -d "osxcross" ]; then - git clone https://github.com/tpoechtrager/osxcross - pushd osxcross - wget -nc https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz - mv MacOSX10.10.sdk.tar.xz tarballs/ - UNATTENDED=yes OSX_VERSION_MIN=10.7 ./build.sh - popd -fi - cargo build --target=i686-unknown-linux-gnu --release cp ../target/i686-unknown-linux-gnu/release/libzwaves_jni.so javalib/src/main/resources/META-INF/native/linux32 diff --git a/zwaves_jni/javalib/build.gradle b/zwaves_jni/javalib/build.gradle index ea8180a..1a904a8 100644 --- a/zwaves_jni/javalib/build.gradle +++ b/zwaves_jni/javalib/build.gradle @@ -1,37 +1,55 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Java Library project to get you started. - * For more details take a look at the Java Libraries chapter in the Gradle - * User Manual available at https://docs.gradle.org/5.4.1/userguide/java_library_plugin.html - */ - plugins { - // Apply the java-library plugin to add support for Java Library - id 'java-library' + id "java-library" + id "maven-publish" + id "signing" + id "io.github.gradle-nexus.publish-plugin" version "1.3.0" } +group = "com.wavesplatform" +version = "0.2.0" + repositories { - // Use jcenter for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + mavenCentral() } dependencies { - // This dependency is exported to consumers, that is to say found on their compile classpath. - api 'org.apache.commons:commons-math3:3.6.1' - - // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation 'com.google.guava:guava:27.0.1-jre' - - // Use JUnit test framework testImplementation 'junit:junit:4.12' } - test { useJUnit() - maxHeapSize = '1G' } +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + + pom { + licenses { + license { + name.set("MIT License") + url.set("LICENSE") + } + } + scm { + connection.set("scm:git:git://github.com/wavesplatform/zwaves.git") + developerConnection.set("scm:git:git@github.com:wavesplatform/zwaves.git") + url.set("https://github.com/wavesplatform/zwaves") + } + } + } + } +} + +signing { + useInMemoryPgpKeys(gpgKey, gpgPassphrase) + sign configurations.archives +} + +nexusPublishing { + repositories { + sonatype() + } +} diff --git a/zwaves_jni/javalib/gradle/wrapper/gradle-wrapper.properties b/zwaves_jni/javalib/gradle/wrapper/gradle-wrapper.properties index f4d7b2b..b7c8c5d 100644 --- a/zwaves_jni/javalib/gradle/wrapper/gradle-wrapper.properties +++ b/zwaves_jni/javalib/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/zwaves_jni/javalib/gradlew b/zwaves_jni/javalib/gradlew old mode 100644 new mode 100755 diff --git a/zwaves_jni/javalib/settings.gradle b/zwaves_jni/javalib/settings.gradle index 059992b..00387bc 100644 --- a/zwaves_jni/javalib/settings.gradle +++ b/zwaves_jni/javalib/settings.gradle @@ -1,10 +1 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/5.4.1/userguide/multi_project_builds.html - */ - rootProject.name = 'zwaves' diff --git a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/JNILibrary.java b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/JNILibrary.java similarity index 99% rename from zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/JNILibrary.java rename to zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/JNILibrary.java index 11e617f..91cf819 100644 --- a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/JNILibrary.java +++ b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/JNILibrary.java @@ -7,7 +7,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ -package com.wavesplatform.zwaves.bls12; +package com.wavesplatform.zwaves; import java.io.*; import java.lang.reflect.Method; @@ -538,4 +538,4 @@ private boolean loadLibrary(ArrayList errors, String lib) { return false; } -} \ No newline at end of file +} diff --git a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/ZWavesJNILibrary.java b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/ZWavesJNILibrary.java new file mode 100644 index 0000000..ae649ff --- /dev/null +++ b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/ZWavesJNILibrary.java @@ -0,0 +1,9 @@ +package com.wavesplatform.zwaves; + +public class ZWavesJNILibrary { + static { + new JNILibrary("zwaves_jni", ZWavesJNILibrary.class).load(); + } + + public static void init() {} +} diff --git a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/Groth16.java b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/Groth16.java index 96f16ba..e18ccff 100644 --- a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/Groth16.java +++ b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bls12/Groth16.java @@ -4,6 +4,6 @@ public class Groth16 { public static native boolean verify(byte[] vk, byte[] proof, byte[] inputs); static { - new JNILibrary("zwaves_jni", Groth16.class).load(); + com.wavesplatform.zwaves.ZWavesJNILibrary.init(); } -} \ No newline at end of file +} diff --git a/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bn256/Groth16.java b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bn256/Groth16.java new file mode 100644 index 0000000..64d75a8 --- /dev/null +++ b/zwaves_jni/javalib/src/main/java/com/wavesplatform/zwaves/bn256/Groth16.java @@ -0,0 +1,9 @@ +package com.wavesplatform.zwaves.bn256; + +public class Groth16 { + public static native boolean verify(byte[] vk, byte[] proof, byte[] inputs); + + static { + com.wavesplatform.zwaves.ZWavesJNILibrary.init(); + } +} diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/linux32/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/linux32/x86/.gitkeep similarity index 100% rename from zwaves_jni/javalib/src/main/resources/META-INF/native/linux32/.gitkeep rename to zwaves_jni/javalib/src/main/resources/META-INF/native/linux32/x86/.gitkeep diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/aarch64/.gitkeep similarity index 100% rename from zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/.gitkeep rename to zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/aarch64/.gitkeep diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/amd64/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/amd64/.gitkeep new file mode 100644 index 0000000..859d1c9 --- /dev/null +++ b/zwaves_jni/javalib/src/main/resources/META-INF/native/linux64/amd64/.gitkeep @@ -0,0 +1 @@ +place here libzwaves_jni.so file \ No newline at end of file diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/osx64/aarch64/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/osx64/aarch64/.gitkeep new file mode 100644 index 0000000..eec68a2 --- /dev/null +++ b/zwaves_jni/javalib/src/main/resources/META-INF/native/osx64/aarch64/.gitkeep @@ -0,0 +1 @@ +place here libzwaves_jni.dylib for Apple ARM file \ No newline at end of file diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/osx/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/osx64/amd64/.gitkeep similarity index 100% rename from zwaves_jni/javalib/src/main/resources/META-INF/native/osx/.gitkeep rename to zwaves_jni/javalib/src/main/resources/META-INF/native/osx64/amd64/.gitkeep diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/.gitkeep deleted file mode 100644 index 795def8..0000000 --- a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -place here libzwaves_jni.dll file \ No newline at end of file diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/x86/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/x86/.gitkeep new file mode 100644 index 0000000..12550e1 --- /dev/null +++ b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows32/x86/.gitkeep @@ -0,0 +1 @@ +place here zwaves_jni.dll file diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/.gitkeep deleted file mode 100644 index 795def8..0000000 --- a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -place here libzwaves_jni.dll file \ No newline at end of file diff --git a/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/amd64/.gitkeep b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/amd64/.gitkeep new file mode 100644 index 0000000..12550e1 --- /dev/null +++ b/zwaves_jni/javalib/src/main/resources/META-INF/native/windows64/amd64/.gitkeep @@ -0,0 +1 @@ +place here zwaves_jni.dll file diff --git a/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bls12/Groth16Test.java b/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bls12/Groth16Test.java index 03d2621..3df4968 100644 --- a/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bls12/Groth16Test.java +++ b/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bls12/Groth16Test.java @@ -1,16 +1,14 @@ package com.wavesplatform.zwaves.bls12; import org.junit.Test; -import static org.junit.Assert.*; import java.util.Base64; -public class Groth16Test { - +import static org.junit.Assert.*; +public class Groth16Test { @Test public void test() { - byte[] vk = Base64.getDecoder().decode("hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r"); byte[] proof = Base64.getDecoder().decode("lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF"); byte[] inputs = Base64.getDecoder().decode("LcMT3OOlkHLzJBKCKjjzzVMg+r+FVgd52LlhZPB4RFg="); @@ -20,8 +18,6 @@ public void test() { assertTrue("Result should be true", Groth16.verify(vk, proof, inputs)); assertFalse("Result should be false", Groth16.verify(vk, proof, inputs2)); - assertFalse("Result should be false", Groth16.verify(vk, proof, inputs3)); - + assertFalse("Result should be false", Groth16.verify(vk, proof, inputs3)); } - -} \ No newline at end of file +} diff --git a/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bn256/Groth16Test.java b/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bn256/Groth16Test.java new file mode 100644 index 0000000..054e6e3 --- /dev/null +++ b/zwaves_jni/javalib/src/test/java/com/wavesplatform/zwaves/bn256/Groth16Test.java @@ -0,0 +1,23 @@ +package com.wavesplatform.zwaves.bn256; + +import org.junit.Test; + +import java.util.Base64; + +import static org.junit.Assert.*; + +public class Groth16Test { + @Test + public void test() { + byte[] vk = Base64.getDecoder().decode("LDCJzjgi5HtcHEXHfU8TZz+ZUHD2ZwsQ7JIEvzdMPYKYs9SoGkKUmg1yya4TE0Ms7x+KOJ4Ze/CPfKp2s5jbniFNM71N/YlHVbNkytLtQi1DzReSh9SNBsvskdY5mavQJe+67PuPVEYnx+lJ97qIG8243njZbGWPqUJ2Vqj49NAunhqX+eIkK3zAB3IPWls3gruzX2t9wrmyE9cVVvf1kgWx63PsQV37qdH0KcFRpCH89k4TPS6fLmqdFxX3YGHCGFTpr6tLogvjbUFJPT98kJ/xck0C0B/s8PTVKdao4VQHT4DBIO8+GB3CQVh6VV4EcMLtDWWNxF4yloAlKcFT0Q4AzJSimpFqd/SwSz9Pb7uk5srte3nwphVamC+fHlJt"); + byte[] proof = Base64.getDecoder().decode("GQPBoHuCPcIosF+WZKE5jZV13Ib4EdjLnABncpSHcMKBZl0LhllnPxcuzExIQwhxcfXvFFAjlnDGpKauQ9OQsjBKUBsdBZnGiV2Sg4TSdyHuLo2AbRRqJN0IV3iH3On8I4ngnL30ZAxVyGQH2EK58aUZGxMbbXGR9pQdh99QaiE="); + byte[] inputs = Base64.getDecoder().decode("IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQo="); + + byte[] inputs2 = Base64.getDecoder().decode("cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s="); + byte[] inputs3 = {}; + + assertTrue("Result should be true", Groth16.verify(vk, proof, inputs)); + assertFalse("Result should be false", Groth16.verify(vk, proof, inputs2)); + assertFalse("Result should be false", Groth16.verify(vk, proof, inputs3)); + } +} diff --git a/zwaves_jni/src/bls12/mod.rs b/zwaves_jni/src/bls12/mod.rs new file mode 100644 index 0000000..f3f3140 --- /dev/null +++ b/zwaves_jni/src/bls12/mod.rs @@ -0,0 +1,122 @@ +use std::io; + +use bellman::groth16::Proof; +use pairing::bls12_381::{Bls12, Fr}; + +use zwaves_primitives::{ + serialization::read_fr_vec, + verifier::{verify_proof, TruncatedVerifyingKey}, +}; + +#[cfg(test)] +pub mod tests; + +pub fn groth16_verify(vk: &[u8], proof: &[u8], inputs: &[u8]) -> io::Result { + let buff_vk_len = vk.len(); + let buff_proof_len = proof.len(); + let buff_inputs_len = inputs.len(); + + if (buff_vk_len % 48 != 0) || (buff_inputs_len % 32 != 0) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); + } + + let inputs_len = buff_inputs_len / 32; + + if ((buff_vk_len / 48) != (inputs_len + 8)) || (buff_proof_len != 192) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); + } + + let vk = TruncatedVerifyingKey::::read(vk)?; + let proof = Proof::::read(proof)?; + let inputs = read_fr_vec::(inputs)?; + + if (inputs.len() != inputs_len) || (vk.ic.len() != (inputs_len + 1)) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer parsing")); + } + + Ok(verify_proof(&vk, &proof, inputs.as_slice()) + .map(|r| r as u8) + .unwrap_or(0)) +} + +#[cfg(test)] +mod local_tests { + use super::*; + use base64::decode; + use test_case::test_case; + + #[test_case( + "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r", + "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF", + "LcMT3OOlkHLzJBKCKjjzzVMg+r+FVgd52LlhZPB4RFg=" + => true + )] + #[test_case( + "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r", + "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF", + "cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s=" + => false + )] + #[test_case( + "kYYCAS8vM2T99GeCr4toQ+iQzvl5fI89mPrncYqx3C1d75BQbFk8LMtcnLWwntd6knkzSwcsialcheg69eZYPK8EzKRVI5FrRHKi8rgB+R5jyPV70ejmYEx1neTmfYKODRmARr/ld6pZTzBWYDfrCkiS1QB+3q3M08OQgYcLzs/vjW4epetDCmk0K1CEGcWdh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0jgld4oAppAOzvQ7eoIx2tbuuKVSdbJm65KDxl/T+boaYnjRm3omdETYnYRk3HAhrAeWpefX+dM/k7PrcheInnxHUyjzSzqlN03xYjg28kdda9FZJaVsQKqdEJ/St9ivXlp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+n", + "sStVLdyxqInmv76iaNnRFB464lGq48iVeqYWSi2linE9DST0fTNhxSnvSXAoPpt8tFsanj5vPafC+ij/Fh98dOUlMbO42bf280pOZ4lm+zr63AWUpOOIugST+S6pq9zeB0OHp2NY8XFmriOEKhxeabhuV89ljqCDjlhXBeNZwM5zti4zg89Hd8TbKcw46jAsjIJe2Siw3Th7ELQQKR5ucX50f0GISmnOSceePPdvjbGJ8fSFOnSmSp8dK7uyehrU", + "" + => true + )] + #[test_case( + "mY//hEITCBCZUJUN/wsOlw1iUSSOESL6PFSbN1abGK80t5jPNICNlPuSorio4mmWpf+4uOyv3gPZe54SYGM4pfhteqJpwFQxdlpwXWyYxMTNaSLDj8VtSn/EJaSu+P6nFmWsda3mTYUPYMZzWE4hMqpDgFPcJhw3prArMThDPbR3Hx7E6NRAAR0LqcrdtsbDqu2T0tto1rpnFILdvHL4PqEUfTmF2mkM+DKj7lKwvvZUbukqBwLrnnbdfyqZJryzGAMIa2JvMEMYszGsYyiPXZvYx6Luk54oWOlOrwEKrCY4NMPwch6DbFq6KpnNSQwOpgRYCz7wpjk57X+NGJmo85tYKc+TNa1rT4/DxG9v6SHkpXmmPeHhzIIW8MOdkFjxB5o6Qn8Fa0c6Tt6br2gzkrGr1eK5/+RiIgEzVhcRrqdY/p7PLmKXqawrEvIv9QZ3ijytPNwinlC8XdRLO/YvP33PjcI9WSMcHV6POP9KPMo1rngaIPMegKgAvTEouNFKp4v3wAXRXX5xEjwXAmM5wyB/SAOaPPCK/emls9kqolHsaj7nuTTbrvSV8bqzUwzQ", + "g53N8ecorvG2sDgNv8D7quVhKMIIpdP9Bqk/8gmV5cJ5Rhk9gKvb4F0ll8J/ZZJVqa27OyciJwx6lym6QpVK9q1ASrqio7rD5POMDGm64Iay/ixXXn+//F+uKgDXADj9AySri2J1j3qEkqqe3kxKthw94DzAfUBPncHfTPazVtE48AfzB1KWZA7Vf/x/3phYs4ckcP7ZrdVViJVLbUgFy543dpKfEH2MD30ZLLYRhw8SatRCyIJuTZcMlluEKG+d", + "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEs=" + => true + )] + #[test_case( + "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" + => true + )] + #[test_case( + "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" + => true + )] + #[test_case( + "pQUlLSBu9HmVa9hB0rEu1weeBv2RKQQ8yCHpwXTHeSkcQqmSOuzednF8o0+MdyNuhKgxmPN2c94UBtlYc0kZS6CwyMEEV/nVGSjajEZPdnpbK7fEcPd0hWNcOxKWq8qBBPfT69Ore74buf8C26ZTyKnjgMsGCvoDAMOsA07DjjQ1nIkkwIGFFUT3iMO83TdEpWgV/2z7WT9axNH/QFPOjXvwQJFnC7hLxHnX6pgKOdAaioKdi6FX3Y2SwWEO3UuxFd3KwsrZ2+mma/W3KP/cPpSzqyHa5VaJwOCw6vSM4wHSGKmDF4TSrrnMxzIYiTbTlrwLi5GjMxD6BKzMMN9+7xFuO7txLCEIhGrIMFIvqTw1QFAO4rmAgyG+ljlYTfWHAkzqvImL1o8dMHhGOTsMLLMg39KsZVqalZwwL3ckpdAf81OJJeWCpCuaSgSXnWhJmHxQuA9zUhrmlR1wHO9eegHh/p01osP0xU03rY1oGonOZ28acYG6MSOfZBkKT+NoqOcEWtL4RCP6t7BWXHgIUmlhCEj/pwNVx92Vc3ZzE8zMh3U196ICHzTSZz0rMwJkmT0l1m7QdvBpqUeqCxyXgY+6afqsdAdGjZeuUOPB2RDam3Cm2j2Z5VygvdIBI12qlIoEBhnrhCxx6TN+ywilfI2aBjzTtn0rCe7IA9sYtcYn3XSooU7TBNB39O8cbGgnmGYQygxBsQ/Emj2KDCqQ4A1MRnSe3q6tQhjToqDjHRXEKzlWka/4+hWNnJpicq/LmT3jxCH9/yre8qFUXy+Hq2ycitjv3rogw+hyXlK3pIoQmDskJnqBk3hxisj3QQrQiv06PubySY5lRIEYlCjr5j8Ahl9gFvN+22cIh1iGiuwByhPjGDgP5h78xZXCBoJekEYPcI2C0LtBch5pZC/JpS1kF9lBLndodhIlutEr3mkKohR+D/czN/FTdxU2b82QqfZOHc+6rv2biEXy8AdoAMykj1dsIw7/d5M8XcgPiUzNko4H6p02Rt2R01MOYboTogaQH8lyU6o8c+iORRGEoZDTq4htC+Qa7AXTodvSmG33IrwJVGOKDMtvWI1VYdhWs32SB0W1d+BrFb0ObBGsz+Un7P+V8qerCMqu906BkbjdWmsKbKQBFC8/YDTdSi92rIq1ISUQWn88AgW/q+u6KPxybU5EZgbA+EZwCDB6MyBNhHcrAvVFeX+kj1RY1Gx1kzCE3ldsT37sCbayFtyMMbL6gDQCoTadJX/jhs9wgp0dZujwOk0Wefhgy1BUHXl/q+2nXAKPvKmli6Wo7/pYr/q13Gcsj7Z7WSKVn4Fm4XfkJD62q6paCxO51BlJQEcnpNPKS7+zjhmQlTRiEryD8ve7KQzk20eb4TgIMR1hI5pnQmjGeT56xZySp2nDnYDsqsnXB5uQY8lyf6IYC/PHzEb3rSx91k0ZEu5w5IMrVK8otNzZHrUuM0aPdImpLQJ4qEgvmezORpcUCq4SRp9bGl3/yzXE5tWZgn3Q6kXyjFMhu+foTYy1NV+HJbJI1nYMjeTr3f+RxSphIYWyMZ7sD3RgDzRk5iQqD1J+8rdOIZliObfrmWaro/BBxNvd1fPA", + "qV2FNaBFqWeL6n9q9OUbCSTcIQvwO0vfaA/f/SxEtLSIaOGIOx8r+WVGFdxmC6i3oOaoEkJWvML7PpKBDtqiK7pKDIaMV5PkV/kQl6UgxZv9OInTwpVPtYcgeeTokG/eBi1qKzJwDoEHVqKeLqrLXJHXhBVQLdoIUOeKj8YMkagVniO9EtK0fW0/9QnRIxXoilxSj5HBEpYwFBitJXRk1ftFGWZFxJXU5PXdRmC+pomyo5Scx+UJQ2NLRWHjKlV0", + "aZ8tqrOeEJKt4AMqiRF/WJhIKTDC0HeDTgiJVLZ8OEtiLNj7hflFeVnNXPguxyoqkI/V7pGJtXBpH5N+RswQNA0b23aM33aH0HKHOWoGY/T/L7TQzYFGJ3vTLiXDFZg1OVqkGOMvqAgonOrHGi6IgcALyUMyCKlL5BQY23SeILJpYKolybJNwJfbjxpg0Oz+D2fr7r9XL1GMvgblu52bVQT1fR8uCRJfSsgA2OGw6k/MpKDCfMcjbR8jnZa8ROEvF4cohm7iV1788Vp2/2bdcEZRQSoaGV8pOmA9EkqzJVRABjkDso40fnQcm2IzjBUOsX+uFExVan56/vl9VZVwB0wnee3Uxiredn0kOayiPB16yimxXCDet+M+0UKjmIlmXYpkrCDrH0dn53w+U3OHqMQxPDnUpYBxadM1eI8xWFFxzaLkvega0q0DmEquyY02yiTqo+7Q4qaJVTLgu6/8ekzPxGKRi845NL8gRgaTtM3kidDzIQpyODZD0yeEZDY1M+3sUKHcVkhoxTQBTMyKJPc+M5DeBL3uaWMrvxuL6q8+X0xeBt+9kguPUNtIYqUgPAaXvM2i041bWHTJ0dZLyDJVOyzGaXRaF4mNkAuh4Et6Zw5PuOpMM2mI1oFKEZj7Xqf/yAmy/Le3GfJnMg5vNgE7QxmVsjuKUP28iN8rdi4bUp7c0KJpqLXE6evfRrdZBDRYp+rmOLLDg55ggNuwog==" + => true + )] + // grothFail from Scala + #[test_case( + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2jekplZYoV0aXEnYEOIvfF7d4xay3qkx2NspooM4HeZpiHknIWkUVhGVJBzBDLjLB", + "jiGBK+TGHfH8Oadexhdet7ExyIWibSmamWQvffZkyl3WnMoVbTQ3lOks4Mca3sU5qgcaLyQQ1FjFW4g6vtoMapZ43hTGKaWO7bQHsOCvdwHCdwJDulVH16cMTyS9F0BfBJxa88F+JKZc4qMTJjQhspmq755SrKhN9Jf+7uPUhgB4hJTSrmlOkTatgW+/HAf5kZKhv2oRK5p5kS4sU48oqlG1azhMtcHEXDQdcwf9ANel4Z9cb+MQyp2RzI/3hlIx", + "" + => false + )] + #[test_case( + "lp7+dPDIOfm77haSFnvr33VwYH/KbIalfOJPRvBLzqlHD8BxunNebMr6Gr6S+u+nh7yLzdqr7HHQNOpZI8mdj/7lR0IBqB9zvRfyTr+guUG22kZo4y2KINDp272xGglKEeTglTxyDUriZJNF/+T6F8w70MR/rV+flvuo6EJ0+HA+A2ZnBbTjOIl9wjisBV+0iISo2JdNY1vPXlpwhlL2fVpW/WlREkF0bKlBadDIbNJBgM4niJGuEZDru3wqrGueETKHPv7hQ8em+p6vQolp7c0iknjXrGnvlpf4QtUtpg3z/D+snWjRPbVqRgKXWtihuIvPFaM6dt7HZEbkeMnXWwSINeYC/j3lqYnce8Jq+XkuF42stVNiooI+TuXECnFdFi9Ib25b9wtyz3H/oKg48He1ftntj5uIRCOBvzkFHGUF6Ty214v3JYvXJjdS4uS2jekplZYoV0aXEnYEOIvfF7d4xay3qkx2NspooM4HeZpiHknIWkUVhGVJBzBDLjLBjiGBK+TGHfH8Oadexhdet7ExyIWibSmamWQvffZkyl3WnMoVbTQ3lOks4Mca3sU5", + "hp1iMepdu0rKoBh0NXcw9F9hkiggDIkRNINq2rlvUypPiSmp8U8tDSMeG0YVSovFteecr3THhBJj0qNeEe9jA2Ci64fKG9WT1heMYzEAQKebOErYXYCm9d72n97mYn1XBq+g1Y730XEDv4BIDI1hBDntJcgcj/cSvcILB1+60axJvtyMyuizxUr1JUBUq9njtmJ9m8zK6QZLNqMiKh0f2jokQb5mVhu6v5guW3KIjwQc/oFK/l5ehKAOPKUUggNh", + "c9BSUPtO0xjPxWVNkEMfXe7O4UZKpaH/nLIyQJj7iA4=" + => false + )] + #[test_case( + "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" + => false + )] + #[test_case( + "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" + => false + )] + fn groth16_verify_test(vk_b64: &str, proof_b64: &str, inputs_b64: &str) -> bool { + let vk = decode(&vk_b64).unwrap(); + let proof = decode(&proof_b64).unwrap(); + let inputs = decode(&inputs_b64).unwrap(); + + return groth16_verify(&vk, &proof, &inputs).unwrap_or(0) != 0; + } +} diff --git a/zwaves_jni/src/tests/mod.rs b/zwaves_jni/src/bls12/tests/mod.rs similarity index 60% rename from zwaves_jni/src/tests/mod.rs rename to zwaves_jni/src/bls12/tests/mod.rs index 6dcc9bc..54c055e 100644 --- a/zwaves_jni/src/tests/mod.rs +++ b/zwaves_jni/src/bls12/tests/mod.rs @@ -1,90 +1,97 @@ extern crate pairing; -use bellman::{Circuit, ConstraintSystem, SynthesisError}; -use sapling_crypto::jubjub::{JubjubEngine, JubjubParams, JubjubBls12}; -use sapling_crypto::circuit::{pedersen_hash}; -use sapling_crypto::circuit::num::{AllocatedNum, Num}; -use bellman::groth16::{Proof, generate_random_parameters, create_random_proof}; -use bellman::LinearCombination; - -use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use pairing::{Engine, PrimeField, Field, PrimeFieldRepr}; -use rand::os::OsRng; -use rand::Rng; - -use std::io::{Cursor, Read, Seek, SeekFrom, Write}; -use zwaves_primitives::verifier::{truncate_verifying_key, TruncatedVerifyingKey, verify_proof}; -use zwaves_primitives::serialization::write_fr_iter; -use zwaves_primitives::pedersen_hasher; - -use base64::encode; -use std::iter; - +use std::io::{Cursor, Read, Seek, SeekFrom}; + +use bellman::{ + groth16::{create_random_proof, generate_random_parameters}, + Circuit, ConstraintSystem, LinearCombination, SynthesisError, +}; +use pairing::{ + bls12_381::{Bls12, Fr}, + Field, +}; +use rand::{os::OsRng, Rng}; + +use sapling_crypto::{ + circuit::{num::AllocatedNum, pedersen_hash}, + jubjub::{JubjubBls12, JubjubEngine}, +}; +use zwaves_primitives::{ + pedersen_hasher, + serialization::write_fr_iter, + verifier::{truncate_verifying_key, verify_proof}, +}; #[derive(Clone)] pub struct PedersenDemo { pub params: Box, pub image: Option, pub data: Vec>, - pub preimage: Option + pub preimage: Option, } -impl Circuit for PedersenDemo { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let image = AllocatedNum::alloc(cs.namespace(|| "signal public input image"), || self.image.ok_or(SynthesisError::AssignmentMissing))?; +impl Circuit for PedersenDemo { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { + let image = AllocatedNum::alloc(cs.namespace(|| "signal public input image"), || { + self.image.ok_or(SynthesisError::AssignmentMissing) + })?; image.inputize(cs.namespace(|| "image inputize"))?; - let preimage = AllocatedNum::alloc(cs.namespace(|| "signal input preimage"), || self.preimage.ok_or(SynthesisError::AssignmentMissing))?; + let preimage = AllocatedNum::alloc(cs.namespace(|| "signal input preimage"), || { + self.preimage.ok_or(SynthesisError::AssignmentMissing) + })?; let preimage_bits = preimage.into_bits_le_strict(cs.namespace(|| "preimage_bits <== bitify(preimage)"))?; let image_calculated = pedersen_hash::pedersen_hash( cs.namespace(|| "image_calculated <== pedersen_hash(preimage_bits)"), pedersen_hash::Personalization::NoteCommitment, &preimage_bits, - &self.params - )?.get_x().clone(); + &self.params, + )? + .get_x() + .clone(); let mut data_sum = LinearCombination::::zero(); - - self.data.into_iter().enumerate().for_each(|(i, e)| { - let n = AllocatedNum::alloc(cs.namespace(|| format!("data_item[{}]", i)), || e.ok_or(SynthesisError::AssignmentMissing)).unwrap(); - n.inputize(cs.namespace(|| format!("data_item[{}] inputize", i))).unwrap(); + let n = AllocatedNum::alloc(cs.namespace(|| format!("data_item[{}]", i)), || { + e.ok_or(SynthesisError::AssignmentMissing) + }) + .unwrap(); + n.inputize(cs.namespace(|| format!("data_item[{}] inputize", i))) + .unwrap(); data_sum = data_sum.clone() + (E::Fr::one(), n.get_variable()); }); - cs.enforce(|| "image_calculated === image", |lc| lc + image.get_variable(), |lc| lc + CS::one(), |lc| lc + image_calculated.get_variable()); + cs.enforce( + || "image_calculated === image", + |lc| lc + image.get_variable(), + |lc| lc + CS::one(), + |lc| lc + image_calculated.get_variable(), + ); cs.enforce(|| "data sum equals zero", |lc| lc, |lc| lc, |lc| lc + &data_sum); Ok(()) } } - #[cfg(test)] mod tests { use super::*; - #[test] pub fn test_groth16_verify_get_vectors() -> std::io::Result<()> { - let rng = &mut OsRng::new().unwrap(); let mut sum = Fr::zero(); - let mut data :Vec = (0..15).into_iter().map(|_| { - let n = rng.gen(); - sum.add_assign(&n); - n - }).collect(); + let mut data: Vec = (0..15) + .into_iter() + .map(|_| { + let n = rng.gen(); + sum.add_assign(&n); + n + }) + .collect(); data[14].sub_assign(&sum); - - - let preimage = rng.gen(); let params = JubjubBls12::new(); @@ -98,25 +105,23 @@ mod tests { let c = PedersenDemo:: { params: Box::new(JubjubBls12::new()), image: None, - data: vec![None;15], - preimage: None + data: vec![None; 15], + preimage: None, }; generate_random_parameters(c, rng).unwrap() }; let tvk = truncate_verifying_key(¶ms.vk); - - println!("Creating proofs..."); let c = PedersenDemo:: { params: Box::new(JubjubBls12::new()), image: Some(image), data: data.iter().map(|e| Some(e.clone())).collect(), - preimage: Some(preimage) + preimage: Some(preimage), }; - + let proof = create_random_proof(c, ¶ms, rng).unwrap(); - + let mut tvk_c = Cursor::new(Vec::new()); tvk.write(&mut tvk_c)?; tvk_c.seek(SeekFrom::Start(0)).unwrap(); @@ -134,21 +139,13 @@ mod tests { let mut inputs = vec![image]; inputs.extend(data.iter().cloned()); - - let mut inputs_b = vec![0u8;32*inputs.len()]; + let mut inputs_b = vec![0u8; 32 * inputs.len()]; write_fr_iter((&inputs).into_iter(), &mut inputs_b)?; println!("Inputs: {}", base64::encode(&inputs_b)); - let result = verify_proof( - &tvk, - &proof, - &inputs - ).unwrap(); + let result = verify_proof(&tvk, &proof, &inputs).unwrap(); assert!(result, "Proof is correct"); Ok(()) } - - - } diff --git a/zwaves_jni/src/bn256/bin/show_test_vectors.rs b/zwaves_jni/src/bn256/bin/show_test_vectors.rs new file mode 100644 index 0000000..a596956 --- /dev/null +++ b/zwaves_jni/src/bn256/bin/show_test_vectors.rs @@ -0,0 +1,88 @@ +extern crate zwaves_jni; + +use std::io::Cursor; + +use ff::Field; +use pairing_ce::{bn256::*, CurveAffine, CurveProjective}; +use rand::{Rand, SeedableRng, XorShiftRng}; +use zwaves_jni::bn256::{ + serialization::write_fr_iter, + verifier::{Proof, TruncatedVerifyingKey}, +}; + +fn main() { + const NINPUTS: usize = 1; + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + const SAMPLES: usize = 1000; + + let v = (0..SAMPLES) + .map(|_| { + let inputs = (0..NINPUTS).map(|_| Fr::rand(&mut rng)).collect::>(); + let mut inputs_buff = vec![0u8; 32 * NINPUTS]; + write_fr_iter(inputs.iter(), &mut inputs_buff).unwrap(); + + let ic = (0..NINPUTS + 1) + .map(|_| G1::rand(&mut rng).into_affine()) + .collect::>(); + + let mut x_sum = ic[0].into_projective(); + for i in 1..NINPUTS + 1 { + let mut t = ic[i].into_projective(); + t.mul_assign(inputs[i - 1]); + x_sum.add_assign(&t); + } + let g1_gen = x_sum.into_affine(); + let g2_gen = G2::rand(&mut rng).into_affine(); + + let a_1 = Fr::one(); + let a_2 = Fr::rand(&mut rng); + let a_3 = Fr::rand(&mut rng); + let b_1 = Fr::one(); + let b_2 = Fr::rand(&mut rng); + let b_3 = Fr::rand(&mut rng); + let b_4 = Fr::rand(&mut rng); + + let mut a_4 = Fr::zero(); + let mut t = a_1; + t.mul_assign(&b_1); + a_4.add_assign(&t); + t = a_2; + t.mul_assign(&b_2); + a_4.add_assign(&t); + t = a_3; + t.mul_assign(&b_3); + a_4.add_assign(&t); + a_4.mul_assign(&b_4.inverse().unwrap()); + + let vk = TruncatedVerifyingKey:: { + alpha_g1: g1_gen.mul(a_3).into_affine(), + beta_g2: g2_gen.mul(b_3).into_affine(), + gamma_g2: g2_gen.clone(), + delta_g2: g2_gen.mul(b_2).into_affine(), + ic, + }; + let mut vk_buff = Cursor::new(Vec::::new()); + vk.write(&mut vk_buff).unwrap(); + + let proof = Proof:: { + a: g1_gen.mul(a_4).into_affine(), + b: g2_gen.mul(b_4).into_affine(), + c: g1_gen.mul(a_2).into_affine(), + }; + let mut proof_buff = Cursor::new(Vec::::new()); + proof.write(&mut proof_buff).unwrap(); + + //let res = crate::verifier::verify_proof(&vk, &proof, &inputs).unwrap_or(false); + //assert!(res, "groth16_verify should be true"); + + ( + base64::encode(vk_buff.get_ref()), + base64::encode(proof_buff.get_ref()), + base64::encode(&inputs_buff), + ) + }) + .collect::>(); + + println!("{:?}", v); +} diff --git a/zwaves_jni/src/bn256/mod.rs b/zwaves_jni/src/bn256/mod.rs new file mode 100644 index 0000000..69ed2b9 --- /dev/null +++ b/zwaves_jni/src/bn256/mod.rs @@ -0,0 +1,115 @@ +use std::io; + +use pairing_ce::bn256::{Bn256, Fr}; +use serialization::read_fr_vec; +use verifier::{verify_proof, Proof, TruncatedVerifyingKey}; + +pub mod serialization; +pub mod verifier; + +pub fn groth16_verify(vk: &[u8], proof: &[u8], inputs: &[u8]) -> io::Result { + let buff_vk_len = vk.len(); + let buff_proof_len = proof.len(); + let buff_inputs_len = inputs.len(); + + if (buff_vk_len % 32 != 0) || (buff_inputs_len % 32 != 0) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); + } + + let inputs_len = buff_inputs_len / 32; + + if ((buff_vk_len / 32) != (inputs_len + 8)) || (buff_proof_len != 128) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); + } + + let vk = TruncatedVerifyingKey::::read(vk)?; + let proof = Proof::::read(proof)?; + let inputs = read_fr_vec::(inputs)?; + + if (inputs.len() != inputs_len) || (vk.ic.len() != (inputs_len + 1)) { + return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer parsing")); + } + + Ok(verify_proof(&vk, &proof, inputs.as_slice()) + .map(|r| r as u8) + .unwrap_or(0)) +} + +#[cfg(test)] +mod local_tests { + use base64::decode; + + use super::*; + use test_case::test_case; + + #[test_case( + "LDCJzjgi5HtcHEXHfU8TZz+ZUHD2ZwsQ7JIEvzdMPYKYs9SoGkKUmg1yya4TE0Ms7x+KOJ4Ze/CPfKp2s5jbniFNM71N/YlHVbNkytLtQi1DzReSh9SNBsvskdY5mavQJe+67PuPVEYnx+lJ97qIG8243njZbGWPqUJ2Vqj49NAunhqX+eIkK3zAB3IPWls3gruzX2t9wrmyE9cVVvf1kgWx63PsQV37qdH0KcFRpCH89k4TPS6fLmqdFxX3YGHCGFTpr6tLogvjbUFJPT98kJ/xck0C0B/s8PTVKdao4VQHT4DBIO8+GB3CQVh6VV4EcMLtDWWNxF4yloAlKcFT0Q4AzJSimpFqd/SwSz9Pb7uk5srte3nwphVamC+fHlJt", + "GQPBoHuCPcIosF+WZKE5jZV13Ib4EdjLnABncpSHcMKBZl0LhllnPxcuzExIQwhxcfXvFFAjlnDGpKauQ9OQsjBKUBsdBZnGiV2Sg4TSdyHuLo2AbRRqJN0IV3iH3On8I4ngnL30ZAxVyGQH2EK58aUZGxMbbXGR9pQdh99QaiE=", + "IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQo="; + )] + #[test_case( + "oNme33MLprvAodIU3H8rA1WVUVN6IwJtouPFt3rD76EhTyetvNmF9cCLETzYB4K9YC4EIAnZywPddo8kG70hDAeEOBf1FwaXr53SXD0A2pGbHJPRuTTj21tXNXAu7D6MkGKUMCACqi7buNhBbz0X7SKNBgh2Lwxo9CFcv4VBCzkljSjsy0dXI1nUz8oAN99WPRgEqsGtH6wFSllr/AMgKxUVjbIGGpcKvAgvuOfP6HYRsVR8XP7Ecnh/A/aARw4jCycuzPPhJlgjUxs+xCwF/AizkOvYoKFAdFlLKACJIFsIOU8NmXM08eizRXg96hvpfbCVjlWYE1hI90EnJLKTBg==", + "G3CEMZl39+IlulSqUjmLUP4tB8pnGGteKKU8AlMzkMMcThMVl9rOa5G3DDcm4iF3BFxS3ubW5JADnVvPhX9wNQXMMjh+BKVLUIaC8gwtwciCscaCMw6cIA5ltWuoWX9jB/ig6Yqg4Hc6u2/9XzKfCWG42Si+BkTh8X0DAQ2fAzY=", + ""; + )] + #[test_case( + "nV33RK4rTODU42ZKyFxTFl9d86FrP+h6acIdT4m/rfAZBBfPWLxcjYyMUBHlXgM/jTBDOH7dTGL1zqbRLr1eGwR9zemG9LJnqPl/eiJ0LZLZKz3/iDde8p1zj5DRvar2Fa6rv0WJRJR32+22iaZHrD/64/SyFb2j5f12ipT5S2Eq+SnYSSr8HhStVu3s4VFK57nhi2aRFUgXWkGaqhJJ6ie6zlaVf52s79qdlBUOuTTVsATXa58FVXVSHJb5wanwK578EWV/BulP1TCq5y0q7k6YCZV15Nu9FHpzIUow9Ged8l8LwPmHxki+/S2MnA0v2mFgdC1ZXE+BesWOx3tXThrq7st5+lUMmaY5S76l0yuzzHoeSZEZAoS6heG8WWUGJW2QBTzq3GVaubssoR/HtIT1dGPswNTF8HY78BPYb8M=", + "pE0Y4zE1A5UvC8ATBJPMOAFm3dDQABrhu5VxxGj5GOom+pFpQsVZe6mMLT8ZwyWXQmJ+od+cYtUOH2Fxiem1yCdMkGi64f5k9qWwYDRrtIxXHhj9f43pHKylJV0Z1jCJgpebExv+hPmwNYh3cWxHxywYMEXwSutAjyqi8Swl1O0=", + "IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQou2EkLZ569itz7cL7GQnzipNe1JRCQ/QK8UXr8IG8k0g=="; + )] + #[test_case( + "q1U6rGRU+/F+e3xx6oCBeokQsIVIQDESLC/l+PK8WX0Rw2NglYMRP6In971j7/puuDsJwZm2AK7fTcmKQd5v/g6InaZLdKGQK1C+52BbMyoGsueMfmML9pJmJvivE2N7m9WyiixGvDawwhz7JYst5Jr3ChczYgLAS7b2WQscCRcm8ZE9FKTNdfu4WAYEDEl6IONCFnNiYw6wR8Kc2J7Z9BkHcOzQj2X4PuxZGdPeWF+7vB1dXQZZlCBScImWeVPNKaYF7H3Ot0wOYzigQXYkSZD5v9vBWXN/f1YajxR1kjMrSZ90fx4WapypjaLREbaNgOcAN5niSzTmwymK3e3Idgpt+Pdq34YPOZ5lDx5+3gMWYl1QYeWi6miDIasts0owjZVOTUXf292iZDsjSWaYurcLNEH3Rf8lTCKSMyosjkAV2Fkselh0/Vy4jkPj3hTFeIpY3inMmI+N6Nvwxv50ZpaUIQmU5rlia4pS8MSMxgO+khyyPKb1OUHbFTgDHf6p", + "mtMjjG0IVNq3t7ICtij1nLFH1UjFu6FaNZmdXam0gdCY/efE2wVHSctp1vqgVcfgiSpl/WCCcaQ2CQGbirLE/wVj2w0eiVEUy6gs9aK01nS0bx4ErymppOugPDPXGCV6FtiAM6Cq+fMbOKhhhDPutn6dIntO3gSqtsWL0KreCPY=", + "IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQou2EkLZ569itz7cL7GQnzipNe1JRCQ/QK8UXr8IG8k0hW3GAoAXun/Pwk0Jq9fst26FET2RehSLbxUdvZQLjEzCJmfahCreklII85wEMuwYctsOv/3JWgvrI8hmn8sWjw="; + )] + #[test_case( + "kikeX/IlYwL5e1nkJ3FbD4/IantLORJJtmgMPywFCoCdYF304ka26knjzRodk7mujA0HqXxknBkzZSqQuuqcSSZkVOudYO1dwOw73U9SlL/nF4UWP4YOkVfKntqi825LkCrBcl3rw7zhMHorldspOwWNVybCLGt86Zbd92hze3wcSIk2GqMxtoBQiurYqlt1SARwIn06tRExJ0YULl/7/4qrYi+Tsjy0xQwltrHJQy/eeVNNq9x/GrVJemN2r+SUK6lF6kWLJzTH5jUUu7HvpUCtRlGJ3JRZIAJ7qChT3v+fD5LNjz86Ei1ItV4Wgqk/iXAAXeORUM3T3RD2NepVgS3U35HXhJ1ZtzJZoFUQyQjlGYp6+U6q8+rXYSQkZjEHmQh/Atr0lb1QRIG+PK+mLj1Nxwb/aibt7z7WtRTfj3mudYCEjXA/ceDVtz8FKkeTo9dcVYGsf/VJaxnteVa7B4UMRQjX0gdNKC+AEjKxcRk373IqLBCCtukQYBG8o2TKFYfJcJuI1geuGtNij1jwgmLxl7hH3Y0JqMZPoS9vKwudBL5Nnt38g/rfNTyoe7UIJV246oAOkuuskfxNUHeEnILjkHYhjfIuuPMGUG4FK2LHkscqib6eHo3wSy31I65urmsiHROrMEtfUdYcGDJxV+IyrTUs2m5KQgmlXo8jvUo=", + "HUaOoIyn6KUkVXzttFMcRobGBZUtpRjAQMId9n3ABZKPUk8Rv0EPKmzp/1Ut0LNJ5cNI48VwD6/kVbhNgoBbdQijsqDktFjjeJtzj6KF2TuHOlcHL6s7dc38cvNVD0O1ISiJlLdrc5QKcXePAGJK/YaD/CUQfKnijgCGDREUDXo=", + "IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQou2EkLZ569itz7cL7GQnzipNe1JRCQ/QK8UXr8IG8k0hW3GAoAXun/Pwk0Jq9fst26FET2RehSLbxUdvZQLjEzCJmfahCreklII85wEMuwYctsOv/3JWgvrI8hmn8sWjwELKgjqMSLQgJ7u5ZHe9PDhBgF/3dliXhY1jUsXFvkig6pfEr0bFuXhXcg2R+vuPErhG0w08SPNOi2SjvPngYpJ8nsOT98G6EDlyNaHtJuRC/xOA+6ftL/k2+hzFsd+1Ui5/1NGTfDxLDndEE1NQ+opvk79ZeaY+qPP7pEc0uQMw=="; + )] + #[test_case( + "qladoBQdTIMTqRD5nLplvCqxlHwZrFv7scw72CqqjkMsK1J9mo3aYYCS8MXIl224CTjyJF/IQ2nFONXeSUdoFAFN1RfVylmeW3Qbeqj8ePv9JA+LjpgE68Zr9u85DqI4hK+0BABhe1S+m79CtKaSOAt7pJNDmiNqEKsGYDBhYBIBLAdgsmLkOfA197v06p/UaXCOXvNQMjprjuvt3SCrkoV8jZU/cSrB+cPPE8s4OgVl0eXr08YRmmDym/veV4eTI1WV59Qxb3uZCOtJFPwwd6gTiXvnGhhWrgJPwjAIJhmFDEUI19IHTSgvgBIysXEZN+9yKiwQgrbpEGARvKNkyhWHyXCbiNYHrhrTYo9Y8IJi8Ze4R92NCajGT6EvbysLnQS+TZ7d/IP63zU8qHu1CCVduOqADpLrrJH8TVB3hJyC45B2IY3yLrjzBlBuBStix5LHKom+nh6N8Est9SOubq5rIh0TqzBLX1HWHBgycVfiMq01LNpuSkIJpV6PI71KmXEqw09G6gPAM1465XNSWZV0gLUTctlavUWfG7jILPafEBGrM69wVNmnBm0lSOq9fBTatb8Ivm4+SDNHALraRo1guaelsx+MuKox7hj5WkuIjo7PSprYHsM6Wc3/10VpJQwX6/Dp5J0MZzYscKLlGX5DXXbaQLcIT6I+cjioLcIwK20hLc56+CaCSZRyKMB9IWUmavploHQrjBW+vyyOPQNIbqUTWjTVHJ9QCCdVxUWP+0yHwCjZUymqnVoG6HrPkYvh0nuIsz552K6SWFMuhddTW+JN/uUIpniAKCI4WwafIl/0mH/DRktCA5uQdpevX62mWKfyYGL1if6TV20CgSMvo6fiK+yC5GCzMKtsHxMFWW5fYkjQ2b/C8RWjCySpDQPFVqJwr5uMYxdqtsSs7ysGZfpoRZS1SDbVgFVL1E6d/ECJMiqIOM0OH0uBRzF7B3q2BT5GChq/naHPEucCcBU8HgairQQ3uV+V+UyWbYmrwjGQZSg0pSQ3Jff41MGe", + "CfEpVT6b8+4NAeDs3QwiSN7zqfxzAkQdIu8eBXzoAQIS+AgJcYppUx7COvtbWa7TDtaER1ydtoYWBcBtRMvrHQJ64u4XmLooTwikzECPz+VRcYknrGEoyGeZanNFWEwgplf9bX3JvW1RshlAfN7iJESdqBCmUNsrObHNxhHFJRo=", + "IfZhAypdtgvecKDWzVyRuvXatmFf2ZYcMWVkCJ0/MQou2EkLZ569itz7cL7GQnzipNe1JRCQ/QK8UXr8IG8k0hW3GAoAXun/Pwk0Jq9fst26FET2RehSLbxUdvZQLjEzCJmfahCreklII85wEMuwYctsOv/3JWgvrI8hmn8sWjwELKgjqMSLQgJ7u5ZHe9PDhBgF/3dliXhY1jUsXFvkig6pfEr0bFuXhXcg2R+vuPErhG0w08SPNOi2SjvPngYpJ8nsOT98G6EDlyNaHtJuRC/xOA+6ftL/k2+hzFsd+1Ui5/1NGTfDxLDndEE1NQ+opvk79ZeaY+qPP7pEc0uQMxnEIHHpcYsRt9dal9bSQpE5hWKu1nOBzIVmXb/Ef51YDg+nW5w9a2tEAY2zQCZ/z3sFs7FwAZ5TXhDfhYR5sQ8tZaF3FWh+Yzf5hgMmXWrApp/arwPszNhKCoxScnhPSgfcxYSdauqvp5+vcacJFY1OkWG6tQ6iuh5CZSdX645oA7oNr9d5kXYSewhTflcV9pufeaH21BtEipHpO3sNRkUngnHC+uj1D8ReSgcCofnv8s0mVme9Ml64r6CbeaHK+x5Mc9bolN96XJZ137xkPDpev+RVrVK6ZIFrH2hFl8/vGoBwWDlmjmVzUt4YQdsCavsf7c0vBa7d33EcvyvQMDY="; + )] + fn groth16_verify_ok_test(vk_b64: &str, proof_b64: &str, inputs_b64: &str) { + let vk = decode(&vk_b64).unwrap(); + let proof = decode(&proof_b64).unwrap(); + let inputs = decode(&inputs_b64).unwrap(); + + let res = groth16_verify(&vk, &proof, &inputs).unwrap_or(0) != 0; + assert!(res, "groth16_verify should return true"); + } + + #[test_case( + vec![1; 256], + "CfEpVT6b8+4NAeDs3QwiSN7zqfxzAkQdIu8eBXzoAQIS+AgJcYppUx7COvtbWa7TDtaER1ydtoYWBcBtRMvrHQJ64u4XmLooTwikzECPz+VRcYknrGEoyGeZanNFWEwgplf9bX3JvW1RshlAfN7iJESdqBCmUNsrObHNxhHFJRo=", + ""; + "256 byte vk, empty inputs" + )] + #[test_case( + [1; 256 + 32].to_vec(), + "CfEpVT6b8+4NAeDs3QwiSN7zqfxzAkQdIu8eBXzoAQIS+AgJcYppUx7COvtbWa7TDtaER1ydtoYWBcBtRMvrHQJ64u4XmLooTwikzECPz+VRcYknrGEoyGeZanNFWEwgplf9bX3JvW1RshlAfN7iJESdqBCmUNsrObHNxhHFJRo=", + "c9BSUPtO0xjPxWVNkEMfXe7O4UZKpaH/nLIyQJj7iA4="; + "288 byte vk" + )] + #[test_case( + [1; 256 + 32 * 15].to_vec(), + "CfEpVT6b8+4NAeDs3QwiSN7zqfxzAkQdIu8eBXzoAQIS+AgJcYppUx7COvtbWa7TDtaER1ydtoYWBcBtRMvrHQJ64u4XmLooTwikzECPz+VRcYknrGEoyGeZanNFWEwgplf9bX3JvW1RshlAfN7iJESdqBCmUNsrObHNxhHFJRo=", + "I8C5RcBDPi2n4omt9oOV2rZk9T9xlSV8PQvLeVHjGb00fCVz7AHOIjLJ03ZCTLQwEKkAk9tQWJ6gFTBnG2+0DDHlXcVkwpMafcpS2diKFe0T4fRb0t9mxNzOFiRVcJoeMU1zb/rE4dIMm9rbEPSDnVSOd8tHNnJDkT+/NcNsQ2w0UEVJJRAEnC7G0Y3522RlDLxpTZ6w0U/9V0pLNkFgDCkFBKvpaEfPDJjoEVyCUWDC1ts9LIR43xh3ZZBdcO/HATHoLzxM3Ef11qF+riV7WDPEJfK11u8WGazzCAFhsx0aKkkbnKl7LnypBzwRvrG2JxdLI/oXL0eoIw9woVjqrg6elHudnHDXezDVXjRWMPaU+L3tOW9aqN+OdP4AhtpgT2CoRCjrOIU3MCFqsrCK9bh33PW1gtNeHC78mIetQM5LWZHtw4KNwafTrQ+GCKPelJhiC2x7ygBtat5rtBsJAVF5wjssLPZx/7fqNqifXB7WyMV7J1M8LBQVXj5kLoS9bpmNHlERRSadC0DEUbY9xhIG2xo7R88R0sq04a299MFv8XJNd+IdueYiMiGF5broHD4UUhPxRBlBO3lOfDTPnRSUGS3Sr6GxwCjKO3MObz/6RNxCk9SnQ4NccD17hS/m"; + "736 byte vk" + )] + #[test_case( + [1; 256 + 32 * 16].to_vec(), + "CfEpVT6b8+4NAeDs3QwiSN7zqfxzAkQdIu8eBXzoAQIS+AgJcYppUx7COvtbWa7TDtaER1ydtoYWBcBtRMvrHQJ64u4XmLooTwikzECPz+VRcYknrGEoyGeZanNFWEwgplf9bX3JvW1RshlAfN7iJESdqBCmUNsrObHNxhHFJRo=", + "I8C5RcBDPi2n4omt9oOV2rZk9T9xlSV8PQvLeVHjGb00fCVz7AHOIjLJ03ZCTLQwEKkAk9tQWJ6gFTBnG2+0DDHlXcVkwpMafcpS2diKFe0T4fRb0t9mxNzOFiRVcJoeMU1zb/rE4dIMm9rbEPSDnVSOd8tHNnJDkT+/NcNsQ2w0UEVJJRAEnC7G0Y3522RlDLxpTZ6w0U/9V0pLNkFgDCkFBKvpaEfPDJjoEVyCUWDC1ts9LIR43xh3ZZBdcO/HATHoLzxM3Ef11qF+riV7WDPEJfK11u8WGazzCAFhsx0aKkkbnKl7LnypBzwRvrG2JxdLI/oXL0eoIw9woVjqrg6elHudnHDXezDVXjRWMPaU+L3tOW9aqN+OdP4AhtpgT2CoRCjrOIU3MCFqsrCK9bh33PW1gtNeHC78mIetQM5LWZHtw4KNwafTrQ+GCKPelJhiC2x7ygBtat5rtBsJAVF5wjssLPZx/7fqNqifXB7WyMV7J1M8LBQVXj5kLoS9bpmNHlERRSadC0DEUbY9xhIG2xo7R88R0sq04a299MFv8XJNd+IdueYiMiGF5broHD4UUhPxRBlBO3lOfDTPnRSUGS3Sr6GxwCjKO3MObz/6RNxCk9SnQ4NccD17hS/mEFt8d4ERZOfmuvD3A0RCPCnx3Fr6rHdm6j+cfn/NM6o="; + "768 byte vk" + )] + fn groth16_verify_fail_test(vk: Vec, proof_b64: &str, inputs_b64: &str) { + let proof = base64::decode(proof_b64).expect("Invalid base64 in proof"); + let inputs = base64::decode(inputs_b64).expect("Invalid base64 in inputs"); + + let res = groth16_verify(&vk, &proof, &inputs).unwrap_or(0) != 0; + assert!(!res, "groth16_verify should return false"); + } +} diff --git a/zwaves_jni/src/bn256/serialization.rs b/zwaves_jni/src/bn256/serialization.rs new file mode 100644 index 0000000..b3469a7 --- /dev/null +++ b/zwaves_jni/src/bn256/serialization.rs @@ -0,0 +1,45 @@ +use std::{io, mem}; + +use ff::{PrimeField, PrimeFieldRepr}; + +pub fn read_fr_repr_be(data: &[u8]) -> io::Result { + let mut fr_repr = Fr::zero().into_repr(); + + match fr_repr.read_be(data) { + Err(e) => return Err(e), + _ => {} + } + Ok(fr_repr) +} + +pub fn read_fr_vec(data: &[u8]) -> io::Result> { + let mut inputs = vec![]; + + let mut offset = 0; + let fr_repr_sz = mem::size_of::(); + + loop { + let fr_repr = match read_fr_repr_be::(&data[offset..]) { + Ok(x) => x, + _ => break, + }; + + offset += fr_repr_sz; + let fr = Fr::from_repr(fr_repr).map_err(|_e| io::Error::new(io::ErrorKind::InvalidData, "not in field"))?; + inputs.push(fr); + } + + Ok(inputs) +} + +pub fn write_fr_iter<'a, I, Fr>(source: I, data: &mut [u8]) -> io::Result<()> +where + Fr: PrimeField, + I: IntoIterator, +{ + let fr_repr_sz = mem::size_of::(); + for (i, e) in source.into_iter().enumerate() { + e.into_repr().write_be(&mut data[fr_repr_sz * i..])?; + } + Ok(()) +} diff --git a/zwaves_jni/src/bn256/verifier.rs b/zwaves_jni/src/bn256/verifier.rs new file mode 100644 index 0000000..6a19142 --- /dev/null +++ b/zwaves_jni/src/bn256/verifier.rs @@ -0,0 +1,229 @@ +use std::{ + io, + io::{Read, Write}, +}; + +use ff::{Field, PrimeField}; +use pairing_ce::{CurveAffine, CurveProjective, EncodedPoint, Engine}; + +#[derive(Debug)] +pub enum SynthesisError { + /// During synthesis, we lacked knowledge of a variable assignment. + AssignmentMissing, + /// During synthesis, we divided by zero. + DivisionByZero, + /// During synthesis, we constructed an unsatisfiable constraint system. + Unsatisfiable, + /// During synthesis, our polynomials ended up being too high of degree + PolynomialDegreeTooLarge, + /// During proof generation, we encountered an identity in the CRS + UnexpectedIdentity, + /// During proof generation, we encountered an I/O error with the CRS + IoError(io::Error), + /// During verification, our verifying key was malformed. + MalformedVerifyingKey, + /// During CRS generation, we observed an unconstrained auxillary variable + UnconstrainedVariable, +} + +#[derive(Clone)] +pub struct Proof { + pub a: E::G1Affine, + pub b: E::G2Affine, + pub c: E::G1Affine, +} + +impl PartialEq for Proof { + fn eq(&self, other: &Self) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c + } +} + +impl Proof { + pub fn write(&self, mut writer: W) -> io::Result<()> { + writer.write_all(self.a.into_compressed().as_ref())?; + writer.write_all(self.b.into_compressed().as_ref())?; + writer.write_all(self.c.into_compressed().as_ref())?; + + Ok(()) + } + + pub fn read(mut reader: R) -> io::Result { + let mut g1_repr = ::Compressed::empty(); + let mut g2_repr = ::Compressed::empty(); + + reader.read_exact(g1_repr.as_mut())?; + let a = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + reader.read_exact(g2_repr.as_mut())?; + let b = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + reader.read_exact(g1_repr.as_mut())?; + let c = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + Ok(Proof { a: a, b: b, c: c }) + } +} + +#[derive(Clone)] +pub struct TruncatedVerifyingKey { + pub alpha_g1: E::G1Affine, + pub beta_g2: E::G2Affine, + pub gamma_g2: E::G2Affine, + pub delta_g2: E::G2Affine, + pub ic: Vec, +} + +impl TruncatedVerifyingKey { + pub fn write(&self, mut writer: W) -> io::Result<()> { + writer.write_all(self.alpha_g1.into_compressed().as_ref())?; + writer.write_all(self.beta_g2.into_compressed().as_ref())?; + writer.write_all(self.gamma_g2.into_compressed().as_ref())?; + writer.write_all(self.delta_g2.into_compressed().as_ref())?; + for ic in &self.ic { + writer.write_all(ic.into_compressed().as_ref())?; + } + Ok(()) + } + + pub fn read(mut reader: R) -> io::Result { + let mut g1_repr = ::Compressed::empty(); + let mut g2_repr = ::Compressed::empty(); + + reader.read_exact(g1_repr.as_mut())?; + let alpha_g1 = g1_repr + .into_affine_unchecked() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + reader.read_exact(g2_repr.as_mut())?; + let beta_g2 = g2_repr + .into_affine_unchecked() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + reader.read_exact(g2_repr.as_mut())?; + let gamma_g2 = g2_repr + .into_affine_unchecked() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + reader.read_exact(g2_repr.as_mut())?; + let delta_g2 = g2_repr + .into_affine_unchecked() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + + let mut ic = vec![]; + + while reader.read_exact(g1_repr.as_mut()).is_ok() { + let g1 = g1_repr + .into_affine_unchecked() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + } else { + Ok(e) + } + })?; + ic.push(g1); + } + + Ok(TruncatedVerifyingKey { + alpha_g1: alpha_g1, + beta_g2: beta_g2, + gamma_g2: gamma_g2, + delta_g2: delta_g2, + ic: ic.clone(), + }) + } +} + +pub fn verify_proof<'a, E: Engine>( + tvk: &'a TruncatedVerifyingKey, + proof: &Proof, + public_inputs: &[E::Fr], +) -> Result { + if (public_inputs.len() + 1) != tvk.ic.len() { + return Err(SynthesisError::MalformedVerifyingKey); + } + + if !proof.b.mul(E::Fr::char()).is_zero() { + return Ok(false); + } + + let mut acc = tvk.ic[0].into_projective(); + + for (i, b) in public_inputs.iter().zip(tvk.ic.iter().skip(1)) { + acc.add_assign(&b.mul(i.into_repr())); + } + + // The original verification equation is: + // A * B = alpha * beta + inputs * gamma + C * delta + // ... however, we rearrange it so that it is: + // (-A) * B + alpha * beta + inputs * gamma + C * delta == 1 + + let mut neg_a = proof.a.clone(); + neg_a.negate(); + + Ok(E::final_exponentiation(&E::miller_loop(&[ + (&neg_a.prepare(), &proof.b.prepare()), + (&tvk.alpha_g1.prepare(), &tvk.beta_g2.prepare()), + (&acc.into_affine().prepare(), &tvk.gamma_g2.prepare()), + (&proof.c.prepare(), &tvk.delta_g2.prepare()), + ])) + .unwrap() + == E::Fqk::one()) +} diff --git a/zwaves_jni/src/lib.rs b/zwaves_jni/src/lib.rs index 6ffcbce..8d5f50f 100644 --- a/zwaves_jni/src/lib.rs +++ b/zwaves_jni/src/lib.rs @@ -1,28 +1,49 @@ -#[cfg(test)] -pub mod tests; +use std::mem; -use jni::JNIEnv; -use jni::sys::{jboolean, jbyteArray, jlong}; -use jni::objects::{JObject, JValue, JClass}; +use jni::{ + objects::JClass, + sys::{jboolean, jbyteArray}, + JNIEnv, +}; -use pairing::bls12_381::{Fr, FrRepr, Bls12}; -use pairing::{Engine, PrimeField, Field, PrimeFieldRepr}; +pub mod bls12; +pub mod bn256; -use bellman::groth16::{Proof}; +#[no_mangle] +pub extern "system" fn Java_com_wavesplatform_zwaves_bls12_Groth16_verify( + env: JNIEnv, + _class: JClass, + jvk: jbyteArray, + jproof: jbyteArray, + jinputs: jbyteArray, +) -> jboolean { + let vk = parse_jni_bytes(&env, jvk); + let proof = parse_jni_bytes(&env, jproof); + let inputs = parse_jni_bytes(&env, jinputs); -use std::{mem, io, iter}; -use std::io::{Read, Write}; -use byteorder::{BigEndian, ReadBytesExt}; + bls12::groth16_verify(&vk, &proof, &inputs).unwrap_or(0u8) +} -use zwaves_primitives::serialization::{read_fr_repr_be, read_fr_vec}; -use zwaves_primitives::verifier::{TruncatedVerifyingKey, verify_proof}; +#[no_mangle] +pub extern "system" fn Java_com_wavesplatform_zwaves_bn256_Groth16_verify( + env: JNIEnv, + _class: JClass, + jvk: jbyteArray, + jproof: jbyteArray, + jinputs: jbyteArray, +) -> jboolean { + let vk = parse_jni_bytes(&env, jvk); + let proof = parse_jni_bytes(&env, jproof); + let inputs = parse_jni_bytes(&env, jinputs); + bn256::groth16_verify(&vk, &proof, &inputs).unwrap_or(0u8) +} fn parse_jni_bytes(env: &JNIEnv, jv: jbyteArray) -> Vec { let v_len = env.get_array_length(jv).unwrap() as usize; let mut v = vec![0i8; v_len]; env.get_byte_array_region(jv, 0, &mut v[..]).unwrap(); - + unsafe { let ptr = v.as_mut_ptr(); let len = v.len(); @@ -31,124 +52,3 @@ fn parse_jni_bytes(env: &JNIEnv, jv: jbyteArray) -> Vec { Vec::from_raw_parts(ptr as *mut u8, len, cap) } } - - - - - -fn groth16_verify(vk:&[u8], proof:&[u8], inputs:&[u8]) -> io::Result { - - let buff_vk_len = vk.len(); - let buff_proof_len = proof.len(); - let buff_inputs_len = inputs.len(); - - if (buff_vk_len % 48 != 0) || (buff_inputs_len % 32 != 0) { - return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); - } - - - let inputs_len = buff_inputs_len / 32; - - if ((buff_vk_len / 48) != (inputs_len + 8)) || (buff_proof_len != 192) { - return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer length")); - } - - - let vk = TruncatedVerifyingKey::::read(vk)?; - let proof = Proof::::read(proof)?; - let inputs = read_fr_vec::(inputs)?; - - if (inputs.len() != inputs_len) || (vk.ic.len() != (inputs_len + 1)) { - return Err(io::Error::new(io::ErrorKind::InvalidData, "wrong buffer parsing")); - } - - Ok(verify_proof( - &vk, - &proof, - inputs.as_slice() - ).map(|r| r as u8).unwrap_or(0)) -} - - - - - - -#[no_mangle] -pub extern "system" fn Java_com_wavesplatform_zwaves_bls12_Groth16_verify(env: JNIEnv, - class: JClass, - jvk: jbyteArray, - jproof: jbyteArray, - jinputs: jbyteArray) - -> jboolean { - - let vk = parse_jni_bytes(&env, jvk); - let proof = parse_jni_bytes(&env, jproof); - let inputs = parse_jni_bytes(&env, jinputs); - - groth16_verify(&vk, &proof, &inputs).unwrap_or(0u8) - -} - - - -#[cfg(test)] -mod local_tests { - use base64::decode; - use super::*; - - - - #[test] - fn test_groth16_verify_binaries_ok() { - - let vk = "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r"; - let proof = "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF"; - let inputs = "LcMT3OOlkHLzJBKCKjjzzVMg+r+FVgd52LlhZPB4RFg="; - - let vk = decode(vk).unwrap(); - let proof = decode(proof).unwrap(); - let inputs = decode(inputs).unwrap(); - - - let res = groth16_verify(&vk, &proof, &inputs).unwrap_or(0) != 0; - assert!(res, "groth16_verify should be true"); - } - - - #[test] - fn test_groth16_verify_binaries_notok() { - - let vk = "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r"; - let proof = "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF"; - let inputs = "cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s="; - - let vk = decode(vk).unwrap(); - let proof = decode(proof).unwrap(); - let inputs = decode(inputs).unwrap(); - - - let res = groth16_verify(&vk, &proof, &inputs).unwrap_or(0) != 0; - assert!(!res, "groth16_verify should be false"); - - } - - #[test] - fn test_groth16_verify_binaries_bad_data() { - - let vk = "hwk883gUlTKCyXYA6XWZa8H9/xKIYZaJ0xEs0M5hQOMxiGpxocuX/8maSDmeCk3bo5ViaDBdO7ZBxAhLSe5k/5TFQyF5Lv7KN2tLKnwgoWMqB16OL8WdbePIwTCuPtJNAFKoTZylLDbSf02kckMcZQDPF9iGh+JC99Pio74vDpwTEjUx5tQ99gNQwxULtztsqDRsPnEvKvLmsxHt8LQVBkEBm2PBJFY+OXf1MNW021viDBpR10mX4WQ6zrsGL5L0GY4cwf4tlbh+Obit+LnN/SQTnREf8fPpdKZ1sa/ui3pGi8lMT6io4D7Ujlwx2RdCkBF+isfMf77HCEGsZANw0hSrO2FGg14Sl26xLAIohdaW8O7gEaag8JdVAZ3OVLd5Df1NkZBEr753Xb8WwaXsJjE7qxwINL1KdqA4+EiYW4edb7+a9bbBeOPtb67ZxmFqgyTNS/4obxahezNkjk00ytswsENg//Ee6dWBJZyLH+QGsaU2jO/W4WvRyZhmKKPdipOhiz4Rlrd2XYgsfHsfWf5v4GOTL+13ZB24dW1/m39n2woJ+v686fXbNW85XP/r"; - let proof = "lvQLU/KqgFhsLkt/5C/scqs7nWR+eYtyPdWiLVBux9GblT4AhHYMdCgwQfSJcudvsgV6fXoK+DUSRgJ++Nqt+Wvb7GlYlHpxCysQhz26TTu8Nyo7zpmVPH92+UYmbvbQCSvX2BhWtvkfHmqDVjmSIQ4RUMfeveA1KZbSf999NE4qKK8Do+8oXcmTM4LZVmh1rlyqznIdFXPN7x3pD4E0gb6/y69xtWMChv9654FMg05bAdueKt9uA4BEcAbpkdHF"; - let inputs = "cmzVCcRVnckw3QUPhmG4Bkppeg4K50oDQwQ9EH+Fq1s="; - - let vk = decode(vk).unwrap(); - let proof = decode(proof).unwrap(); - let inputs = decode(inputs).unwrap(); - - - let res = groth16_verify(&vk, &proof, &inputs[0..1]).unwrap_or(0) != 0; - assert!(!res, "groth16_verify should be false"); - - } - - -} \ No newline at end of file