diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..0a8d8ac
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,31 @@
+name: Java CI
+
+on:
+ push:
+ branches: [ gluon ]
+ pull_request:
+ branches: [ gluon ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ env:
+ JAVA_VERSION: 17
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: 'Download OpenJDK'
+ run: |
+ wget --no-verbose \
+ --directory-prefix ${{ runner.temp }} \
+ https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz
+ - name: Setup java
+ uses: actions/setup-java@v2
+ with:
+ java-version: ${{ env.JAVA_VERSION }}
+ distribution: jdkfile
+ jdkFile: ${{ runner.temp }}/openjdk-${{ env.JAVA_VERSION }}_linux-x64_bin.tar.gz
+ - name: Build with Maven
+ run: mvn clean install
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index c18d487..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,4 +0,0 @@
-subprojects {
- ext.version_number = "0.5.0"
- ext.group_info = "org.whispersystems"
-}
diff --git a/common/src/main/java/org/whispersystems/curve25519/Curve25519.java b/common/src/main/java/org/whispersystems/curve25519/Curve25519.java
index 78f7b25..2c34c07 100644
--- a/common/src/main/java/org/whispersystems/curve25519/Curve25519.java
+++ b/common/src/main/java/org/whispersystems/curve25519/Curve25519.java
@@ -156,6 +156,18 @@ public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signat
return provider.verifyVrfSignature(publicKey, message, signature);
}
+ /**
+ * Create a public key from the bytes used to generate a private key
+ *
+ * @param privateKey the bytes used for a private key
+ *
+ * @return the bytes for the public key, not containing a type.
+ */
+ public byte[] createPublicKeyFromPrivateKey(byte[] privateKey) {
+ byte[] publicKey = provider.generatePublicKey(privateKey);
+ return publicKey;
+ }
+
private static Curve25519Provider constructNativeProvider(SecureRandomProvider random) throws NoSuchProviderException {
return constructClass("NativeCurve25519Provider", random);
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index a1a7687..0000000
--- a/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Mon Oct 17 15:10:52 PDT 2016
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/gradlew b/gradlew
deleted file mode 100755
index 91a7e26..0000000
--- a/gradlew
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/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
deleted file mode 100644
index aec9973..0000000
--- a/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@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
deleted file mode 100644
index 3373133..0000000
--- a/java/build.gradle
+++ /dev/null
@@ -1,98 +0,0 @@
-apply plugin: 'java'
-
-apply plugin: 'maven'
-apply plugin: 'signing'
-
-sourceCompatibility = 1.7
-archivesBaseName = "curve25519-java"
-version = version_number
-group = group_info
-
-repositories {
- mavenCentral()
-}
-
-sourceSets {
- main {
- java {
- srcDirs = ['src/main/java', project(':common').file('src/main/java')]
- }
- }
-}
-
-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'
- }
-
- licenses {
- license {
- name 'GPLv3'
- url 'https://www.gnu.org/licenses/gpl-3.0.txt'
- distribution 'repo'
- }
- }
-
- 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"
- }
- }
-}
-
-
-task packageJavadoc(type: Jar, dependsOn: 'javadoc') {
- from javadoc.destinationDir
- classifier = 'javadoc'
-}
-
-task packageSources(type: Jar) {
- from sourceSets.main.allSource
- classifier = 'sources'
-}
-
-artifacts {
- archives(packageJavadoc) {
- type = 'javadoc'
- }
-
- archives packageSources
-}
diff --git a/java/pom.xml b/java/pom.xml
new file mode 100755
index 0000000..d187969
--- /dev/null
+++ b/java/pom.xml
@@ -0,0 +1,69 @@
+
+
+ 4.0.0
+
+ org.whispersystems
+ curve25519-java
+ 0.6.0-SNAPSHOT
+ jar
+
+ curve25519-java
+
+
+ UTF-8
+ 11
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.5.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 2.7
+
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.9
+
+ false
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.6.1
+
+ /usr/bin/protoc
+
+
+
+
+ compile
+ test-compile
+
+
+
+
+
+
+
+
diff --git a/java/src/main/java/module-info.java b/java/src/main/java/module-info.java
new file mode 100644
index 0000000..ceca05e
--- /dev/null
+++ b/java/src/main/java/module-info.java
@@ -0,0 +1,3 @@
+module org.whispersystems.curve25519 {
+ exports org.whispersystems.curve25519;
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/BaseJavaCurve25519Provider.java b/java/src/main/java/org/whispersystems/curve25519/BaseJavaCurve25519Provider.java
new file mode 100644
index 0000000..18e7941
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/BaseJavaCurve25519Provider.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+import org.whispersystems.curve25519.java.Sha512;
+import org.whispersystems.curve25519.java.curve_sigs;
+import org.whispersystems.curve25519.java.scalarmult;
+
+abstract class BaseJavaCurve25519Provider implements Curve25519Provider {
+
+ private final Sha512 sha512provider;
+ private SecureRandomProvider secureRandomProvider;
+
+ protected BaseJavaCurve25519Provider(Sha512 sha512provider,
+ SecureRandomProvider secureRandomProvider)
+ {
+ this.sha512provider = sha512provider;
+ this.secureRandomProvider = secureRandomProvider;
+ }
+
+ public abstract boolean isNative();
+
+ public void setRandomProvider(SecureRandomProvider secureRandomProvider) {
+ this.secureRandomProvider = secureRandomProvider;
+ }
+
+ public byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic) {
+ byte[] agreement = new byte[32];
+ scalarmult.crypto_scalarmult(agreement, ourPrivate, theirPublic);
+
+ return agreement;
+ }
+
+ public byte[] generatePublicKey(byte[] privateKey) {
+ byte[] publicKey = new byte[32];
+ curve_sigs.curve25519_keygen(publicKey, privateKey);
+
+ return publicKey;
+ }
+
+ public byte[] generatePrivateKey() {
+ byte[] random = getRandom(PRIVATE_KEY_LEN);
+ return generatePrivateKey(random);
+ }
+
+ public byte[] generatePrivateKey(byte[] random) {
+ byte[] privateKey = new byte[32];
+
+ System.arraycopy(random, 0, privateKey, 0, 32);
+
+ privateKey[0] &= 248;
+ privateKey[31] &= 127;
+ privateKey[31] |= 64;
+
+ return privateKey;
+ }
+
+ public byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message) {
+ byte[] result = new byte[64];
+
+ if (curve_sigs.curve25519_sign(sha512provider, result, privateKey, message, message.length, random) != 0) {
+ throw new IllegalArgumentException("Message exceeds max length!");
+ }
+
+ return result;
+ }
+
+ public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
+ return curve_sigs.curve25519_verify(sha512provider, signature, publicKey, message, message.length) == 0;
+ }
+
+ public byte[] calculateVrfSignature(byte[] random, byte[] privateKey, byte[] message) {
+ throw new AssertionError("NYI");
+ }
+
+ public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
+ throws VrfSignatureVerificationFailedException
+ {
+ throw new AssertionError("NYI");
+ }
+
+ public byte[] getRandom(int length) {
+ byte[] result = new byte[length];
+ secureRandomProvider.nextBytes(result);
+ return result;
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/Curve25519.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519.java
new file mode 100644
index 0000000..73f1c33
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/Curve25519.java
@@ -0,0 +1,208 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+/**
+ * A Curve25519 interface for generating keys, calculating agreements, creating signatures,
+ * and verifying signatures.
+ *
+ * @author Moxie Marlinspike
+ */
+public class Curve25519 {
+
+ public static final String NATIVE = "native";
+ public static final String JAVA = "java";
+ public static final String J2ME = "j2me";
+ public static final String BEST = "best";
+
+ public static Curve25519 getInstance(String type) throws NoSuchProviderException {
+ return getInstance(type, null);
+ }
+
+ public static Curve25519 getInstance(String type, SecureRandomProvider random)
+ throws NoSuchProviderException
+ {
+ return new Curve25519(new JavaCurve25519Provider());
+/*
+ if (NATIVE.equals(type)) return new Curve25519(constructNativeProvider(random));
+ else if (JAVA.equals(type)) return new Curve25519(constructJavaProvider(random));
+ else if (J2ME.equals(type)) return new Curve25519(constructJ2meProvider(random));
+ else if (BEST.equals(type)) return new Curve25519(constructOpportunisticProvider(random));
+ else throw new NoSuchProviderException(type);
+*/
+ }
+
+ private final Curve25519Provider provider;
+
+ private Curve25519(Curve25519Provider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * {@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.
+ *
+ * @return true if backed by a native provider, false otherwise.
+ */
+ public boolean isNative() {
+ return provider.isNative();
+ }
+
+ /**
+ * Generates a Curve25519 keypair.
+ *
+ * @return A randomly generated Curve25519 keypair.
+ */
+ public Curve25519KeyPair generateKeyPair() {
+ byte[] privateKey = provider.generatePrivateKey();
+ byte[] publicKey = provider.generatePublicKey(privateKey);
+
+ return new Curve25519KeyPair(publicKey, privateKey);
+ }
+
+ /**
+ * Calculates an ECDH agreement.
+ *
+ * @param publicKey The Curve25519 (typically remote party's) public key.
+ * @param privateKey The Curve25519 (typically yours) private key.
+ * @return A 32-byte shared secret.
+ */
+ public byte[] calculateAgreement(byte[] publicKey, byte[] privateKey) {
+ if (publicKey == null || privateKey == null) {
+ throw new IllegalArgumentException("Keys must not be null!");
+ }
+
+ if (publicKey.length != 32 || privateKey.length != 32) {
+ throw new IllegalArgumentException("Keys must be 32 bytes!");
+ }
+
+ return provider.calculateAgreement(privateKey, publicKey);
+ }
+
+ /**
+ * Calculates a Curve25519 signature.
+ *
+ * @param privateKey The private Curve25519 key to create the signature with.
+ * @param message The message to sign.
+ * @return A 64-byte signature.
+ */
+ public byte[] calculateSignature(byte[] privateKey, byte[] message) {
+ if (privateKey == null || privateKey.length != 32) {
+ throw new IllegalArgumentException("Invalid private key length!");
+ }
+
+ byte[] random = provider.getRandom(64);
+ return provider.calculateSignature(random, privateKey, message);
+ }
+
+ /**
+ * Verify a Curve25519 signature.
+ *
+ * @param publicKey The Curve25519 public key the signature belongs to.
+ * @param message The message that was signed.
+ * @param signature The signature to verify.
+ * @return true if valid, false if not.
+ */
+ public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
+ if (publicKey == null || publicKey.length != 32) {
+ throw new IllegalArgumentException("Invalid public key!");
+ }
+
+ if (message == null || signature == null || signature.length != 64) {
+ return false;
+ }
+
+ return provider.verifySignature(publicKey, message, signature);
+ }
+
+ /**
+ * Calculates a Unique Curve25519 signature.
+ *
+ * @param privateKey The private Curve25519 key to create the signature with.
+ * @param message The message to sign.
+ * @return A 96-byte signature.
+ */
+ public byte[] calculateVrfSignature(byte[] privateKey, byte[] message) {
+ if (privateKey == null || privateKey.length != 32) {
+ throw new IllegalArgumentException("Invalid private key!");
+ }
+
+ byte[] random = provider.getRandom(64);
+ return provider.calculateVrfSignature(random, privateKey, message);
+ }
+
+ /**
+ * Verify a Unique Curve25519 signature.
+ *
+ * @param publicKey The Curve25519 public key the unique signature belongs to.
+ * @param message The message that was signed.
+ * @param signature The unique signature to verify.
+ *
+ * @return The vrf for this signature.
+ */
+ public byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
+ throws VrfSignatureVerificationFailedException
+ {
+ if (publicKey == null || publicKey.length != 32) {
+ throw new IllegalArgumentException("Invalid public key!");
+ }
+
+ if (message == null || signature == null || signature.length != 96) {
+ throw new VrfSignatureVerificationFailedException("Invalid message or signature format");
+ }
+
+ return provider.verifyVrfSignature(publicKey, message, signature);
+ }
+
+ /**
+ * Create a public key from the bytes used to generate a private key
+ *
+ * @param privateKey the bytes used for a private key
+ *
+ * @return the bytes for the public key, not containing a type.
+ */
+ public byte[] createPublicKeyFromPrivateKey(byte[] privateKey) {
+ byte[] publicKey = provider.generatePublicKey(privateKey);
+ return publicKey;
+ }
+
+ private static Curve25519Provider constructNativeProvider(SecureRandomProvider random) throws NoSuchProviderException {
+ return constructClass("NativeCurve25519Provider", random);
+ }
+
+ private static Curve25519Provider constructJavaProvider(SecureRandomProvider random) throws NoSuchProviderException {
+ return constructClass("JavaCurve25519Provider", random);
+ }
+
+ private static Curve25519Provider constructJ2meProvider(SecureRandomProvider random) throws NoSuchProviderException {
+ return constructClass("J2meCurve25519Provider", random);
+ }
+
+ private static Curve25519Provider constructOpportunisticProvider(SecureRandomProvider random) throws NoSuchProviderException {
+ return constructClass("OpportunisticCurve25519Provider", random);
+ }
+
+ private static Curve25519Provider constructClass(String name, SecureRandomProvider random) throws NoSuchProviderException {
+ try {
+ Curve25519Provider provider = (Curve25519Provider)Class.forName("org.whispersystems.curve25519." + name).newInstance();
+
+ if (random != null) {
+ provider.setRandomProvider(random);
+ }
+
+ return provider;
+ } catch (InstantiationException e) {
+ throw new NoSuchProviderException(e);
+ } catch (IllegalAccessException e) {
+ throw new NoSuchProviderException(e);
+ } catch (ClassNotFoundException e) {
+ throw new NoSuchProviderException(e);
+ }
+ }
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java
new file mode 100644
index 0000000..84a7dd7
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/Curve25519KeyPair.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+/**
+ * A tuple that contains a Curve25519 public and private key.
+ *
+ * @author Moxie Marlinspike
+ */
+public class Curve25519KeyPair {
+
+ private final byte[] publicKey;
+ private final byte[] privateKey;
+
+ Curve25519KeyPair(byte[] publicKey, byte[] privateKey) {
+ this.publicKey = publicKey;
+ this.privateKey = privateKey;
+ }
+
+ /**
+ * @return The Curve25519 public key.
+ */
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ /**
+ * @return The Curve25519 private key.
+ */
+ public byte[] getPrivateKey() {
+ return privateKey;
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java b/java/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java
new file mode 100644
index 0000000..abad023
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/Curve25519Provider.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+interface Curve25519Provider {
+
+ static final int PRIVATE_KEY_LEN = 32;
+
+ boolean isNative();
+ byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic);
+ byte[] generatePublicKey(byte[] privateKey);
+ byte[] generatePrivateKey();
+ byte[] generatePrivateKey(byte[] random);
+
+ byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message);
+ boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
+ byte[] calculateVrfSignature(byte[] random, byte[] privateKey, byte[] message);
+ byte[] verifyVrfSignature(byte[] publicKey, byte[] message, byte[] signature)
+ throws VrfSignatureVerificationFailedException;
+
+ byte[] getRandom(int length);
+
+ void setRandomProvider(SecureRandomProvider provider);
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/NoSuchProviderException.java b/java/src/main/java/org/whispersystems/curve25519/NoSuchProviderException.java
new file mode 100644
index 0000000..79a14bd
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/NoSuchProviderException.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+public class NoSuchProviderException extends RuntimeException {
+
+ private final Throwable nested;
+
+ public NoSuchProviderException(Throwable e) {
+ this.nested = e;
+ }
+
+ public NoSuchProviderException(String type) {
+ super(type);
+ this.nested = null;
+ }
+
+ public Throwable getNested() {
+ return nested;
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/SecureRandomProvider.java b/java/src/main/java/org/whispersystems/curve25519/SecureRandomProvider.java
new file mode 100644
index 0000000..e3a773f
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/SecureRandomProvider.java
@@ -0,0 +1,12 @@
+/**
+ * Copyright (C) 2014-2016 Open Whisper Systems
+ *
+ * Licensed according to the LICENSE file in this repository.
+ */
+
+package org.whispersystems.curve25519;
+
+public interface SecureRandomProvider {
+ public void nextBytes(byte[] output);
+ public int nextInt(int maxValue);
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/VrfSignatureVerificationFailedException.java b/java/src/main/java/org/whispersystems/curve25519/VrfSignatureVerificationFailedException.java
new file mode 100644
index 0000000..a417124
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/VrfSignatureVerificationFailedException.java
@@ -0,0 +1,16 @@
+package org.whispersystems.curve25519;
+
+public class VrfSignatureVerificationFailedException extends Exception {
+
+ public VrfSignatureVerificationFailedException() {
+ super();
+ }
+
+ public VrfSignatureVerificationFailedException(String message) {
+ super(message);
+ }
+
+ public VrfSignatureVerificationFailedException(Exception exception) {
+ super(exception);
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/Arrays.java b/java/src/main/java/org/whispersystems/curve25519/java/Arrays.java
new file mode 100644
index 0000000..0291048
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/Arrays.java
@@ -0,0 +1,16 @@
+package org.whispersystems.curve25519.java;
+
+public class Arrays {
+ /**
+ * Assigns the specified byte value to each element of the specified array
+ * of bytes.
+ *
+ * @param a the array to be filled
+ * @param val the value to be stored in all elements of the array
+ */
+ public static void fill(byte[] a, byte val) {
+ for (int i = 0, len = a.length; i < len; i++)
+ a[i] = val;
+ }
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/Sha512.java b/java/src/main/java/org/whispersystems/curve25519/java/Sha512.java
new file mode 100644
index 0000000..90ee796
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/Sha512.java
@@ -0,0 +1,7 @@
+package org.whispersystems.curve25519.java;
+
+public interface Sha512 {
+
+ public void calculateDigest(byte[] out, byte[] in, long length);
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java b/java/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java
new file mode 100644
index 0000000..efd5d23
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/crypto_verify_32.java
@@ -0,0 +1,12 @@
+package org.whispersystems.curve25519.java;
+
+public class crypto_verify_32 {
+
+ public static int crypto_verify_32(byte[] x, byte[] y) {
+ int differentbits = 0;
+ for (int count = 0; count < 32; count++) {
+ differentbits |= (x[count] ^ y[count]);
+ }
+ return differentbits;
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java b/java/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java
new file mode 100644
index 0000000..8c72d1e
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/curve_sigs.java
@@ -0,0 +1,112 @@
+package org.whispersystems.curve25519.java;
+
+public class curve_sigs {
+
+ public static void curve25519_keygen(byte[] curve25519_pubkey_out,
+ byte[] curve25519_privkey_in)
+ {
+ ge_p3 ed = new ge_p3(); /* Ed25519 pubkey point */
+ int[] ed_y_plus_one = new int[10];
+ int[] one_minus_ed_y = new int[10];
+ int[] inv_one_minus_ed_y = new int[10];
+ int[] mont_x = new int[10];
+
+ /* Perform a fixed-base multiplication of the Edwards base point,
+ (which is efficient due to precalculated tables), then convert
+ to the Curve25519 montgomery-format public key. In particular,
+ convert Curve25519's "montgomery" x-coordinate into an Ed25519
+ "edwards" y-coordinate:
+
+ mont_x = (ed_y + 1) / (1 - ed_y)
+
+ with projective coordinates:
+
+ mont_x = (ed_y + ed_z) / (ed_z - ed_y)
+
+ NOTE: ed_y=1 is converted to mont_x=0 since fe_invert is mod-exp
+ */
+
+ ge_scalarmult_base.ge_scalarmult_base(ed, curve25519_privkey_in);
+ fe_add.fe_add(ed_y_plus_one, ed.Y, ed.Z);
+ fe_sub.fe_sub(one_minus_ed_y, ed.Z, ed.Y);
+ fe_invert.fe_invert(inv_one_minus_ed_y, one_minus_ed_y);
+ fe_mul.fe_mul(mont_x, ed_y_plus_one, inv_one_minus_ed_y);
+ fe_tobytes.fe_tobytes(curve25519_pubkey_out, mont_x);
+ }
+
+ public static int curve25519_sign(Sha512 sha512provider, byte[] signature_out,
+ byte[] curve25519_privkey,
+ byte[] msg, int msg_len,
+ byte[] random)
+ {
+ ge_p3 ed_pubkey_point = new ge_p3(); /* Ed25519 pubkey point */
+ byte[] ed_pubkey = new byte[32]; /* Ed25519 encoded pubkey */
+ byte[] sigbuf = new byte[msg_len + 128]; /* working buffer */
+ byte sign_bit = 0;
+
+ /* Convert the Curve25519 privkey to an Ed25519 public key */
+ ge_scalarmult_base.ge_scalarmult_base(ed_pubkey_point, curve25519_privkey);
+ ge_p3_tobytes.ge_p3_tobytes(ed_pubkey, ed_pubkey_point);
+ sign_bit = (byte)(ed_pubkey[31] & 0x80);
+
+ /* Perform an Ed25519 signature with explicit private key */
+ sign_modified.crypto_sign_modified(sha512provider, sigbuf, msg, msg_len, curve25519_privkey,
+ ed_pubkey, random);
+ System.arraycopy(sigbuf, 0, signature_out, 0, 64);
+
+ /* Encode the sign bit into signature (in unused high bit of S) */
+ signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */
+ signature_out[63] |= sign_bit;
+ return 0;
+ }
+
+ public static int curve25519_verify(Sha512 sha512provider, byte[] signature,
+ byte[] curve25519_pubkey,
+ byte[] msg, int msg_len)
+ {
+ int[] mont_x = new int[10];
+ int[] mont_x_minus_one = new int[10];
+ int[] mont_x_plus_one = new int[10];
+ int[] inv_mont_x_plus_one = new int[10];
+ int[] one = new int[10];
+ int[] ed_y = new int[10];
+ byte[] ed_pubkey = new byte[32];
+ long some_retval = 0;
+ byte[] verifybuf = new byte[msg_len + 64]; /* working buffer */
+ byte[] verifybuf2 = new byte[msg_len + 64]; /* working buffer #2 */
+
+ /* Convert the Curve25519 public key into an Ed25519 public key. In
+ particular, convert Curve25519's "montgomery" x-coordinate into an
+ Ed25519 "edwards" y-coordinate:
+
+ ed_y = (mont_x - 1) / (mont_x + 1)
+
+ NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
+
+ Then move the sign bit into the pubkey from the signature.
+ */
+ fe_frombytes.fe_frombytes(mont_x, curve25519_pubkey);
+ fe_1.fe_1(one);
+ fe_sub.fe_sub(mont_x_minus_one, mont_x, one);
+ fe_add.fe_add(mont_x_plus_one, mont_x, one);
+ fe_invert.fe_invert(inv_mont_x_plus_one, mont_x_plus_one);
+ fe_mul.fe_mul(ed_y, mont_x_minus_one, inv_mont_x_plus_one);
+ fe_tobytes.fe_tobytes(ed_pubkey, ed_y);
+
+ /* Copy the sign bit, and remove it from signature */
+ ed_pubkey[31] &= 0x7F; /* bit should be zero already, but just in case */
+ ed_pubkey[31] |= (signature[63] & 0x80);
+ System.arraycopy(signature, 0, verifybuf, 0, 64);
+ verifybuf[63] &= 0x7F;
+
+ System.arraycopy(msg, 0, verifybuf, 64, (int)msg_len);
+
+ /* Then perform a normal Ed25519 verification, return 0 on success */
+ /* The below call has a strange API: */
+ /* verifybuf = R || S || message */
+ /* verifybuf2 = java to next call gets a copy of verifybuf, S gets
+ replaced with pubkey for hashing, then the whole thing gets zeroized
+ (if bad sig), or contains a copy of msg (good sig) */
+ return open.crypto_sign_open(sha512provider, verifybuf2, some_retval, verifybuf, 64 + msg_len, ed_pubkey);
+ }
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_0.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_0.java
new file mode 100644
index 0000000..250f65c
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_0.java
@@ -0,0 +1,26 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_0 {
+
+//CONVERT #include "fe.h"
+
+/*
+h = 0
+*/
+
+public static void fe_0(int[] h)
+{
+ h[0] = 0;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_1.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_1.java
new file mode 100644
index 0000000..b653736
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_1.java
@@ -0,0 +1,26 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_1 {
+
+//CONVERT #include "fe.h"
+
+/*
+h = 1
+*/
+
+public static void fe_1(int[] h)
+{
+ h[0] = 1;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_add.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_add.java
new file mode 100644
index 0000000..247179e
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_add.java
@@ -0,0 +1,64 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_add {
+
+//CONVERT #include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+public static void fe_add(int[] h,int[] f,int[] g)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int g0 = g[0];
+ int g1 = g[1];
+ int g2 = g[2];
+ int g3 = g[3];
+ int g4 = g[4];
+ int g5 = g[5];
+ int g6 = g[6];
+ int g7 = g[7];
+ int g8 = g[8];
+ int g9 = g[9];
+ int h0 = f0 + g0;
+ int h1 = f1 + g1;
+ int h2 = f2 + g2;
+ int h3 = f3 + g3;
+ int h4 = f4 + g4;
+ int h5 = f5 + g5;
+ int h6 = f6 + g6;
+ int h7 = f7 + g7;
+ int h8 = f8 + g8;
+ int h9 = f9 + g9;
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java
new file mode 100644
index 0000000..d63335d
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_cmov.java
@@ -0,0 +1,70 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_cmov {
+
+//CONVERT #include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+public static void fe_cmov(int[] f,int[] g,int b)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int g0 = g[0];
+ int g1 = g[1];
+ int g2 = g[2];
+ int g3 = g[3];
+ int g4 = g[4];
+ int g5 = g[5];
+ int g6 = g[6];
+ int g7 = g[7];
+ int g8 = g[8];
+ int g9 = g[9];
+ int x0 = f0 ^ g0;
+ int x1 = f1 ^ g1;
+ int x2 = f2 ^ g2;
+ int x3 = f3 ^ g3;
+ int x4 = f4 ^ g4;
+ int x5 = f5 ^ g5;
+ int x6 = f6 ^ g6;
+ int x7 = f7 ^ g7;
+ int x8 = f8 ^ g8;
+ int x9 = f9 ^ g9;
+ b = -b;
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_copy.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_copy.java
new file mode 100644
index 0000000..1085c55
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_copy.java
@@ -0,0 +1,36 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_copy {
+
+//CONVERT #include "fe.h"
+
+/*
+h = f
+*/
+
+public static void fe_copy(int[] h,int[] f)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ h[0] = f0;
+ h[1] = f1;
+ h[2] = f2;
+ h[3] = f3;
+ h[4] = f4;
+ h[5] = f5;
+ h[6] = f6;
+ h[7] = f7;
+ h[8] = f8;
+ h[9] = f9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java
new file mode 100644
index 0000000..ddd99d5
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_cswap.java
@@ -0,0 +1,82 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_cswap {
+
+//CONVERT #include
+//CONVERT #include "fe.h"
+
+/*
+Replace (f,g) with (g,f) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+public static void fe_cswap(int[] f,int[] g,int b)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int g0 = g[0];
+ int g1 = g[1];
+ int g2 = g[2];
+ int g3 = g[3];
+ int g4 = g[4];
+ int g5 = g[5];
+ int g6 = g[6];
+ int g7 = g[7];
+ int g8 = g[8];
+ int g9 = g[9];
+ int x0 = f0 ^ g0;
+ int x1 = f1 ^ g1;
+ int x2 = f2 ^ g2;
+ int x3 = f3 ^ g3;
+ int x4 = f4 ^ g4;
+ int x5 = f5 ^ g5;
+ int x6 = f6 ^ g6;
+ int x7 = f7 ^ g7;
+ int x8 = f8 ^ g8;
+ int x9 = f9 ^ g9;
+ b = -b;
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+ g[0] = g0 ^ x0;
+ g[1] = g1 ^ x1;
+ g[2] = g2 ^ x2;
+ g[3] = g3 ^ x3;
+ g[4] = g4 ^ x4;
+ g[5] = g5 ^ x5;
+ g[6] = g6 ^ x6;
+ g[7] = g7 ^ x7;
+ g[8] = g8 ^ x8;
+ g[9] = g9 ^ x9;
+}
+
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java
new file mode 100644
index 0000000..0845bed
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_frombytes.java
@@ -0,0 +1,80 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_frombytes {
+
+//CONVERT #include "fe.h"
+//CONVERT #include "long.h"
+//CONVERT #include "long.h"
+
+public static long load_3(byte[] in, int index)
+{
+ long result;
+ result = ((long) in[index + 0]) & 0xFF;
+ result |= (((long) in[index + 1]) << 8) & 0xFF00;
+ result |= (((long) in[index + 2]) << 16) & 0xFF0000;
+ return result;
+}
+
+public static long load_4(byte[] in, int index)
+{
+ long result;
+ result = (((long) in[index + 0]) & 0xFF);
+ result |= ((((long) in[index + 1]) << 8) & 0xFF00);
+ result |= ((((long) in[index + 2]) << 16) & 0xFF0000);
+ result |= ((((long) in[index + 3]) << 24) & 0xFF000000L);
+ return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+public static void fe_frombytes(int[] h,byte[] s)
+{
+ long h0 = load_4(s, 0);
+ long h1 = load_3(s, 4) << 6;
+ long h2 = load_3(s, 7) << 5;
+ long h3 = load_3(s, 10) << 3;
+ long h4 = load_3(s, 13) << 2;
+ long h5 = load_4(s, 16);
+ long h6 = load_3(s, 20) << 7;
+ long h7 = load_3(s, 23) << 5;
+ long h8 = load_3(s, 26) << 4;
+ long h9 = (load_3(s, 29) & 8388607) << 2;
+ long carry0;
+ long carry1;
+ long carry2;
+ long carry3;
+ long carry4;
+ long carry5;
+ long carry6;
+ long carry7;
+ long carry8;
+ long carry9;
+
+ carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_invert.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_invert.java
new file mode 100644
index 0000000..4346a6f
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_invert.java
@@ -0,0 +1,181 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_invert {
+
+//CONVERT #include "fe.h"
+
+public static void fe_invert(int[] out,int[] z)
+{
+ int[] t0 = new int[10];
+ int[] t1 = new int[10];
+ int[] t2 = new int[10];
+ int[] t3 = new int[10];
+ int i;
+
+//CONVERT #include "pow225521.h"
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq.fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq.fe_sq(>z2=t0,z2=t0,>z2=t0); */
+fe_sq.fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq.fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq.fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z8=t1,z8=t1,>z8=t1); */
+fe_sq.fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul.fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z22=t2,z22=t2,>z22=t2); */
+fe_sq.fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul.fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */
+fe_sq.fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul.fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */
+fe_sq.fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul.fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq.fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */
+fe_sq.fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq.fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul.fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */
+fe_sq.fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul.fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */
+fe_sq.fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul.fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq.fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */
+fe_sq.fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq.fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul.fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */
+fe_sq.fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul.fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */
+fe_sq.fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul.fe_mul(>z_255_21=fe#12,z_255_21=out,> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ /* |h0| <= 2^25 */
+ /* |h4| <= 2^25 */
+ /* |h1| <= 1.71*2^59 */
+ /* |h5| <= 1.71*2^59 */
+
+ carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ /* |h1| <= 2^24; from now on fits into int32 */
+ /* |h5| <= 2^24; from now on fits into int32 */
+ /* |h2| <= 1.41*2^60 */
+ /* |h6| <= 1.41*2^60 */
+
+ carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ /* |h2| <= 2^25; from now on fits into int32 unchanged */
+ /* |h6| <= 2^25; from now on fits into int32 unchanged */
+ /* |h3| <= 1.71*2^59 */
+ /* |h7| <= 1.71*2^59 */
+
+ carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ /* |h3| <= 2^24; from now on fits into int32 unchanged */
+ /* |h7| <= 2^24; from now on fits into int32 unchanged */
+ /* |h4| <= 1.72*2^34 */
+ /* |h8| <= 1.41*2^60 */
+
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ /* |h4| <= 2^25; from now on fits into int32 unchanged */
+ /* |h8| <= 2^25; from now on fits into int32 unchanged */
+ /* |h5| <= 1.01*2^24 */
+ /* |h9| <= 1.71*2^59 */
+
+ carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ /* |h9| <= 2^24; from now on fits into int32 unchanged */
+ /* |h0| <= 1.1*2^39 */
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ /* |h0| <= 2^25; from now on fits into int32 unchanged */
+ /* |h1| <= 1.01*2^24 */
+
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java
new file mode 100644
index 0000000..f9761d6
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_mul121666.java
@@ -0,0 +1,77 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_mul121666 {
+
+//CONVERT #include "fe.h"
+//CONVERT #include "long.h"
+
+/*
+h = f * 121666
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+public static void fe_mul121666(int[] h,int[] f)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ long h0 = f0 * (long) 121666;
+ long h1 = f1 * (long) 121666;
+ long h2 = f2 * (long) 121666;
+ long h3 = f3 * (long) 121666;
+ long h4 = f4 * (long) 121666;
+ long h5 = f5 * (long) 121666;
+ long h6 = f6 * (long) 121666;
+ long h7 = f7 * (long) 121666;
+ long h8 = f8 * (long) 121666;
+ long h9 = f9 * (long) 121666;
+ long carry0;
+ long carry1;
+ long carry2;
+ long carry3;
+ long carry4;
+ long carry5;
+ long carry6;
+ long carry7;
+ long carry8;
+ long carry9;
+
+ carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_neg.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_neg.java
new file mode 100644
index 0000000..e88b6e2
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_neg.java
@@ -0,0 +1,52 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_neg {
+
+//CONVERT #include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+public static void fe_neg(int[] h,int[] f)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int h0 = -f0;
+ int h1 = -f1;
+ int h2 = -f2;
+ int h3 = -f3;
+ int h4 = -f4;
+ int h5 = -f5;
+ int h6 = -f6;
+ int h7 = -f7;
+ int h8 = -f8;
+ int h9 = -f9;
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java
new file mode 100644
index 0000000..194426e
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_pow22523.java
@@ -0,0 +1,180 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_pow22523 {
+
+//CONVERT #include "fe.h"
+
+public static void fe_pow22523(int[] out,int[] z)
+{
+ int[] t0 = new int[10];
+ int[] t1 = new int[10];
+ int[] t2 = new int[10];
+ int i;
+
+//CONVERT #include "pow22523.h"
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq.fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq.fe_sq(>z2=t0,z2=t0,>z2=t0); */
+fe_sq.fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq.fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq.fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z8=t1,z8=t1,>z8=t1); */
+fe_sq.fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul.fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq.fe_sq(>z22=t0,z22=t0,>z22=t0); */
+fe_sq.fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq.fe_sq(t0,t0);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul.fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */
+fe_sq.fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul.fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */
+fe_sq.fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul.fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */
+fe_sq.fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul.fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */
+fe_sq.fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul.fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */
+fe_sq.fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul.fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq.fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */
+fe_sq.fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq.fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul.fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq.fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */
+fe_sq.fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq.fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul.fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq.fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */
+fe_sq.fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq.fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul.fe_mul(>z_252_3=fe#12,z_252_3=out,> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java
new file mode 100644
index 0000000..55b67d4
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_sq2.java
@@ -0,0 +1,167 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_sq2 {
+
+//CONVERT #include "fe.h"
+//CONVERT #include "long.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+public static void fe_sq2(int[] h,int[] f)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int f0_2 = 2 * f0;
+ int f1_2 = 2 * f1;
+ int f2_2 = 2 * f2;
+ int f3_2 = 2 * f3;
+ int f4_2 = 2 * f4;
+ int f5_2 = 2 * f5;
+ int f6_2 = 2 * f6;
+ int f7_2 = 2 * f7;
+ int f5_38 = 38 * f5; /* 1.959375*2^30 */
+ int f6_19 = 19 * f6; /* 1.959375*2^30 */
+ int f7_38 = 38 * f7; /* 1.959375*2^30 */
+ int f8_19 = 19 * f8; /* 1.959375*2^30 */
+ int f9_38 = 38 * f9; /* 1.959375*2^30 */
+ long f0f0 = f0 * (long) f0;
+ long f0f1_2 = f0_2 * (long) f1;
+ long f0f2_2 = f0_2 * (long) f2;
+ long f0f3_2 = f0_2 * (long) f3;
+ long f0f4_2 = f0_2 * (long) f4;
+ long f0f5_2 = f0_2 * (long) f5;
+ long f0f6_2 = f0_2 * (long) f6;
+ long f0f7_2 = f0_2 * (long) f7;
+ long f0f8_2 = f0_2 * (long) f8;
+ long f0f9_2 = f0_2 * (long) f9;
+ long f1f1_2 = f1_2 * (long) f1;
+ long f1f2_2 = f1_2 * (long) f2;
+ long f1f3_4 = f1_2 * (long) f3_2;
+ long f1f4_2 = f1_2 * (long) f4;
+ long f1f5_4 = f1_2 * (long) f5_2;
+ long f1f6_2 = f1_2 * (long) f6;
+ long f1f7_4 = f1_2 * (long) f7_2;
+ long f1f8_2 = f1_2 * (long) f8;
+ long f1f9_76 = f1_2 * (long) f9_38;
+ long f2f2 = f2 * (long) f2;
+ long f2f3_2 = f2_2 * (long) f3;
+ long f2f4_2 = f2_2 * (long) f4;
+ long f2f5_2 = f2_2 * (long) f5;
+ long f2f6_2 = f2_2 * (long) f6;
+ long f2f7_2 = f2_2 * (long) f7;
+ long f2f8_38 = f2_2 * (long) f8_19;
+ long f2f9_38 = f2 * (long) f9_38;
+ long f3f3_2 = f3_2 * (long) f3;
+ long f3f4_2 = f3_2 * (long) f4;
+ long f3f5_4 = f3_2 * (long) f5_2;
+ long f3f6_2 = f3_2 * (long) f6;
+ long f3f7_76 = f3_2 * (long) f7_38;
+ long f3f8_38 = f3_2 * (long) f8_19;
+ long f3f9_76 = f3_2 * (long) f9_38;
+ long f4f4 = f4 * (long) f4;
+ long f4f5_2 = f4_2 * (long) f5;
+ long f4f6_38 = f4_2 * (long) f6_19;
+ long f4f7_38 = f4 * (long) f7_38;
+ long f4f8_38 = f4_2 * (long) f8_19;
+ long f4f9_38 = f4 * (long) f9_38;
+ long f5f5_38 = f5 * (long) f5_38;
+ long f5f6_38 = f5_2 * (long) f6_19;
+ long f5f7_76 = f5_2 * (long) f7_38;
+ long f5f8_38 = f5_2 * (long) f8_19;
+ long f5f9_76 = f5_2 * (long) f9_38;
+ long f6f6_19 = f6 * (long) f6_19;
+ long f6f7_38 = f6 * (long) f7_38;
+ long f6f8_38 = f6_2 * (long) f8_19;
+ long f6f9_38 = f6 * (long) f9_38;
+ long f7f7_38 = f7 * (long) f7_38;
+ long f7f8_38 = f7_2 * (long) f8_19;
+ long f7f9_76 = f7_2 * (long) f9_38;
+ long f8f8_19 = f8 * (long) f8_19;
+ long f8f9_38 = f8 * (long) f9_38;
+ long f9f9_38 = f9 * (long) f9_38;
+ long h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ long h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ long h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ long h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ long h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ long h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ long h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ long h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ long h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ long h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ long carry0;
+ long carry1;
+ long carry2;
+ long carry3;
+ long carry4;
+ long carry5;
+ long carry6;
+ long carry7;
+ long carry8;
+ long carry9;
+
+ h0 += h0;
+ h1 += h1;
+ h2 += h2;
+ h3 += h3;
+ h4 += h4;
+ h5 += h5;
+ h6 += h6;
+ h7 += h7;
+ h8 += h8;
+ h9 += h9;
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_sub.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_sub.java
new file mode 100644
index 0000000..80baa16
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_sub.java
@@ -0,0 +1,64 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_sub {
+
+//CONVERT #include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+public static void fe_sub(int[] h,int[] f,int[] g)
+{
+ int f0 = f[0];
+ int f1 = f[1];
+ int f2 = f[2];
+ int f3 = f[3];
+ int f4 = f[4];
+ int f5 = f[5];
+ int f6 = f[6];
+ int f7 = f[7];
+ int f8 = f[8];
+ int f9 = f[9];
+ int g0 = g[0];
+ int g1 = g[1];
+ int g2 = g[2];
+ int g3 = g[3];
+ int g4 = g[4];
+ int g5 = g[5];
+ int g6 = g[6];
+ int g7 = g[7];
+ int g8 = g[8];
+ int g9 = g[9];
+ int h0 = f0 - g0;
+ int h1 = f1 - g1;
+ int h2 = f2 - g2;
+ int h3 = f3 - g3;
+ int h4 = f4 - g4;
+ int h5 = f5 - g5;
+ int h6 = f6 - g6;
+ int h7 = f7 - g7;
+ int h8 = f8 - g8;
+ int h9 = f9 - g9;
+ h[0] = (int)h0;
+ h[1] = (int)h1;
+ h[2] = (int)h2;
+ h[3] = (int)h3;
+ h[4] = (int)h4;
+ h[5] = (int)h5;
+ h[6] = (int)h6;
+ h[7] = (int)h7;
+ h[8] = (int)h8;
+ h[9] = (int)h9;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java b/java/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java
new file mode 100644
index 0000000..2fb32bc
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/fe_tobytes.java
@@ -0,0 +1,126 @@
+package org.whispersystems.curve25519.java;
+
+public class fe_tobytes {
+
+//CONVERT #include "fe.h"
+
+/*
+Preconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+ Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+ Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ Then 0> 25;
+ q = (h0 + q) >> 26;
+ q = (h1 + q) >> 25;
+ q = (h2 + q) >> 26;
+ q = (h3 + q) >> 25;
+ q = (h4 + q) >> 26;
+ q = (h5 + q) >> 25;
+ q = (h6 + q) >> 26;
+ q = (h7 + q) >> 25;
+ q = (h8 + q) >> 26;
+ q = (h9 + q) >> 25;
+
+ /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+ h0 += 19 * q;
+ /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+ carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry9 = h9 >> 25; h9 -= carry9 << 25;
+ /* h10 = carry9 */
+
+ /*
+ Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ Have h0+...+2^230 h9 between 0 and 2^255-1;
+ evidently 2^255 h10-2^255 q = 0.
+ Goal: Output h0+...+2^230 h9.
+ */
+
+ s[0] = (byte)(h0 >> 0);
+ s[1] = (byte)(h0 >> 8);
+ s[2] = (byte)(h0 >> 16);
+ s[3] = (byte)((h0 >> 24) | (h1 << 2));
+ s[4] = (byte)(h1 >> 6);
+ s[5] = (byte)(h1 >> 14);
+ s[6] = (byte)((h1 >> 22) | (h2 << 3));
+ s[7] = (byte)(h2 >> 5);
+ s[8] = (byte)(h2 >> 13);
+ s[9] = (byte)((h2 >> 21) | (h3 << 5));
+ s[10] = (byte)(h3 >> 3);
+ s[11] = (byte)(h3 >> 11);
+ s[12] = (byte)((h3 >> 19) | (h4 << 6));
+ s[13] = (byte)(h4 >> 2);
+ s[14] = (byte)(h4 >> 10);
+ s[15] = (byte)(h4 >> 18);
+ s[16] = (byte)(h5 >> 0);
+ s[17] = (byte)(h5 >> 8);
+ s[18] = (byte)(h5 >> 16);
+ s[19] = (byte)((h5 >> 24) | (h6 << 1));
+ s[20] = (byte)(h6 >> 7);
+ s[21] = (byte)(h6 >> 15);
+ s[22] = (byte)((h6 >> 23) | (h7 << 3));
+ s[23] = (byte)(h7 >> 5);
+ s[24] = (byte)(h7 >> 13);
+ s[25] = (byte)((h7 >> 21) | (h8 << 4));
+ s[26] = (byte)(h8 >> 4);
+ s[27] = (byte)(h8 >> 12);
+ s[28] = (byte)((h8 >> 20) | (h9 << 6));
+ s[29] = (byte)(h9 >> 2);
+ s[30] = (byte)(h9 >> 10);
+ s[31] = (byte)(h9 >> 18);
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/ge_add.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_add.java
new file mode 100644
index 0000000..9f8c016
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/ge_add.java
@@ -0,0 +1,115 @@
+package org.whispersystems.curve25519.java;
+
+public class ge_add {
+
+//CONVERT #include "ge.h"
+
+/*
+r = p + q
+*/
+
+public static void ge_add(ge_p1p1 r,ge_p3 p,ge_cached q)
+{
+ int[] t0 = new int[10];
+//CONVERT #include "ge_add.h"
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add.fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,> 3] >> (i & 7));
+ r[i] = (byte)(1 & (a[i >> 3] >>> (i & 7)));
+ }
+
+ for (i = 0;i < 256;++i)
+ if (r[i] != 0) {
+ for (b = 1;b <= 6 && i + b < 256;++b) {
+ if (r[i + b] != 0) {
+ if (r[i] + (r[i + b] << b) <= 15) {
+ r[i] += r[i + b] << b; r[i + b] = 0;
+ } else if (r[i] - (r[i + b] << b) >= -15) {
+ r[i] -= r[i + b] << b;
+ for (k = i + b;k < 256;++k) {
+ if (r[k] == 0) {
+ r[k] = 1;
+ break;
+ }
+ r[k] = 0;
+ }
+ } else
+ break;
+ }
+ }
+ }
+
+}
+
+static ge_precomp Bi[];
+
+static {
+ Bi = new ge_precomp[8];
+ Bi[0] = new ge_precomp(
+ new int[]{ 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ new int[]{ -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ new int[]{ -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 }
+ );
+ Bi[1] = new ge_precomp(
+ new int[]{ 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ new int[]{ 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ new int[]{ 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 }
+ );
+ Bi[2] = new ge_precomp(
+ new int[]{ 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ new int[]{ 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ new int[]{ 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 }
+ );
+ Bi[3] = new ge_precomp(
+ new int[]{ 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ new int[]{ -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ new int[]{ 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 }
+ );
+ Bi[4] = new ge_precomp(
+ new int[]{ -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+ new int[]{ -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+ new int[]{ 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 }
+ );
+ Bi[5] = new ge_precomp(
+ new int[]{ -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+ new int[]{ 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+ new int[]{ 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 }
+ );
+ Bi[6] = new ge_precomp(
+ new int[]{ -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+ new int[]{ -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+ new int[]{ -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 }
+ );
+ Bi[7] = new ge_precomp(
+ new int[]{ -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+ new int[]{ -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+ new int[]{ -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 }
+ );
+}
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+public static void ge_double_scalarmult_vartime(ge_p2 r,byte[] a,ge_p3 A,byte[] b)
+{
+ byte[] aslide = new byte[256];
+ byte[] bslide = new byte[256];
+ ge_cached Ai[] = new ge_cached[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+ for (int count=0; count < 8; count++)
+ Ai[count] = new ge_cached();
+ ge_p1p1 t = new ge_p1p1();
+ ge_p3 u = new ge_p3();
+ ge_p3 A2 = new ge_p3();
+ int i;
+
+ slide(aslide,a);
+ slide(bslide,b);
+
+ ge_p3_to_cached.ge_p3_to_cached(Ai[0],A);
+ ge_p3_dbl.ge_p3_dbl(t,A); ge_p1p1_to_p3.ge_p1p1_to_p3(A2,t);
+ ge_add.ge_add(t,A2,Ai[0]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[1],u);
+ ge_add.ge_add(t,A2,Ai[1]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[2],u);
+ ge_add.ge_add(t,A2,Ai[2]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[3],u);
+ ge_add.ge_add(t,A2,Ai[3]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[4],u);
+ ge_add.ge_add(t,A2,Ai[4]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[5],u);
+ ge_add.ge_add(t,A2,Ai[5]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[6],u);
+ ge_add.ge_add(t,A2,Ai[6]); ge_p1p1_to_p3.ge_p1p1_to_p3(u,t); ge_p3_to_cached.ge_p3_to_cached(Ai[7],u);
+
+ ge_p2_0.ge_p2_0(r);
+
+ for (i = 255;i >= 0;--i) {
+ if (aslide[i] !=0 || bslide[i] != 0) break;
+ }
+
+ for (;i >= 0;--i) {
+ ge_p2_dbl.ge_p2_dbl(t,r);
+
+ if (aslide[i] > 0) {
+ ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
+ ge_add.ge_add(t,u,Ai[aslide[i]/2]);
+ } else if (aslide[i] < 0) {
+ ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
+ ge_sub.ge_sub(t,u,Ai[(-aslide[i])/2]);
+ }
+
+ if (bslide[i] > 0) {
+ ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
+ ge_madd.ge_madd(t,u,Bi[bslide[i]/2]);
+ } else if (bslide[i] < 0) {
+ ge_p1p1_to_p3.ge_p1p1_to_p3(u,t);
+ ge_msub.ge_msub(t,u,Bi[(-bslide[i])/2]);
+ }
+
+ ge_p1p1_to_p2.ge_p1p1_to_p2(r,t);
+ }
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java
new file mode 100644
index 0000000..a67acff
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/ge_frombytes.java
@@ -0,0 +1,60 @@
+package org.whispersystems.curve25519.java;
+
+public class ge_frombytes {
+
+//CONVERT #include "ge.h"
+
+static int[] d = {
+//CONVERT #include "d.h"
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
+} ;
+
+static int[] sqrtm1 = {
+//CONVERT #include "sqrtm1.h"
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
+} ;
+
+static int ge_frombytes_negate_vartime(ge_p3 h,byte[] s)
+{
+ int[] u = new int[10];
+ int[] v = new int[10];
+ int[] v3 = new int[10];
+ int[] vxx = new int[10];
+ int[] check = new int[10];
+
+ fe_frombytes.fe_frombytes(h.Y,s);
+ fe_1.fe_1(h.Z);
+ fe_sq.fe_sq(u,h.Y);
+ fe_mul.fe_mul(v,u,d);
+ fe_sub.fe_sub(u,u,h.Z); /* u = y^2-1 */
+ fe_add.fe_add(v,v,h.Z); /* v = dy^2+1 */
+
+ fe_sq.fe_sq(v3,v);
+ fe_mul.fe_mul(v3,v3,v); /* v3 = v^3 */
+ fe_sq.fe_sq(h.X,v3);
+ fe_mul.fe_mul(h.X,h.X,v);
+ fe_mul.fe_mul(h.X,h.X,u); /* x = uv^7 */
+
+ fe_pow22523.fe_pow22523(h.X,h.X); /* x = (uv^7)^((q-5)/8) */
+ fe_mul.fe_mul(h.X,h.X,v3);
+ fe_mul.fe_mul(h.X,h.X,u); /* x = uv^3(uv^7)^((q-5)/8) */
+
+ fe_sq.fe_sq(vxx,h.X);
+ fe_mul.fe_mul(vxx,vxx,v);
+ fe_sub.fe_sub(check,vxx,u); /* vx^2-u */
+ if (fe_isnonzero.fe_isnonzero(check) != 0) {
+ fe_add.fe_add(check,vxx,u); /* vx^2+u */
+ if (fe_isnonzero.fe_isnonzero(check) != 0) return -1;
+ fe_mul.fe_mul(h.X,h.X,sqrtm1);
+ }
+
+ if (fe_isnegative.fe_isnegative(h.X) == ((s[31] >>> 7) & 0x01)) {
+ fe_neg.fe_neg(h.X,h.X);
+ }
+
+ fe_mul.fe_mul(h.T,h.X,h.Y);
+ return 0;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/ge_madd.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_madd.java
new file mode 100644
index 0000000..5a3076c
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/ge_madd.java
@@ -0,0 +1,106 @@
+package org.whispersystems.curve25519.java;
+
+public class ge_madd {
+
+//CONVERT #include "ge.h"
+
+/*
+r = p + q
+*/
+
+public static void ge_madd(ge_p1p1 r,ge_p3 p,ge_precomp q)
+{
+ int[] t0 = new int[10];
+//CONVERT #include "ge_madd.h"
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add.fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,XX=fe#1,XX=r.X,YY=fe#3,YY=r.Z,B=fe#4,B=r.T,A=fe#2,A=r.Y,AA=fe#5,AA=t0,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,X3=fe#1,X3=r.X,T3=fe#4,T3=r.T,>>= 31; /* 1: yes; 0: no */
+ return y;
+}
+
+static int negative(byte b)
+{
+ long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>>= 63; /* 1: yes; 0: no */
+ return (int)x;
+}
+
+static void cmov(ge_precomp t,ge_precomp u,int b)
+{
+ fe_cmov.fe_cmov(t.yplusx,u.yplusx,b);
+ fe_cmov.fe_cmov(t.yminusx,u.yminusx,b);
+ fe_cmov.fe_cmov(t.xy2d,u.xy2d,b);
+}
+
+static void select(ge_precomp t,int pos,byte b)
+{
+ ge_precomp base[][] = (pos <= 7 ? ge_precomp_base_0_7.base :
+ (pos <= 15 ? ge_precomp_base_8_15.base :
+ (pos <= 23 ? ge_precomp_base_16_23.base : ge_precomp_base_24_31.base)));
+
+ ge_precomp minust = new ge_precomp();
+ int bnegative = negative(b);
+ int babs = b - (((-bnegative) & b) << 1);
+
+ ge_precomp_0.ge_precomp_0(t);
+ cmov(t,base[pos][0],equal((byte)babs,(byte)1));
+ cmov(t,base[pos][1],equal((byte)babs,(byte)2));
+ cmov(t,base[pos][2],equal((byte)babs,(byte)3));
+ cmov(t,base[pos][3],equal((byte)babs,(byte)4));
+ cmov(t,base[pos][4],equal((byte)babs,(byte)5));
+ cmov(t,base[pos][5],equal((byte)babs,(byte)6));
+ cmov(t,base[pos][6],equal((byte)babs,(byte)7));
+ cmov(t,base[pos][7],equal((byte)babs,(byte)8));
+ fe_copy.fe_copy(minust.yplusx,t.yminusx);
+ fe_copy.fe_copy(minust.yminusx,t.yplusx);
+ fe_neg.fe_neg(minust.xy2d,t.xy2d);
+ cmov(t,minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+public static void ge_scalarmult_base(ge_p3 h,byte[] a)
+{
+ byte[] e = new byte[64];
+ byte carry;
+ ge_p1p1 r = new ge_p1p1();
+ ge_p2 s = new ge_p2();
+ ge_precomp t = new ge_precomp();
+ int i;
+
+ for (i = 0;i < 32;++i) {
+ e[2 * i + 0] = (byte)((a[i] >>> 0) & 15);
+ e[2 * i + 1] = (byte)((a[i] >>> 4) & 15);
+ }
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+
+ carry = 0;
+ for (i = 0;i < 63;++i) {
+ e[i] += carry;
+ carry = (byte)(e[i] + 8);
+ carry >>= 4;
+ e[i] -= carry << 4;
+ }
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+
+ ge_p3_0.ge_p3_0(h);
+ for (i = 1;i < 64;i += 2) {
+ select(t,i / 2,e[i]);
+ ge_madd.ge_madd(r,h,t); ge_p1p1_to_p3.ge_p1p1_to_p3(h,r);
+ }
+
+ ge_p3_dbl.ge_p3_dbl(r,h); ge_p1p1_to_p2.ge_p1p1_to_p2(s,r);
+ ge_p2_dbl.ge_p2_dbl(r,s); ge_p1p1_to_p2.ge_p1p1_to_p2(s,r);
+ ge_p2_dbl.ge_p2_dbl(r,s); ge_p1p1_to_p2.ge_p1p1_to_p2(s,r);
+ ge_p2_dbl.ge_p2_dbl(r,s); ge_p1p1_to_p3.ge_p1p1_to_p3(h,r);
+
+ for (i = 0;i < 64;i += 2) {
+ select(t,i / 2,e[i]);
+ ge_madd.ge_madd(r,h,t); ge_p1p1_to_p3.ge_p1p1_to_p3(h,r);
+ }
+}
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/ge_sub.java b/java/src/main/java/org/whispersystems/curve25519/java/ge_sub.java
new file mode 100644
index 0000000..b5c8597
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/ge_sub.java
@@ -0,0 +1,115 @@
+package org.whispersystems.curve25519.java;
+
+public class ge_sub {
+
+//CONVERT #include "ge.h"
+
+/*
+r = p - q
+*/
+
+public static void ge_sub(ge_p1p1 r,ge_p3 p,ge_cached q)
+{
+ int[] t0 = new int[10];
+//CONVERT #include "ge_sub.h"
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add.fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,
+//CONVERT #include "crypto_sign.h"
+//CONVERT #include "crypto_hash_sha512.h"
+//CONVERT #include "crypto_verify_32.h"
+//CONVERT #include "ge.h"
+//CONVERT #include "sc.h"
+
+public static int crypto_sign_open(
+ Sha512 sha512provider,
+ byte[] m, long mlen,
+ byte[] sm, long smlen,
+ byte[] pk
+)
+{
+ byte[] pkcopy = new byte[32];
+ byte[] rcopy = new byte[32];
+ byte[] scopy = new byte[32];
+ byte[] h = new byte[64];
+ byte[] rcheck = new byte[32];
+ ge_p3 A = new ge_p3();
+ ge_p2 R = new ge_p2();
+
+ if (smlen < 64) return -1;
+ if ((sm[63] & 224) != 0) return -1;
+ if (ge_frombytes.ge_frombytes_negate_vartime(A,pk) != 0) return -1;
+
+ byte[] pubkeyhash = new byte[64];
+ sha512provider.calculateDigest(pubkeyhash,pk,32);
+
+ System.arraycopy(pk, 0, pkcopy, 0, 32);
+ System.arraycopy(sm, 0, rcopy, 0, 32);
+ System.arraycopy(sm, 32, scopy, 0, 32);
+
+ System.arraycopy(sm, 0, m, 0, (int)smlen);
+ System.arraycopy(pkcopy, 0, m, 32, 32);
+ sha512provider.calculateDigest(h,m,smlen);
+ sc_reduce.sc_reduce(h);
+
+ ge_double_scalarmult.ge_double_scalarmult_vartime(R,h,A,scopy);
+ ge_tobytes.ge_tobytes(rcheck,R);
+ if (crypto_verify_32.crypto_verify_32(rcheck,rcopy) == 0) {
+ System.arraycopy(m, 64, m, 0, (int)(smlen - 64));
+ //memset(m + smlen - 64,0,64);
+ return 0;
+ }
+
+//badsig:
+ //memset(m,0,smlen);
+ return -1;
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java b/java/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java
new file mode 100644
index 0000000..60780b2
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/sc_muladd.java
@@ -0,0 +1,375 @@
+package org.whispersystems.curve25519.java;
+
+public class sc_muladd {
+
+//CONVERT #include "sc.h"
+//CONVERT #include "long.h"
+//CONVERT #include "crypto_uint32.h"
+//CONVERT #include "long.h"
+
+public static long load_3(byte[] in, int index)
+{
+ long result;
+ result = ((long) in[index + 0]) & 0xFF;
+ result |= (((long) in[index + 1]) << 8) & 0xFF00;
+ result |= (((long) in[index + 2]) << 16) & 0xFF0000;
+ return result;
+}
+
+public static long load_4(byte[] in, int index)
+{
+ long result;
+ result = (((long) in[index + 0]) & 0xFF);
+ result |= ((((long) in[index + 1]) << 8) & 0xFF00);
+ result |= ((((long) in[index + 2]) << 16) & 0xFF0000);
+ result |= ((((long) in[index + 3]) << 24) & 0xFF000000L);
+ return result;
+}
+
+/*
+Input:
+ a[0]+256*a[1]+...+256^31*a[31] = a
+ b[0]+256*b[1]+...+256^31*b[31] = b
+ c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+public static void sc_muladd(byte[] s,byte[] a,byte[] b,byte[] c)
+{
+ long a0 = 2097151 & load_3(a, 0);
+ long a1 = 2097151 & (load_4(a, 2) >>> 5);
+ long a2 = 2097151 & (load_3(a, 5) >>> 2);
+ long a3 = 2097151 & (load_4(a, 7) >>> 7);
+ long a4 = 2097151 & (load_4(a, 10) >>> 4);
+ long a5 = 2097151 & (load_3(a, 13) >>> 1);
+ long a6 = 2097151 & (load_4(a, 15) >>> 6);
+ long a7 = 2097151 & (load_3(a, 18) >>> 3);
+ long a8 = 2097151 & load_3(a, 21);
+ long a9 = 2097151 & (load_4(a, 23) >>> 5);
+ long a10 = 2097151 & (load_3(a, 26) >>> 2);
+ long a11 = (load_4(a, 28) >>> 7);
+ long b0 = 2097151 & load_3(b, 0);
+ long b1 = 2097151 & (load_4(b, 2) >>> 5);
+ long b2 = 2097151 & (load_3(b, 5) >>> 2);
+ long b3 = 2097151 & (load_4(b, 7) >>> 7);
+ long b4 = 2097151 & (load_4(b, 10) >>> 4);
+ long b5 = 2097151 & (load_3(b, 13) >>> 1);
+ long b6 = 2097151 & (load_4(b, 15) >>> 6);
+ long b7 = 2097151 & (load_3(b, 18) >>> 3);
+ long b8 = 2097151 & load_3(b, 21);
+ long b9 = 2097151 & (load_4(b, 23) >>> 5);
+ long b10 = 2097151 & (load_3(b, 26) >>> 2);
+ long b11 = (load_4(b, 28) >>> 7);
+ long c0 = 2097151 & load_3(c, 0);
+ long c1 = 2097151 & (load_4(c, 2) >>> 5);
+ long c2 = 2097151 & (load_3(c, 5) >>> 2);
+ long c3 = 2097151 & (load_4(c, 7) >>> 7);
+ long c4 = 2097151 & (load_4(c, 10) >>> 4);
+ long c5 = 2097151 & (load_3(c, 13) >>> 1);
+ long c6 = 2097151 & (load_4(c, 15) >>> 6);
+ long c7 = 2097151 & (load_3(c, 18) >>> 3);
+ long c8 = 2097151 & load_3(c, 21);
+ long c9 = 2097151 & (load_4(c, 23) >>> 5);
+ long c10 = 2097151 & (load_3(c, 26) >>> 2);
+ long c11 = (load_4(c, 28) >>> 7);
+ long s0;
+ long s1;
+ long s2;
+ long s3;
+ long s4;
+ long s5;
+ long s6;
+ long s7;
+ long s8;
+ long s9;
+ long s10;
+ long s11;
+ long s12;
+ long s13;
+ long s14;
+ long s15;
+ long s16;
+ long s17;
+ long s18;
+ long s19;
+ long s20;
+ long s21;
+ long s22;
+ long s23;
+ long carry0;
+ long carry1;
+ long carry2;
+ long carry3;
+ long carry4;
+ long carry5;
+ long carry6;
+ long carry7;
+ long carry8;
+ long carry9;
+ long carry10;
+ long carry11;
+ long carry12;
+ long carry13;
+ long carry14;
+ long carry15;
+ long carry16;
+ long carry17;
+ long carry18;
+ long carry19;
+ long carry20;
+ long carry21;
+ long carry22;
+
+ s0 = c0 + a0*b0;
+ s1 = c1 + a0*b1 + a1*b0;
+ s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+ s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+ s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+ s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+ s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+ s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+ s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+ s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+ s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+ s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+ s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+ s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+ s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+ s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+ s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+ s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+ s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+ s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+ s20 = a9*b11 + a10*b10 + a11*b9;
+ s21 = a10*b11 + a11*b10;
+ s22 = a11*b11;
+ s23 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+ carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+ carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+ carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+ carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+ carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+ carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = (byte)(s0 >> 0);
+ s[1] = (byte)(s0 >> 8);
+ s[2] = (byte)((s0 >> 16) | (s1 << 5));
+ s[3] = (byte)(s1 >> 3);
+ s[4] = (byte)(s1 >> 11);
+ s[5] = (byte)((s1 >> 19) | (s2 << 2));
+ s[6] = (byte)(s2 >> 6);
+ s[7] = (byte)((s2 >> 14) | (s3 << 7));
+ s[8] = (byte)(s3 >> 1);
+ s[9] = (byte)(s3 >> 9);
+ s[10] = (byte)((s3 >> 17) | (s4 << 4));
+ s[11] = (byte)(s4 >> 4);
+ s[12] = (byte)(s4 >> 12);
+ s[13] = (byte)((s4 >> 20) | (s5 << 1));
+ s[14] = (byte)(s5 >> 7);
+ s[15] = (byte)((s5 >> 15) | (s6 << 6));
+ s[16] = (byte)(s6 >> 2);
+ s[17] = (byte)(s6 >> 10);
+ s[18] = (byte)((s6 >> 18) | (s7 << 3));
+ s[19] = (byte)(s7 >> 5);
+ s[20] = (byte)(s7 >> 13);
+ s[21] = (byte)(s8 >> 0);
+ s[22] = (byte)(s8 >> 8);
+ s[23] = (byte)((s8 >> 16) | (s9 << 5));
+ s[24] = (byte)(s9 >> 3);
+ s[25] = (byte)(s9 >> 11);
+ s[26] = (byte)((s9 >> 19) | (s10 << 2));
+ s[27] = (byte)(s10 >> 6);
+ s[28] = (byte)((s10 >> 14) | (s11 << 7));
+ s[29] = (byte)(s11 >> 1);
+ s[30] = (byte)(s11 >> 9);
+ s[31] = (byte)(s11 >> 17);
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java b/java/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java
new file mode 100644
index 0000000..b24b481
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/sc_reduce.java
@@ -0,0 +1,282 @@
+package org.whispersystems.curve25519.java;
+
+public class sc_reduce {
+
+//CONVERT #include "sc.h"
+//CONVERT #include "long.h"
+//CONVERT #include "crypto_uint32.h"
+//CONVERT #include "long.h"
+
+public static long load_3(byte[] in, int index)
+{
+ long result;
+ result = ((long) in[index + 0]) & 0xFF;
+ result |= (((long) in[index + 1]) << 8) & 0xFF00;
+ result |= (((long) in[index + 2]) << 16) & 0xFF0000;
+ return result;
+}
+
+public static long load_4(byte[] in, int index)
+{
+ long result;
+ result = (((long) in[index + 0]) & 0xFF);
+ result |= ((((long) in[index + 1]) << 8) & 0xFF00);
+ result |= ((((long) in[index + 2]) << 16) & 0xFF0000);
+ result |= ((((long) in[index + 3]) << 24) & 0xFF000000L);
+ return result;
+}
+
+/*
+Input:
+ s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = s mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+ Overwrites s in place.
+*/
+
+public static void sc_reduce(byte[] s)
+{
+ long s0 = 2097151 & load_3(s, 0);
+ long s1 = 2097151 & (load_4(s, 2) >>> 5);
+ long s2 = 2097151 & (load_3(s, 5) >>> 2);
+ long s3 = 2097151 & (load_4(s, 7) >>> 7);
+ long s4 = 2097151 & (load_4(s, 10) >>> 4);
+ long s5 = 2097151 & (load_3(s, 13) >>> 1);
+ long s6 = 2097151 & (load_4(s, 15) >>> 6);
+ long s7 = 2097151 & (load_3(s, 18) >>> 3);
+ long s8 = 2097151 & load_3(s, 21);
+ long s9 = 2097151 & (load_4(s, 23) >>> 5);
+ long s10 = 2097151 & (load_3(s, 26) >>> 2);
+ long s11 = 2097151 & (load_4(s, 28) >>> 7);
+ long s12 = 2097151 & (load_4(s, 31) >>> 4);
+ long s13 = 2097151 & (load_3(s, 34) >>> 1);
+ long s14 = 2097151 & (load_4(s, 36) >>> 6);
+ long s15 = 2097151 & (load_3(s, 39) >>> 3);
+ long s16 = 2097151 & load_3(s, 42);
+ long s17 = 2097151 & (load_4(s, 44) >>> 5);
+ long s18 = 2097151 & (load_3(s, 47) >>> 2);
+ long s19 = 2097151 & (load_4(s, 49) >>> 7);
+ long s20 = 2097151 & (load_4(s, 52) >>> 4);
+ long s21 = 2097151 & (load_3(s, 55) >>> 1);
+ long s22 = 2097151 & (load_4(s, 57) >>> 6);
+ long s23 = (load_4(s, 60) >>> 3);
+ long carry0;
+ long carry1;
+ long carry2;
+ long carry3;
+ long carry4;
+ long carry5;
+ long carry6;
+ long carry7;
+ long carry8;
+ long carry9;
+ long carry10;
+ long carry11;
+ long carry12;
+ long carry13;
+ long carry14;
+ long carry15;
+ long carry16;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = (byte)(s0 >> 0);
+ s[1] = (byte)(s0 >> 8);
+ s[2] = (byte)((s0 >> 16) | (s1 << 5));
+ s[3] = (byte)(s1 >> 3);
+ s[4] = (byte)(s1 >> 11);
+ s[5] = (byte)((s1 >> 19) | (s2 << 2));
+ s[6] = (byte)(s2 >> 6);
+ s[7] = (byte)((s2 >> 14) | (s3 << 7));
+ s[8] = (byte)(s3 >> 1);
+ s[9] = (byte)(s3 >> 9);
+ s[10] = (byte)((s3 >> 17) | (s4 << 4));
+ s[11] = (byte)(s4 >> 4);
+ s[12] = (byte)(s4 >> 12);
+ s[13] = (byte)((s4 >> 20) | (s5 << 1));
+ s[14] = (byte)(s5 >> 7);
+ s[15] = (byte)((s5 >> 15) | (s6 << 6));
+ s[16] = (byte)(s6 >> 2);
+ s[17] = (byte)(s6 >> 10);
+ s[18] = (byte)((s6 >> 18) | (s7 << 3));
+ s[19] = (byte)(s7 >> 5);
+ s[20] = (byte)(s7 >> 13);
+ s[21] = (byte)(s8 >> 0);
+ s[22] = (byte)(s8 >> 8);
+ s[23] = (byte)((s8 >> 16) | (s9 << 5));
+ s[24] = (byte)(s9 >> 3);
+ s[25] = (byte)(s9 >> 11);
+ s[26] = (byte)((s9 >> 19) | (s10 << 2));
+ s[27] = (byte)(s10 >> 6);
+ s[28] = (byte)((s10 >> 14) | (s11 << 7));
+ s[29] = (byte)(s11 >> 1);
+ s[30] = (byte)(s11 >> 9);
+ s[31] = (byte)(s11 >> 17);
+}
+
+
+}
diff --git a/java/src/main/java/org/whispersystems/curve25519/java/scalarmult.java b/java/src/main/java/org/whispersystems/curve25519/java/scalarmult.java
new file mode 100644
index 0000000..4d7b59d
--- /dev/null
+++ b/java/src/main/java/org/whispersystems/curve25519/java/scalarmult.java
@@ -0,0 +1,195 @@
+package org.whispersystems.curve25519.java;
+
+public class scalarmult {
+
+//CONVERT #include "crypto_scalarmult.h"
+//CONVERT #include "fe.h"
+
+public static int crypto_scalarmult(byte[] q,
+ byte[] n,
+ byte[] p)
+{
+ byte[] e = new byte[32];
+ int i;
+ int[] x1 = new int[10];
+ int[] x2 = new int[10];
+ int[] z2 = new int[10];
+ int[] x3 = new int[10];
+ int[] z3 = new int[10];
+ int[] tmp0 = new int[10];
+ int[] tmp1 = new int[10];
+ int pos;
+ int swap;
+ int b;
+
+ for (i = 0;i < 32;++i) e[i] = n[i];
+// e[0] &= 248;
+// e[31] &= 127;
+// e[31] |= 64;
+ fe_frombytes.fe_frombytes(x1,p);
+ fe_1.fe_1(x2);
+ fe_0.fe_0(z2);
+ fe_copy.fe_copy(x3,x1);
+ fe_1.fe_1(z3);
+
+ swap = 0;
+ for (pos = 254;pos >= 0;--pos) {
+ b = e[pos / 8] >>> (pos & 7);
+ b &= 1;
+ swap ^= b;
+ fe_cswap.fe_cswap(x2,x3,swap);
+ fe_cswap.fe_cswap(z2,z3,swap);
+ swap = b;
+//CONVERT #include "montgomery.h"
+
+/* qhasm: fe X2 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe X4 */
+
+/* qhasm: fe Z4 */
+
+/* qhasm: fe X5 */
+
+/* qhasm: fe Z5 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: fe E */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe BB */
+
+/* qhasm: fe DA */
+
+/* qhasm: fe CB */
+
+/* qhasm: fe t0 */
+
+/* qhasm: fe t1 */
+
+/* qhasm: fe t2 */
+
+/* qhasm: fe t3 */
+
+/* qhasm: fe t4 */
+
+/* qhasm: enter ladder */
+
+/* qhasm: D = X3-Z3 */
+/* asm 1: fe_sub.fe_sub(>D=fe#5,D=tmp0,B=fe#6,B=tmp1,A=fe#1,A=x2,C=fe#2,C=z2,DA=fe#4,DA=z3,CB=fe#2,CB=z2,BB=fe#5,BB=tmp0,AA=fe#6,AA=tmp1,t0=fe#3,t0=x3,t1=fe#2,t1=z2,X4=fe#1,X4=x2,E=fe#6,E=tmp1,t2=fe#2,t2=z2,t3=fe#4,t3=z3,X5=fe#3,X5=x3,t4=fe#5,t4=tmp0,Z5=fe#4,x1,Z5=z3,x1,Z4=fe#2,Z4=z2,
+//CONVERT #include "crypto_sign.h"
+//CONVERT #include "crypto_hash_sha512.h"
+//CONVERT #include "ge.h"
+//CONVERT #include "sc.h"
+//CONVERT #include "zeroize.h"
+
+/* NEW: Compare to pristine crypto_sign()
+ Uses explicit private key for nonce derivation and as scalar,
+ instead of deriving both from a master key.
+*/
+static int crypto_sign_modified (
+ Sha512 sha512provider,
+ byte[] sm,
+ byte[] m, long mlen,
+ byte[] sk, byte[] pk,
+ byte[] random
+)
+{
+ byte[] nonce = new byte[64];
+ byte[] hram = new byte[64];
+ ge_p3 R = new ge_p3();
+ int count=0;
+
+ System.arraycopy(m, 0, sm, 64, (int)mlen);
+ System.arraycopy(sk, 0, sm, 32, 32);
+
+ /* NEW : add prefix to separate hash uses - see .h */
+ sm[0] = (byte)0xFE;
+ for (count = 1; count < 32; count++)
+ sm[count] = (byte)0xFF;
+
+ /* NEW: add suffix of random data */
+ System.arraycopy(random, 0, sm, (int)(mlen + 64), 64);
+
+ sha512provider.calculateDigest(nonce,sm,mlen + 128);
+ System.arraycopy(pk, 0, sm, 32, 32);
+
+ sc_reduce.sc_reduce(nonce);
+ ge_scalarmult_base.ge_scalarmult_base(R,nonce);
+ ge_p3_tobytes.ge_p3_tobytes(sm,R);
+
+ sha512provider.calculateDigest(hram,sm,mlen + 64);
+ sc_reduce.sc_reduce(hram);
+ byte[] S = new byte[32];
+ sc_muladd.sc_muladd(S,hram,sk,nonce); /* NEW: Use privkey directly */
+ System.arraycopy(S, 0, sm, 32, 32);
+
+ return 0;
+}
+
+
+}
diff --git a/java/src/test/java/org/whispersystems/curve25519/Curve25519ProviderTest.java b/java/src/test/java/org/whispersystems/curve25519/Curve25519ProviderTest.java
new file mode 100644
index 0000000..db73317
--- /dev/null
+++ b/java/src/test/java/org/whispersystems/curve25519/Curve25519ProviderTest.java
@@ -0,0 +1,91 @@
+package org.whispersystems.curve25519;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+public abstract class Curve25519ProviderTest {
+
+ protected abstract Curve25519Provider createProvider() throws NoSuchProviderException;
+
+ @Test
+ public void testKeyGen() throws NoSuchProviderException {
+ Curve25519Provider provider = createProvider();
+
+ byte[] in = new byte[32];
+ byte[] out = null;
+
+ in[0] = 123;
+
+ for (int count = 0; count < 1000; count++) {
+ out = provider.generatePublicKey(in);
+ System.arraycopy(out, 0, in, 0, 32);
+ }
+
+ byte[] result2 = new byte[]{(byte) 0xa2, (byte) 0x3c, (byte) 0x84, (byte) 0x09, (byte) 0xf2,
+ (byte) 0x93, (byte) 0xb4, (byte) 0x42, (byte) 0x6a, (byte) 0xf5,
+ (byte) 0xe5, (byte) 0xe7, (byte) 0xca, (byte) 0xee, (byte) 0x22,
+ (byte) 0xa0, (byte) 0x01, (byte) 0xc7, (byte) 0x9a, (byte) 0xca,
+ (byte) 0x1a, (byte) 0xf2, (byte) 0xea, (byte) 0xcb, (byte) 0x4d,
+ (byte) 0xdd, (byte) 0xfa, (byte) 0x05, (byte) 0xf8, (byte) 0xbc,
+ (byte) 0x7f, (byte) 0x37};
+
+ assertArrayEquals(out, result2);
+ }
+
+ @Test
+ public void testEcDh() throws NoSuchProviderException {
+ Curve25519Provider provider = createProvider();
+
+ byte[] p = new byte[32];
+ byte[] q = null;
+ byte[] n = new byte[32];
+
+ p[0] = 100;
+ n[0] = 100;
+
+ n = provider.generatePrivateKey(n);
+
+ for (int count = 0; count < 1000; count++) {
+ q = provider.calculateAgreement(n, p);
+ System.arraycopy(q, 0, p, 0, 32);
+ q = provider.calculateAgreement(n, p);
+ System.arraycopy(q, 0, n, 0, 32);
+ n = provider.generatePrivateKey(n);
+ }
+
+ byte[] result = new byte[]{(byte) 0xce, (byte) 0xb4, (byte) 0x4e, (byte) 0xd6, (byte) 0x4a,
+ (byte) 0xd4, (byte) 0xc2, (byte) 0xb5, (byte) 0x43, (byte) 0x9d,
+ (byte) 0x25, (byte) 0xde, (byte) 0xb1, (byte) 0x10, (byte) 0xa8,
+ (byte) 0xd7, (byte) 0x2e, (byte) 0xb3, (byte) 0xe3, (byte) 0x8e,
+ (byte) 0xf4, (byte) 0x8a, (byte) 0x42, (byte) 0x73, (byte) 0xb1,
+ (byte) 0x1b, (byte) 0x4b, (byte) 0x13, (byte) 0x8d, (byte) 0x17,
+ (byte) 0xf9, (byte) 0x34};
+
+ assertArrayEquals(q, result);
+ }
+
+ // FIXME: There's no actual vector here. If verifySignature is broken and always returns true,
+ // this test will pass.
+ @Test
+ public void testSignVerify() throws NoSuchProviderException {
+ Curve25519Provider provider = createProvider();
+
+ byte[] msg = new byte[100];
+ byte[] sig_out = new byte[64];
+ byte[] privkey = new byte[32];
+ byte[] pubkey = new byte[32];
+ byte[] random = new byte[64];
+
+ privkey[0] = 123;
+
+ for (int count = 0; count < 1000; count++) {
+ privkey = provider.generatePrivateKey(privkey);
+ pubkey = provider.generatePublicKey(privkey);
+ sig_out = provider.calculateSignature(random, privkey, msg);
+
+ assertTrue(provider.verifySignature(pubkey, msg, sig_out));
+
+ System.arraycopy(sig_out, 0, privkey, 0, 32);
+ }
+ }
+}
diff --git a/java/src/test/java/org/whispersystems/curve25519/Curve25519Test.java b/java/src/test/java/org/whispersystems/curve25519/Curve25519Test.java
new file mode 100644
index 0000000..f59c671
--- /dev/null
+++ b/java/src/test/java/org/whispersystems/curve25519/Curve25519Test.java
@@ -0,0 +1,148 @@
+package org.whispersystems.curve25519;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+public abstract class Curve25519Test {
+
+ public abstract void testCheckProvider() throws NoSuchProviderException;
+ public abstract String getProviderName();
+
+ public void testAgreement() throws NoSuchProviderException {
+
+ byte[] alicePublic = {(byte) 0x1b, (byte) 0xb7, (byte) 0x59, (byte) 0x66,
+ (byte) 0xf2, (byte) 0xe9, (byte) 0x3a, (byte) 0x36, (byte) 0x91,
+ (byte) 0xdf, (byte) 0xff, (byte) 0x94, (byte) 0x2b, (byte) 0xb2,
+ (byte) 0xa4, (byte) 0x66, (byte) 0xa1, (byte) 0xc0, (byte) 0x8b,
+ (byte) 0x8d, (byte) 0x78, (byte) 0xca, (byte) 0x3f, (byte) 0x4d,
+ (byte) 0x6d, (byte) 0xf8, (byte) 0xb8, (byte) 0xbf, (byte) 0xa2,
+ (byte) 0xe4, (byte) 0xee, (byte) 0x28};
+
+ byte[] alicePrivate = {(byte) 0xc8, (byte) 0x06, (byte) 0x43, (byte) 0x9d, (byte) 0xc9,
+ (byte) 0xd2, (byte) 0xc4, (byte) 0x76, (byte) 0xff, (byte) 0xed,
+ (byte) 0x8f, (byte) 0x25, (byte) 0x80, (byte) 0xc0, (byte) 0x88,
+ (byte) 0x8d, (byte) 0x58, (byte) 0xab, (byte) 0x40, (byte) 0x6b,
+ (byte) 0xf7, (byte) 0xae, (byte) 0x36, (byte) 0x98, (byte) 0x87,
+ (byte) 0x90, (byte) 0x21, (byte) 0xb9, (byte) 0x6b, (byte) 0xb4,
+ (byte) 0xbf, (byte) 0x59};
+
+ byte[] bobPublic = {(byte) 0x65, (byte) 0x36, (byte) 0x14, (byte) 0x99,
+ (byte) 0x3d, (byte) 0x2b, (byte) 0x15, (byte) 0xee, (byte) 0x9e,
+ (byte) 0x5f, (byte) 0xd3, (byte) 0xd8, (byte) 0x6c, (byte) 0xe7,
+ (byte) 0x19, (byte) 0xef, (byte) 0x4e, (byte) 0xc1, (byte) 0xda,
+ (byte) 0xae, (byte) 0x18, (byte) 0x86, (byte) 0xa8, (byte) 0x7b,
+ (byte) 0x3f, (byte) 0x5f, (byte) 0xa9, (byte) 0x56, (byte) 0x5a,
+ (byte) 0x27, (byte) 0xa2, (byte) 0x2f};
+
+ byte[] bobPrivate = {(byte) 0xb0, (byte) 0x3b, (byte) 0x34, (byte) 0xc3, (byte) 0x3a,
+ (byte) 0x1c, (byte) 0x44, (byte) 0xf2, (byte) 0x25, (byte) 0xb6,
+ (byte) 0x62, (byte) 0xd2, (byte) 0xbf, (byte) 0x48, (byte) 0x59,
+ (byte) 0xb8, (byte) 0x13, (byte) 0x54, (byte) 0x11, (byte) 0xfa,
+ (byte) 0x7b, (byte) 0x03, (byte) 0x86, (byte) 0xd4, (byte) 0x5f,
+ (byte) 0xb7, (byte) 0x5d, (byte) 0xc5, (byte) 0xb9, (byte) 0x1b,
+ (byte) 0x44, (byte) 0x66};
+
+ byte[] shared = {(byte) 0x32, (byte) 0x5f, (byte) 0x23, (byte) 0x93, (byte) 0x28,
+ (byte) 0x94, (byte) 0x1c, (byte) 0xed, (byte) 0x6e, (byte) 0x67,
+ (byte) 0x3b, (byte) 0x86, (byte) 0xba, (byte) 0x41, (byte) 0x01,
+ (byte) 0x74, (byte) 0x48, (byte) 0xe9, (byte) 0x9b, (byte) 0x64,
+ (byte) 0x9a, (byte) 0x9c, (byte) 0x38, (byte) 0x06, (byte) 0xc1,
+ (byte) 0xdd, (byte) 0x7c, (byte) 0xa4, (byte) 0xc4, (byte) 0x77,
+ (byte) 0xe6, (byte) 0x29};
+
+ byte[] sharedOne = getInstance().calculateAgreement(bobPublic, alicePrivate);
+ byte[] sharedTwo = getInstance().calculateAgreement(alicePublic, bobPrivate);
+
+ assertArrayEquals(sharedOne, shared);
+ assertArrayEquals(sharedTwo, shared);
+ }
+
+ public void testRandomAgreements() throws NoSuchAlgorithmException, NoSuchProviderException {
+ for (int i=0;i<50;i++) {
+ Curve25519KeyPair alice = getInstance().generateKeyPair();
+ Curve25519KeyPair bob = getInstance().generateKeyPair();
+
+ byte[] sharedAlice = getInstance().calculateAgreement(bob.getPublicKey(), alice.getPrivateKey());
+ byte[] sharedBob = getInstance().calculateAgreement(alice.getPublicKey(), bob.getPrivateKey());
+
+ assertArrayEquals(sharedAlice, sharedBob);
+ }
+ }
+
+ public void testSignature() throws NoSuchProviderException {
+ byte[] aliceIdentityPrivate = {(byte)0xc0, (byte)0x97, (byte)0x24, (byte)0x84, (byte)0x12,
+ (byte)0xe5, (byte)0x8b, (byte)0xf0, (byte)0x5d, (byte)0xf4,
+ (byte)0x87, (byte)0x96, (byte)0x82, (byte)0x05, (byte)0x13,
+ (byte)0x27, (byte)0x94, (byte)0x17, (byte)0x8e, (byte)0x36,
+ (byte)0x76, (byte)0x37, (byte)0xf5, (byte)0x81, (byte)0x8f,
+ (byte)0x81, (byte)0xe0, (byte)0xe6, (byte)0xce, (byte)0x73,
+ (byte)0xe8, (byte)0x65};
+
+ byte[] aliceIdentityPublic = {(byte)0xab, (byte)0x7e, (byte)0x71, (byte)0x7d,
+ (byte)0x4a, (byte)0x16, (byte)0x3b, (byte)0x7d, (byte)0x9a,
+ (byte)0x1d, (byte)0x80, (byte)0x71, (byte)0xdf, (byte)0xe9,
+ (byte)0xdc, (byte)0xf8, (byte)0xcd, (byte)0xcd, (byte)0x1c,
+ (byte)0xea, (byte)0x33, (byte)0x39, (byte)0xb6, (byte)0x35,
+ (byte)0x6b, (byte)0xe8, (byte)0x4d, (byte)0x88, (byte)0x7e,
+ (byte)0x32, (byte)0x2c, (byte)0x64};
+
+ byte[] aliceEphemeralPublic = {(byte)0x05, (byte)0xed, (byte)0xce, (byte)0x9d, (byte)0x9c,
+ (byte)0x41, (byte)0x5c, (byte)0xa7, (byte)0x8c, (byte)0xb7,
+ (byte)0x25, (byte)0x2e, (byte)0x72, (byte)0xc2, (byte)0xc4,
+ (byte)0xa5, (byte)0x54, (byte)0xd3, (byte)0xeb, (byte)0x29,
+ (byte)0x48, (byte)0x5a, (byte)0x0e, (byte)0x1d, (byte)0x50,
+ (byte)0x31, (byte)0x18, (byte)0xd1, (byte)0xa8, (byte)0x2d,
+ (byte)0x99, (byte)0xfb, (byte)0x4a};
+
+ byte[] aliceSignature = {(byte)0x5d, (byte)0xe8, (byte)0x8c, (byte)0xa9, (byte)0xa8,
+ (byte)0x9b, (byte)0x4a, (byte)0x11, (byte)0x5d, (byte)0xa7,
+ (byte)0x91, (byte)0x09, (byte)0xc6, (byte)0x7c, (byte)0x9c,
+ (byte)0x74, (byte)0x64, (byte)0xa3, (byte)0xe4, (byte)0x18,
+ (byte)0x02, (byte)0x74, (byte)0xf1, (byte)0xcb, (byte)0x8c,
+ (byte)0x63, (byte)0xc2, (byte)0x98, (byte)0x4e, (byte)0x28,
+ (byte)0x6d, (byte)0xfb, (byte)0xed, (byte)0xe8, (byte)0x2d,
+ (byte)0xeb, (byte)0x9d, (byte)0xcd, (byte)0x9f, (byte)0xae,
+ (byte)0x0b, (byte)0xfb, (byte)0xb8, (byte)0x21, (byte)0x56,
+ (byte)0x9b, (byte)0x3d, (byte)0x90, (byte)0x01, (byte)0xbd,
+ (byte)0x81, (byte)0x30, (byte)0xcd, (byte)0x11, (byte)0xd4,
+ (byte)0x86, (byte)0xce, (byte)0xf0, (byte)0x47, (byte)0xbd,
+ (byte)0x60, (byte)0xb8, (byte)0x6e, (byte)0x88};
+
+ if (!getInstance().verifySignature(aliceIdentityPublic, aliceEphemeralPublic, aliceSignature)) {
+ throw new AssertionError("Sig verification failed!");
+ }
+
+ for (int i=0;i
+
+ 4.0.0
+
+ org.whispersystems
+ curve25519
+ 0.6.0-SNAPSHOT
+ pom
+
+ curve25519
+
+
+ java
+
+
+
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index 314cf5e..0000000
--- a/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':java', ':android', ':j2me', ':common', ':tests'