From c8d383bbb017fcff145a63ef4f3eef3548ec4fec Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 7 Jan 2015 15:26:41 -0800 Subject: [PATCH] Move over to gradle for all building. Use separate modules in order to build both a java as well as an android artifact, with separate and shared test cases. --- .gitignore | 1 + android/.gitignore | 1 + android/build.gradle | 94 ++++++++++ {jni => android/jni}/Android.mk | 0 {jni => android/jni}/Application.mk | 0 {jni => android/jni}/curve25519-donna.c | 0 {jni => android/jni}/curve25519-donna.h | 0 {jni => android/jni}/curve25519-jni.c | 0 .../jni}/ed25519/additions/compare.c | 0 .../jni}/ed25519/additions/compare.h | 0 .../ed25519/additions/crypto_hash_sha512.h | 0 .../jni}/ed25519/additions/curve_sigs.c | 0 .../jni}/ed25519/additions/curve_sigs.h | 0 .../jni}/ed25519/additions/sign_modified.c | 0 .../jni}/ed25519/additions/zeroize.c | 0 .../jni}/ed25519/additions/zeroize.h | 0 {jni => android/jni}/ed25519/api.h | 0 {jni => android/jni}/ed25519/base.h | 0 {jni => android/jni}/ed25519/base2.h | 0 {jni => android/jni}/ed25519/d.h | 0 {jni => android/jni}/ed25519/d2.h | 0 {jni => android/jni}/ed25519/fe.h | 0 {jni => android/jni}/ed25519/fe_0.c | 0 {jni => android/jni}/ed25519/fe_1.c | 0 {jni => android/jni}/ed25519/fe_add.c | 0 {jni => android/jni}/ed25519/fe_cmov.c | 0 {jni => android/jni}/ed25519/fe_copy.c | 0 {jni => android/jni}/ed25519/fe_frombytes.c | 0 {jni => android/jni}/ed25519/fe_invert.c | 0 {jni => android/jni}/ed25519/fe_isnegative.c | 0 {jni => android/jni}/ed25519/fe_isnonzero.c | 0 {jni => android/jni}/ed25519/fe_mul.c | 0 {jni => android/jni}/ed25519/fe_neg.c | 0 {jni => android/jni}/ed25519/fe_pow22523.c | 0 {jni => android/jni}/ed25519/fe_sq.c | 0 {jni => android/jni}/ed25519/fe_sq2.c | 0 {jni => android/jni}/ed25519/fe_sub.c | 0 {jni => android/jni}/ed25519/fe_tobytes.c | 0 {jni => android/jni}/ed25519/ge.h | 0 {jni => android/jni}/ed25519/ge_add.c | 0 {jni => android/jni}/ed25519/ge_add.h | 0 .../jni}/ed25519/ge_double_scalarmult.c | 0 {jni => android/jni}/ed25519/ge_frombytes.c | 0 {jni => android/jni}/ed25519/ge_madd.c | 0 {jni => android/jni}/ed25519/ge_madd.h | 0 {jni => android/jni}/ed25519/ge_msub.c | 0 {jni => android/jni}/ed25519/ge_msub.h | 0 {jni => android/jni}/ed25519/ge_p1p1_to_p2.c | 0 {jni => android/jni}/ed25519/ge_p1p1_to_p3.c | 0 {jni => android/jni}/ed25519/ge_p2_0.c | 0 {jni => android/jni}/ed25519/ge_p2_dbl.c | 0 {jni => android/jni}/ed25519/ge_p2_dbl.h | 0 {jni => android/jni}/ed25519/ge_p3_0.c | 0 {jni => android/jni}/ed25519/ge_p3_dbl.c | 0 .../jni}/ed25519/ge_p3_to_cached.c | 0 {jni => android/jni}/ed25519/ge_p3_to_p2.c | 0 {jni => android/jni}/ed25519/ge_p3_tobytes.c | 0 {jni => android/jni}/ed25519/ge_precomp_0.c | 0 .../jni}/ed25519/ge_scalarmult_base.c | 0 {jni => android/jni}/ed25519/ge_sub.c | 0 {jni => android/jni}/ed25519/ge_sub.h | 0 {jni => android/jni}/ed25519/ge_tobytes.c | 0 {jni => android/jni}/ed25519/main/main.c | 0 .../jni}/ed25519/nacl_includes/crypto_int32.h | 0 .../jni}/ed25519/nacl_includes/crypto_int64.h | 0 .../jni}/ed25519/nacl_includes/crypto_sign.h | 0 .../crypto_sign_edwards25519sha512batch.h | 0 .../ed25519/nacl_includes/crypto_uint32.h | 0 .../ed25519/nacl_includes/crypto_uint64.h | 0 .../ed25519/nacl_includes/crypto_verify_32.h | 0 .../jni}/ed25519/nacl_sha512/blocks.c | 0 .../jni}/ed25519/nacl_sha512/hash.c | 0 {jni => android/jni}/ed25519/open.c | 0 {jni => android/jni}/ed25519/pow22523.h | 0 {jni => android/jni}/ed25519/pow225521.h | 0 {jni => android/jni}/ed25519/sc.h | 0 {jni => android/jni}/ed25519/sc_muladd.c | 0 {jni => android/jni}/ed25519/sc_reduce.c | 0 {jni => android/jni}/ed25519/sign.c | 0 {jni => android/jni}/ed25519/sqrtm1.h | 0 .../libs}/armeabi-v7a/libcurve25519.so | Bin .../libs}/armeabi/libcurve25519.so | Bin {libs => android/libs}/mips/libcurve25519.so | Bin {libs => android/libs}/x86/libcurve25519.so | Bin .../NativeCurve25519ProviderTest.java | 0 .../curve25519/NativeCurve25519Test.java | 3 - {src => android/src}/main/AndroidManifest.xml | 0 build.gradle | 97 +---------- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 51010 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ java/build.gradle | 63 +++++++ .../whispersystems/curve25519/Curve25519.java | 2 +- .../curve25519/Curve25519KeyPair.java | 0 .../curve25519/Curve25519Provider.java | 0 .../curve25519/JavaCurve25519Provider.java | 0 .../curve25519/NativeCurve25519Provider.java | 0 .../curve25519/java/crypto_hash_sha512.java | 0 .../curve25519/java/crypto_verify_32.java | 0 .../curve25519/java/curve_sigs.java | 0 .../whispersystems/curve25519/java/fe_0.java | 0 .../whispersystems/curve25519/java/fe_1.java | 0 .../curve25519/java/fe_add.java | 0 .../curve25519/java/fe_cmov.java | 0 .../curve25519/java/fe_copy.java | 0 .../curve25519/java/fe_cswap.java | 0 .../curve25519/java/fe_frombytes.java | 0 .../curve25519/java/fe_invert.java | 0 .../curve25519/java/fe_isnegative.java | 0 .../curve25519/java/fe_isnonzero.java | 0 .../curve25519/java/fe_mul.java | 0 .../curve25519/java/fe_mul121666.java | 0 .../curve25519/java/fe_neg.java | 0 .../curve25519/java/fe_pow22523.java | 0 .../whispersystems/curve25519/java/fe_sq.java | 0 .../curve25519/java/fe_sq2.java | 0 .../curve25519/java/fe_sub.java | 0 .../curve25519/java/fe_tobytes.java | 0 .../curve25519/java/ge_add.java | 0 .../curve25519/java/ge_cached.java | 0 .../curve25519/java/ge_double_scalarmult.java | 0 .../curve25519/java/ge_frombytes.java | 0 .../curve25519/java/ge_madd.java | 0 .../curve25519/java/ge_msub.java | 0 .../curve25519/java/ge_p1p1.java | 0 .../curve25519/java/ge_p1p1_to_p2.java | 0 .../curve25519/java/ge_p1p1_to_p3.java | 0 .../whispersystems/curve25519/java/ge_p2.java | 0 .../curve25519/java/ge_p2_0.java | 0 .../curve25519/java/ge_p2_dbl.java | 0 .../whispersystems/curve25519/java/ge_p3.java | 0 .../curve25519/java/ge_p3_0.java | 0 .../curve25519/java/ge_p3_dbl.java | 0 .../curve25519/java/ge_p3_to_cached.java | 0 .../curve25519/java/ge_p3_to_p2.java | 0 .../curve25519/java/ge_p3_tobytes.java | 0 .../curve25519/java/ge_precomp.java | 0 .../curve25519/java/ge_precomp_0.java | 0 .../curve25519/java/ge_scalarmult_base.java | 0 .../curve25519/java/ge_sub.java | 0 .../curve25519/java/ge_tobytes.java | 0 .../whispersystems/curve25519/java/open.java | 0 .../curve25519/java/sc_muladd.java | 0 .../curve25519/java/sc_reduce.java | 0 .../curve25519/java/scalarmult.java | 0 .../curve25519/java/sign_modified.java | 0 .../JavaCurve25519ProviderTest.java | 0 .../curve25519/JavaCurve25519Test.java | 0 pom.xml | 129 -------------- settings.gradle | 1 + .../curve25519/AndroidWrapper.java | 44 ----- tests/build.gradle | 13 ++ .../curve25519/Curve25519ProviderTest.java | 15 +- .../curve25519/Curve25519Test.java | 19 +- 155 files changed, 447 insertions(+), 295 deletions(-) create mode 100644 android/.gitignore create mode 100644 android/build.gradle rename {jni => android/jni}/Android.mk (100%) rename {jni => android/jni}/Application.mk (100%) rename {jni => android/jni}/curve25519-donna.c (100%) rename {jni => android/jni}/curve25519-donna.h (100%) rename {jni => android/jni}/curve25519-jni.c (100%) rename {jni => android/jni}/ed25519/additions/compare.c (100%) rename {jni => android/jni}/ed25519/additions/compare.h (100%) rename {jni => android/jni}/ed25519/additions/crypto_hash_sha512.h (100%) rename {jni => android/jni}/ed25519/additions/curve_sigs.c (100%) rename {jni => android/jni}/ed25519/additions/curve_sigs.h (100%) rename {jni => android/jni}/ed25519/additions/sign_modified.c (100%) rename {jni => android/jni}/ed25519/additions/zeroize.c (100%) rename {jni => android/jni}/ed25519/additions/zeroize.h (100%) rename {jni => android/jni}/ed25519/api.h (100%) rename {jni => android/jni}/ed25519/base.h (100%) rename {jni => android/jni}/ed25519/base2.h (100%) rename {jni => android/jni}/ed25519/d.h (100%) rename {jni => android/jni}/ed25519/d2.h (100%) rename {jni => android/jni}/ed25519/fe.h (100%) rename {jni => android/jni}/ed25519/fe_0.c (100%) rename {jni => android/jni}/ed25519/fe_1.c (100%) rename {jni => android/jni}/ed25519/fe_add.c (100%) rename {jni => android/jni}/ed25519/fe_cmov.c (100%) rename {jni => android/jni}/ed25519/fe_copy.c (100%) rename {jni => android/jni}/ed25519/fe_frombytes.c (100%) rename {jni => android/jni}/ed25519/fe_invert.c (100%) rename {jni => android/jni}/ed25519/fe_isnegative.c (100%) rename {jni => android/jni}/ed25519/fe_isnonzero.c (100%) rename {jni => android/jni}/ed25519/fe_mul.c (100%) rename {jni => android/jni}/ed25519/fe_neg.c (100%) rename {jni => android/jni}/ed25519/fe_pow22523.c (100%) rename {jni => android/jni}/ed25519/fe_sq.c (100%) rename {jni => android/jni}/ed25519/fe_sq2.c (100%) rename {jni => android/jni}/ed25519/fe_sub.c (100%) rename {jni => android/jni}/ed25519/fe_tobytes.c (100%) rename {jni => android/jni}/ed25519/ge.h (100%) rename {jni => android/jni}/ed25519/ge_add.c (100%) rename {jni => android/jni}/ed25519/ge_add.h (100%) rename {jni => android/jni}/ed25519/ge_double_scalarmult.c (100%) rename {jni => android/jni}/ed25519/ge_frombytes.c (100%) rename {jni => android/jni}/ed25519/ge_madd.c (100%) rename {jni => android/jni}/ed25519/ge_madd.h (100%) rename {jni => android/jni}/ed25519/ge_msub.c (100%) rename {jni => android/jni}/ed25519/ge_msub.h (100%) rename {jni => android/jni}/ed25519/ge_p1p1_to_p2.c (100%) rename {jni => android/jni}/ed25519/ge_p1p1_to_p3.c (100%) rename {jni => android/jni}/ed25519/ge_p2_0.c (100%) rename {jni => android/jni}/ed25519/ge_p2_dbl.c (100%) rename {jni => android/jni}/ed25519/ge_p2_dbl.h (100%) rename {jni => android/jni}/ed25519/ge_p3_0.c (100%) rename {jni => android/jni}/ed25519/ge_p3_dbl.c (100%) rename {jni => android/jni}/ed25519/ge_p3_to_cached.c (100%) rename {jni => android/jni}/ed25519/ge_p3_to_p2.c (100%) rename {jni => android/jni}/ed25519/ge_p3_tobytes.c (100%) rename {jni => android/jni}/ed25519/ge_precomp_0.c (100%) rename {jni => android/jni}/ed25519/ge_scalarmult_base.c (100%) rename {jni => android/jni}/ed25519/ge_sub.c (100%) rename {jni => android/jni}/ed25519/ge_sub.h (100%) rename {jni => android/jni}/ed25519/ge_tobytes.c (100%) rename {jni => android/jni}/ed25519/main/main.c (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_int32.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_int64.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_sign.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_uint32.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_uint64.h (100%) rename {jni => android/jni}/ed25519/nacl_includes/crypto_verify_32.h (100%) rename {jni => android/jni}/ed25519/nacl_sha512/blocks.c (100%) rename {jni => android/jni}/ed25519/nacl_sha512/hash.c (100%) rename {jni => android/jni}/ed25519/open.c (100%) rename {jni => android/jni}/ed25519/pow22523.h (100%) rename {jni => android/jni}/ed25519/pow225521.h (100%) rename {jni => android/jni}/ed25519/sc.h (100%) rename {jni => android/jni}/ed25519/sc_muladd.c (100%) rename {jni => android/jni}/ed25519/sc_reduce.c (100%) rename {jni => android/jni}/ed25519/sign.c (100%) rename {jni => android/jni}/ed25519/sqrtm1.h (100%) rename {libs => android/libs}/armeabi-v7a/libcurve25519.so (100%) rename {libs => android/libs}/armeabi/libcurve25519.so (100%) rename {libs => android/libs}/mips/libcurve25519.so (100%) rename {libs => android/libs}/x86/libcurve25519.so (100%) rename {src => android/src}/androidTest/java/org/whispersystems/curve25519/NativeCurve25519ProviderTest.java (100%) rename {src => android/src}/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java (81%) rename {src => android/src}/main/AndroidManifest.xml (100%) create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 java/build.gradle rename {src => java/src}/main/java/org/whispersystems/curve25519/Curve25519.java (97%) rename {src => java/src}/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/Curve25519Provider.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/JavaCurve25519Provider.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/NativeCurve25519Provider.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/crypto_hash_sha512.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/curve_sigs.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_0.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_1.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_add.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_cmov.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_copy.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_cswap.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_frombytes.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_invert.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_isnegative.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_mul.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_mul121666.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_neg.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_pow22523.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_sq.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_sq2.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_sub.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/fe_tobytes.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_add.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_cached.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_frombytes.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_madd.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_msub.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p1p1.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p2.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p2_0.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3_0.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_precomp.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_sub.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/ge_tobytes.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/open.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/sc_muladd.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/sc_reduce.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/scalarmult.java (100%) rename {src => java/src}/main/java/org/whispersystems/curve25519/java/sign_modified.java (100%) rename {src/javaTest => java/src/test}/java/org/whispersystems/curve25519/JavaCurve25519ProviderTest.java (100%) rename {src/javaTest => java/src/test}/java/org/whispersystems/curve25519/JavaCurve25519Test.java (100%) delete mode 100644 pom.xml create mode 100644 settings.gradle delete mode 100644 src/androidTest/java/org/whispersystems/curve25519/AndroidWrapper.java create mode 100644 tests/build.gradle rename {src/commonTest => tests/src/main}/java/org/whispersystems/curve25519/Curve25519ProviderTest.java (90%) rename {src/commonTest => tests/src/main}/java/org/whispersystems/curve25519/Curve25519Test.java (95%) diff --git a/.gitignore b/.gitignore index 1e967e2..b94479b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ target/ obj/ build/ .gradle/ +local.properties diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..26ff498 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,94 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0' + } +} + +apply plugin: 'com.android.library' +apply plugin: 'maven' +apply plugin: 'signing' + +archivesBaseName = "curve25519-android" +version = version_number +group = group_info + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${archivesBaseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } +} + +repositories { + mavenCentral() +} + +dependencies { + compile project(':java') + + androidTestCompile project(":tests") +} + +signing { + required { has("release") && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives +} + +uploadArchives { + configuration = configurations.archives + repositories.mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: sonatypeRepo) { + authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword) + } + + pom.project { + name 'curve25519-android' + packaging 'aar' + description 'Curve25519 library for Android' + url 'https://github.com/WhisperSystems/curve25519-java' + + scm { + url 'scm:git@github.com:WhisperSystems/curve25519-java.git' + connection 'scm:git@github.com:WhisperSystems/curve25519-java.git' + developerConnection 'scm:git@github.com:WhisperSystems/curve25519-java.git' + } + + developers { + developer { + name 'Trevor Perrin' + name 'Moxie Marlinspike' + } + } + } + } +} + +task installArchives(type: Upload) { + description "Installs the artifacts to the local Maven repository." + configuration = configurations['archives'] + repositories { + mavenDeployer { + repository url: "file://${System.properties['user.home']}/.m2/repository" + } + } +} diff --git a/jni/Android.mk b/android/jni/Android.mk similarity index 100% rename from jni/Android.mk rename to android/jni/Android.mk diff --git a/jni/Application.mk b/android/jni/Application.mk similarity index 100% rename from jni/Application.mk rename to android/jni/Application.mk diff --git a/jni/curve25519-donna.c b/android/jni/curve25519-donna.c similarity index 100% rename from jni/curve25519-donna.c rename to android/jni/curve25519-donna.c diff --git a/jni/curve25519-donna.h b/android/jni/curve25519-donna.h similarity index 100% rename from jni/curve25519-donna.h rename to android/jni/curve25519-donna.h diff --git a/jni/curve25519-jni.c b/android/jni/curve25519-jni.c similarity index 100% rename from jni/curve25519-jni.c rename to android/jni/curve25519-jni.c diff --git a/jni/ed25519/additions/compare.c b/android/jni/ed25519/additions/compare.c similarity index 100% rename from jni/ed25519/additions/compare.c rename to android/jni/ed25519/additions/compare.c diff --git a/jni/ed25519/additions/compare.h b/android/jni/ed25519/additions/compare.h similarity index 100% rename from jni/ed25519/additions/compare.h rename to android/jni/ed25519/additions/compare.h diff --git a/jni/ed25519/additions/crypto_hash_sha512.h b/android/jni/ed25519/additions/crypto_hash_sha512.h similarity index 100% rename from jni/ed25519/additions/crypto_hash_sha512.h rename to android/jni/ed25519/additions/crypto_hash_sha512.h diff --git a/jni/ed25519/additions/curve_sigs.c b/android/jni/ed25519/additions/curve_sigs.c similarity index 100% rename from jni/ed25519/additions/curve_sigs.c rename to android/jni/ed25519/additions/curve_sigs.c diff --git a/jni/ed25519/additions/curve_sigs.h b/android/jni/ed25519/additions/curve_sigs.h similarity index 100% rename from jni/ed25519/additions/curve_sigs.h rename to android/jni/ed25519/additions/curve_sigs.h diff --git a/jni/ed25519/additions/sign_modified.c b/android/jni/ed25519/additions/sign_modified.c similarity index 100% rename from jni/ed25519/additions/sign_modified.c rename to android/jni/ed25519/additions/sign_modified.c diff --git a/jni/ed25519/additions/zeroize.c b/android/jni/ed25519/additions/zeroize.c similarity index 100% rename from jni/ed25519/additions/zeroize.c rename to android/jni/ed25519/additions/zeroize.c diff --git a/jni/ed25519/additions/zeroize.h b/android/jni/ed25519/additions/zeroize.h similarity index 100% rename from jni/ed25519/additions/zeroize.h rename to android/jni/ed25519/additions/zeroize.h diff --git a/jni/ed25519/api.h b/android/jni/ed25519/api.h similarity index 100% rename from jni/ed25519/api.h rename to android/jni/ed25519/api.h diff --git a/jni/ed25519/base.h b/android/jni/ed25519/base.h similarity index 100% rename from jni/ed25519/base.h rename to android/jni/ed25519/base.h diff --git a/jni/ed25519/base2.h b/android/jni/ed25519/base2.h similarity index 100% rename from jni/ed25519/base2.h rename to android/jni/ed25519/base2.h diff --git a/jni/ed25519/d.h b/android/jni/ed25519/d.h similarity index 100% rename from jni/ed25519/d.h rename to android/jni/ed25519/d.h diff --git a/jni/ed25519/d2.h b/android/jni/ed25519/d2.h similarity index 100% rename from jni/ed25519/d2.h rename to android/jni/ed25519/d2.h diff --git a/jni/ed25519/fe.h b/android/jni/ed25519/fe.h similarity index 100% rename from jni/ed25519/fe.h rename to android/jni/ed25519/fe.h diff --git a/jni/ed25519/fe_0.c b/android/jni/ed25519/fe_0.c similarity index 100% rename from jni/ed25519/fe_0.c rename to android/jni/ed25519/fe_0.c diff --git a/jni/ed25519/fe_1.c b/android/jni/ed25519/fe_1.c similarity index 100% rename from jni/ed25519/fe_1.c rename to android/jni/ed25519/fe_1.c diff --git a/jni/ed25519/fe_add.c b/android/jni/ed25519/fe_add.c similarity index 100% rename from jni/ed25519/fe_add.c rename to android/jni/ed25519/fe_add.c diff --git a/jni/ed25519/fe_cmov.c b/android/jni/ed25519/fe_cmov.c similarity index 100% rename from jni/ed25519/fe_cmov.c rename to android/jni/ed25519/fe_cmov.c diff --git a/jni/ed25519/fe_copy.c b/android/jni/ed25519/fe_copy.c similarity index 100% rename from jni/ed25519/fe_copy.c rename to android/jni/ed25519/fe_copy.c diff --git a/jni/ed25519/fe_frombytes.c b/android/jni/ed25519/fe_frombytes.c similarity index 100% rename from jni/ed25519/fe_frombytes.c rename to android/jni/ed25519/fe_frombytes.c diff --git a/jni/ed25519/fe_invert.c b/android/jni/ed25519/fe_invert.c similarity index 100% rename from jni/ed25519/fe_invert.c rename to android/jni/ed25519/fe_invert.c diff --git a/jni/ed25519/fe_isnegative.c b/android/jni/ed25519/fe_isnegative.c similarity index 100% rename from jni/ed25519/fe_isnegative.c rename to android/jni/ed25519/fe_isnegative.c diff --git a/jni/ed25519/fe_isnonzero.c b/android/jni/ed25519/fe_isnonzero.c similarity index 100% rename from jni/ed25519/fe_isnonzero.c rename to android/jni/ed25519/fe_isnonzero.c diff --git a/jni/ed25519/fe_mul.c b/android/jni/ed25519/fe_mul.c similarity index 100% rename from jni/ed25519/fe_mul.c rename to android/jni/ed25519/fe_mul.c diff --git a/jni/ed25519/fe_neg.c b/android/jni/ed25519/fe_neg.c similarity index 100% rename from jni/ed25519/fe_neg.c rename to android/jni/ed25519/fe_neg.c diff --git a/jni/ed25519/fe_pow22523.c b/android/jni/ed25519/fe_pow22523.c similarity index 100% rename from jni/ed25519/fe_pow22523.c rename to android/jni/ed25519/fe_pow22523.c diff --git a/jni/ed25519/fe_sq.c b/android/jni/ed25519/fe_sq.c similarity index 100% rename from jni/ed25519/fe_sq.c rename to android/jni/ed25519/fe_sq.c diff --git a/jni/ed25519/fe_sq2.c b/android/jni/ed25519/fe_sq2.c similarity index 100% rename from jni/ed25519/fe_sq2.c rename to android/jni/ed25519/fe_sq2.c diff --git a/jni/ed25519/fe_sub.c b/android/jni/ed25519/fe_sub.c similarity index 100% rename from jni/ed25519/fe_sub.c rename to android/jni/ed25519/fe_sub.c diff --git a/jni/ed25519/fe_tobytes.c b/android/jni/ed25519/fe_tobytes.c similarity index 100% rename from jni/ed25519/fe_tobytes.c rename to android/jni/ed25519/fe_tobytes.c diff --git a/jni/ed25519/ge.h b/android/jni/ed25519/ge.h similarity index 100% rename from jni/ed25519/ge.h rename to android/jni/ed25519/ge.h diff --git a/jni/ed25519/ge_add.c b/android/jni/ed25519/ge_add.c similarity index 100% rename from jni/ed25519/ge_add.c rename to android/jni/ed25519/ge_add.c diff --git a/jni/ed25519/ge_add.h b/android/jni/ed25519/ge_add.h similarity index 100% rename from jni/ed25519/ge_add.h rename to android/jni/ed25519/ge_add.h diff --git a/jni/ed25519/ge_double_scalarmult.c b/android/jni/ed25519/ge_double_scalarmult.c similarity index 100% rename from jni/ed25519/ge_double_scalarmult.c rename to android/jni/ed25519/ge_double_scalarmult.c diff --git a/jni/ed25519/ge_frombytes.c b/android/jni/ed25519/ge_frombytes.c similarity index 100% rename from jni/ed25519/ge_frombytes.c rename to android/jni/ed25519/ge_frombytes.c diff --git a/jni/ed25519/ge_madd.c b/android/jni/ed25519/ge_madd.c similarity index 100% rename from jni/ed25519/ge_madd.c rename to android/jni/ed25519/ge_madd.c diff --git a/jni/ed25519/ge_madd.h b/android/jni/ed25519/ge_madd.h similarity index 100% rename from jni/ed25519/ge_madd.h rename to android/jni/ed25519/ge_madd.h diff --git a/jni/ed25519/ge_msub.c b/android/jni/ed25519/ge_msub.c similarity index 100% rename from jni/ed25519/ge_msub.c rename to android/jni/ed25519/ge_msub.c diff --git a/jni/ed25519/ge_msub.h b/android/jni/ed25519/ge_msub.h similarity index 100% rename from jni/ed25519/ge_msub.h rename to android/jni/ed25519/ge_msub.h diff --git a/jni/ed25519/ge_p1p1_to_p2.c b/android/jni/ed25519/ge_p1p1_to_p2.c similarity index 100% rename from jni/ed25519/ge_p1p1_to_p2.c rename to android/jni/ed25519/ge_p1p1_to_p2.c diff --git a/jni/ed25519/ge_p1p1_to_p3.c b/android/jni/ed25519/ge_p1p1_to_p3.c similarity index 100% rename from jni/ed25519/ge_p1p1_to_p3.c rename to android/jni/ed25519/ge_p1p1_to_p3.c diff --git a/jni/ed25519/ge_p2_0.c b/android/jni/ed25519/ge_p2_0.c similarity index 100% rename from jni/ed25519/ge_p2_0.c rename to android/jni/ed25519/ge_p2_0.c diff --git a/jni/ed25519/ge_p2_dbl.c b/android/jni/ed25519/ge_p2_dbl.c similarity index 100% rename from jni/ed25519/ge_p2_dbl.c rename to android/jni/ed25519/ge_p2_dbl.c diff --git a/jni/ed25519/ge_p2_dbl.h b/android/jni/ed25519/ge_p2_dbl.h similarity index 100% rename from jni/ed25519/ge_p2_dbl.h rename to android/jni/ed25519/ge_p2_dbl.h diff --git a/jni/ed25519/ge_p3_0.c b/android/jni/ed25519/ge_p3_0.c similarity index 100% rename from jni/ed25519/ge_p3_0.c rename to android/jni/ed25519/ge_p3_0.c diff --git a/jni/ed25519/ge_p3_dbl.c b/android/jni/ed25519/ge_p3_dbl.c similarity index 100% rename from jni/ed25519/ge_p3_dbl.c rename to android/jni/ed25519/ge_p3_dbl.c diff --git a/jni/ed25519/ge_p3_to_cached.c b/android/jni/ed25519/ge_p3_to_cached.c similarity index 100% rename from jni/ed25519/ge_p3_to_cached.c rename to android/jni/ed25519/ge_p3_to_cached.c diff --git a/jni/ed25519/ge_p3_to_p2.c b/android/jni/ed25519/ge_p3_to_p2.c similarity index 100% rename from jni/ed25519/ge_p3_to_p2.c rename to android/jni/ed25519/ge_p3_to_p2.c diff --git a/jni/ed25519/ge_p3_tobytes.c b/android/jni/ed25519/ge_p3_tobytes.c similarity index 100% rename from jni/ed25519/ge_p3_tobytes.c rename to android/jni/ed25519/ge_p3_tobytes.c diff --git a/jni/ed25519/ge_precomp_0.c b/android/jni/ed25519/ge_precomp_0.c similarity index 100% rename from jni/ed25519/ge_precomp_0.c rename to android/jni/ed25519/ge_precomp_0.c diff --git a/jni/ed25519/ge_scalarmult_base.c b/android/jni/ed25519/ge_scalarmult_base.c similarity index 100% rename from jni/ed25519/ge_scalarmult_base.c rename to android/jni/ed25519/ge_scalarmult_base.c diff --git a/jni/ed25519/ge_sub.c b/android/jni/ed25519/ge_sub.c similarity index 100% rename from jni/ed25519/ge_sub.c rename to android/jni/ed25519/ge_sub.c diff --git a/jni/ed25519/ge_sub.h b/android/jni/ed25519/ge_sub.h similarity index 100% rename from jni/ed25519/ge_sub.h rename to android/jni/ed25519/ge_sub.h diff --git a/jni/ed25519/ge_tobytes.c b/android/jni/ed25519/ge_tobytes.c similarity index 100% rename from jni/ed25519/ge_tobytes.c rename to android/jni/ed25519/ge_tobytes.c diff --git a/jni/ed25519/main/main.c b/android/jni/ed25519/main/main.c similarity index 100% rename from jni/ed25519/main/main.c rename to android/jni/ed25519/main/main.c diff --git a/jni/ed25519/nacl_includes/crypto_int32.h b/android/jni/ed25519/nacl_includes/crypto_int32.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_int32.h rename to android/jni/ed25519/nacl_includes/crypto_int32.h diff --git a/jni/ed25519/nacl_includes/crypto_int64.h b/android/jni/ed25519/nacl_includes/crypto_int64.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_int64.h rename to android/jni/ed25519/nacl_includes/crypto_int64.h diff --git a/jni/ed25519/nacl_includes/crypto_sign.h b/android/jni/ed25519/nacl_includes/crypto_sign.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_sign.h rename to android/jni/ed25519/nacl_includes/crypto_sign.h diff --git a/jni/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h b/android/jni/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h rename to android/jni/ed25519/nacl_includes/crypto_sign_edwards25519sha512batch.h diff --git a/jni/ed25519/nacl_includes/crypto_uint32.h b/android/jni/ed25519/nacl_includes/crypto_uint32.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_uint32.h rename to android/jni/ed25519/nacl_includes/crypto_uint32.h diff --git a/jni/ed25519/nacl_includes/crypto_uint64.h b/android/jni/ed25519/nacl_includes/crypto_uint64.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_uint64.h rename to android/jni/ed25519/nacl_includes/crypto_uint64.h diff --git a/jni/ed25519/nacl_includes/crypto_verify_32.h b/android/jni/ed25519/nacl_includes/crypto_verify_32.h similarity index 100% rename from jni/ed25519/nacl_includes/crypto_verify_32.h rename to android/jni/ed25519/nacl_includes/crypto_verify_32.h diff --git a/jni/ed25519/nacl_sha512/blocks.c b/android/jni/ed25519/nacl_sha512/blocks.c similarity index 100% rename from jni/ed25519/nacl_sha512/blocks.c rename to android/jni/ed25519/nacl_sha512/blocks.c diff --git a/jni/ed25519/nacl_sha512/hash.c b/android/jni/ed25519/nacl_sha512/hash.c similarity index 100% rename from jni/ed25519/nacl_sha512/hash.c rename to android/jni/ed25519/nacl_sha512/hash.c diff --git a/jni/ed25519/open.c b/android/jni/ed25519/open.c similarity index 100% rename from jni/ed25519/open.c rename to android/jni/ed25519/open.c diff --git a/jni/ed25519/pow22523.h b/android/jni/ed25519/pow22523.h similarity index 100% rename from jni/ed25519/pow22523.h rename to android/jni/ed25519/pow22523.h diff --git a/jni/ed25519/pow225521.h b/android/jni/ed25519/pow225521.h similarity index 100% rename from jni/ed25519/pow225521.h rename to android/jni/ed25519/pow225521.h diff --git a/jni/ed25519/sc.h b/android/jni/ed25519/sc.h similarity index 100% rename from jni/ed25519/sc.h rename to android/jni/ed25519/sc.h diff --git a/jni/ed25519/sc_muladd.c b/android/jni/ed25519/sc_muladd.c similarity index 100% rename from jni/ed25519/sc_muladd.c rename to android/jni/ed25519/sc_muladd.c diff --git a/jni/ed25519/sc_reduce.c b/android/jni/ed25519/sc_reduce.c similarity index 100% rename from jni/ed25519/sc_reduce.c rename to android/jni/ed25519/sc_reduce.c diff --git a/jni/ed25519/sign.c b/android/jni/ed25519/sign.c similarity index 100% rename from jni/ed25519/sign.c rename to android/jni/ed25519/sign.c diff --git a/jni/ed25519/sqrtm1.h b/android/jni/ed25519/sqrtm1.h similarity index 100% rename from jni/ed25519/sqrtm1.h rename to android/jni/ed25519/sqrtm1.h diff --git a/libs/armeabi-v7a/libcurve25519.so b/android/libs/armeabi-v7a/libcurve25519.so similarity index 100% rename from libs/armeabi-v7a/libcurve25519.so rename to android/libs/armeabi-v7a/libcurve25519.so diff --git a/libs/armeabi/libcurve25519.so b/android/libs/armeabi/libcurve25519.so similarity index 100% rename from libs/armeabi/libcurve25519.so rename to android/libs/armeabi/libcurve25519.so diff --git a/libs/mips/libcurve25519.so b/android/libs/mips/libcurve25519.so similarity index 100% rename from libs/mips/libcurve25519.so rename to android/libs/mips/libcurve25519.so diff --git a/libs/x86/libcurve25519.so b/android/libs/x86/libcurve25519.so similarity index 100% rename from libs/x86/libcurve25519.so rename to android/libs/x86/libcurve25519.so diff --git a/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519ProviderTest.java b/android/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519ProviderTest.java similarity index 100% rename from src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519ProviderTest.java rename to android/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519ProviderTest.java diff --git a/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java b/android/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java similarity index 81% rename from src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java rename to android/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java index f5397ae..75a9410 100644 --- a/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java +++ b/android/src/androidTest/java/org/whispersystems/curve25519/NativeCurve25519Test.java @@ -1,8 +1,5 @@ package org.whispersystems.curve25519; -import static org.junit.Assert.assertTrue; - - public class NativeCurve25519Test extends Curve25519Test { @Override diff --git a/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml similarity index 100% rename from src/main/AndroidManifest.xml rename to android/src/main/AndroidManifest.xml diff --git a/build.gradle b/build.gradle index c007f60..a2799be 100644 --- a/build.gradle +++ b/build.gradle @@ -1,95 +1,2 @@ -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' - } -} - -apply plugin: 'com.android.library' -apply plugin: 'maven' -apply plugin: 'signing' - -archivesBaseName = "curve25519-android" -version = "0.0.1" -group = "org.whispersystems" - -repositories { - mavenCentral() -} - -dependencies { - androidTestCompile 'junit:junit:4.11' -} - -android { - compileSdkVersion 21 - buildToolsVersion '21.1.1' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - - android { - sourceSets { - main { - jniLibs.srcDirs = ['libs'] - } - androidTest { - java.srcDirs = ['src/androidTest/java', 'src/commonTest/java'] - } - } - packagingOptions { - exclude 'LICENSE.txt' - } - } - - libraryVariants.all { variant -> - variant.outputs.each { output -> - def outputFile = output.outputFile - if (outputFile != null && outputFile.name.endsWith('.aar')) { - def fileName = "${archivesBaseName}-${version}.aar" - output.outputFile = new File(outputFile.parent, fileName) - } - } - } -} - -signing { - required { has("release") && gradle.taskGraph.hasTask("uploadArchives") } - sign configurations.archives -} - -uploadArchives { - configuration = configurations.archives - repositories.mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - repository(url: sonatypeRepo) { - authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword) - } - - pom.project { - name 'curve25519-android' - packaging 'aar' - description 'Curve25519 library for Android' - url 'https://github.com/WhisperSystems/curve25519-java' - - scm { - url 'scm:git@github.com:WhisperSystems/curve25519-java.git' - connection 'scm:git@github.com:WhisperSystems/curve25519-java.git' - developerConnection 'scm:git@github.com:WhisperSystems/curve25519-java.git' - } - - developers { - developer { - name 'Trevor Perrin' - name 'Moxie Marlinspike' - } - } - } - } -} \ No newline at end of file +ext.version_number = "0.1.3" +ext.group_info = "org.whispersystems" \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2322723c7ed5f591adfa4c87b6c51932f591249a GIT binary patch literal 51010 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∓LFg$ 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c51665c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jan 06 14:11:31 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/build.gradle b/java/build.gradle new file mode 100644 index 0000000..62c61fc --- /dev/null +++ b/java/build.gradle @@ -0,0 +1,63 @@ +apply plugin: 'java' + +apply plugin: 'maven' +apply plugin: 'signing' + +sourceCompatibility = 1.7 +archivesBaseName = "curve25519-java" +version = version_number +group = group_info + +repositories { + mavenCentral() +} + +dependencies { + testCompile project(':tests') +} + +signing { + required { has("release") && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives +} + +uploadArchives { + configuration = configurations.archives + repositories.mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: sonatypeRepo) { + authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword) + } + + pom.project { + name 'curve25519-java' + packaging 'jar' + description 'Curve25519 library for Java' + url 'https://github.com/WhisperSystems/curve25519-java' + + scm { + url 'scm:git@github.com:WhisperSystems/curve25519-java.git' + connection 'scm:git@github.com:WhisperSystems/curve25519-java.git' + developerConnection 'scm:git@github.com:WhisperSystems/curve25519-java.git' + } + + developers { + developer { + name 'Trevor Perrin' + name 'Moxie Marlinspike' + } + } + } + } +} + +task installArchives(type: Upload) { + description "Installs the artifacts to the local Maven repository." + configuration = configurations['archives'] + repositories { + mavenDeployer { + repository url: "file://${System.properties['user.home']}/.m2/repository" + } + } +} diff --git a/src/main/java/org/whispersystems/curve25519/Curve25519.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519.java similarity index 97% rename from src/main/java/org/whispersystems/curve25519/Curve25519.java rename to java/src/main/java/org/whispersystems/curve25519/Curve25519.java index 672adb8..69bc920 100644 --- a/src/main/java/org/whispersystems/curve25519/Curve25519.java +++ b/java/src/main/java/org/whispersystems/curve25519/Curve25519.java @@ -21,7 +21,7 @@ public class Curve25519 { } /** - * {@link org.whispersystems.curve25519.Curve25519} is backed by either a native (via JNI) + * {@link Curve25519} is backed by either a native (via JNI) * or pure-Java provider. By default it prefers the native provider, and falls back to the * pure-Java provider if the native library fails to load. * diff --git a/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java rename to java/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java diff --git a/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/Curve25519Provider.java rename to java/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java diff --git a/src/main/java/org/whispersystems/curve25519/JavaCurve25519Provider.java b/java/src/main/java/org/whispersystems/curve25519/JavaCurve25519Provider.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/JavaCurve25519Provider.java rename to java/src/main/java/org/whispersystems/curve25519/JavaCurve25519Provider.java diff --git a/src/main/java/org/whispersystems/curve25519/NativeCurve25519Provider.java b/java/src/main/java/org/whispersystems/curve25519/NativeCurve25519Provider.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/NativeCurve25519Provider.java rename to java/src/main/java/org/whispersystems/curve25519/NativeCurve25519Provider.java diff --git a/src/main/java/org/whispersystems/curve25519/java/crypto_hash_sha512.java b/java/src/main/java/org/whispersystems/curve25519/java/crypto_hash_sha512.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/crypto_hash_sha512.java rename to java/src/main/java/org/whispersystems/curve25519/java/crypto_hash_sha512.java diff --git a/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java b/java/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java rename to java/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java diff --git a/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java b/java/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/curve_sigs.java rename to java/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_0.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_0.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_0.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_0.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_1.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_1.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_1.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_1.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_add.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_add.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_add.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_add.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_cmov.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_copy.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_copy.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_copy.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_copy.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_cswap.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_invert.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_invert.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_invert.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_invert.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_isnegative.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_isnonzero.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_mul.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_mul.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_mul.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_mul.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_neg.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_neg.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_neg.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_neg.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_sq.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_sq.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_sq.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_sq.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_sq2.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_sub.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_sub.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_sub.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_sub.java diff --git a/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java rename to java/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_add.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_add.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_add.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_add.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_cached.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_cached.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_cached.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_cached.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_double_scalarmult.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_madd.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_madd.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_madd.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_madd.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_msub.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_msub.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_msub.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_msub.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p2.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p1p1_to_p3.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p2.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p2.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p2.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p2.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p2_0.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p2_dbl.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3_0.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3_dbl.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_cached.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3_to_p2.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_p3_tobytes.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_precomp.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_precomp.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_precomp.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_precomp.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_precomp_0.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_scalarmult_base.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_sub.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_sub.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_sub.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_sub.java diff --git a/src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java rename to java/src/main/java/org/whispersystems/curve25519/java/ge_tobytes.java diff --git a/src/main/java/org/whispersystems/curve25519/java/open.java b/java/src/main/java/org/whispersystems/curve25519/java/open.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/open.java rename to java/src/main/java/org/whispersystems/curve25519/java/open.java diff --git a/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java b/java/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/sc_muladd.java rename to java/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java diff --git a/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java b/java/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/sc_reduce.java rename to java/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java diff --git a/src/main/java/org/whispersystems/curve25519/java/scalarmult.java b/java/src/main/java/org/whispersystems/curve25519/java/scalarmult.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/scalarmult.java rename to java/src/main/java/org/whispersystems/curve25519/java/scalarmult.java diff --git a/src/main/java/org/whispersystems/curve25519/java/sign_modified.java b/java/src/main/java/org/whispersystems/curve25519/java/sign_modified.java similarity index 100% rename from src/main/java/org/whispersystems/curve25519/java/sign_modified.java rename to java/src/main/java/org/whispersystems/curve25519/java/sign_modified.java diff --git a/src/javaTest/java/org/whispersystems/curve25519/JavaCurve25519ProviderTest.java b/java/src/test/java/org/whispersystems/curve25519/JavaCurve25519ProviderTest.java similarity index 100% rename from src/javaTest/java/org/whispersystems/curve25519/JavaCurve25519ProviderTest.java rename to java/src/test/java/org/whispersystems/curve25519/JavaCurve25519ProviderTest.java diff --git a/src/javaTest/java/org/whispersystems/curve25519/JavaCurve25519Test.java b/java/src/test/java/org/whispersystems/curve25519/JavaCurve25519Test.java similarity index 100% rename from src/javaTest/java/org/whispersystems/curve25519/JavaCurve25519Test.java rename to java/src/test/java/org/whispersystems/curve25519/JavaCurve25519Test.java diff --git a/pom.xml b/pom.xml deleted file mode 100644 index ef93757..0000000 --- a/pom.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - 4.0.0 - - 3.0.0 - - - org.whispersystems - curve25519 - 0.0.1 - - curve25519 - A Curve25519 implementation. - https://github.com/WhisperSystems/curve25519-java - - - - Trevor Perrin - - - Moxie Marlinspike - - - - - https://github.com/WhisperSystems/curve25519-java - scm:git:https://github.com/WhisperSystems/curve25519-java.git - scm:git:https://github.com/WhisperSystems/curve25519-java.git - - - - - junit - junit - 4.11 - test - - - org.mockito - mockito-core - 1.9.5 - test - - - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.9.1 - - - add-test-source - generate-test-sources - - add-test-source - - - - src/commonTest/java/ - src/javaTest/java/ - - - - - - - - diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..7412250 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':java', ':android', ':tests' diff --git a/src/androidTest/java/org/whispersystems/curve25519/AndroidWrapper.java b/src/androidTest/java/org/whispersystems/curve25519/AndroidWrapper.java deleted file mode 100644 index 2bfe906..0000000 --- a/src/androidTest/java/org/whispersystems/curve25519/AndroidWrapper.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.whispersystems.curve25519; - -import android.test.AndroidTestCase; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -public class AndroidWrapper extends AndroidTestCase { - - private final NativeCurve25519ProviderTest providerTest = new NativeCurve25519ProviderTest(); - private final NativeCurve25519Test curveTest = new NativeCurve25519Test (); - - public void testEcDh() { - providerTest.testEcDh(); - } - - public void testKeyGen() { - providerTest.testKeyGen(); - } - - public void testSignVerify() { - providerTest.testSignVerify(); - } - - public void testNative() { - curveTest.testCheckProvider(); - } - - public void testAgreement() { - curveTest.testAgreement(); - } - - public void testRandomAgreements() throws NoSuchAlgorithmException { - curveTest.testRandomAgreements(); - } - - public void testSignature() { - curveTest.testSignature(); - } - - public void testSignatureOverflow() throws InvalidKeyException, NoSuchAlgorithmException { - curveTest.testSignatureOverflow(); - } -} diff --git a/tests/build.gradle b/tests/build.gradle new file mode 100644 index 0000000..5b30561 --- /dev/null +++ b/tests/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java' + +sourceCompatibility = 1.7 + +repositories { + mavenCentral() +} + +dependencies { + compile project(':java') + compile 'junit:junit:3.8.2' + compile 'org.easytesting:fest-assert:1.4' +} \ No newline at end of file diff --git a/src/commonTest/java/org/whispersystems/curve25519/Curve25519ProviderTest.java b/tests/src/main/java/org/whispersystems/curve25519/Curve25519ProviderTest.java similarity index 90% rename from src/commonTest/java/org/whispersystems/curve25519/Curve25519ProviderTest.java rename to tests/src/main/java/org/whispersystems/curve25519/Curve25519ProviderTest.java index d7235f0..a7b7af6 100644 --- a/src/commonTest/java/org/whispersystems/curve25519/Curve25519ProviderTest.java +++ b/tests/src/main/java/org/whispersystems/curve25519/Curve25519ProviderTest.java @@ -1,16 +1,13 @@ package org.whispersystems.curve25519; -import org.junit.Test; -import org.whispersystems.curve25519.Curve25519Provider; +import junit.framework.TestCase; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertTrue; +import static org.fest.assertions.Assertions.assertThat; -public abstract class Curve25519ProviderTest { +public abstract class Curve25519ProviderTest extends TestCase { protected abstract Curve25519Provider createProvider(); - @Test public void testKeyGen() { Curve25519Provider provider = createProvider(); @@ -32,10 +29,9 @@ public abstract class Curve25519ProviderTest { (byte)0xdd, (byte)0xfa, (byte)0x05, (byte)0xf8, (byte)0xbc, (byte)0x7f, (byte)0x37}; - assertArrayEquals(out, result2); + assertThat(out).isEqualTo(result2); } - @Test public void testEcDh() { Curve25519Provider provider = createProvider(); @@ -64,12 +60,11 @@ public abstract class Curve25519ProviderTest { (byte)0x1b, (byte)0x4b, (byte)0x13, (byte)0x8d, (byte)0x17, (byte)0xf9, (byte)0x34}; - assertArrayEquals(q, result); + assertThat(q).isEqualTo(result); } // FIXME: There's no actual vector here. If verifySignature is broken and always returns true, // this test will pass. - @Test public void testSignVerify() { Curve25519Provider provider = createProvider(); diff --git a/src/commonTest/java/org/whispersystems/curve25519/Curve25519Test.java b/tests/src/main/java/org/whispersystems/curve25519/Curve25519Test.java similarity index 95% rename from src/commonTest/java/org/whispersystems/curve25519/Curve25519Test.java rename to tests/src/main/java/org/whispersystems/curve25519/Curve25519Test.java index 37f2d00..6641cbd 100644 --- a/src/commonTest/java/org/whispersystems/curve25519/Curve25519Test.java +++ b/tests/src/main/java/org/whispersystems/curve25519/Curve25519Test.java @@ -1,22 +1,18 @@ package org.whispersystems.curve25519; -import org.junit.Test; -import org.whispersystems.curve25519.Curve25519; -import org.whispersystems.curve25519.Curve25519KeyPair; +import junit.framework.TestCase; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import static org.junit.Assert.assertArrayEquals; +import static org.fest.assertions.Assertions.assertThat; -public abstract class Curve25519Test { +public abstract class Curve25519Test extends TestCase { - @Test public abstract void testCheckProvider(); - @Test public void testAgreement() { byte[] alicePublic = {(byte) 0x1b, (byte) 0xb7, (byte) 0x59, (byte) 0x66, @@ -62,11 +58,10 @@ public abstract class Curve25519Test { byte[] sharedOne = Curve25519.calculateAgreement(bobPublic, alicePrivate); byte[] sharedTwo = Curve25519.calculateAgreement(alicePublic, bobPrivate); - assertArrayEquals(sharedOne, shared); - assertArrayEquals(sharedTwo, shared); + assertThat(sharedOne).isEqualTo(shared); + assertThat(sharedTwo).isEqualTo(shared); } - @Test public void testRandomAgreements() throws NoSuchAlgorithmException { SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); @@ -77,11 +72,10 @@ public abstract class Curve25519Test { byte[] sharedAlice = Curve25519.calculateAgreement(bob.getPublicKey(), alice.getPrivateKey()); byte[] sharedBob = Curve25519.calculateAgreement(alice.getPublicKey(), bob.getPrivateKey()); - assertArrayEquals(sharedAlice, sharedBob); + assertThat(sharedAlice).isEqualTo(sharedBob); } } - @Test public void testSignature() { byte[] aliceIdentityPrivate = {(byte)0xc0, (byte)0x97, (byte)0x24, (byte)0x84, (byte)0x12, (byte)0xe5, (byte)0x8b, (byte)0xf0, (byte)0x5d, (byte)0xf4, @@ -137,7 +131,6 @@ public abstract class Curve25519Test { } } - @Test public void testSignatureOverflow() throws NoSuchAlgorithmException, InvalidKeyException { SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); Curve25519KeyPair keys = Curve25519.generateKeyPair(secureRandom);