diff --git a/address/pom.xml b/address/pom.xml
index 6dc9a255..69409f16 100644
--- a/address/pom.xml
+++ b/address/pom.xml
@@ -56,11 +56,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile
diff --git a/bitstring/pom.xml b/bitstring/pom.xml
index ca79b5b5..bc385f9a 100644
--- a/bitstring/pom.xml
+++ b/bitstring/pom.xml
@@ -67,11 +67,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile
diff --git a/cell/pom.xml b/cell/pom.xml
index fdb04aa1..0e3df682 100644
--- a/cell/pom.xml
+++ b/cell/pom.xml
@@ -79,11 +79,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile
diff --git a/pom.xml b/pom.xml
index 5130578a..7775b17e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,6 +20,7 @@
tl
emulator
liteclient
+ tweetnacl-java
diff --git a/smartcontract/pom.xml b/smartcontract/pom.xml
index 574f830e..ca962905 100644
--- a/smartcontract/pom.xml
+++ b/smartcontract/pom.xml
@@ -84,11 +84,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile
diff --git a/tonlib/pom.xml b/tonlib/pom.xml
index e3d77de5..c26f8356 100644
--- a/tonlib/pom.xml
+++ b/tonlib/pom.xml
@@ -72,11 +72,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile
net.java.dev.jna
diff --git a/tweetnacl-java/pom.xml b/tweetnacl-java/pom.xml
new file mode 100644
index 00000000..ee6b5225
--- /dev/null
+++ b/tweetnacl-java/pom.xml
@@ -0,0 +1,13 @@
+
+ 4.0.0
+
+ io.github.neodix42
+ top
+ 0.4.3
+
+
+ tweetnacl-java-8
+ 1.1.12
+ TON Java - tweetnacl-java-8
+
diff --git a/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNacl.java b/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNacl.java
new file mode 100644
index 00000000..67bbd1b9
--- /dev/null
+++ b/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNacl.java
@@ -0,0 +1,2423 @@
+// Copyright (c) 2014 Tom Zhou
+
+package com.iwebpp.crypto;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.util.concurrent.atomic.AtomicLong;
+
+
+/*
+ * @description
+ * TweetNacl.c Java porting
+ * */
+public final class TweetNacl {
+
+ private final static String TAG = "TweetNacl";
+
+ /*
+ * @description
+ * Box algorithm, Public-key authenticated encryption
+ * */
+ public static final class Box {
+
+ private final static String TAG = "Box";
+
+ private AtomicLong nonce;
+
+ private byte[] theirPublicKey;
+ private byte[] mySecretKey;
+ private byte[] sharedKey;
+
+ public Box(byte[] theirPublicKey, byte[] mySecretKey) {
+ this(theirPublicKey, mySecretKey, 68);
+ }
+
+ public Box(byte[] theirPublicKey, byte[] mySecretKey, long nonce) {
+ this.theirPublicKey = theirPublicKey;
+ this.mySecretKey = mySecretKey;
+
+ this.nonce = new AtomicLong(nonce);
+
+ // generate pre-computed shared key
+ before();
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce.set(nonce);
+ }
+
+ public long getNonce() {
+ return this.nonce.get();
+ }
+
+ public long incrNonce() {
+ return this.nonce.incrementAndGet();
+ }
+
+ private byte[] generateNonce() {
+ // generate nonce
+ long nonce = this.nonce.get();
+
+ byte[] n = new byte[nonceLength];
+ for (int i = 0; i < nonceLength; i += 8) {
+ n[i + 0] = (byte) (nonce >>> 0);
+ n[i + 1] = (byte) (nonce >>> 8);
+ n[i + 2] = (byte) (nonce >>> 16);
+ n[i + 3] = (byte) (nonce >>> 24);
+ n[i + 4] = (byte) (nonce >>> 32);
+ n[i + 5] = (byte) (nonce >>> 40);
+ n[i + 6] = (byte) (nonce >>> 48);
+ n[i + 7] = (byte) (nonce >>> 56);
+ }
+
+ return n;
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using peer's public key,
+ * our secret key, and the given nonce, which must be unique
+ * for each distinct message for a key pair.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.box.overheadLength longer than the original message.
+ * */
+ ///public byte_buf_t box(byte [] message) {
+ public byte[] box(byte[] message) {
+
+ return box(message, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using peer's public key,
+ * our secret key, and the explicitly provided nonce.
+ * Caller is responsible for ensuring that nonce is unique
+ * for each distinct message for a key pair.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.box.overheadLength longer than the original message.
+ * */
+ ///public byte_buf_t box(byte [] message) {
+ public byte[] box(byte[] message, byte[] theNonce) {
+
+ // check message
+ if (!(message != null && message.length > 0 &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // message buffer
+ byte[] m = new byte[message.length + zerobytesLength];
+
+ // cipher buffer
+ byte[] c = new byte[m.length];
+
+ for (int i = 0; i < message.length; i++)
+ m[i + zerobytesLength] = message[i];
+
+ if (0 != crypto_box(c, m, m.length, theNonce, theirPublicKey, mySecretKey))
+ return null;
+
+ // wrap byte_buf_t on c offset@boxzerobytesLength
+ ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
+ byte[] ret = new byte[c.length - boxzerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = c[i + boxzerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given box with peer's public key,
+ * our secret key, and the given nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box) {
+
+ return open(box, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given box with peer's public key,
+ * our secret key, and the explicitly provided nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box, byte[] theNonce) {
+ // check message
+ if (!(box != null && box.length > boxzerobytesLength &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // cipher buffer
+ byte[] c = new byte[box.length + boxzerobytesLength];
+
+ // message buffer
+ byte[] m = new byte[c.length];
+
+ for (int i = 0; i < box.length; i++)
+ c[i + boxzerobytesLength] = box[i];
+
+ if (0 != crypto_box_open(m, c, c.length, theNonce, theirPublicKey, mySecretKey))
+ return null;
+
+ // wrap byte_buf_t on m offset@zerobytesLength
+ ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
+ byte[] ret = new byte[m.length - zerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = m[i + zerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Returns a precomputed shared key
+ * which can be used in nacl.box.after and nacl.box.open.after.
+ * */
+ public byte[] before() {
+ if (this.sharedKey == null) {
+ this.sharedKey = new byte[sharedKeyLength];
+ crypto_box_beforenm(this.sharedKey, this.theirPublicKey, this.mySecretKey);
+ }
+
+ return this.sharedKey;
+ }
+
+ /*
+ * @description
+ * Same as nacl.box, but uses a shared key precomputed with nacl.box.before.
+ * */
+ public byte[] after(byte[] message) {
+
+ return after(message, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Same as nacl.box, but uses a shared key precomputed with nacl.box.before
+ * and explicitly provided nonce
+ * */
+ public byte[] after(byte[] message, byte[] theNonce) {
+ // check message
+ if (!(message != null && message.length > 0 &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // message buffer
+ byte[] m = new byte[message.length + zerobytesLength];
+
+ // cipher buffer
+ byte[] c = new byte[m.length];
+
+ for (int i = 0; i < message.length; i++)
+ m[i + zerobytesLength] = message[i];
+
+ if (0 != crypto_box_afternm(c, m, m.length, theNonce, sharedKey))
+ return null;
+
+ // wrap byte_buf_t on c offset@boxzerobytesLength
+ ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
+ byte[] ret = new byte[c.length - boxzerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = c[i + boxzerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Same as nacl.box.open,
+ * but uses a shared key pre-computed with nacl.box.before.
+ * */
+ public byte[] open_after(byte[] box) {
+
+ return open_after(box, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Same as nacl.box.open,
+ * but uses a shared key pre-computed with nacl.box.before,
+ * and explicitly passed nonce
+ * */
+ public byte[] open_after(byte[] box, byte[] theNonce) {
+ // check message
+ if (!(box != null && box.length > boxzerobytesLength &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // cipher buffer
+ byte[] c = new byte[box.length + boxzerobytesLength];
+
+ // message buffer
+ byte[] m = new byte[c.length];
+
+ for (int i = 0; i < box.length; i++)
+ c[i + boxzerobytesLength] = box[i];
+
+ if (crypto_box_open_afternm(m, c, c.length, theNonce, sharedKey) != 0)
+ return null;
+
+ // wrap byte_buf_t on m offset@zerobytesLength
+ ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
+ byte[] ret = new byte[m.length - zerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = m[i + zerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Length of public key in bytes.
+ * */
+ public static final int publicKeyLength = 32;
+
+ /*
+ * @description
+ * Length of secret key in bytes.
+ * */
+ public static final int secretKeyLength = 32;
+
+ /*
+ * @description
+ * Length of precomputed shared key in bytes.
+ * */
+ public static final int sharedKeyLength = 32;
+
+ /*
+ * @description
+ * Length of nonce in bytes.
+ * */
+ public static final int nonceLength = 24;
+
+ /*
+ * @description
+ * zero bytes in case box
+ * */
+ public static final int zerobytesLength = 32;
+ /*
+ * @description
+ * zero bytes in case open box
+ * */
+ public static final int boxzerobytesLength = 16;
+
+ /*
+ * @description
+ * Length of overhead added to box compared to original message.
+ * */
+ public static final int overheadLength = 16;
+
+ public static class KeyPair {
+ private byte[] publicKey;
+ private byte[] secretKey;
+
+ public KeyPair() {
+ publicKey = new byte[publicKeyLength];
+ secretKey = new byte[secretKeyLength];
+ }
+
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ public byte[] getSecretKey() {
+ return secretKey;
+ }
+ }
+
+ /*
+ * @description
+ * Generates a new random key pair for box and
+ * returns it as an object with publicKey and secretKey members:
+ * */
+ public static KeyPair keyPair() {
+ KeyPair kp = new KeyPair();
+
+ crypto_box_keypair(kp.getPublicKey(), kp.getSecretKey());
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSecretKey(byte[] secretKey) {
+ KeyPair kp = new KeyPair();
+ byte[] sk = kp.getSecretKey();
+ byte[] pk = kp.getPublicKey();
+
+ // copy sk
+ for (int i = 0; i < sk.length; i++)
+ sk[i] = secretKey[i];
+
+ crypto_scalarmult_base(pk, sk);
+ return kp;
+ }
+
+ }
+
+ /*
+ * @description
+ * Secret Box algorithm, secret key
+ * */
+ public static final class SecretBox {
+
+ private final static String TAG = "SecretBox";
+
+ private AtomicLong nonce;
+
+ private byte[] key;
+
+ public SecretBox(byte[] key) {
+ this(key, 68);
+ }
+
+ public SecretBox(byte[] key, long nonce) {
+ this.key = key;
+
+ this.nonce = new AtomicLong(nonce);
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce.set(nonce);
+ }
+
+ public long getNonce() {
+ return this.nonce.get();
+ }
+
+ public long incrNonce() {
+ return this.nonce.incrementAndGet();
+ }
+
+ private byte[] generateNonce() {
+ // generate nonce
+ long nonce = this.nonce.get();
+
+ byte[] n = new byte[nonceLength];
+ for (int i = 0; i < nonceLength; i += 8) {
+ n[i + 0] = (byte) (nonce >>> 0);
+ n[i + 1] = (byte) (nonce >>> 8);
+ n[i + 2] = (byte) (nonce >>> 16);
+ n[i + 3] = (byte) (nonce >>> 24);
+ n[i + 4] = (byte) (nonce >>> 32);
+ n[i + 5] = (byte) (nonce >>> 40);
+ n[i + 6] = (byte) (nonce >>> 48);
+ n[i + 7] = (byte) (nonce >>> 56);
+ }
+
+ return n;
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using the key and the nonce.
+ * The nonce must be unique for each distinct message for this key.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.secretbox.overheadLength longer than the original message.
+ * */
+ ///public byte_buf_t box(byte [] message) {
+ public byte[] box(byte[] message) {
+
+ return box(message, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using the key
+ * and the explicitly passed nonce.
+ * The nonce must be unique for each distinct message for this key.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.secretbox.overheadLength longer than the original message.
+ * */
+ ///public byte_buf_t box(byte [] message) {
+ public byte[] box(byte[] message, byte[] theNonce) {
+ // check message
+ if (!(message != null && message.length > 0 &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // message buffer
+ byte[] m = new byte[message.length + zerobytesLength];
+
+ // cipher buffer
+ byte[] c = new byte[m.length];
+
+ for (int i = 0; i < message.length; i++)
+ m[i + zerobytesLength] = message[i];
+
+ if (0 != crypto_secretbox(c, m, m.length, theNonce, key))
+ return null;
+
+ // TBD optimizing ...
+ // wrap byte_buf_t on c offset@boxzerobytesLength
+ ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
+ byte[] ret = new byte[c.length - boxzerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = c[i + boxzerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given secret box
+ * using the key and the nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box) {
+
+ return open(box, generateNonce());
+
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given secret box
+ * using the key and the explicitly passed nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box, byte[] theNonce) {
+ // check message
+ if (!(box != null && box.length > boxzerobytesLength &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // cipher buffer
+ byte[] c = new byte[box.length + boxzerobytesLength];
+
+ // message buffer
+ byte[] m = new byte[c.length];
+
+ for (int i = 0; i < box.length; i++)
+ c[i + boxzerobytesLength] = box[i];
+
+ if (0 != crypto_secretbox_open(m, c, c.length, theNonce, key))
+ return null;
+
+ // wrap byte_buf_t on m offset@zerobytesLength
+ ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
+ byte[] ret = new byte[m.length - zerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = m[i + zerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Length of key in bytes.
+ * */
+ public static final int keyLength = 32;
+
+ /*
+ * @description
+ * Length of nonce in bytes.
+ * */
+ public static final int nonceLength = 24;
+
+ /*
+ * @description
+ * Length of overhead added to secret box compared to original message.
+ * */
+ public static final int overheadLength = 16;
+
+ /*
+ * @description
+ * zero bytes in case box
+ * */
+ public static final int zerobytesLength = 32;
+ /*
+ * @description
+ * zero bytes in case open box
+ * */
+ public static final int boxzerobytesLength = 16;
+
+ }
+
+ /*
+ * @description
+ * Scalar multiplication, Implements curve25519.
+ * */
+ public static final class ScalarMult {
+
+ private final static String TAG = "ScalarMult";
+
+ /*
+ * @description
+ * Multiplies an integer n by a group element p and
+ * returns the resulting group element.
+ * */
+ public static byte[] scalseMult(byte[] n, byte[] p) {
+ if (!(n.length == scalarLength && p.length == groupElementLength))
+ return null;
+
+ byte[] q = new byte[scalarLength];
+
+ crypto_scalarmult(q, n, p);
+
+ return q;
+ }
+
+ /*
+ * @description
+ * Multiplies an integer n by a standard group element and
+ * returns the resulting group element.
+ * */
+ public static byte[] scalseMult_base(byte[] n) {
+ if (!(n.length == scalarLength))
+ return null;
+
+ byte[] q = new byte[scalarLength];
+
+ crypto_scalarmult_base(q, n);
+
+ return q;
+ }
+
+ /*
+ * @description
+ * Length of scalar in bytes.
+ * */
+ public static final int scalarLength = 32;
+
+ /*
+ * @description
+ * Length of group element in bytes.
+ * */
+ public static final int groupElementLength = 32;
+
+ }
+
+
+ /*
+ * @description
+ * Hash algorithm, Implements SHA-512.
+ * */
+ public static final class Hash {
+
+ private final static String TAG = "Hash";
+
+ /*
+ * @description
+ * Returns SHA-512 hash of the message.
+ * */
+ public static byte[] sha512(byte[] message) {
+ if (!(message != null && message.length > 0))
+ return null;
+
+ byte[] out = new byte[hashLength];
+
+ crypto_hash(out, message);
+
+ return out;
+ }
+
+ public static byte[] sha512(String message) throws UnsupportedEncodingException {
+ return sha512(message.getBytes("utf-8"));
+ }
+
+ /*
+ * @description
+ * Length of hash in bytes.
+ * */
+ public static final int hashLength = 64;
+
+ }
+
+
+ /*
+ * @description
+ * Signature algorithm, Implements ed25519.
+ * */
+ public static final class Signature {
+
+ private final static String TAG = "Signature";
+
+ private byte[] theirPublicKey;
+ private byte[] mySecretKey;
+
+ public Signature(byte[] theirPublicKey, byte[] mySecretKey) {
+ this.theirPublicKey = theirPublicKey;
+ this.mySecretKey = mySecretKey;
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signed message.
+ * */
+ public byte[] sign(byte[] message) {
+ // signed message
+ byte[] sm = new byte[message.length + signatureLength];
+
+ crypto_sign(sm, -1, message, message.length, mySecretKey);
+
+ return sm;
+ }
+
+ /*
+ * @description
+ * Verifies the signed message and returns the message without signature.
+ * Returns null if verification failed.
+ * */
+ public byte[] open(byte[] signedMessage) {
+ // check sm length
+ if (!(signedMessage != null && signedMessage.length > signatureLength))
+ return null;
+
+ // temp buffer
+ byte[] tmp = new byte[signedMessage.length];
+
+ if (0 != crypto_sign_open(tmp, -1, signedMessage, signedMessage.length, theirPublicKey))
+ return null;
+
+ // message
+ byte[] msg = new byte[signedMessage.length - signatureLength];
+ for (int i = 0; i < msg.length; i++)
+ msg[i] = signedMessage[i + signatureLength];
+
+ return msg;
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signature.
+ * */
+ public byte[] detached(byte[] message) {
+ byte[] signedMsg = this.sign(message);
+ byte[] sig = new byte[signatureLength];
+ for (int i = 0; i < sig.length; i++)
+ sig[i] = signedMsg[i];
+ return sig;
+ }
+
+ /*
+ * @description
+ * Verifies the signature for the message and
+ * returns true if verification succeeded or false if it failed.
+ * */
+ public boolean detached_verify(byte[] message, byte[] signature) {
+ if (signature.length != signatureLength)
+ return false;
+ if (theirPublicKey.length != publicKeyLength)
+ return false;
+ byte[] sm = new byte[signatureLength + message.length];
+ byte[] m = new byte[signatureLength + message.length];
+ for (int i = 0; i < signatureLength; i++)
+ sm[i] = signature[i];
+ for (int i = 0; i < message.length; i++)
+ sm[i + signatureLength] = message[i];
+ return (crypto_sign_open(m, -1, sm, sm.length, theirPublicKey) >= 0);
+ }
+
+ /*
+ * @description
+ * Generates new random key pair for signing and
+ * returns it as an object with publicKey and secretKey members
+ * */
+ public static class KeyPair {
+ private byte[] publicKey;
+ private byte[] secretKey;
+
+ public KeyPair() {
+ publicKey = new byte[publicKeyLength];
+ secretKey = new byte[secretKeyLength];
+ }
+
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ public byte[] getSecretKey() {
+ return secretKey;
+ }
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signed message.
+ * */
+ public static KeyPair keyPair() {
+ KeyPair kp = new KeyPair();
+
+ crypto_sign_keypair(kp.getPublicKey(), kp.getSecretKey(), false);
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSecretKey(byte[] secretKey) {
+ KeyPair kp = new KeyPair();
+ byte[] pk = kp.getPublicKey();
+ byte[] sk = kp.getSecretKey();
+
+ // copy sk
+ for (int i = 0; i < kp.getSecretKey().length; i++)
+ sk[i] = secretKey[i];
+
+ // copy pk from sk
+ for (int i = 0; i < kp.getPublicKey().length; i++)
+ pk[i] = secretKey[32 + i]; // hard-copy
+
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSeed(byte[] seed) {
+ KeyPair kp = new KeyPair();
+ byte[] pk = kp.getPublicKey();
+ byte[] sk = kp.getSecretKey();
+
+ // copy sk
+ for (int i = 0; i < seedLength; i++)
+ sk[i] = seed[i];
+
+ // generate pk from sk
+ crypto_sign_keypair(pk, sk, true);
+
+ return kp;
+ }
+
+ /*
+ * @description
+ * Length of signing public key in bytes.
+ * */
+ public static final int publicKeyLength = 32;
+
+ /*
+ * @description
+ * Length of signing secret key in bytes.
+ * */
+ public static final int secretKeyLength = 64;
+
+ /*
+ * @description
+ * Length of seed for nacl.sign.keyPair.fromSeed in bytes.
+ * */
+ public static final int seedLength = 32;
+
+ /*
+ * @description
+ * Length of signature in bytes.
+ * */
+ public static final int signatureLength = 64;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ /*
+ * @description
+ * Codes below are ported from TweetNacl.c/TweetNacl.h
+ * */
+
+ private static final byte[] _0 = new byte[16];
+ private static final byte[] _9 = new byte[32];
+
+ static {
+ for (int i = 0; i < _0.length; i++) _0[i] = 0;
+
+ for (int i = 0; i < _9.length; i++) _9[i] = 0;
+ _9[0] = 9;
+ }
+
+ private static final long[] gf0 = new long[16];
+ private static final long[] gf1 = new long[16];
+ private static final long[] _121665 = new long[16];
+
+ static {
+ for (int i = 0; i < gf0.length; i++) gf0[i] = 0;
+
+ for (int i = 0; i < gf1.length; i++) gf1[i] = 0;
+ gf1[0] = 1;
+
+ for (int i = 0; i < _121665.length; i++) _121665[i] = 0;
+ _121665[0] = 0xDB41;
+ _121665[1] = 1;
+ }
+
+ private static final long[] D = new long[]{
+ 0x78a3, 0x1359, 0x4dca, 0x75eb,
+ 0xd8ab, 0x4141, 0x0a4d, 0x0070,
+ 0xe898, 0x7779, 0x4079, 0x8cc7,
+ 0xfe73, 0x2b6f, 0x6cee, 0x5203
+ };
+ private static final long[] D2 = new long[]{
+ 0xf159, 0x26b2, 0x9b94, 0xebd6,
+ 0xb156, 0x8283, 0x149a, 0x00e0,
+ 0xd130, 0xeef3, 0x80f2, 0x198e,
+ 0xfce7, 0x56df, 0xd9dc, 0x2406
+ };
+ private static final long[] X = new long[]{
+ 0xd51a, 0x8f25, 0x2d60, 0xc956,
+ 0xa7b2, 0x9525, 0xc760, 0x692c,
+ 0xdc5c, 0xfdd6, 0xe231, 0xc0a4,
+ 0x53fe, 0xcd6e, 0x36d3, 0x2169
+ };
+ private static final long[] Y = new long[]{
+ 0x6658, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666
+ };
+ private static final long[] I = new long[]{
+ 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee,
+ 0xe478, 0xad2f, 0x1806, 0x2f43,
+ 0xd7a7, 0x3dfb, 0x0099, 0x2b4d,
+ 0xdf0b, 0x4fc1, 0x2480, 0x2b83
+ };
+
+ private static int L32(int x, int c) {
+ return (x << c) | ((x & 0xffffffff) >>> (32 - c));
+ }
+
+ private static int ld32(byte[] x, final int xoff, final int xlen) {
+ int u = (x[3 + xoff] & 0xff);
+ u = (u << 8) | (x[2 + xoff] & 0xff);
+ u = (u << 8) | (x[1 + xoff] & 0xff);
+ return (u << 8) | (x[0 + xoff] & 0xff);
+ }
+
+ private static long dl64(byte[] x, final int xoff, final int xlen) {
+ int i;
+ long u = 0;
+ for (i = 0; i < 8; i++) u = (u << 8) | (x[i + xoff] & 0xff);
+ return u;
+ }
+
+ private static void st32(byte[] x, final int xoff, final int xlen, int u) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ x[i + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ }
+ }
+
+ private static void ts64(byte[] x, final int xoff, final int xlen, long u) {
+ int i;
+ for (i = 7; i >= 0; --i) {
+ x[i + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ }
+ }
+
+ private static int vn(
+ byte[] x, final int xoff, final int xlen,
+ byte[] y, final int yoff, final int ylen,
+ int n) {
+ int i, d = 0;
+ for (i = 0; i < n; i++) d |= (x[i + xoff] ^ y[i + yoff]) & 0xff;
+ return (1 & ((d - 1) >>> 8)) - 1;
+ }
+
+ private static int crypto_verify_16(
+ byte[] x, final int xoff, final int xlen,
+ byte[] y, final int yoff, final int ylen) {
+ return vn(x, xoff, xlen, y, yoff, ylen, 16);
+ }
+
+ public static int crypto_verify_16(byte[] x, byte[] y) {
+ return crypto_verify_16(x, 0, x.length, y, 0, y.length);
+ }
+
+ private static int crypto_verify_32(
+ byte[] x, final int xoff, final int xlen,
+ byte[] y, final int yoff, final int ylen) {
+ return vn(x, xoff, xlen, y, yoff, ylen, 32);
+ }
+
+ public static int crypto_verify_32(byte[] x, byte[] y) {
+ return crypto_verify_32(x, 0, x.length, y, 0, y.length);
+ }
+
+ private static void core(byte[] out, byte[] in, byte[] k, byte[] c, int h) {
+ int[] w = new int[16], x = new int[16], y = new int[16], t = new int[4];
+ int i, j, m;
+
+ for (i = 0; i < 4; i++) {
+ x[5 * i] = ld32(c, 4 * i, 4);
+ x[1 + i] = ld32(k, 4 * i, 4);
+ x[6 + i] = ld32(in, 4 * i, 4);
+ x[11 + i] = ld32(k, 16 + 4 * i, 4);
+ }
+
+ for (i = 0; i < 16; i++) y[i] = x[i];
+
+ for (i = 0; i < 20; i++) {
+ for (j = 0; j < 4; j++) {
+ for (m = 0; m < 4; m++) t[m] = x[(5 * j + 4 * m) % 16];
+ t[1] ^= L32(t[0] + t[3], 7);
+ t[2] ^= L32(t[1] + t[0], 9);
+ t[3] ^= L32(t[2] + t[1], 13);
+ t[0] ^= L32(t[3] + t[2], 18);
+ for (m = 0; m < 4; m++) w[4 * j + (j + m) % 4] = t[m];
+ }
+ for (m = 0; m < 16; m++) x[m] = w[m];
+ }
+
+ if (h != 0) {
+ for (i = 0; i < 16; i++) x[i] += y[i];
+ for (i = 0; i < 4; i++) {
+ x[5 * i] -= ld32(c, 4 * i, 4);
+ x[6 + i] -= ld32(in, 4 * i, 4);
+ }
+ for (i = 0; i < 4; i++) {
+ st32(out, 4 * i, 4, x[5 * i]);
+ st32(out, 16 + 4 * i, 4, x[6 + i]);
+ }
+ } else
+ for (i = 0; i < 16; i++) st32(out, 4 * i, 4, x[i] + y[i]);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
+ ///L/og.d(TAG, "core -> "+dbgt);
+ }
+
+ public static int crypto_core_salsa20(byte[] out, byte[] in, byte[] k, byte[] c) {
+ core(out, in, k, c, 0);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
+ ///L/og.d(TAG, "crypto_core_salsa20 -> "+dbgt);
+
+ return 0;
+ }
+
+ public static int crypto_core_hsalsa20(byte[] out, byte[] in, byte[] k, byte[] c) {
+ core(out, in, k, c, 1);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
+ ///L/og.d(TAG, "crypto_core_hsalsa20 -> "+dbgt);
+
+ return 0;
+ }
+
+ private static final byte[] sigma = {101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107};
+ /*static {
+ try {
+ sigma = "expand 32-byte k".getBytes("utf-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }*/
+
+ private static int crypto_stream_salsa20_xor(byte[] c, byte[] m, long b, byte[] n, final int noff, final int nlen, byte[] k) {
+ byte[] z = new byte[16], x = new byte[64];
+ int u, i;
+ if (0 == b) return 0;
+
+ for (i = 0; i < 16; i++) z[i] = 0;
+ for (i = 0; i < 8; i++) z[i] = n[i + noff];
+
+ int coffset = 0;
+ int moffset = 0;
+ while (b >= 64) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < 64; i++) c[i + coffset] = (byte) (((m != null ? m[i + moffset] : 0) ^ x[i]) & 0xff);
+ u = 1;
+ for (i = 8; i < 16; ++i) {
+ u += (int) (z[i] & 0xff);
+ z[i] = (byte) (u & 0xff);
+ u >>>= 8;
+ }
+ b -= 64;
+ coffset += 64;
+ if (m != null) moffset += 64;
+ }
+ if (b != 0) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < b; i++) c[i + coffset] = (byte) (((m != null ? m[i + moffset] : 0) ^ x[i]) & 0xff);
+ }
+ return 0;
+ }
+
+ public static int crypto_stream_salsa20_xor(byte[] c, byte[] m, long b, byte[] n, byte[] k) {
+ return crypto_stream_salsa20_xor(c, m, b, n, 0, n.length, k);
+ }
+
+ private static int crypto_stream_salsa20(byte[] c, long d, byte[] n, final int noff, final int nlen, byte[] k) {
+ return crypto_stream_salsa20_xor(c, null, d, n, noff, nlen, k);
+ }
+
+ public static int crypto_stream_salsa20(byte[] c, long d, byte[] n, byte[] k) {
+ return crypto_stream_salsa20(c, d, n, 0, n.length, k);
+ }
+
+ public static int crypto_stream(byte[] c, long d, byte[] n, byte[] k) {
+ byte[] s = new byte[32];
+ crypto_core_hsalsa20(s, n, k, sigma);
+ return crypto_stream_salsa20(c, d, n, 16, n.length - 16, s);
+ }
+
+ public static int crypto_stream_xor(byte[] c, byte[] m, long d, byte[] n, byte[] k) {
+ byte[] s = new byte[32];
+ crypto_core_hsalsa20(s, n, k, sigma);
+ return crypto_stream_salsa20_xor(c, m, d, n, 16, n.length - 16, s);
+ }
+
+/* !!! Use TweetNaclFast.java onetimeauth function
+ private static void add1305(int [] h,int [] c)
+ {
+ int j;
+ int u = 0;
+ for (j = 0; j < 17; j ++) {
+ u = (u + ((h[j] + c[j]) | 0)) | 0;
+ h[j] = u & 255;
+ u >>>= 8;
+ }
+ }
+
+ private final static int minusp[] = { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 };
+
+ private static int crypto_onetimeauth(
+ byte[] out,final int outoff,final int outlen,
+ byte[] m,final int moff,final int mlen,
+ long n,
+ byte [] k)
+ {
+ int i,j;
+ int s,u;
+ int [] x = new int[17], r = new int [17],
+ h = new int[17], c = new int [17], g = new int[17];
+
+ for (j = 0; j < 17; j ++) r[j] = h[j] = 0;
+
+ for (j = 0; j < 16; j ++) r[j] = k[j] & 0xff;
+
+ r[3]&=15;
+ r[4]&=252;
+ r[7]&=15;
+ r[8]&=252;
+ r[11]&=15;
+ r[12]&=252;
+ r[15]&=15;
+
+ int moffset = moff;
+ while (n > 0) {
+ for (j = 0; j < 17; j ++) c[j] = 0;
+ for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j+moffset] & 0xff;
+ c[j] = 1;
+
+ moffset += j;
+
+ n -= j;
+ add1305(h,c);
+ for (i = 0; i < 17; i ++) {
+ x[i] = 0;
+ for (j = 0; j < 17; j ++) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]);
+ for (j = 0; j < 17; j++) x[i] = (x[i] + (h[j] * ((j <= i) ? r[i - j] : ((320 * r[i + 17 - j])|0))) | 0) | 0;
+ }
+ for (i = 0; i < 17; i ++) h[i] = x[i];
+ u = 0;
+ for (j = 0; j < 16; j ++) {
+ u = (u + h[j]) | 0;
+ h[j] = u & 255;
+ u >>>= 8;
+ }
+ u = (u + h[16]) | 0; h[16] = u & 3;
+ u = (5 * (u >>> 2)) | 0;
+ for (j = 0; j < 16; j ++) {
+ u = (u + h[j]) | 0;
+ h[j] = u & 255;
+ u >>>= 8;
+ }
+ u = (u + h[16]) | 0; h[16] = u;
+ }
+
+ for (j = 0; j < 17; j ++) g[j] = h[j];
+ add1305(h,minusp);
+ s = (-(h[16] >>> 7) | 0);
+ for (j = 0; j < 17; j ++) h[j] ^= s & (g[j] ^ h[j]);
+
+ for (j = 0; j < 16; j ++) c[j] = k[j + 16] & 0xff;
+ c[16] = 0;
+ add1305(h,c);
+ for (j = 0; j < 16; j ++) out[j+outoff] = (byte) (h[j]&0xff);
+
+ return 0;
+ }*/
+
+ /*
+ * Port of Andrew Moon's Poly1305-donna-16. Public domain.
+ * https://github.com/floodyberry/poly1305-donna
+ */
+ public static final class poly1305 {
+
+ private byte[] buffer;
+ private int[] r;
+ private int[] h;
+ private int[] pad;
+ private int leftover;
+ private int fin;
+
+ public poly1305(byte[] key) {
+ this.buffer = new byte[16];
+ this.r = new int[10];
+ this.h = new int[10];
+ this.pad = new int[8];
+ this.leftover = 0;
+ this.fin = 0;
+
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ t0 = key[0] & 0xff | (key[1] & 0xff) << 8;
+ this.r[0] = (t0) & 0x1fff;
+ t1 = key[2] & 0xff | (key[3] & 0xff) << 8;
+ this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
+ t2 = key[4] & 0xff | (key[5] & 0xff) << 8;
+ this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;
+ t3 = key[6] & 0xff | (key[7] & 0xff) << 8;
+ this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
+ t4 = key[8] & 0xff | (key[9] & 0xff) << 8;
+ this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;
+ this.r[5] = ((t4 >>> 1)) & 0x1ffe;
+ t5 = key[10] & 0xff | (key[11] & 0xff) << 8;
+ this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
+ t6 = key[12] & 0xff | (key[13] & 0xff) << 8;
+ this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;
+ t7 = key[14] & 0xff | (key[15] & 0xff) << 8;
+ this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
+ this.r[9] = ((t7 >>> 5)) & 0x007f;
+
+ this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8;
+ this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8;
+ this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8;
+ this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8;
+ this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8;
+ this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8;
+ this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8;
+ this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8;
+ }
+
+ public poly1305 blocks(byte[] m, int mpos, int bytes) {
+ int hibit = this.fin != 0 ? 0 : (1 << 11);
+ int t0, t1, t2, t3, t4, t5, t6, t7, c;
+ int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9;
+
+ int h0 = this.h[0],
+ h1 = this.h[1],
+ h2 = this.h[2],
+ h3 = this.h[3],
+ h4 = this.h[4],
+ h5 = this.h[5],
+ h6 = this.h[6],
+ h7 = this.h[7],
+ h8 = this.h[8],
+ h9 = this.h[9];
+
+ int r0 = this.r[0],
+ r1 = this.r[1],
+ r2 = this.r[2],
+ r3 = this.r[3],
+ r4 = this.r[4],
+ r5 = this.r[5],
+ r6 = this.r[6],
+ r7 = this.r[7],
+ r8 = this.r[8],
+ r9 = this.r[9];
+
+ while (bytes >= 16) {
+ t0 = m[mpos + 0] & 0xff | (m[mpos + 1] & 0xff) << 8;
+ h0 += (t0) & 0x1fff;
+ t1 = m[mpos + 2] & 0xff | (m[mpos + 3] & 0xff) << 8;
+ h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
+ t2 = m[mpos + 4] & 0xff | (m[mpos + 5] & 0xff) << 8;
+ h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff;
+ t3 = m[mpos + 6] & 0xff | (m[mpos + 7] & 0xff) << 8;
+ h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
+ t4 = m[mpos + 8] & 0xff | (m[mpos + 9] & 0xff) << 8;
+ h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff;
+ h5 += ((t4 >>> 1)) & 0x1fff;
+ t5 = m[mpos + 10] & 0xff | (m[mpos + 11] & 0xff) << 8;
+ h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
+ t6 = m[mpos + 12] & 0xff | (m[mpos + 13] & 0xff) << 8;
+ h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff;
+ t7 = m[mpos + 14] & 0xff | (m[mpos + 15] & 0xff) << 8;
+ h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
+ h9 += ((t7 >>> 5)) | hibit;
+
+ c = 0;
+
+ d0 = c;
+ d0 += h0 * r0;
+ d0 += h1 * (5 * r9);
+ d0 += h2 * (5 * r8);
+ d0 += h3 * (5 * r7);
+ d0 += h4 * (5 * r6);
+ c = (d0 >>> 13);
+ d0 &= 0x1fff;
+ d0 += h5 * (5 * r5);
+ d0 += h6 * (5 * r4);
+ d0 += h7 * (5 * r3);
+ d0 += h8 * (5 * r2);
+ d0 += h9 * (5 * r1);
+ c += (d0 >>> 13);
+ d0 &= 0x1fff;
+
+ d1 = c;
+ d1 += h0 * r1;
+ d1 += h1 * r0;
+ d1 += h2 * (5 * r9);
+ d1 += h3 * (5 * r8);
+ d1 += h4 * (5 * r7);
+ c = (d1 >>> 13);
+ d1 &= 0x1fff;
+ d1 += h5 * (5 * r6);
+ d1 += h6 * (5 * r5);
+ d1 += h7 * (5 * r4);
+ d1 += h8 * (5 * r3);
+ d1 += h9 * (5 * r2);
+ c += (d1 >>> 13);
+ d1 &= 0x1fff;
+
+ d2 = c;
+ d2 += h0 * r2;
+ d2 += h1 * r1;
+ d2 += h2 * r0;
+ d2 += h3 * (5 * r9);
+ d2 += h4 * (5 * r8);
+ c = (d2 >>> 13);
+ d2 &= 0x1fff;
+ d2 += h5 * (5 * r7);
+ d2 += h6 * (5 * r6);
+ d2 += h7 * (5 * r5);
+ d2 += h8 * (5 * r4);
+ d2 += h9 * (5 * r3);
+ c += (d2 >>> 13);
+ d2 &= 0x1fff;
+
+ d3 = c;
+ d3 += h0 * r3;
+ d3 += h1 * r2;
+ d3 += h2 * r1;
+ d3 += h3 * r0;
+ d3 += h4 * (5 * r9);
+ c = (d3 >>> 13);
+ d3 &= 0x1fff;
+ d3 += h5 * (5 * r8);
+ d3 += h6 * (5 * r7);
+ d3 += h7 * (5 * r6);
+ d3 += h8 * (5 * r5);
+ d3 += h9 * (5 * r4);
+ c += (d3 >>> 13);
+ d3 &= 0x1fff;
+
+ d4 = c;
+ d4 += h0 * r4;
+ d4 += h1 * r3;
+ d4 += h2 * r2;
+ d4 += h3 * r1;
+ d4 += h4 * r0;
+ c = (d4 >>> 13);
+ d4 &= 0x1fff;
+ d4 += h5 * (5 * r9);
+ d4 += h6 * (5 * r8);
+ d4 += h7 * (5 * r7);
+ d4 += h8 * (5 * r6);
+ d4 += h9 * (5 * r5);
+ c += (d4 >>> 13);
+ d4 &= 0x1fff;
+
+ d5 = c;
+ d5 += h0 * r5;
+ d5 += h1 * r4;
+ d5 += h2 * r3;
+ d5 += h3 * r2;
+ d5 += h4 * r1;
+ c = (d5 >>> 13);
+ d5 &= 0x1fff;
+ d5 += h5 * r0;
+ d5 += h6 * (5 * r9);
+ d5 += h7 * (5 * r8);
+ d5 += h8 * (5 * r7);
+ d5 += h9 * (5 * r6);
+ c += (d5 >>> 13);
+ d5 &= 0x1fff;
+
+ d6 = c;
+ d6 += h0 * r6;
+ d6 += h1 * r5;
+ d6 += h2 * r4;
+ d6 += h3 * r3;
+ d6 += h4 * r2;
+ c = (d6 >>> 13);
+ d6 &= 0x1fff;
+ d6 += h5 * r1;
+ d6 += h6 * r0;
+ d6 += h7 * (5 * r9);
+ d6 += h8 * (5 * r8);
+ d6 += h9 * (5 * r7);
+ c += (d6 >>> 13);
+ d6 &= 0x1fff;
+
+ d7 = c;
+ d7 += h0 * r7;
+ d7 += h1 * r6;
+ d7 += h2 * r5;
+ d7 += h3 * r4;
+ d7 += h4 * r3;
+ c = (d7 >>> 13);
+ d7 &= 0x1fff;
+ d7 += h5 * r2;
+ d7 += h6 * r1;
+ d7 += h7 * r0;
+ d7 += h8 * (5 * r9);
+ d7 += h9 * (5 * r8);
+ c += (d7 >>> 13);
+ d7 &= 0x1fff;
+
+ d8 = c;
+ d8 += h0 * r8;
+ d8 += h1 * r7;
+ d8 += h2 * r6;
+ d8 += h3 * r5;
+ d8 += h4 * r4;
+ c = (d8 >>> 13);
+ d8 &= 0x1fff;
+ d8 += h5 * r3;
+ d8 += h6 * r2;
+ d8 += h7 * r1;
+ d8 += h8 * r0;
+ d8 += h9 * (5 * r9);
+ c += (d8 >>> 13);
+ d8 &= 0x1fff;
+
+ d9 = c;
+ d9 += h0 * r9;
+ d9 += h1 * r8;
+ d9 += h2 * r7;
+ d9 += h3 * r6;
+ d9 += h4 * r5;
+ c = (d9 >>> 13);
+ d9 &= 0x1fff;
+ d9 += h5 * r4;
+ d9 += h6 * r3;
+ d9 += h7 * r2;
+ d9 += h8 * r1;
+ d9 += h9 * r0;
+ c += (d9 >>> 13);
+ d9 &= 0x1fff;
+
+ c = (((c << 2) + c)) | 0;
+ c = (c + d0) | 0;
+ d0 = c & 0x1fff;
+ c = (c >>> 13);
+ d1 += c;
+
+ h0 = d0;
+ h1 = d1;
+ h2 = d2;
+ h3 = d3;
+ h4 = d4;
+ h5 = d5;
+ h6 = d6;
+ h7 = d7;
+ h8 = d8;
+ h9 = d9;
+
+ mpos += 16;
+ bytes -= 16;
+ }
+ this.h[0] = h0;
+ this.h[1] = h1;
+ this.h[2] = h2;
+ this.h[3] = h3;
+ this.h[4] = h4;
+ this.h[5] = h5;
+ this.h[6] = h6;
+ this.h[7] = h7;
+ this.h[8] = h8;
+ this.h[9] = h9;
+
+ return this;
+ }
+
+ public poly1305 finish(byte[] mac, int macpos) {
+ int[] g = new int[10];
+ int c, mask, f, i;
+
+ if (this.leftover != 0) {
+ i = this.leftover;
+ this.buffer[i++] = 1;
+ for (; i < 16; i++) this.buffer[i] = 0;
+ this.fin = 1;
+ this.blocks(this.buffer, 0, 16);
+ }
+
+ c = this.h[1] >>> 13;
+ this.h[1] &= 0x1fff;
+ for (i = 2; i < 10; i++) {
+ this.h[i] += c;
+ c = this.h[i] >>> 13;
+ this.h[i] &= 0x1fff;
+ }
+ this.h[0] += (c * 5);
+ c = this.h[0] >>> 13;
+ this.h[0] &= 0x1fff;
+ this.h[1] += c;
+ c = this.h[1] >>> 13;
+ this.h[1] &= 0x1fff;
+ this.h[2] += c;
+
+ g[0] = this.h[0] + 5;
+ c = g[0] >>> 13;
+ g[0] &= 0x1fff;
+ for (i = 1; i < 10; i++) {
+ g[i] = this.h[i] + c;
+ c = g[i] >>> 13;
+ g[i] &= 0x1fff;
+ }
+ g[9] -= (1 << 13);
+ g[9] &= 0xffff;
+
+ mask = (g[9] >>> ((2 * 8) - 1)) - 1;
+ mask &= 0xffff;
+ for (i = 0; i < 10; i++) g[i] &= mask;
+ mask = ~mask;
+ for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i];
+
+ this.h[0] = ((this.h[0]) | (this.h[1] << 13)) & 0xffff;
+ this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10)) & 0xffff;
+ this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7)) & 0xffff;
+ this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4)) & 0xffff;
+ this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff;
+ this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11)) & 0xffff;
+ this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8)) & 0xffff;
+ this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff;
+
+ f = this.h[0] + this.pad[0];
+ this.h[0] = f & 0xffff;
+ for (i = 1; i < 8; i++) {
+ f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0;
+ this.h[i] = f & 0xffff;
+ }
+
+ mac[macpos + 0] = (byte) ((this.h[0] >>> 0) & 0xff);
+ mac[macpos + 1] = (byte) ((this.h[0] >>> 8) & 0xff);
+ mac[macpos + 2] = (byte) ((this.h[1] >>> 0) & 0xff);
+ mac[macpos + 3] = (byte) ((this.h[1] >>> 8) & 0xff);
+ mac[macpos + 4] = (byte) ((this.h[2] >>> 0) & 0xff);
+ mac[macpos + 5] = (byte) ((this.h[2] >>> 8) & 0xff);
+ mac[macpos + 6] = (byte) ((this.h[3] >>> 0) & 0xff);
+ mac[macpos + 7] = (byte) ((this.h[3] >>> 8) & 0xff);
+ mac[macpos + 8] = (byte) ((this.h[4] >>> 0) & 0xff);
+ mac[macpos + 9] = (byte) ((this.h[4] >>> 8) & 0xff);
+ mac[macpos + 10] = (byte) ((this.h[5] >>> 0) & 0xff);
+ mac[macpos + 11] = (byte) ((this.h[5] >>> 8) & 0xff);
+ mac[macpos + 12] = (byte) ((this.h[6] >>> 0) & 0xff);
+ mac[macpos + 13] = (byte) ((this.h[6] >>> 8) & 0xff);
+ mac[macpos + 14] = (byte) ((this.h[7] >>> 0) & 0xff);
+ mac[macpos + 15] = (byte) ((this.h[7] >>> 8) & 0xff);
+
+ return this;
+ }
+
+ public poly1305 update(byte[] m, int mpos, int bytes) {
+ int i, want;
+
+ if (this.leftover != 0) {
+ want = (16 - this.leftover);
+ if (want > bytes)
+ want = bytes;
+ for (i = 0; i < want; i++)
+ this.buffer[this.leftover + i] = m[mpos + i];
+ bytes -= want;
+ mpos += want;
+ this.leftover += want;
+ if (this.leftover < 16)
+ return this;
+ this.blocks(buffer, 0, 16);
+ this.leftover = 0;
+ }
+
+ if (bytes >= 16) {
+ want = bytes - (bytes % 16);
+ this.blocks(m, mpos, want);
+ mpos += want;
+ bytes -= want;
+ }
+
+ if (bytes != 0) {
+ for (i = 0; i < bytes; i++)
+ this.buffer[this.leftover + i] = m[mpos + i];
+ this.leftover += bytes;
+ }
+
+ return this;
+ }
+
+ }
+
+ private static int crypto_onetimeauth(
+ byte[] out, final int outpos, final int outlen,
+ byte[] m, final int mpos, final int mlen,
+ int n,
+ byte[] k) {
+ poly1305 s = new poly1305(k);
+ s.update(m, mpos, n);
+ s.finish(out, outpos);
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < out.length-outpos; dbg ++) dbgt += " "+out[dbg+outpos];
+ Log.d(TAG, "crypto_onetimeauth -> "+dbgt);
+ */
+
+ return 0;
+ }
+
+ public static int crypto_onetimeauth(byte[] out, byte[] m, int n, byte[] k) {
+ return crypto_onetimeauth(out, 0, out.length, m, 0, m.length, n, k);
+ }
+
+ private static int crypto_onetimeauth_verify(
+ byte[] h, final int hoff, final int hlen,
+ byte[] m, final int moff, final int mlen,
+ int n,
+ byte[] k) {
+ byte[] x = new byte[16];
+ crypto_onetimeauth(x, 0, x.length, m, moff, mlen, n, k);
+ return crypto_verify_16(h, hoff, hlen, x, 0, x.length);
+ }
+
+ public static int crypto_onetimeauth_verify(byte[] h, byte[] m, int n, byte[] k) {
+ return crypto_onetimeauth_verify(h, 0, h.length, m, 0, m.length, n, k);
+ }
+
+ public static int crypto_onetimeauth_verify(byte[] h, byte[] m, byte[] k) {
+ return crypto_onetimeauth_verify(h, m, m != null ? m.length : 0, k);
+ }
+
+ public static int crypto_secretbox(byte[] c, byte[] m, int d, byte[] n, byte[] k) {
+ int i;
+
+ if (d < 32) return -1;
+
+ crypto_stream_xor(c, m, d, n, k);
+ crypto_onetimeauth(c, 16, c.length - 16, c, 32, c.length - 32, d - 32, c);
+
+ ///for (i = 0; i < 16; i ++) c[i] = 0;
+
+ return 0;
+ }
+
+ public static int crypto_secretbox_open(byte[] m, byte[] c, int d, byte[] n, byte[] k) {
+ int i;
+ byte[] x = new byte[32];
+
+ if (d < 32) return -1;
+
+ crypto_stream(x, 32, n, k);
+ if (crypto_onetimeauth_verify(c, 16, 16, c, 32, c.length - 32, d - 32, x) != 0) return -1;
+ crypto_stream_xor(m, c, d, n, k);
+
+ ///for (i = 0; i < 32; i ++) m[i] = 0;
+
+ return 0;
+ }
+
+ private static void set25519(long[] r, long[] a) {
+ int i;
+ for (i = 0; i < 16; i++) r[i] = a[i];
+ }
+
+ private static void car25519(long[] o, final int ooff, final int olen) {
+ int i;
+ long c;
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg);
+ ///L/og.d(TAG, "car25519 pre -> "+dbgt);
+
+ for (i = 0; i < 16; i++) {
+ o[i + ooff] += (1L << 16);
+
+ c = o[i + ooff] >> 16;
+
+ o[(i + 1) * ((i < 15) ? 1 : 0) + ooff] += c - 1 + 37 * (c - 1) * ((i == 15) ? 1 : 0);
+
+ o[i + ooff] -= (c << 16);
+ }
+
+ ///dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg);
+ ///L/og.d(TAG, "car25519 -> "+dbgt);
+
+ }
+
+ private static void sel25519(
+ long[] p, final int poff, final int plen,
+ long[] q, final int qoff, final int qlen,
+ int b) {
+ int i;
+ long t, c = ~(b - 1);
+
+ for (i = 0; i < 16; i++) {
+ t = c & (p[i + poff] ^ q[i + qoff]);
+ p[i + poff] ^= t;
+ q[i + qoff] ^= t;
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < p.length; dbg ++) dbgt += " "+p.get(dbg);
+ ///L/og.d(TAG, "sel25519 -> "+dbgt);
+
+ }
+
+ private static void pack25519(byte[] o, long[] n, final int noff, final int nlen) {
+ int i, j, b;
+ long[] m = new long[16], t = new long[16];
+
+ for (i = 0; i < 16; i++) t[i] = n[i + noff];
+
+ car25519(t, 0, t.length);
+ car25519(t, 0, t.length);
+ car25519(t, 0, t.length);
+
+ for (j = 0; j < 2; j++) {
+ m[0] = t[0] - 0xffed;
+
+ for (i = 1; i < 15; i++) {
+ m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
+ m[i - 1] &= 0xffff;
+ }
+
+ m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
+ b = (int) ((m[15] >> 16) & 1);
+ m[14] &= 0xffff;
+
+ sel25519(t, 0, t.length, m, 0, m.length, 1 - b);
+ }
+
+ for (i = 0; i < 16; i++) {
+ o[2 * i] = (byte) (t[i] & 0xff);
+ o[2 * i + 1] = (byte) (t[i] >> 8);
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
+ ///L/og.d(TAG, "pack25519 -> "+dbgt);
+ }
+
+ private static int neq25519(long[] a, long[] b) {
+ byte[] c = new byte[32], d = new byte[32];
+
+ pack25519(c, a, 0, a.length);
+ pack25519(d, b, 0, b.length);
+
+ return crypto_verify_32(c, 0, c.length, d, 0, d.length);
+ }
+
+ private static byte par25519(long[] a) {
+ byte[] d = new byte[32];
+
+ pack25519(d, a, 0, a.length);
+
+ return (byte) (d[0] & 1);
+ }
+
+ private static void unpack25519(long[] o, byte[] n) {
+ int i;
+
+ for (i = 0; i < 16; i++) o[i] = (n[2 * i] & 0xff) + ((long) ((n[2 * i + 1] << 8) & 0xffff));
+
+ o[15] &= 0x7fff;
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
+ ///L/og.d(TAG, "unpack25519 -> "+dbgt);
+ }
+
+ private static void A(
+ long[] o, final int ooff, final int olen,
+ long[] a, final int aoff, final int alen,
+ long[] b, final int boff, final int blen) {
+ int i;
+ for (i = 0; i < 16; i++) o[i + ooff] = a[i + aoff] + b[i + boff];
+ }
+
+ private static void Z(
+ long[] o, final int ooff, final int olen,
+ long[] a, final int aoff, final int alen,
+ long[] b, final int boff, final int blen) {
+ int i;
+ for (i = 0; i < 16; i++) o[i + ooff] = a[i + aoff] - b[i + boff];
+ }
+
+ private static void M(
+ long[] o, final int ooff, final int olen,
+ long[] a, final int aoff, final int alen,
+ long[] b, final int boff, final int blen) {
+ int i, j;
+ long[] t = new long[31];
+
+ for (i = 0; i < 31; i++) t[i] = 0;
+
+ for (i = 0; i < 16; i++) for (j = 0; j < 16; j++) t[i + j] += a[i + aoff] * b[j + boff];
+
+ for (i = 0; i < 15; i++) t[i] += 38 * t[i + 16];
+
+ for (i = 0; i < 16; i++) o[i + ooff] = t[i];
+
+ car25519(o, ooff, olen);
+ car25519(o, ooff, olen);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg);
+ ///L/og.d(TAG, "M -> "+dbgt);
+ }
+
+ private static void S(
+ long[] o, final int ooff, final int olen,
+ long[] a, final int aoff, final int alen) {
+ M(o, ooff, olen, a, aoff, alen, a, aoff, alen);
+ }
+
+ private static void inv25519(
+ long[] o, final int ooff, final int olen,
+ long[] i, final int ioff, final int ilen) {
+ long[] c = new long[16];
+ int a;
+
+ for (a = 0; a < 16; a++) c[a] = i[a + ioff];
+
+ for (a = 253; a >= 0; a--) {
+ S(c, 0, c.length, c, 0, c.length);
+ if (a != 2 && a != 4) M(c, 0, c.length, c, 0, c.length, i, ioff, ilen);
+ }
+
+ for (a = 0; a < 16; a++) o[a + ooff] = c[a];
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o.get(dbg);
+ ///L/og.d(TAG, "inv25519 -> "+dbgt);
+ }
+
+ private static void pow2523(long[] o, long[] i) {
+ long[] c = new long[16];
+ int a;
+
+ for (a = 0; a < 16; a++) c[a] = i[a];
+
+ for (a = 250; a >= 0; a--) {
+ S(c, 0, c.length, c, 0, c.length);
+ if (a != 1) M(c, 0, c.length, c, 0, c.length, i, 0, i.length);
+ }
+
+ for (a = 0; a < 16; a++) o[a] = c[a];
+ }
+
+ public static int crypto_scalarmult(byte[] q, byte[] n, byte[] p) {
+ byte[] z = new byte[32];
+ long[] x = new long[80];
+ int r, i;
+
+ long[] a = new long[16], b = new long[16], c = new long[16],
+ d = new long[16], e = new long[16], f = new long[16];
+
+ for (i = 0; i < 31; i++) z[i] = n[i];
+
+ z[31] = (byte) (((n[31] & 127) | 64) & 0xff);
+ z[0] &= 248;
+
+ unpack25519(x, p);
+
+ for (i = 0; i < 16; i++) {
+ b[i] = x[i];
+ d[i] = a[i] = c[i] = 0;
+ }
+ a[0] = d[0] = 1;
+
+ for (i = 254; i >= 0; --i) {
+ r = (z[i >>> 3] >>> (i & 7)) & 1;
+ sel25519(a, 0, a.length, b, 0, b.length, r);
+ sel25519(c, 0, c.length, d, 0, d.length, r);
+ A(e, 0, e.length, a, 0, a.length, c, 0, c.length);
+ Z(a, 0, a.length, a, 0, a.length, c, 0, c.length);
+ A(c, 0, c.length, b, 0, b.length, d, 0, d.length);
+ Z(b, 0, b.length, b, 0, b.length, d, 0, d.length);
+ S(d, 0, d.length, e, 0, e.length);
+ S(f, 0, f.length, a, 0, a.length);
+ M(a, 0, a.length, c, 0, c.length, a, 0, a.length);
+ M(c, 0, c.length, b, 0, b.length, e, 0, e.length);
+ A(e, 0, e.length, a, 0, a.length, c, 0, c.length);
+ Z(a, 0, a.length, a, 0, a.length, c, 0, c.length);
+ S(b, 0, b.length, a, 0, a.length);
+ Z(c, 0, c.length, d, 0, d.length, f, 0, f.length);
+ M(a, 0, a.length, c, 0, c.length, _121665, 0, _121665.length);
+ A(a, 0, a.length, a, 0, a.length, d, 0, d.length);
+ M(c, 0, c.length, c, 0, c.length, a, 0, a.length);
+ M(a, 0, a.length, d, 0, d.length, f, 0, f.length);
+ M(d, 0, d.length, b, 0, b.length, x, 0, x.length);
+ S(b, 0, b.length, e, 0, e.length);
+ sel25519(a, 0, a.length, b, 0, b.length, r);
+ sel25519(c, 0, c.length, d, 0, d.length, r);
+ }
+
+ for (i = 0; i < 16; i++) {
+ x[i + 16] = a[i];
+ x[i + 32] = c[i];
+ x[i + 48] = b[i];
+ x[i + 64] = d[i];
+ }
+
+ inv25519(x, 32, x.length - 32, x, 32, x.length - 32);
+
+ M(x, 16, x.length - 16, x, 16, x.length - 16, x, 32, x.length - 32);
+
+ pack25519(q, x, 16, x.length - 16);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < q.length; dbg ++) dbgt += " "+q[dbg];
+ ///L/og.d(TAG, "crypto_scalarmult -> "+dbgt);
+
+ return 0;
+ }
+
+ public static int crypto_scalarmult_base(byte[] q, byte[] n) {
+ return crypto_scalarmult(q, n, _9);
+ }
+
+ public static int crypto_box_keypair(byte[] y, byte[] x) {
+ randombytes(x, 32);
+ return crypto_scalarmult_base(y, x);
+ }
+
+ public static int crypto_box_beforenm(byte[] k, byte[] y, byte[] x) {
+ byte[] s = new byte[32];
+ crypto_scalarmult(s, x, y);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < s.length; dbg ++) dbgt += " "+s[dbg];
+ ///L/og.d(TAG, "crypto_box_beforenm -> "+dbgt);
+
+ return crypto_core_hsalsa20(k, _0, s, sigma);
+ }
+
+ public static int crypto_box_afternm(byte[] c, byte[] m, int d, byte[] n, byte[] k) {
+ return crypto_secretbox(c, m, d, n, k);
+ }
+
+ public static int crypto_box_open_afternm(byte[] m, byte[] c, int d, byte[] n, byte[] k) {
+ return crypto_secretbox_open(m, c, d, n, k);
+ }
+
+ public static int crypto_box(byte[] c, byte[] m, int d, byte[] n, byte[] y, byte[] x) {
+ byte[] k = new byte[32];
+
+ ///L/og.d(TAG, "crypto_box start ...");
+
+ crypto_box_beforenm(k, y, x);
+ return crypto_box_afternm(c, m, d, n, k);
+ }
+
+ public static int crypto_box_open(byte[] m, byte[] c, int d, byte[] n, byte[] y, byte[] x) {
+ byte[] k = new byte[32];
+ crypto_box_beforenm(k, y, x);
+ return crypto_box_open_afternm(m, c, d, n, k);
+ }
+
+ private static long R(long x, int c) {
+ return (x >>> c) | (x << (64 - c));
+ }
+
+ private static long Ch(long x, long y, long z) {
+ return (x & y) ^ (~x & z);
+ }
+
+ private static long Maj(long x, long y, long z) {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ private static long Sigma0(long x) {
+ return R(x, 28) ^ R(x, 34) ^ R(x, 39);
+ }
+
+ private static long Sigma1(long x) {
+ return R(x, 14) ^ R(x, 18) ^ R(x, 41);
+ }
+
+ private static long sigma0(long x) {
+ return R(x, 1) ^ R(x, 8) ^ (x >>> 7);
+ }
+
+ private static long sigma1(long x) {
+ return R(x, 19) ^ R(x, 61) ^ (x >>> 6);
+ }
+
+ private static final long K[] = {
+ 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
+ 0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
+ 0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+ 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
+ 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
+ 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+ 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
+ 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
+ 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+ 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
+ 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
+ 0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+ 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
+ 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
+ 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+ 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
+ 0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
+ 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+ 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
+ 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
+ };
+
+ // TBD... long length n
+ ///int crypto_hashblocks(byte [] x, byte [] m, long n)
+ private static int crypto_hashblocks(byte[] x, byte[] m, final int moff, final int mlen, int n) {
+ long[] z = new long[8], b = new long[8], a = new long[8], w = new long[16];
+ long t;
+ int i, j;
+
+ for (i = 0; i < 8; i++) z[i] = a[i] = dl64(x, 8 * i, x.length - 8 * i);
+
+ int moffset = moff;
+
+ while (n >= 128) {
+ for (i = 0; i < 16; i++) w[i] = dl64(m, 8 * i + moffset, mlen - 8 * i);
+
+ for (i = 0; i < 80; i++) {
+ for (j = 0; j < 8; j++) b[j] = a[j];
+
+ t = a[7] + Sigma1(a[4]) + Ch(a[4], a[5], a[6]) + K[i] + w[i % 16];
+ b[7] = t + Sigma0(a[0]) + Maj(a[0], a[1], a[2]);
+ b[3] += t;
+
+ for (j = 0; j < 8; j++) a[(j + 1) % 8] = b[j];
+
+ if (i % 16 == 15)
+ for (j = 0; j < 16; j++)
+ w[j] += w[(j + 9) % 16] + sigma0(w[(j + 1) % 16]) + sigma1(w[(j + 14) % 16]);
+ }
+
+ for (i = 0; i < 8; i++) {
+ a[i] += z[i];
+ z[i] = a[i];
+ }
+
+ moffset += 128;
+ n -= 128;
+ }
+
+ for (i = 0; i < 8; i++) ts64(x, 8 * i, x.length - 8 * i, z[i]);
+
+ return n;
+ }
+
+ public static int crypto_hashblocks(byte[] x, byte[] m, int n) {
+ return crypto_hashblocks(x, m, 0, m.length, n);
+ }
+
+ private final static byte iv[] = {
+ 0x6a, 0x09, (byte) 0xe6, 0x67, (byte) 0xf3, (byte) 0xbc, (byte) 0xc9, 0x08,
+ (byte) 0xbb, 0x67, (byte) 0xae, (byte) 0x85, (byte) 0x84, (byte) 0xca, (byte) 0xa7, 0x3b,
+ 0x3c, 0x6e, (byte) 0xf3, 0x72, (byte) 0xfe, (byte) 0x94, (byte) 0xf8, 0x2b,
+ (byte) 0xa5, 0x4f, (byte) 0xf5, 0x3a, 0x5f, 0x1d, 0x36, (byte) 0xf1,
+ 0x51, 0x0e, 0x52, 0x7f, (byte) 0xad, (byte) 0xe6, (byte) 0x82, (byte) 0xd1,
+ (byte) 0x9b, 0x05, 0x68, (byte) 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
+ 0x1f, (byte) 0x83, (byte) 0xd9, (byte) 0xab, (byte) 0xfb, 0x41, (byte) 0xbd, 0x6b,
+ 0x5b, (byte) 0xe0, (byte) 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79
+ };
+
+ // TBD 64bits of n
+ ///int crypto_hash(byte [] out, byte [] m, long n)
+ private static int crypto_hash(byte[] out, byte[] m, final int moff, final int mlen, int n) {
+ byte[] h = new byte[64], x = new byte[256];
+ long b = n;
+ int i;
+
+ for (i = 0; i < 64; i++) h[i] = iv[i];
+
+ crypto_hashblocks(h, m, moff, mlen, n);
+ ///m += n;
+ n &= 127;
+ ///m -= n;
+
+ for (i = 0; i < 256; i++) x[i] = 0;
+
+ for (i = 0; i < n; i++) x[i] = m[i + moff];
+ x[n] = (byte) 128;
+
+ n = 256 - 128 * (n < 112 ? 1 : 0);
+ x[n - 9] = (byte) (b >>> 61);
+ ts64(x, n - 8, x.length - (n - 8), b << 3);
+ crypto_hashblocks(h, x, 0, x.length, n);
+
+ for (i = 0; i < 64; i++) out[i] = h[i];
+
+ return 0;
+ }
+
+ public static int crypto_hash(byte[] out, byte[] m, int n) {
+ return crypto_hash(out, m, 0, m.length, n);
+ }
+
+ public static int crypto_hash(byte[] out, byte[] m) {
+ return crypto_hash(out, m, m != null ? m.length : 0);
+ }
+
+ // gf: long[16]
+ ///private static void add(gf p[4],gf q[4])
+ private static void add(long[] p[], long[] q[]) {
+ long[] a = new long[16];
+ long[] b = new long[16];
+ long[] c = new long[16];
+ long[] d = new long[16];
+ long[] t = new long[16];
+ long[] e = new long[16];
+ long[] f = new long[16];
+ long[] g = new long[16];
+ long[] h = new long[16];
+
+
+ long[] p0 = p[0];
+ long[] p1 = p[1];
+ long[] p2 = p[2];
+ long[] p3 = p[3];
+
+ long[] q0 = q[0];
+ long[] q1 = q[1];
+ long[] q2 = q[2];
+ long[] q3 = q[3];
+
+ Z(a, 0, a.length, p1, 0, p1.length, p0, 0, p0.length);
+ Z(t, 0, t.length, q1, 0, q1.length, q0, 0, q0.length);
+ M(a, 0, a.length, a, 0, a.length, t, 0, t.length);
+ A(b, 0, b.length, p0, 0, p0.length, p1, 0, p1.length);
+ A(t, 0, t.length, q0, 0, q0.length, q1, 0, q1.length);
+ M(b, 0, b.length, b, 0, b.length, t, 0, t.length);
+ M(c, 0, c.length, p3, 0, p3.length, q3, 0, q3.length);
+ M(c, 0, c.length, c, 0, c.length, D2, 0, D2.length);
+ M(d, 0, d.length, p2, 0, p2.length, q2, 0, q2.length);
+
+ A(d, 0, d.length, d, 0, d.length, d, 0, d.length);
+ Z(e, 0, e.length, b, 0, b.length, a, 0, a.length);
+ Z(f, 0, f.length, d, 0, d.length, c, 0, c.length);
+ A(g, 0, g.length, d, 0, d.length, c, 0, c.length);
+ A(h, 0, h.length, b, 0, b.length, a, 0, a.length);
+
+ M(p0, 0, p0.length, e, 0, e.length, f, 0, f.length);
+ M(p1, 0, p1.length, h, 0, h.length, g, 0, g.length);
+ M(p2, 0, p2.length, g, 0, g.length, f, 0, f.length);
+ M(p3, 0, p3.length, e, 0, e.length, h, 0, h.length);
+ }
+
+ private static void cswap(long[] p[], long[] q[], byte b) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ sel25519(p[i], 0, p[i].length, q[i], 0, q[i].length, b);
+ }
+
+ private static void pack(byte[] r, long[] p[]) {
+ long[] tx = new long[16];
+ long[] ty = new long[16];
+ long[] zi = new long[16];
+
+ inv25519(zi, 0, zi.length, p[2], 0, p[2].length);
+
+ M(tx, 0, tx.length, p[0], 0, p[0].length, zi, 0, zi.length);
+ M(ty, 0, ty.length, p[1], 0, p[1].length, zi, 0, zi.length);
+
+ pack25519(r, ty, 0, ty.length);
+
+ r[31] ^= par25519(tx) << 7;
+ }
+
+ private static void scalarmult(long[] p[], long[] q[], byte[] s, final int soff, final int slen) {
+ int i;
+
+ set25519(p[0], gf0);
+ set25519(p[1], gf1);
+ set25519(p[2], gf1);
+ set25519(p[3], gf0);
+
+ for (i = 255; i >= 0; --i) {
+ byte b = (byte) ((s[i / 8 + soff] >> (i & 7)) & 1);
+
+ cswap(p, q, b);
+ add(q, p);
+ add(p, p);
+ cswap(p, q, b);
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < p.length; dbg ++) for (int dd = 0; dd < p[dbg].length; dd ++) dbgt += " "+p[dbg][dd];
+ ///L/og.d(TAG, "scalarmult -> "+dbgt);
+ }
+
+ private static void scalarbase(long[] p[], byte[] s, final int soff, final int slen) {
+ long[][] q = new long[4][];
+
+ q[0] = new long[16];
+ q[1] = new long[16];
+ q[2] = new long[16];
+ q[3] = new long[16];
+
+ set25519(q[0], X);
+ set25519(q[1], Y);
+ set25519(q[2], gf1);
+ M(q[3], 0, q[3].length, X, 0, X.length, Y, 0, Y.length);
+ scalarmult(p, q, s, soff, slen);
+ }
+
+ public static int crypto_sign_keypair(byte[] pk, byte[] sk, boolean seeded) {
+ byte[] d = new byte[64];
+ long[][] p = new long[4][];
+
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ int i;
+
+ if (!seeded) randombytes(sk, 32);
+ crypto_hash(d, sk, 0, sk.length, 32);
+ d[0] &= 248;
+ d[31] &= 127;
+ d[31] |= 64;
+
+ scalarbase(p, d, 0, d.length);
+ pack(pk, p);
+
+ for (i = 0; i < 32; i++) sk[i + 32] = pk[i];
+ return 0;
+ }
+
+ private static final long L[] = {
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x10
+ };
+
+ private static void modL(byte[] r, final int roff, final int rlen, long x[]) {
+ long carry;
+ int i, j;
+
+ for (i = 63; i >= 32; --i) {
+ carry = 0;
+ for (j = i - 32; j < i - 12; ++j) {
+ x[j] += carry - 16 * x[i] * L[j - (i - 32)];
+ carry = (x[j] + 128) >> 8;
+ x[j] -= carry << 8;
+ }
+ x[j] += carry;
+ x[i] = 0;
+ }
+ carry = 0;
+
+ for (j = 0; j < 32; j++) {
+ x[j] += carry - (x[31] >> 4) * L[j];
+ carry = x[j] >> 8;
+ x[j] &= 255;
+ }
+
+ for (j = 0; j < 32; j++) x[j] -= carry * L[j];
+
+ for (i = 0; i < 32; i++) {
+ x[i + 1] += x[i] >> 8;
+ r[i + roff] = (byte) (x[i] & 255);
+ }
+ }
+
+ private static void reduce(byte[] r) {
+ long[] x = new long[64];
+ int i;
+
+ for (i = 0; i < 64; i++) x[i] = (long) (r[i] & 0xff);
+
+ for (i = 0; i < 64; i++) r[i] = 0;
+
+ modL(r, 0, r.length, x);
+ }
+
+ // TBD... 64bits of n
+ ///int crypto_sign(byte [] sm, long * smlen, byte [] m, long n, byte [] sk)
+ public static int crypto_sign(byte[] sm, long dummy /* *smlen not used*/, byte[] m, int/*long*/ n, byte[] sk) {
+ byte[] d = new byte[64], h = new byte[64], r = new byte[64];
+
+ int i, j;
+ long[] x = new long[64];
+
+ long[][] p = new long[4][];
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ crypto_hash(d, sk, 0, sk.length, 32);
+ d[0] &= 248;
+ d[31] &= 127;
+ d[31] |= 64;
+
+ ///*smlen = n+64;
+
+ for (i = 0; i < n; i++) sm[64 + i] = m[i];
+
+ for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
+
+ crypto_hash(r, sm, 32, sm.length - 32, n + 32);
+ reduce(r);
+ scalarbase(p, r, 0, r.length);
+ pack(sm, p);
+
+ for (i = 0; i < 32; i++) sm[i + 32] = sk[i + 32];
+ crypto_hash(h, sm, 0, sm.length, n + 64);
+ reduce(h);
+
+ for (i = 0; i < 64; i++) x[i] = 0;
+
+ for (i = 0; i < 32; i++) x[i] = (long) (r[i] & 0xff);
+
+ for (i = 0; i < 32; i++) for (j = 0; j < 32; j++) x[i + j] += (h[i] & 0xff) * (long) (d[j] & 0xff);
+
+ modL(sm, 32, sm.length - 32, x);
+
+ return 0;
+ }
+
+ private static int unpackneg(long[] r[], byte p[]) {
+ long[] t = new long[16];
+ long[] chk = new long[16];
+ long[] num = new long[16];
+ long[] den = new long[16];
+ long[] den2 = new long[16];
+ long[] den4 = new long[16];
+ long[] den6 = new long[16];
+
+ set25519(r[2], gf1);
+ unpack25519(r[1], p);
+ S(num, 0, num.length, r[1], 0, r[1].length);
+ M(den, 0, den.length, num, 0, num.length, D, 0, D.length);
+ Z(num, 0, num.length, num, 0, num.length, r[2], 0, r[2].length);
+ A(den, 0, den.length, r[2], 0, r[2].length, den, 0, den.length);
+
+ S(den2, 0, den2.length, den, 0, den.length);
+ S(den4, 0, den4.length, den2, 0, den2.length);
+ M(den6, 0, den6.length, den4, 0, den4.length, den2, 0, den2.length);
+ M(t, 0, t.length, den6, 0, den6.length, num, 0, num.length);
+ M(t, 0, t.length, t, 0, t.length, den, 0, den.length);
+
+ pow2523(t, t);
+ M(t, 0, t.length, t, 0, t.length, num, 0, num.length);
+ M(t, 0, t.length, t, 0, t.length, den, 0, den.length);
+ M(t, 0, t.length, t, 0, t.length, den, 0, den.length);
+ M(r[0], 0, r[0].length, t, 0, t.length, den, 0, den.length);
+
+ S(chk, 0, chk.length, r[0], 0, r[0].length);
+ M(chk, 0, chk.length, chk, 0, chk.length, den, 0, den.length);
+ if (neq25519(chk, num) != 0) M(r[0], 0, r[0].length, r[0], 0, r[0].length, I, 0, I.length);
+
+ S(chk, 0, chk.length, r[0], 0, r[0].length);
+ M(chk, 0, chk.length, chk, 0, chk.length, den, 0, den.length);
+ if (neq25519(chk, num) != 0) return -1;
+
+ if (par25519(r[0]) == ((p[31] & 0xFF) >> 7)) Z(r[0], 0, r[0].length, gf0, 0, gf0.length, r[0], 0, r[0].length);
+
+ M(r[3], 0, r[3].length, r[0], 0, r[0].length, r[1], 0, r[1].length);
+ return 0;
+ }
+
+ /// TBD 64bits of mlen
+ ///int crypto_sign_open(byte []m,long *mlen,byte []sm,long n,byte []pk)
+ public static int crypto_sign_open(byte[] m, long dummy /* *mlen not used*/, byte[] sm, int/*long*/ n, byte[] pk) {
+ int i;
+ byte[] t = new byte[32], h = new byte[64];
+
+ long[][] p = new long[4][];
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ long[][] q = new long[4][];
+ q[0] = new long[16];
+ q[1] = new long[16];
+ q[2] = new long[16];
+ q[3] = new long[16];
+
+ ///*mlen = -1;
+
+ if (n < 64) return -1;
+
+ if (unpackneg(q, pk) != 0) return -1;
+
+ for (i = 0; i < n; i++) m[i] = sm[i];
+
+ for (i = 0; i < 32; i++) m[i + 32] = pk[i];
+
+ crypto_hash(h, m, 0, m.length, n);
+
+ reduce(h);
+ scalarmult(p, q, h, 0, h.length);
+
+ scalarbase(q, sm, 32, sm.length - 32);
+ add(p, q);
+ pack(t, p);
+
+ n -= 64;
+ if (crypto_verify_32(sm, 0, sm.length, t, 0, t.length) != 0) {
+ // optimizing it
+ ///for (i = 0; i < n; i ++) m[i] = 0;
+ return -1;
+ }
+
+ // TBD optimizing ...
+ ///for (i = 0; i < n; i ++) m[i] = sm[i + 64];
+ ///*mlen = n;
+
+ return 0;
+ }
+
+ /*
+ * @description
+ * Java SecureRandom generator
+ * */
+ private static final SecureRandom jrandom = new SecureRandom();
+
+ public static void randombytes(byte[] x, int len) {
+ int ret = len % 8;
+ long rnd;
+
+ for (int i = 0; i < len - ret; i += 8) {
+ rnd = jrandom.nextLong();
+
+ x[i + 0] = (byte) (rnd >>> 0);
+ x[i + 1] = (byte) (rnd >>> 8);
+ x[i + 2] = (byte) (rnd >>> 16);
+ x[i + 3] = (byte) (rnd >>> 24);
+ x[i + 4] = (byte) (rnd >>> 32);
+ x[i + 5] = (byte) (rnd >>> 40);
+ x[i + 6] = (byte) (rnd >>> 48);
+ x[i + 7] = (byte) (rnd >>> 56);
+ }
+
+ if (ret > 0) {
+ rnd = jrandom.nextLong();
+ for (int i = len - ret; i < len; i++)
+ x[i] = (byte) (rnd >>> 8 * i);
+ }
+ }
+
+}
diff --git a/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNaclFast.java b/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNaclFast.java
new file mode 100644
index 00000000..6caa67bf
--- /dev/null
+++ b/tweetnacl-java/src/main/java/com/iwebpp/crypto/TweetNaclFast.java
@@ -0,0 +1,3562 @@
+// Copyright (c) 2014-present Tom Zhou
+
+package com.iwebpp.crypto;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.util.concurrent.atomic.AtomicLong;
+
+
+/*
+ * @description
+ * TweetNacl.c Java porting
+ * */
+public final class TweetNaclFast {
+
+ private final static String TAG = "TweetNaclFast";
+
+ /*
+ * @description
+ * Box algorithm, Public-key authenticated encryption
+ * */
+ public static final class Box {
+
+ private final static String TAG = "Box";
+
+ private AtomicLong nonce;
+
+ private byte[] theirPublicKey;
+ private byte[] mySecretKey;
+ private byte[] sharedKey;
+
+ public Box(byte[] theirPublicKey, byte[] mySecretKey) {
+ this(theirPublicKey, mySecretKey, 68);
+ }
+
+ public Box(byte[] theirPublicKey, byte[] mySecretKey, long nonce) {
+ this.theirPublicKey = theirPublicKey;
+ this.mySecretKey = mySecretKey;
+
+ this.nonce = new AtomicLong(nonce);
+
+ // generate pre-computed shared key
+ before();
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce.set(nonce);
+ }
+
+ public long getNonce() {
+ return this.nonce.get();
+ }
+
+ public long incrNonce() {
+ return this.nonce.incrementAndGet();
+ }
+
+ private byte[] generateNonce() {
+ // generate nonce
+ long nonce = this.nonce.get();
+
+ byte[] n = new byte[nonceLength];
+ for (int i = 0; i < nonceLength; i += 8) {
+ n[i + 0] = (byte) (nonce >>> 0);
+ n[i + 1] = (byte) (nonce >>> 8);
+ n[i + 2] = (byte) (nonce >>> 16);
+ n[i + 3] = (byte) (nonce >>> 24);
+ n[i + 4] = (byte) (nonce >>> 32);
+ n[i + 5] = (byte) (nonce >>> 40);
+ n[i + 6] = (byte) (nonce >>> 48);
+ n[i + 7] = (byte) (nonce >>> 56);
+ }
+
+ return n;
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using peer's public key,
+ * our secret key, and the given nonce, which must be unique
+ * for each distinct message for a key pair.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.box.overheadLength longer than the original message.
+ * */
+ public byte[] box(byte[] message) {
+ if (message == null) return null;
+ return box(message, 0, message.length);
+ }
+
+ public byte[] box(byte[] message, final int moff) {
+ if (!(message != null && message.length > moff)) return null;
+ return box(message, moff, message.length - moff);
+ }
+
+ public byte[] box(byte[] message, final int moff, final int mlen) {
+ if (!(message != null && message.length >= (moff + mlen))) return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return after(message, moff, mlen);
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using peer's public key,
+ * our secret key, and the given nonce, which must be unique
+ * for each distinct message for a key pair.
+ *
+ * Explicitly pass the nonce
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.box.overheadLength longer than the original message.
+ * */
+ public byte[] box(byte[] message, byte[] theNonce) {
+ if (message == null) return null;
+ return box(message, 0, message.length, theNonce);
+ }
+
+ public byte[] box(byte[] message, final int moff, byte[] theNonce) {
+ if (!(message != null && message.length > moff)) return null;
+ return box(message, moff, message.length - moff, theNonce);
+ }
+
+ public byte[] box(byte[] message, final int moff, final int mlen, byte[] theNonce) {
+ if (!(message != null && message.length >= (moff + mlen) &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return after(message, moff, mlen, theNonce);
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given box with peer's public key,
+ * our secret key, and the given nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box) {
+ if (box == null) return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, 0, box.length);
+ }
+
+ public byte[] open(byte[] box, final int boxoff) {
+ if (!(box != null && box.length > boxoff)) return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, boxoff, box.length - boxoff);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, final int boxlen) {
+ if (!(box != null && box.length >= (boxoff + boxlen))) return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, boxoff, boxlen);
+ }
+
+
+ /*
+ * @description
+ * Authenticates and decrypts the given box with peer's public key,
+ * our secret key, and the given nonce.
+ * Explicit passing of nonce
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box, byte[] theNonce) {
+ if (!(box != null &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, 0, box.length, theNonce);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, byte[] theNonce) {
+ if (!(box != null && box.length > boxoff &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, boxoff, box.length - boxoff, theNonce);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, final int boxlen, byte[] theNonce) {
+ if (!(box != null && box.length >= (boxoff + boxlen) &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // prepare shared key
+ if (this.sharedKey == null) before();
+
+ return open_after(box, boxoff, boxlen, theNonce);
+ }
+
+
+ /*
+ * @description
+ * Returns a precomputed shared key
+ * which can be used in nacl.box.after and nacl.box.open.after.
+ * */
+ public byte[] before() {
+ if (this.sharedKey == null) {
+ this.sharedKey = new byte[sharedKeyLength];
+ crypto_box_beforenm(this.sharedKey, this.theirPublicKey, this.mySecretKey);
+ }
+
+ return this.sharedKey;
+ }
+
+ /*
+ * @description
+ * Same as nacl.box, but uses a shared key precomputed with nacl.box.before.
+ * */
+ public byte[] after(byte[] message, final int moff, final int mlen) {
+ return after(message, moff, mlen, generateNonce());
+ }
+
+ /*
+ * @description
+ * Same as nacl.box, but uses a shared key precomputed with nacl.box.before,
+ * and passes a nonce explicitly.
+ * */
+ public byte[] after(byte[] message, final int moff, final int mlen, byte[] theNonce) {
+ // check message
+ if (!(message != null && message.length >= (moff + mlen) &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // message buffer
+ byte[] m = new byte[mlen + zerobytesLength];
+
+ // cipher buffer
+ byte[] c = new byte[m.length];
+
+ for (int i = 0; i < mlen; i++)
+ m[i + zerobytesLength] = message[i + moff];
+
+ if (0 != crypto_box_afternm(c, m, m.length, theNonce, sharedKey))
+ return null;
+
+ // wrap byte_buf_t on c offset@boxzerobytesLength
+ ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
+ byte[] ret = new byte[c.length - boxzerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = c[i + boxzerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Same as nacl.box.open,
+ * but uses a shared key pre-computed with nacl.box.before.
+ * */
+ public byte[] open_after(byte[] box, final int boxoff, final int boxlen) {
+ return open_after(box, boxoff, boxlen, generateNonce());
+ }
+
+ public byte[] open_after(byte[] box, final int boxoff, final int boxlen, byte[] theNonce) {
+ // check message
+ if (!(box != null && box.length >= (boxoff + boxlen) && boxlen >= boxzerobytesLength))
+ return null;
+
+ // cipher buffer
+ byte[] c = new byte[boxlen + boxzerobytesLength];
+
+ // message buffer
+ byte[] m = new byte[c.length];
+
+ for (int i = 0; i < boxlen; i++)
+ c[i + boxzerobytesLength] = box[i + boxoff];
+
+ if (crypto_box_open_afternm(m, c, c.length, theNonce, sharedKey) != 0)
+ return null;
+
+ // wrap byte_buf_t on m offset@zerobytesLength
+ ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
+ byte[] ret = new byte[m.length - zerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = m[i + zerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Length of public key in bytes.
+ * */
+ public static final int publicKeyLength = 32;
+
+ /*
+ * @description
+ * Length of secret key in bytes.
+ * */
+ public static final int secretKeyLength = 32;
+
+ /*
+ * @description
+ * Length of precomputed shared key in bytes.
+ * */
+ public static final int sharedKeyLength = 32;
+
+ /*
+ * @description
+ * Length of nonce in bytes.
+ * */
+ public static final int nonceLength = 24;
+
+ /*
+ * @description
+ * zero bytes in case box
+ * */
+ public static final int zerobytesLength = 32;
+ /*
+ * @description
+ * zero bytes in case open box
+ * */
+ public static final int boxzerobytesLength = 16;
+
+ /*
+ * @description
+ * Length of overhead added to box compared to original message.
+ * */
+ public static final int overheadLength = 16;
+
+ public static class KeyPair {
+ private byte[] publicKey;
+ private byte[] secretKey;
+
+ public KeyPair() {
+ publicKey = new byte[publicKeyLength];
+ secretKey = new byte[secretKeyLength];
+ }
+
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ public byte[] getSecretKey() {
+ return secretKey;
+ }
+ }
+
+ /*
+ * @description
+ * Generates a new random key pair for box and
+ * returns it as an object with publicKey and secretKey members:
+ * */
+ public static KeyPair keyPair() {
+ KeyPair kp = new KeyPair();
+
+ crypto_box_keypair(kp.getPublicKey(), kp.getSecretKey());
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSecretKey(byte[] secretKey) {
+ KeyPair kp = new KeyPair();
+ byte[] sk = kp.getSecretKey();
+ byte[] pk = kp.getPublicKey();
+
+ // copy sk
+ for (int i = 0; i < sk.length; i++)
+ sk[i] = secretKey[i];
+
+ crypto_scalarmult_base(pk, sk);
+ return kp;
+ }
+
+ }
+
+ /*
+ * @description
+ * Secret Box algorithm, secret key
+ * */
+ public static final class SecretBox {
+
+ private final static String TAG = "SecretBox";
+
+ private AtomicLong nonce;
+
+ private byte[] key;
+
+ public SecretBox(byte[] key) {
+ this(key, 68);
+ }
+
+ public SecretBox(byte[] key, long nonce) {
+ this.key = key;
+
+ this.nonce = new AtomicLong(nonce);
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce.set(nonce);
+ }
+
+ public long getNonce() {
+ return this.nonce.get();
+ }
+
+ public long incrNonce() {
+ return this.nonce.incrementAndGet();
+ }
+
+ private byte[] generateNonce() {
+ // generate nonce
+ long nonce = this.nonce.get();
+
+ byte[] n = new byte[nonceLength];
+ for (int i = 0; i < nonceLength; i += 8) {
+ n[i + 0] = (byte) (nonce >>> 0);
+ n[i + 1] = (byte) (nonce >>> 8);
+ n[i + 2] = (byte) (nonce >>> 16);
+ n[i + 3] = (byte) (nonce >>> 24);
+ n[i + 4] = (byte) (nonce >>> 32);
+ n[i + 5] = (byte) (nonce >>> 40);
+ n[i + 6] = (byte) (nonce >>> 48);
+ n[i + 7] = (byte) (nonce >>> 56);
+ }
+
+ return n;
+ }
+
+ /*
+ * @description
+ * Encrypt and authenticates message using the key and the nonce.
+ * The nonce must be unique for each distinct message for this key.
+ *
+ * Returns an encrypted and authenticated message,
+ * which is nacl.secretbox.overheadLength longer than the original message.
+ * */
+ public byte[] box(byte[] message) {
+ if (message == null) return null;
+ return box(message, 0, message.length);
+ }
+
+ public byte[] box(byte[] message, final int moff) {
+ if (!(message != null && message.length > moff)) return null;
+ return box(message, moff, message.length - moff);
+ }
+
+ public byte[] box(byte[] message, final int moff, final int mlen) {
+ // check message
+ if (!(message != null && message.length >= (moff + mlen)))
+ return null;
+ return box(message, moff, message.length - moff, generateNonce());
+ }
+
+ public byte[] box(byte[] message, byte[] theNonce) {
+ if (message == null) return null;
+ return box(message, 0, message.length, theNonce);
+ }
+
+ public byte[] box(byte[] message, final int moff, byte[] theNonce) {
+ if (!(message != null && message.length > moff)) return null;
+ return box(message, moff, message.length - moff, theNonce);
+ }
+
+ public byte[] box(byte[] message, final int moff, final int mlen, byte[] theNonce) {
+ // check message
+ if (!(message != null && message.length >= (moff + mlen) &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // message buffer
+ byte[] m = new byte[mlen + zerobytesLength];
+
+ // cipher buffer
+ byte[] c = new byte[m.length];
+
+ for (int i = 0; i < mlen; i++)
+ m[i + zerobytesLength] = message[i + moff];
+
+ if (0 != crypto_secretbox(c, m, m.length, theNonce, key))
+ return null;
+
+ // TBD optimizing ...
+ // wrap byte_buf_t on c offset@boxzerobytesLength
+ ///return new byte_buf_t(c, boxzerobytesLength, c.length-boxzerobytesLength);
+ byte[] ret = new byte[c.length - boxzerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = c[i + boxzerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Authenticates and decrypts the given secret box
+ * using the key and the nonce.
+ *
+ * Returns the original message, or null if authentication fails.
+ * */
+ public byte[] open(byte[] box) {
+ if (box == null) return null;
+ return open(box, 0, box.length);
+ }
+
+ public byte[] open(byte[] box, final int boxoff) {
+ if (!(box != null && box.length > boxoff)) return null;
+ return open(box, boxoff, box.length - boxoff);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, final int boxlen) {
+ // check message
+ if (!(box != null && box.length >= (boxoff + boxlen) && boxlen >= boxzerobytesLength))
+ return null;
+ return open(box, boxoff, box.length - boxoff, generateNonce());
+ }
+
+ public byte[] open(byte[] box, byte[] theNonce) {
+ if (box == null) return null;
+ return open(box, 0, box.length, theNonce);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, byte[] theNonce) {
+ if (!(box != null && box.length > boxoff)) return null;
+ return open(box, boxoff, box.length - boxoff, theNonce);
+ }
+
+ public byte[] open(byte[] box, final int boxoff, final int boxlen, byte[] theNonce) {
+ // check message
+ if (!(box != null && box.length >= (boxoff + boxlen) && boxlen >= boxzerobytesLength &&
+ theNonce != null && theNonce.length == nonceLength))
+ return null;
+
+ // cipher buffer
+ byte[] c = new byte[boxlen + boxzerobytesLength];
+
+ // message buffer
+ byte[] m = new byte[c.length];
+
+ for (int i = 0; i < boxlen; i++)
+ c[i + boxzerobytesLength] = box[i + boxoff];
+
+ if (0 != crypto_secretbox_open(m, c, c.length, theNonce, key))
+ return null;
+
+ // wrap byte_buf_t on m offset@zerobytesLength
+ ///return new byte_buf_t(m, zerobytesLength, m.length-zerobytesLength);
+ byte[] ret = new byte[m.length - zerobytesLength];
+
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = m[i + zerobytesLength];
+
+ return ret;
+ }
+
+ /*
+ * @description
+ * Length of key in bytes.
+ * */
+ public static final int keyLength = 32;
+
+ /*
+ * @description
+ * Length of nonce in bytes.
+ * */
+ public static final int nonceLength = 24;
+
+ /*
+ * @description
+ * Length of overhead added to secret box compared to original message.
+ * */
+ public static final int overheadLength = 16;
+
+ /*
+ * @description
+ * zero bytes in case box
+ * */
+ public static final int zerobytesLength = 32;
+ /*
+ * @description
+ * zero bytes in case open box
+ * */
+ public static final int boxzerobytesLength = 16;
+
+ }
+
+ /*
+ * @description
+ * Scalar multiplication, Implements curve25519.
+ * */
+ public static final class ScalarMult {
+
+ private final static String TAG = "ScalarMult";
+
+ /*
+ * @description
+ * Multiplies an integer n by a group element p and
+ * returns the resulting group element.
+ * */
+ public static byte[] scalseMult(byte[] n, byte[] p) {
+ if (!(n.length == scalarLength && p.length == groupElementLength))
+ return null;
+
+ byte[] q = new byte[scalarLength];
+
+ crypto_scalarmult(q, n, p);
+
+ return q;
+ }
+
+ /*
+ * @description
+ * Multiplies an integer n by a standard group element and
+ * returns the resulting group element.
+ * */
+ public static byte[] scalseMult_base(byte[] n) {
+ if (!(n.length == scalarLength))
+ return null;
+
+ byte[] q = new byte[scalarLength];
+
+ crypto_scalarmult_base(q, n);
+
+ return q;
+ }
+
+ /*
+ * @description
+ * Length of scalar in bytes.
+ * */
+ public static final int scalarLength = 32;
+
+ /*
+ * @description
+ * Length of group element in bytes.
+ * */
+ public static final int groupElementLength = 32;
+
+ }
+
+
+ /*
+ * @description
+ * Hash algorithm, Implements SHA-512.
+ * */
+ public static final class Hash {
+
+ private final static String TAG = "Hash";
+
+ /*
+ * @description
+ * Returns SHA-512 hash of the message.
+ * */
+ public static byte[] sha512(byte[] message) {
+ if (!(message != null && message.length > 0))
+ return null;
+
+ byte[] out = new byte[hashLength];
+
+ crypto_hash(out, message);
+
+ return out;
+ }
+
+ public static byte[] sha512(String message) throws UnsupportedEncodingException {
+ return sha512(message.getBytes("utf-8"));
+ }
+
+ /*
+ * @description
+ * Length of hash in bytes.
+ * */
+ public static final int hashLength = 64;
+
+ }
+
+
+ /*
+ * @description
+ * Signature algorithm, Implements ed25519.
+ * */
+ public static final class Signature {
+
+ private final static String TAG = "Signature";
+
+ private byte[] theirPublicKey;
+ private byte[] mySecretKey;
+
+ public Signature(byte[] theirPublicKey, byte[] mySecretKey) {
+ this.theirPublicKey = theirPublicKey;
+ this.mySecretKey = mySecretKey;
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signed message.
+ * */
+ public byte[] sign(byte[] message) {
+ if (message == null) return null;
+
+ return sign(message, 0, message.length);
+ }
+
+ public byte[] sign(byte[] message, final int moff) {
+ if (!(message != null && message.length > moff)) return null;
+
+ return sign(message, moff, message.length - moff);
+ }
+
+ public byte[] sign(byte[] message, final int moff, final int mlen) {
+ // check message
+ if (!(message != null && message.length >= (moff + mlen)))
+ return null;
+
+ // signed message
+ byte[] sm = new byte[mlen + signatureLength];
+
+ crypto_sign(sm, -1, message, moff, mlen, mySecretKey);
+
+ return sm;
+ }
+
+ /*
+ * @description
+ * Verifies the signed message and returns the message without signature.
+ * Returns null if verification failed.
+ * */
+ public byte[] open(byte[] signedMessage) {
+ if (signedMessage == null) return null;
+
+ return open(signedMessage, 0, signedMessage.length);
+ }
+
+ public byte[] open(byte[] signedMessage, final int smoff) {
+ if (!(signedMessage != null && signedMessage.length > smoff)) return null;
+
+ return open(signedMessage, smoff, signedMessage.length - smoff);
+ }
+
+ public byte[] open(byte[] signedMessage, final int smoff, final int smlen) {
+ // check sm length
+ if (!(signedMessage != null && signedMessage.length >= (smoff + smlen) && smlen >= signatureLength))
+ return null;
+
+ // temp buffer
+ byte[] tmp = new byte[smlen];
+
+ if (0 != crypto_sign_open(tmp, -1, signedMessage, smoff, smlen, theirPublicKey))
+ return null;
+
+ // message
+ byte[] msg = new byte[smlen - signatureLength];
+ for (int i = 0; i < msg.length; i++)
+ msg[i] = signedMessage[smoff + i + signatureLength];
+
+ return msg;
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signature.
+ * */
+ public byte[] detached(byte[] message) {
+ byte[] signedMsg = this.sign(message);
+ byte[] sig = new byte[signatureLength];
+ for (int i = 0; i < sig.length; i++)
+ sig[i] = signedMsg[i];
+ return sig;
+ }
+
+ /*
+ * @description
+ * Verifies the signature for the message and
+ * returns true if verification succeeded or false if it failed.
+ * */
+ public boolean detached_verify(byte[] message, byte[] signature) {
+ if (signature.length != signatureLength)
+ return false;
+ if (theirPublicKey.length != publicKeyLength)
+ return false;
+ byte[] sm = new byte[signatureLength + message.length];
+ byte[] m = new byte[signatureLength + message.length];
+ for (int i = 0; i < signatureLength; i++)
+ sm[i] = signature[i];
+ for (int i = 0; i < message.length; i++)
+ sm[i + signatureLength] = message[i];
+ return (crypto_sign_open(m, -1, sm, 0, sm.length, theirPublicKey) >= 0);
+ }
+
+ /*
+ * @description
+ * Generates new random key pair for signing and
+ * returns it as an object with publicKey and secretKey members
+ * */
+ public static class KeyPair {
+ private byte[] publicKey;
+ private byte[] secretKey;
+
+ public KeyPair() {
+ publicKey = new byte[publicKeyLength];
+ secretKey = new byte[secretKeyLength];
+ }
+
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ public byte[] getSecretKey() {
+ return secretKey;
+ }
+ }
+
+ /*
+ * @description
+ * Signs the message using the secret key and returns a signed message.
+ * */
+ public static KeyPair keyPair() {
+ KeyPair kp = new KeyPair();
+
+ crypto_sign_keypair(kp.getPublicKey(), kp.getSecretKey(), false);
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSecretKey(byte[] secretKey) {
+ KeyPair kp = new KeyPair();
+ byte[] pk = kp.getPublicKey();
+ byte[] sk = kp.getSecretKey();
+
+ // copy sk
+ for (int i = 0; i < kp.getSecretKey().length; i++)
+ sk[i] = secretKey[i];
+
+ // copy pk from sk
+ for (int i = 0; i < kp.getPublicKey().length; i++)
+ pk[i] = secretKey[32 + i]; // hard-copy
+
+ return kp;
+ }
+
+ public static KeyPair keyPair_fromSeed(byte[] seed) {
+ KeyPair kp = new KeyPair();
+ byte[] pk = kp.getPublicKey();
+ byte[] sk = kp.getSecretKey();
+
+ // copy sk
+ for (int i = 0; i < seedLength; i++)
+ sk[i] = seed[i];
+
+ // generate pk from sk
+ crypto_sign_keypair(pk, sk, true);
+
+ return kp;
+ }
+
+ /*
+ * @description
+ * Length of signing public key in bytes.
+ * */
+ public static final int publicKeyLength = 32;
+
+ /*
+ * @description
+ * Length of signing secret key in bytes.
+ * */
+ public static final int secretKeyLength = 64;
+
+ /*
+ * @description
+ * Length of seed for nacl.sign.keyPair.fromSeed in bytes.
+ * */
+ public static final int seedLength = 32;
+
+ /*
+ * @description
+ * Length of signature in bytes.
+ * */
+ public static final int signatureLength = 64;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ /*
+ * @description
+ * Codes below are ported tweetnacl-fast.js from TweetNacl.c/TweetNacl.h
+ * */
+
+ private static final byte[] _0 = new byte[16];
+ private static final byte[] _9 = new byte[32];
+
+ static {
+ ///for (int i = 0; i < _0.length; i ++) _0[i] = 0;
+
+ ///for (int i = 0; i < _9.length; i ++) _9[i] = 0;
+ _9[0] = 9;
+ }
+
+ private static final long[] gf0 = new long[16];
+ private static final long[] gf1 = new long[16];
+ private static final long[] _121665 = new long[16];
+
+ static {
+ ///for (int i = 0; i < gf0.length; i ++) gf0[i] = 0;
+
+ ///for (int i = 0; i < gf1.length; i ++) gf1[i] = 0;
+ gf1[0] = 1;
+
+ ///for (int i = 0; i < _121665.length; i ++) _121665[i] = 0;
+ _121665[0] = 0xDB41;
+ _121665[1] = 1;
+ }
+
+ private static final long[] D = new long[]{
+ 0x78a3, 0x1359, 0x4dca, 0x75eb,
+ 0xd8ab, 0x4141, 0x0a4d, 0x0070,
+ 0xe898, 0x7779, 0x4079, 0x8cc7,
+ 0xfe73, 0x2b6f, 0x6cee, 0x5203
+ };
+ private static final long[] D2 = new long[]{
+ 0xf159, 0x26b2, 0x9b94, 0xebd6,
+ 0xb156, 0x8283, 0x149a, 0x00e0,
+ 0xd130, 0xeef3, 0x80f2, 0x198e,
+ 0xfce7, 0x56df, 0xd9dc, 0x2406
+ };
+ private static final long[] X = new long[]{
+ 0xd51a, 0x8f25, 0x2d60, 0xc956,
+ 0xa7b2, 0x9525, 0xc760, 0x692c,
+ 0xdc5c, 0xfdd6, 0xe231, 0xc0a4,
+ 0x53fe, 0xcd6e, 0x36d3, 0x2169
+ };
+ private static final long[] Y = new long[]{
+ 0x6658, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666,
+ 0x6666, 0x6666, 0x6666, 0x6666
+ };
+ private static final long[] I = new long[]{
+ 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee,
+ 0xe478, 0xad2f, 0x1806, 0x2f43,
+ 0xd7a7, 0x3dfb, 0x0099, 0x2b4d,
+ 0xdf0b, 0x4fc1, 0x2480, 0x2b83
+ };
+
+ private static void ts64(byte[] x, final int xoff, long u) {
+ ///int i;
+ ///for (i = 7;i >= 0;--i) { x[i+xoff] = (byte)(u&0xff); u >>>= 8; }
+
+ x[7 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[6 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[5 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[4 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[3 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[2 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[1 + xoff] = (byte) (u & 0xff);
+ u >>>= 8;
+ x[0 + xoff] = (byte) (u & 0xff); ///u >>>= 8;
+ }
+
+ private static int vn(
+ byte[] x, final int xoff,
+ byte[] y, final int yoff,
+ int n) {
+ int i, d = 0;
+ for (i = 0; i < n; i++) d |= (x[i + xoff] ^ y[i + yoff]) & 0xff;
+ return (1 & ((d - 1) >>> 8)) - 1;
+ }
+
+ private static int crypto_verify_16(
+ byte[] x, final int xoff,
+ byte[] y, final int yoff) {
+ return vn(x, xoff, y, yoff, 16);
+ }
+
+ public static int crypto_verify_16(byte[] x, byte[] y) {
+ return crypto_verify_16(x, 0, y, 0);
+ }
+
+ private static int crypto_verify_32(
+ byte[] x, final int xoff,
+ byte[] y, final int yoff) {
+ return vn(x, xoff, y, yoff, 32);
+ }
+
+ public static int crypto_verify_32(byte[] x, byte[] y) {
+ return crypto_verify_32(x, 0, y, 0);
+ }
+
+ private static void core_salsa20(byte[] o, byte[] p, byte[] k, byte[] c) {
+ int j0 = c[0] & 0xff | (c[1] & 0xff) << 8 | (c[2] & 0xff) << 16 | (c[3] & 0xff) << 24,
+ j1 = k[0] & 0xff | (k[1] & 0xff) << 8 | (k[2] & 0xff) << 16 | (k[3] & 0xff) << 24,
+ j2 = k[4] & 0xff | (k[5] & 0xff) << 8 | (k[6] & 0xff) << 16 | (k[7] & 0xff) << 24,
+ j3 = k[8] & 0xff | (k[9] & 0xff) << 8 | (k[10] & 0xff) << 16 | (k[11] & 0xff) << 24,
+ j4 = k[12] & 0xff | (k[13] & 0xff) << 8 | (k[14] & 0xff) << 16 | (k[15] & 0xff) << 24,
+ j5 = c[4] & 0xff | (c[5] & 0xff) << 8 | (c[6] & 0xff) << 16 | (c[7] & 0xff) << 24,
+ j6 = p[0] & 0xff | (p[1] & 0xff) << 8 | (p[2] & 0xff) << 16 | (p[3] & 0xff) << 24,
+ j7 = p[4] & 0xff | (p[5] & 0xff) << 8 | (p[6] & 0xff) << 16 | (p[7] & 0xff) << 24,
+ j8 = p[8] & 0xff | (p[9] & 0xff) << 8 | (p[10] & 0xff) << 16 | (p[11] & 0xff) << 24,
+ j9 = p[12] & 0xff | (p[13] & 0xff) << 8 | (p[14] & 0xff) << 16 | (p[15] & 0xff) << 24,
+ j10 = c[8] & 0xff | (c[9] & 0xff) << 8 | (c[10] & 0xff) << 16 | (c[11] & 0xff) << 24,
+ j11 = k[16] & 0xff | (k[17] & 0xff) << 8 | (k[18] & 0xff) << 16 | (k[19] & 0xff) << 24,
+ j12 = k[20] & 0xff | (k[21] & 0xff) << 8 | (k[22] & 0xff) << 16 | (k[23] & 0xff) << 24,
+ j13 = k[24] & 0xff | (k[25] & 0xff) << 8 | (k[26] & 0xff) << 16 | (k[27] & 0xff) << 24,
+ j14 = k[28] & 0xff | (k[29] & 0xff) << 8 | (k[30] & 0xff) << 16 | (k[31] & 0xff) << 24,
+ j15 = c[12] & 0xff | (c[13] & 0xff) << 8 | (c[14] & 0xff) << 16 | (c[15] & 0xff) << 24;
+
+ int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
+ x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
+ x15 = j15, u;
+
+ for (int i = 0; i < 20; i += 2) {
+ u = x0 + x12 | 0;
+ x4 ^= u << 7 | u >>> (32 - 7);
+ u = x4 + x0 | 0;
+ x8 ^= u << 9 | u >>> (32 - 9);
+ u = x8 + x4 | 0;
+ x12 ^= u << 13 | u >>> (32 - 13);
+ u = x12 + x8 | 0;
+ x0 ^= u << 18 | u >>> (32 - 18);
+
+ u = x5 + x1 | 0;
+ x9 ^= u << 7 | u >>> (32 - 7);
+ u = x9 + x5 | 0;
+ x13 ^= u << 9 | u >>> (32 - 9);
+ u = x13 + x9 | 0;
+ x1 ^= u << 13 | u >>> (32 - 13);
+ u = x1 + x13 | 0;
+ x5 ^= u << 18 | u >>> (32 - 18);
+
+ u = x10 + x6 | 0;
+ x14 ^= u << 7 | u >>> (32 - 7);
+ u = x14 + x10 | 0;
+ x2 ^= u << 9 | u >>> (32 - 9);
+ u = x2 + x14 | 0;
+ x6 ^= u << 13 | u >>> (32 - 13);
+ u = x6 + x2 | 0;
+ x10 ^= u << 18 | u >>> (32 - 18);
+
+ u = x15 + x11 | 0;
+ x3 ^= u << 7 | u >>> (32 - 7);
+ u = x3 + x15 | 0;
+ x7 ^= u << 9 | u >>> (32 - 9);
+ u = x7 + x3 | 0;
+ x11 ^= u << 13 | u >>> (32 - 13);
+ u = x11 + x7 | 0;
+ x15 ^= u << 18 | u >>> (32 - 18);
+
+ u = x0 + x3 | 0;
+ x1 ^= u << 7 | u >>> (32 - 7);
+ u = x1 + x0 | 0;
+ x2 ^= u << 9 | u >>> (32 - 9);
+ u = x2 + x1 | 0;
+ x3 ^= u << 13 | u >>> (32 - 13);
+ u = x3 + x2 | 0;
+ x0 ^= u << 18 | u >>> (32 - 18);
+
+ u = x5 + x4 | 0;
+ x6 ^= u << 7 | u >>> (32 - 7);
+ u = x6 + x5 | 0;
+ x7 ^= u << 9 | u >>> (32 - 9);
+ u = x7 + x6 | 0;
+ x4 ^= u << 13 | u >>> (32 - 13);
+ u = x4 + x7 | 0;
+ x5 ^= u << 18 | u >>> (32 - 18);
+
+ u = x10 + x9 | 0;
+ x11 ^= u << 7 | u >>> (32 - 7);
+ u = x11 + x10 | 0;
+ x8 ^= u << 9 | u >>> (32 - 9);
+ u = x8 + x11 | 0;
+ x9 ^= u << 13 | u >>> (32 - 13);
+ u = x9 + x8 | 0;
+ x10 ^= u << 18 | u >>> (32 - 18);
+
+ u = x15 + x14 | 0;
+ x12 ^= u << 7 | u >>> (32 - 7);
+ u = x12 + x15 | 0;
+ x13 ^= u << 9 | u >>> (32 - 9);
+ u = x13 + x12 | 0;
+ x14 ^= u << 13 | u >>> (32 - 13);
+ u = x14 + x13 | 0;
+ x15 ^= u << 18 | u >>> (32 - 18);
+ }
+ x0 = x0 + j0 | 0;
+ x1 = x1 + j1 | 0;
+ x2 = x2 + j2 | 0;
+ x3 = x3 + j3 | 0;
+ x4 = x4 + j4 | 0;
+ x5 = x5 + j5 | 0;
+ x6 = x6 + j6 | 0;
+ x7 = x7 + j7 | 0;
+ x8 = x8 + j8 | 0;
+ x9 = x9 + j9 | 0;
+ x10 = x10 + j10 | 0;
+ x11 = x11 + j11 | 0;
+ x12 = x12 + j12 | 0;
+ x13 = x13 + j13 | 0;
+ x14 = x14 + j14 | 0;
+ x15 = x15 + j15 | 0;
+
+ o[0] = (byte) (x0 >>> 0 & 0xff);
+ o[1] = (byte) (x0 >>> 8 & 0xff);
+ o[2] = (byte) (x0 >>> 16 & 0xff);
+ o[3] = (byte) (x0 >>> 24 & 0xff);
+
+ o[4] = (byte) (x1 >>> 0 & 0xff);
+ o[5] = (byte) (x1 >>> 8 & 0xff);
+ o[6] = (byte) (x1 >>> 16 & 0xff);
+ o[7] = (byte) (x1 >>> 24 & 0xff);
+
+ o[8] = (byte) (x2 >>> 0 & 0xff);
+ o[9] = (byte) (x2 >>> 8 & 0xff);
+ o[10] = (byte) (x2 >>> 16 & 0xff);
+ o[11] = (byte) (x2 >>> 24 & 0xff);
+
+ o[12] = (byte) (x3 >>> 0 & 0xff);
+ o[13] = (byte) (x3 >>> 8 & 0xff);
+ o[14] = (byte) (x3 >>> 16 & 0xff);
+ o[15] = (byte) (x3 >>> 24 & 0xff);
+
+ o[16] = (byte) (x4 >>> 0 & 0xff);
+ o[17] = (byte) (x4 >>> 8 & 0xff);
+ o[18] = (byte) (x4 >>> 16 & 0xff);
+ o[19] = (byte) (x4 >>> 24 & 0xff);
+
+ o[20] = (byte) (x5 >>> 0 & 0xff);
+ o[21] = (byte) (x5 >>> 8 & 0xff);
+ o[22] = (byte) (x5 >>> 16 & 0xff);
+ o[23] = (byte) (x5 >>> 24 & 0xff);
+
+ o[24] = (byte) (x6 >>> 0 & 0xff);
+ o[25] = (byte) (x6 >>> 8 & 0xff);
+ o[26] = (byte) (x6 >>> 16 & 0xff);
+ o[27] = (byte) (x6 >>> 24 & 0xff);
+
+ o[28] = (byte) (x7 >>> 0 & 0xff);
+ o[29] = (byte) (x7 >>> 8 & 0xff);
+ o[30] = (byte) (x7 >>> 16 & 0xff);
+ o[31] = (byte) (x7 >>> 24 & 0xff);
+
+ o[32] = (byte) (x8 >>> 0 & 0xff);
+ o[33] = (byte) (x8 >>> 8 & 0xff);
+ o[34] = (byte) (x8 >>> 16 & 0xff);
+ o[35] = (byte) (x8 >>> 24 & 0xff);
+
+ o[36] = (byte) (x9 >>> 0 & 0xff);
+ o[37] = (byte) (x9 >>> 8 & 0xff);
+ o[38] = (byte) (x9 >>> 16 & 0xff);
+ o[39] = (byte) (x9 >>> 24 & 0xff);
+
+ o[40] = (byte) (x10 >>> 0 & 0xff);
+ o[41] = (byte) (x10 >>> 8 & 0xff);
+ o[42] = (byte) (x10 >>> 16 & 0xff);
+ o[43] = (byte) (x10 >>> 24 & 0xff);
+
+ o[44] = (byte) (x11 >>> 0 & 0xff);
+ o[45] = (byte) (x11 >>> 8 & 0xff);
+ o[46] = (byte) (x11 >>> 16 & 0xff);
+ o[47] = (byte) (x11 >>> 24 & 0xff);
+
+ o[48] = (byte) (x12 >>> 0 & 0xff);
+ o[49] = (byte) (x12 >>> 8 & 0xff);
+ o[50] = (byte) (x12 >>> 16 & 0xff);
+ o[51] = (byte) (x12 >>> 24 & 0xff);
+
+ o[52] = (byte) (x13 >>> 0 & 0xff);
+ o[53] = (byte) (x13 >>> 8 & 0xff);
+ o[54] = (byte) (x13 >>> 16 & 0xff);
+ o[55] = (byte) (x13 >>> 24 & 0xff);
+
+ o[56] = (byte) (x14 >>> 0 & 0xff);
+ o[57] = (byte) (x14 >>> 8 & 0xff);
+ o[58] = (byte) (x14 >>> 16 & 0xff);
+ o[59] = (byte) (x14 >>> 24 & 0xff);
+
+ o[60] = (byte) (x15 >>> 0 & 0xff);
+ o[61] = (byte) (x15 >>> 8 & 0xff);
+ o[62] = (byte) (x15 >>> 16 & 0xff);
+ o[63] = (byte) (x15 >>> 24 & 0xff);
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
+ Log.d(TAG, "core_salsa20 -> "+dbgt);
+*/
+ }
+
+ private static void core_hsalsa20(byte[] o, byte[] p, byte[] k, byte[] c) {
+ int j0 = c[0] & 0xff | (c[1] & 0xff) << 8 | (c[2] & 0xff) << 16 | (c[3] & 0xff) << 24,
+ j1 = k[0] & 0xff | (k[1] & 0xff) << 8 | (k[2] & 0xff) << 16 | (k[3] & 0xff) << 24,
+ j2 = k[4] & 0xff | (k[5] & 0xff) << 8 | (k[6] & 0xff) << 16 | (k[7] & 0xff) << 24,
+ j3 = k[8] & 0xff | (k[9] & 0xff) << 8 | (k[10] & 0xff) << 16 | (k[11] & 0xff) << 24,
+ j4 = k[12] & 0xff | (k[13] & 0xff) << 8 | (k[14] & 0xff) << 16 | (k[15] & 0xff) << 24,
+ j5 = c[4] & 0xff | (c[5] & 0xff) << 8 | (c[6] & 0xff) << 16 | (c[7] & 0xff) << 24,
+ j6 = p[0] & 0xff | (p[1] & 0xff) << 8 | (p[2] & 0xff) << 16 | (p[3] & 0xff) << 24,
+ j7 = p[4] & 0xff | (p[5] & 0xff) << 8 | (p[6] & 0xff) << 16 | (p[7] & 0xff) << 24,
+ j8 = p[8] & 0xff | (p[9] & 0xff) << 8 | (p[10] & 0xff) << 16 | (p[11] & 0xff) << 24,
+ j9 = p[12] & 0xff | (p[13] & 0xff) << 8 | (p[14] & 0xff) << 16 | (p[15] & 0xff) << 24,
+ j10 = c[8] & 0xff | (c[9] & 0xff) << 8 | (c[10] & 0xff) << 16 | (c[11] & 0xff) << 24,
+ j11 = k[16] & 0xff | (k[17] & 0xff) << 8 | (k[18] & 0xff) << 16 | (k[19] & 0xff) << 24,
+ j12 = k[20] & 0xff | (k[21] & 0xff) << 8 | (k[22] & 0xff) << 16 | (k[23] & 0xff) << 24,
+ j13 = k[24] & 0xff | (k[25] & 0xff) << 8 | (k[26] & 0xff) << 16 | (k[27] & 0xff) << 24,
+ j14 = k[28] & 0xff | (k[29] & 0xff) << 8 | (k[30] & 0xff) << 16 | (k[31] & 0xff) << 24,
+ j15 = c[12] & 0xff | (c[13] & 0xff) << 8 | (c[14] & 0xff) << 16 | (c[15] & 0xff) << 24;
+
+ int x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,
+ x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,
+ x15 = j15, u;
+
+ for (int i = 0; i < 20; i += 2) {
+ u = x0 + x12 | 0;
+ x4 ^= u << 7 | u >>> (32 - 7);
+ u = x4 + x0 | 0;
+ x8 ^= u << 9 | u >>> (32 - 9);
+ u = x8 + x4 | 0;
+ x12 ^= u << 13 | u >>> (32 - 13);
+ u = x12 + x8 | 0;
+ x0 ^= u << 18 | u >>> (32 - 18);
+
+ u = x5 + x1 | 0;
+ x9 ^= u << 7 | u >>> (32 - 7);
+ u = x9 + x5 | 0;
+ x13 ^= u << 9 | u >>> (32 - 9);
+ u = x13 + x9 | 0;
+ x1 ^= u << 13 | u >>> (32 - 13);
+ u = x1 + x13 | 0;
+ x5 ^= u << 18 | u >>> (32 - 18);
+
+ u = x10 + x6 | 0;
+ x14 ^= u << 7 | u >>> (32 - 7);
+ u = x14 + x10 | 0;
+ x2 ^= u << 9 | u >>> (32 - 9);
+ u = x2 + x14 | 0;
+ x6 ^= u << 13 | u >>> (32 - 13);
+ u = x6 + x2 | 0;
+ x10 ^= u << 18 | u >>> (32 - 18);
+
+ u = x15 + x11 | 0;
+ x3 ^= u << 7 | u >>> (32 - 7);
+ u = x3 + x15 | 0;
+ x7 ^= u << 9 | u >>> (32 - 9);
+ u = x7 + x3 | 0;
+ x11 ^= u << 13 | u >>> (32 - 13);
+ u = x11 + x7 | 0;
+ x15 ^= u << 18 | u >>> (32 - 18);
+
+ u = x0 + x3 | 0;
+ x1 ^= u << 7 | u >>> (32 - 7);
+ u = x1 + x0 | 0;
+ x2 ^= u << 9 | u >>> (32 - 9);
+ u = x2 + x1 | 0;
+ x3 ^= u << 13 | u >>> (32 - 13);
+ u = x3 + x2 | 0;
+ x0 ^= u << 18 | u >>> (32 - 18);
+
+ u = x5 + x4 | 0;
+ x6 ^= u << 7 | u >>> (32 - 7);
+ u = x6 + x5 | 0;
+ x7 ^= u << 9 | u >>> (32 - 9);
+ u = x7 + x6 | 0;
+ x4 ^= u << 13 | u >>> (32 - 13);
+ u = x4 + x7 | 0;
+ x5 ^= u << 18 | u >>> (32 - 18);
+
+ u = x10 + x9 | 0;
+ x11 ^= u << 7 | u >>> (32 - 7);
+ u = x11 + x10 | 0;
+ x8 ^= u << 9 | u >>> (32 - 9);
+ u = x8 + x11 | 0;
+ x9 ^= u << 13 | u >>> (32 - 13);
+ u = x9 + x8 | 0;
+ x10 ^= u << 18 | u >>> (32 - 18);
+
+ u = x15 + x14 | 0;
+ x12 ^= u << 7 | u >>> (32 - 7);
+ u = x12 + x15 | 0;
+ x13 ^= u << 9 | u >>> (32 - 9);
+ u = x13 + x12 | 0;
+ x14 ^= u << 13 | u >>> (32 - 13);
+ u = x14 + x13 | 0;
+ x15 ^= u << 18 | u >>> (32 - 18);
+ }
+
+ o[0] = (byte) (x0 >>> 0 & 0xff);
+ o[1] = (byte) (x0 >>> 8 & 0xff);
+ o[2] = (byte) (x0 >>> 16 & 0xff);
+ o[3] = (byte) (x0 >>> 24 & 0xff);
+
+ o[4] = (byte) (x5 >>> 0 & 0xff);
+ o[5] = (byte) (x5 >>> 8 & 0xff);
+ o[6] = (byte) (x5 >>> 16 & 0xff);
+ o[7] = (byte) (x5 >>> 24 & 0xff);
+
+ o[8] = (byte) (x10 >>> 0 & 0xff);
+ o[9] = (byte) (x10 >>> 8 & 0xff);
+ o[10] = (byte) (x10 >>> 16 & 0xff);
+ o[11] = (byte) (x10 >>> 24 & 0xff);
+
+ o[12] = (byte) (x15 >>> 0 & 0xff);
+ o[13] = (byte) (x15 >>> 8 & 0xff);
+ o[14] = (byte) (x15 >>> 16 & 0xff);
+ o[15] = (byte) (x15 >>> 24 & 0xff);
+
+ o[16] = (byte) (x6 >>> 0 & 0xff);
+ o[17] = (byte) (x6 >>> 8 & 0xff);
+ o[18] = (byte) (x6 >>> 16 & 0xff);
+ o[19] = (byte) (x6 >>> 24 & 0xff);
+
+ o[20] = (byte) (x7 >>> 0 & 0xff);
+ o[21] = (byte) (x7 >>> 8 & 0xff);
+ o[22] = (byte) (x7 >>> 16 & 0xff);
+ o[23] = (byte) (x7 >>> 24 & 0xff);
+
+ o[24] = (byte) (x8 >>> 0 & 0xff);
+ o[25] = (byte) (x8 >>> 8 & 0xff);
+ o[26] = (byte) (x8 >>> 16 & 0xff);
+ o[27] = (byte) (x8 >>> 24 & 0xff);
+
+ o[28] = (byte) (x9 >>> 0 & 0xff);
+ o[29] = (byte) (x9 >>> 8 & 0xff);
+ o[30] = (byte) (x9 >>> 16 & 0xff);
+ o[31] = (byte) (x9 >>> 24 & 0xff);
+
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < o.length; dbg ++) dbgt += " "+o[dbg];
+ Log.d(TAG, "core_hsalsa20 -> "+dbgt);
+*/
+ }
+
+ public static int crypto_core_salsa20(byte[] out, byte[] in, byte[] k, byte[] c) {
+ ///core(out,in,k,c,0);
+ core_salsa20(out, in, k, c);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
+ ///L/og.d(TAG, "crypto_core_salsa20 -> "+dbgt);
+
+ return 0;
+ }
+
+ public static int crypto_core_hsalsa20(byte[] out, byte[] in, byte[] k, byte[] c) {
+ ///core(out,in,k,c,1);
+ core_hsalsa20(out, in, k, c);
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < out.length; dbg ++) dbgt += " "+out[dbg];
+ ///L/og.d(TAG, "crypto_core_hsalsa20 -> "+dbgt);
+
+ return 0;
+ }
+
+ // "expand 32-byte k"
+ private static final byte[] sigma = {101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107};
+
+ /*static {
+ try {
+ sigma = "expand 32-byte k".getBytes("utf-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }*/
+
+ private static int crypto_stream_salsa20_xor(byte[] c, int cpos, byte[] m, int mpos, long b, byte[] n, byte[] k) {
+ byte[] z = new byte[16], x = new byte[64];
+ int u, i;
+ for (i = 0; i < 16; i++) z[i] = 0;
+ for (i = 0; i < 8; i++) z[i] = n[i];
+ while (b >= 64) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < 64; i++) c[cpos + i] = (byte) ((m[mpos + i] ^ x[i]) & 0xff);
+ u = 1;
+ for (i = 8; i < 16; i++) {
+ u = u + (z[i] & 0xff) | 0;
+ z[i] = (byte) (u & 0xff);
+ u >>>= 8;
+ }
+ b -= 64;
+ cpos += 64;
+ mpos += 64;
+ }
+ if (b > 0) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < b; i++) c[cpos + i] = (byte) ((m[mpos + i] ^ x[i]) & 0xff);
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos];
+ ///Log.d(TAG, "crypto_stream_salsa20_xor, c -> "+dbgt);
+
+ return 0;
+ }
+
+ public static int crypto_stream_salsa20(byte[] c, int cpos, long b, byte[] n, byte[] k) {
+ byte[] z = new byte[16], x = new byte[64];
+ int u, i;
+ for (i = 0; i < 16; i++) z[i] = 0;
+ for (i = 0; i < 8; i++) z[i] = n[i];
+ while (b >= 64) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < 64; i++) c[cpos + i] = x[i];
+ u = 1;
+ for (i = 8; i < 16; i++) {
+ u = u + (z[i] & 0xff) | 0;
+ z[i] = (byte) (u & 0xff);
+ u >>>= 8;
+ }
+ b -= 64;
+ cpos += 64;
+ }
+ if (b > 0) {
+ crypto_core_salsa20(x, z, k, sigma);
+ for (i = 0; i < b; i++) c[cpos + i] = x[i];
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < c.length-cpos; dbg ++) dbgt += " "+c[dbg +cpos];
+ ///Log.d(TAG, "crypto_stream_salsa20, c -> "+dbgt);
+
+ return 0;
+ }
+
+ public static int crypto_stream(byte[] c, int cpos, long d, byte[] n, byte[] k) {
+ byte[] s = new byte[32];
+ crypto_core_hsalsa20(s, n, k, sigma);
+ byte[] sn = new byte[8];
+ for (int i = 0; i < 8; i++) sn[i] = n[i + 16];
+ return crypto_stream_salsa20(c, cpos, d, sn, s);
+ }
+
+ public static int crypto_stream_xor(byte[] c, int cpos, byte[] m, int mpos, long d, byte[] n, byte[] k) {
+ byte[] s = new byte[32];
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < n.length; dbg ++) dbgt += " "+n[dbg];
+ Log.d(TAG, "crypto_stream_xor, nonce -> "+dbgt);
+
+ dbgt = "";
+ for (int dbg = 0; dbg < k.length; dbg ++) dbgt += " "+k[dbg];
+ Log.d(TAG, "crypto_stream_xor, shk -> "+dbgt);
+ */
+
+ crypto_core_hsalsa20(s, n, k, sigma);
+ byte[] sn = new byte[8];
+ for (int i = 0; i < 8; i++) sn[i] = n[i + 16];
+ return crypto_stream_salsa20_xor(c, cpos, m, mpos, d, sn, s);
+ }
+
+ /*
+ * Port of Andrew Moon's Poly1305-donna-16. Public domain.
+ * https://github.com/floodyberry/poly1305-donna
+ */
+ public static final class poly1305 {
+
+ private byte[] buffer;
+ private int[] r;
+ private int[] h;
+ private int[] pad;
+ private int leftover;
+ private int fin;
+
+ public poly1305(byte[] key) {
+ this.buffer = new byte[16];
+ this.r = new int[10];
+ this.h = new int[10];
+ this.pad = new int[8];
+ this.leftover = 0;
+ this.fin = 0;
+
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ t0 = key[0] & 0xff | (key[1] & 0xff) << 8;
+ this.r[0] = (t0) & 0x1fff;
+ t1 = key[2] & 0xff | (key[3] & 0xff) << 8;
+ this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
+ t2 = key[4] & 0xff | (key[5] & 0xff) << 8;
+ this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;
+ t3 = key[6] & 0xff | (key[7] & 0xff) << 8;
+ this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
+ t4 = key[8] & 0xff | (key[9] & 0xff) << 8;
+ this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;
+ this.r[5] = ((t4 >>> 1)) & 0x1ffe;
+ t5 = key[10] & 0xff | (key[11] & 0xff) << 8;
+ this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
+ t6 = key[12] & 0xff | (key[13] & 0xff) << 8;
+ this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;
+ t7 = key[14] & 0xff | (key[15] & 0xff) << 8;
+ this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
+ this.r[9] = ((t7 >>> 5)) & 0x007f;
+
+ this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8;
+ this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8;
+ this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8;
+ this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8;
+ this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8;
+ this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8;
+ this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8;
+ this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8;
+ }
+
+ public poly1305 blocks(byte[] m, int mpos, int bytes) {
+ int hibit = this.fin != 0 ? 0 : (1 << 11);
+ int t0, t1, t2, t3, t4, t5, t6, t7, c;
+ int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9;
+
+ int h0 = this.h[0],
+ h1 = this.h[1],
+ h2 = this.h[2],
+ h3 = this.h[3],
+ h4 = this.h[4],
+ h5 = this.h[5],
+ h6 = this.h[6],
+ h7 = this.h[7],
+ h8 = this.h[8],
+ h9 = this.h[9];
+
+ int r0 = this.r[0],
+ r1 = this.r[1],
+ r2 = this.r[2],
+ r3 = this.r[3],
+ r4 = this.r[4],
+ r5 = this.r[5],
+ r6 = this.r[6],
+ r7 = this.r[7],
+ r8 = this.r[8],
+ r9 = this.r[9];
+
+ while (bytes >= 16) {
+ t0 = m[mpos + 0] & 0xff | (m[mpos + 1] & 0xff) << 8;
+ h0 += (t0) & 0x1fff;
+ t1 = m[mpos + 2] & 0xff | (m[mpos + 3] & 0xff) << 8;
+ h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;
+ t2 = m[mpos + 4] & 0xff | (m[mpos + 5] & 0xff) << 8;
+ h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff;
+ t3 = m[mpos + 6] & 0xff | (m[mpos + 7] & 0xff) << 8;
+ h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff;
+ t4 = m[mpos + 8] & 0xff | (m[mpos + 9] & 0xff) << 8;
+ h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff;
+ h5 += ((t4 >>> 1)) & 0x1fff;
+ t5 = m[mpos + 10] & 0xff | (m[mpos + 11] & 0xff) << 8;
+ h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff;
+ t6 = m[mpos + 12] & 0xff | (m[mpos + 13] & 0xff) << 8;
+ h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff;
+ t7 = m[mpos + 14] & 0xff | (m[mpos + 15] & 0xff) << 8;
+ h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff;
+ h9 += ((t7 >>> 5)) | hibit;
+
+ c = 0;
+
+ d0 = c;
+ d0 += h0 * r0;
+ d0 += h1 * (5 * r9);
+ d0 += h2 * (5 * r8);
+ d0 += h3 * (5 * r7);
+ d0 += h4 * (5 * r6);
+ c = (d0 >>> 13);
+ d0 &= 0x1fff;
+ d0 += h5 * (5 * r5);
+ d0 += h6 * (5 * r4);
+ d0 += h7 * (5 * r3);
+ d0 += h8 * (5 * r2);
+ d0 += h9 * (5 * r1);
+ c += (d0 >>> 13);
+ d0 &= 0x1fff;
+
+ d1 = c;
+ d1 += h0 * r1;
+ d1 += h1 * r0;
+ d1 += h2 * (5 * r9);
+ d1 += h3 * (5 * r8);
+ d1 += h4 * (5 * r7);
+ c = (d1 >>> 13);
+ d1 &= 0x1fff;
+ d1 += h5 * (5 * r6);
+ d1 += h6 * (5 * r5);
+ d1 += h7 * (5 * r4);
+ d1 += h8 * (5 * r3);
+ d1 += h9 * (5 * r2);
+ c += (d1 >>> 13);
+ d1 &= 0x1fff;
+
+ d2 = c;
+ d2 += h0 * r2;
+ d2 += h1 * r1;
+ d2 += h2 * r0;
+ d2 += h3 * (5 * r9);
+ d2 += h4 * (5 * r8);
+ c = (d2 >>> 13);
+ d2 &= 0x1fff;
+ d2 += h5 * (5 * r7);
+ d2 += h6 * (5 * r6);
+ d2 += h7 * (5 * r5);
+ d2 += h8 * (5 * r4);
+ d2 += h9 * (5 * r3);
+ c += (d2 >>> 13);
+ d2 &= 0x1fff;
+
+ d3 = c;
+ d3 += h0 * r3;
+ d3 += h1 * r2;
+ d3 += h2 * r1;
+ d3 += h3 * r0;
+ d3 += h4 * (5 * r9);
+ c = (d3 >>> 13);
+ d3 &= 0x1fff;
+ d3 += h5 * (5 * r8);
+ d3 += h6 * (5 * r7);
+ d3 += h7 * (5 * r6);
+ d3 += h8 * (5 * r5);
+ d3 += h9 * (5 * r4);
+ c += (d3 >>> 13);
+ d3 &= 0x1fff;
+
+ d4 = c;
+ d4 += h0 * r4;
+ d4 += h1 * r3;
+ d4 += h2 * r2;
+ d4 += h3 * r1;
+ d4 += h4 * r0;
+ c = (d4 >>> 13);
+ d4 &= 0x1fff;
+ d4 += h5 * (5 * r9);
+ d4 += h6 * (5 * r8);
+ d4 += h7 * (5 * r7);
+ d4 += h8 * (5 * r6);
+ d4 += h9 * (5 * r5);
+ c += (d4 >>> 13);
+ d4 &= 0x1fff;
+
+ d5 = c;
+ d5 += h0 * r5;
+ d5 += h1 * r4;
+ d5 += h2 * r3;
+ d5 += h3 * r2;
+ d5 += h4 * r1;
+ c = (d5 >>> 13);
+ d5 &= 0x1fff;
+ d5 += h5 * r0;
+ d5 += h6 * (5 * r9);
+ d5 += h7 * (5 * r8);
+ d5 += h8 * (5 * r7);
+ d5 += h9 * (5 * r6);
+ c += (d5 >>> 13);
+ d5 &= 0x1fff;
+
+ d6 = c;
+ d6 += h0 * r6;
+ d6 += h1 * r5;
+ d6 += h2 * r4;
+ d6 += h3 * r3;
+ d6 += h4 * r2;
+ c = (d6 >>> 13);
+ d6 &= 0x1fff;
+ d6 += h5 * r1;
+ d6 += h6 * r0;
+ d6 += h7 * (5 * r9);
+ d6 += h8 * (5 * r8);
+ d6 += h9 * (5 * r7);
+ c += (d6 >>> 13);
+ d6 &= 0x1fff;
+
+ d7 = c;
+ d7 += h0 * r7;
+ d7 += h1 * r6;
+ d7 += h2 * r5;
+ d7 += h3 * r4;
+ d7 += h4 * r3;
+ c = (d7 >>> 13);
+ d7 &= 0x1fff;
+ d7 += h5 * r2;
+ d7 += h6 * r1;
+ d7 += h7 * r0;
+ d7 += h8 * (5 * r9);
+ d7 += h9 * (5 * r8);
+ c += (d7 >>> 13);
+ d7 &= 0x1fff;
+
+ d8 = c;
+ d8 += h0 * r8;
+ d8 += h1 * r7;
+ d8 += h2 * r6;
+ d8 += h3 * r5;
+ d8 += h4 * r4;
+ c = (d8 >>> 13);
+ d8 &= 0x1fff;
+ d8 += h5 * r3;
+ d8 += h6 * r2;
+ d8 += h7 * r1;
+ d8 += h8 * r0;
+ d8 += h9 * (5 * r9);
+ c += (d8 >>> 13);
+ d8 &= 0x1fff;
+
+ d9 = c;
+ d9 += h0 * r9;
+ d9 += h1 * r8;
+ d9 += h2 * r7;
+ d9 += h3 * r6;
+ d9 += h4 * r5;
+ c = (d9 >>> 13);
+ d9 &= 0x1fff;
+ d9 += h5 * r4;
+ d9 += h6 * r3;
+ d9 += h7 * r2;
+ d9 += h8 * r1;
+ d9 += h9 * r0;
+ c += (d9 >>> 13);
+ d9 &= 0x1fff;
+
+ c = (((c << 2) + c)) | 0;
+ c = (c + d0) | 0;
+ d0 = c & 0x1fff;
+ c = (c >>> 13);
+ d1 += c;
+
+ h0 = d0;
+ h1 = d1;
+ h2 = d2;
+ h3 = d3;
+ h4 = d4;
+ h5 = d5;
+ h6 = d6;
+ h7 = d7;
+ h8 = d8;
+ h9 = d9;
+
+ mpos += 16;
+ bytes -= 16;
+ }
+ this.h[0] = h0;
+ this.h[1] = h1;
+ this.h[2] = h2;
+ this.h[3] = h3;
+ this.h[4] = h4;
+ this.h[5] = h5;
+ this.h[6] = h6;
+ this.h[7] = h7;
+ this.h[8] = h8;
+ this.h[9] = h9;
+
+ return this;
+ }
+
+ public poly1305 finish(byte[] mac, int macpos) {
+ int[] g = new int[10];
+ int c, mask, f, i;
+
+ if (this.leftover != 0) {
+ i = this.leftover;
+ this.buffer[i++] = 1;
+ for (; i < 16; i++) this.buffer[i] = 0;
+ this.fin = 1;
+ this.blocks(this.buffer, 0, 16);
+ }
+
+ c = this.h[1] >>> 13;
+ this.h[1] &= 0x1fff;
+ for (i = 2; i < 10; i++) {
+ this.h[i] += c;
+ c = this.h[i] >>> 13;
+ this.h[i] &= 0x1fff;
+ }
+ this.h[0] += (c * 5);
+ c = this.h[0] >>> 13;
+ this.h[0] &= 0x1fff;
+ this.h[1] += c;
+ c = this.h[1] >>> 13;
+ this.h[1] &= 0x1fff;
+ this.h[2] += c;
+
+ g[0] = this.h[0] + 5;
+ c = g[0] >>> 13;
+ g[0] &= 0x1fff;
+ for (i = 1; i < 10; i++) {
+ g[i] = this.h[i] + c;
+ c = g[i] >>> 13;
+ g[i] &= 0x1fff;
+ }
+ g[9] -= (1 << 13);
+ g[9] &= 0xffff;
+
+ /*
+ backport from tweetnacl-fast.js https://github.com/dchest/tweetnacl-js/releases/tag/v0.14.3
+ <<<
+ "The issue was not properly detecting if st->h was >= 2^130 - 5,
+ coupled with [testing mistake] not catching the failure.
+ The chance of the bug affecting anything in the real world is essentially zero luckily,
+ but it's good to have it fixed."
+ >>>
+ */
+ ///change mask = (g[9] >>> ((2 * 8) - 1)) - 1; to as
+ mask = (c ^ 1) - 1;
+ mask &= 0xffff;
+ ///////////////////////////////////////
+
+ for (i = 0; i < 10; i++) g[i] &= mask;
+ mask = ~mask;
+ for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i];
+
+ this.h[0] = ((this.h[0]) | (this.h[1] << 13)) & 0xffff;
+ this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10)) & 0xffff;
+ this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7)) & 0xffff;
+ this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4)) & 0xffff;
+ this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff;
+ this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11)) & 0xffff;
+ this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8)) & 0xffff;
+ this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff;
+
+ f = this.h[0] + this.pad[0];
+ this.h[0] = f & 0xffff;
+ for (i = 1; i < 8; i++) {
+ f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0;
+ this.h[i] = f & 0xffff;
+ }
+
+ mac[macpos + 0] = (byte) ((this.h[0] >>> 0) & 0xff);
+ mac[macpos + 1] = (byte) ((this.h[0] >>> 8) & 0xff);
+ mac[macpos + 2] = (byte) ((this.h[1] >>> 0) & 0xff);
+ mac[macpos + 3] = (byte) ((this.h[1] >>> 8) & 0xff);
+ mac[macpos + 4] = (byte) ((this.h[2] >>> 0) & 0xff);
+ mac[macpos + 5] = (byte) ((this.h[2] >>> 8) & 0xff);
+ mac[macpos + 6] = (byte) ((this.h[3] >>> 0) & 0xff);
+ mac[macpos + 7] = (byte) ((this.h[3] >>> 8) & 0xff);
+ mac[macpos + 8] = (byte) ((this.h[4] >>> 0) & 0xff);
+ mac[macpos + 9] = (byte) ((this.h[4] >>> 8) & 0xff);
+ mac[macpos + 10] = (byte) ((this.h[5] >>> 0) & 0xff);
+ mac[macpos + 11] = (byte) ((this.h[5] >>> 8) & 0xff);
+ mac[macpos + 12] = (byte) ((this.h[6] >>> 0) & 0xff);
+ mac[macpos + 13] = (byte) ((this.h[6] >>> 8) & 0xff);
+ mac[macpos + 14] = (byte) ((this.h[7] >>> 0) & 0xff);
+ mac[macpos + 15] = (byte) ((this.h[7] >>> 8) & 0xff);
+
+ return this;
+ }
+
+ public poly1305 update(byte[] m, int mpos, int bytes) {
+ int i, want;
+
+ if (this.leftover != 0) {
+ want = (16 - this.leftover);
+ if (want > bytes)
+ want = bytes;
+ for (i = 0; i < want; i++)
+ this.buffer[this.leftover + i] = m[mpos + i];
+ bytes -= want;
+ mpos += want;
+ this.leftover += want;
+ if (this.leftover < 16)
+ return this;
+ this.blocks(buffer, 0, 16);
+ this.leftover = 0;
+ }
+
+ if (bytes >= 16) {
+ want = bytes - (bytes % 16);
+ this.blocks(m, mpos, want);
+ mpos += want;
+ bytes -= want;
+ }
+
+ if (bytes != 0) {
+ for (i = 0; i < bytes; i++)
+ this.buffer[this.leftover + i] = m[mpos + i];
+ this.leftover += bytes;
+ }
+
+ return this;
+ }
+
+ }
+
+ private static int crypto_onetimeauth(
+ byte[] out, final int outpos,
+ byte[] m, final int mpos,
+ int n,
+ byte[] k) {
+ poly1305 s = new poly1305(k);
+ s.update(m, mpos, n);
+ s.finish(out, outpos);
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < out.length-outpos; dbg ++) dbgt += " "+out[dbg+outpos];
+ Log.d(TAG, "crypto_onetimeauth -> "+dbgt);
+ */
+
+ return 0;
+ }
+
+ public static int crypto_onetimeauth(byte[] out, byte[] m, int /*long*/ n, byte[] k) {
+ return crypto_onetimeauth(out, 0, m, 0, n, k);
+ }
+
+ private static int crypto_onetimeauth_verify(
+ byte[] h, final int hoff,
+ byte[] m, final int moff,
+ int /*long*/ n,
+ byte[] k) {
+ byte[] x = new byte[16];
+ crypto_onetimeauth(x, 0, m, moff, n, k);
+ return crypto_verify_16(h, hoff, x, 0);
+ }
+
+ public static int crypto_onetimeauth_verify(byte[] h, byte[] m, int /*long*/ n, byte[] k) {
+ return crypto_onetimeauth_verify(h, 0, m, 0, n, k);
+ }
+
+ public static int crypto_onetimeauth_verify(byte[] h, byte[] m, byte[] k) {
+ return crypto_onetimeauth_verify(h, m, m != null ? m.length : 0, k);
+ }
+
+ public static int crypto_secretbox(byte[] c, byte[] m, int /*long*/ d, byte[] n, byte[] k) {
+ int i;
+ if (d < 32) return -1;
+ crypto_stream_xor(c, 0, m, 0, d, n, k);
+ crypto_onetimeauth(c, 16, c, 32, d - 32, c);
+ ///for (i = 0; i < 16; i++) c[i] = 0;
+ return 0;
+ }
+
+ public static int crypto_secretbox_open(byte[] m, byte[] c, int /*long*/ d, byte[] n, byte[] k) {
+ int i;
+ byte[] x = new byte[32];
+ if (d < 32) return -1;
+ crypto_stream(x, 0, 32, n, k);
+ if (crypto_onetimeauth_verify(c, 16, c, 32, d - 32, x) != 0) return -1;
+ crypto_stream_xor(m, 0, c, 0, d, n, k);
+ ///for (i = 0; i < 32; i++) m[i] = 0;
+ return 0;
+ }
+
+ private static void set25519(long[] r, long[] a) {
+ int i;
+ for (i = 0; i < 16; i++) r[i] = a[i];
+ }
+
+ private static void car25519(long[] o) {
+ int i;
+ long v, c = 1;
+ for (i = 0; i < 16; i++) {
+ v = o[i] + c + 65535;
+ c = v >> 16;
+ o[i] = v - c * 65536;
+ }
+ o[0] += c - 1 + 37 * (c - 1);
+ }
+
+ private static void sel25519(
+ long[] p,
+ long[] q,
+ int b) {
+ sel25519(p, 0, q, 0, b);
+ }
+
+ private static void sel25519(
+ long[] p, final int poff,
+ long[] q, final int qoff,
+ int b) {
+ long t, c = ~(b - 1);
+ for (int i = 0; i < 16; i++) {
+ t = c & (p[i + poff] ^ q[i + qoff]);
+ p[i + poff] ^= t;
+ q[i + qoff] ^= t;
+ }
+ }
+
+ private static void pack25519(byte[] o, long[] n, final int noff) {
+ int i, j, b;
+ long[] m = new long[16], t = new long[16];
+ for (i = 0; i < 16; i++) t[i] = n[i + noff];
+ car25519(t);
+ car25519(t);
+ car25519(t);
+ for (j = 0; j < 2; j++) {
+ m[0] = t[0] - 0xffed;
+ for (i = 1; i < 15; i++) {
+ m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
+ m[i - 1] &= 0xffff;
+ }
+ m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
+ b = (int) ((m[15] >> 16) & 1);
+ m[14] &= 0xffff;
+ sel25519(t, 0, m, 0, 1 - b);
+ }
+ for (i = 0; i < 16; i++) {
+ o[2 * i] = (byte) (t[i] & 0xff);
+ o[2 * i + 1] = (byte) (t[i] >> 8);
+ }
+ }
+
+ private static int neq25519(long[] a, long[] b) {
+ return neq25519(a, 0, b, 0);
+ }
+
+ private static int neq25519(long[] a, final int aoff, long[] b, final int boff) {
+ byte[] c = new byte[32], d = new byte[32];
+ pack25519(c, a, aoff);
+ pack25519(d, b, boff);
+ return crypto_verify_32(c, 0, d, 0);
+ }
+
+ private static byte par25519(long[] a) {
+ return par25519(a, 0);
+ }
+
+ private static byte par25519(long[] a, final int aoff) {
+ byte[] d = new byte[32];
+ pack25519(d, a, aoff);
+ return (byte) (d[0] & 1);
+ }
+
+ private static void unpack25519(long[] o, byte[] n) {
+ int i;
+ for (i = 0; i < 16; i++) o[i] = (n[2 * i] & 0xff) + ((long) ((n[2 * i + 1] << 8) & 0xffff));
+ o[15] &= 0x7fff;
+ }
+
+ private static void A(
+ long[] o,
+ long[] a,
+ long[] b) {
+ A(o, 0, a, 0, b, 0);
+ }
+
+ private static void A(
+ long[] o, final int ooff,
+ long[] a, final int aoff,
+ long[] b, final int boff) {
+ int i;
+ for (i = 0; i < 16; i++) o[i + ooff] = a[i + aoff] + b[i + boff];
+ }
+
+ private static void Z(
+ long[] o,
+ long[] a,
+ long[] b) {
+ Z(o, 0, a, 0, b, 0);
+ }
+
+ private static void Z(
+ long[] o, final int ooff,
+ long[] a, final int aoff,
+ long[] b, final int boff) {
+ int i;
+ for (i = 0; i < 16; i++) o[i + ooff] = a[i + aoff] - b[i + boff];
+ }
+
+ private static void M(
+ long[] o,
+ long[] a,
+ long[] b) {
+ M(o, 0, a, 0, b, 0);
+ }
+
+ private static void M(
+ long[] o, final int ooff,
+ long[] a, final int aoff,
+ long[] b, final int boff) {
+ long v, c,
+ t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
+ t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,
+ t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,
+ t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,
+ b0 = b[0 + boff],
+ b1 = b[1 + boff],
+ b2 = b[2 + boff],
+ b3 = b[3 + boff],
+ b4 = b[4 + boff],
+ b5 = b[5 + boff],
+ b6 = b[6 + boff],
+ b7 = b[7 + boff],
+ b8 = b[8 + boff],
+ b9 = b[9 + boff],
+ b10 = b[10 + boff],
+ b11 = b[11 + boff],
+ b12 = b[12 + boff],
+ b13 = b[13 + boff],
+ b14 = b[14 + boff],
+ b15 = b[15 + boff];
+
+ v = a[0 + aoff];
+ t0 += v * b0;
+ t1 += v * b1;
+ t2 += v * b2;
+ t3 += v * b3;
+ t4 += v * b4;
+ t5 += v * b5;
+ t6 += v * b6;
+ t7 += v * b7;
+ t8 += v * b8;
+ t9 += v * b9;
+ t10 += v * b10;
+ t11 += v * b11;
+ t12 += v * b12;
+ t13 += v * b13;
+ t14 += v * b14;
+ t15 += v * b15;
+ v = a[1 + aoff];
+ t1 += v * b0;
+ t2 += v * b1;
+ t3 += v * b2;
+ t4 += v * b3;
+ t5 += v * b4;
+ t6 += v * b5;
+ t7 += v * b6;
+ t8 += v * b7;
+ t9 += v * b8;
+ t10 += v * b9;
+ t11 += v * b10;
+ t12 += v * b11;
+ t13 += v * b12;
+ t14 += v * b13;
+ t15 += v * b14;
+ t16 += v * b15;
+ v = a[2 + aoff];
+ t2 += v * b0;
+ t3 += v * b1;
+ t4 += v * b2;
+ t5 += v * b3;
+ t6 += v * b4;
+ t7 += v * b5;
+ t8 += v * b6;
+ t9 += v * b7;
+ t10 += v * b8;
+ t11 += v * b9;
+ t12 += v * b10;
+ t13 += v * b11;
+ t14 += v * b12;
+ t15 += v * b13;
+ t16 += v * b14;
+ t17 += v * b15;
+ v = a[3 + aoff];
+ t3 += v * b0;
+ t4 += v * b1;
+ t5 += v * b2;
+ t6 += v * b3;
+ t7 += v * b4;
+ t8 += v * b5;
+ t9 += v * b6;
+ t10 += v * b7;
+ t11 += v * b8;
+ t12 += v * b9;
+ t13 += v * b10;
+ t14 += v * b11;
+ t15 += v * b12;
+ t16 += v * b13;
+ t17 += v * b14;
+ t18 += v * b15;
+ v = a[4 + aoff];
+ t4 += v * b0;
+ t5 += v * b1;
+ t6 += v * b2;
+ t7 += v * b3;
+ t8 += v * b4;
+ t9 += v * b5;
+ t10 += v * b6;
+ t11 += v * b7;
+ t12 += v * b8;
+ t13 += v * b9;
+ t14 += v * b10;
+ t15 += v * b11;
+ t16 += v * b12;
+ t17 += v * b13;
+ t18 += v * b14;
+ t19 += v * b15;
+ v = a[5 + aoff];
+ t5 += v * b0;
+ t6 += v * b1;
+ t7 += v * b2;
+ t8 += v * b3;
+ t9 += v * b4;
+ t10 += v * b5;
+ t11 += v * b6;
+ t12 += v * b7;
+ t13 += v * b8;
+ t14 += v * b9;
+ t15 += v * b10;
+ t16 += v * b11;
+ t17 += v * b12;
+ t18 += v * b13;
+ t19 += v * b14;
+ t20 += v * b15;
+ v = a[6 + aoff];
+ t6 += v * b0;
+ t7 += v * b1;
+ t8 += v * b2;
+ t9 += v * b3;
+ t10 += v * b4;
+ t11 += v * b5;
+ t12 += v * b6;
+ t13 += v * b7;
+ t14 += v * b8;
+ t15 += v * b9;
+ t16 += v * b10;
+ t17 += v * b11;
+ t18 += v * b12;
+ t19 += v * b13;
+ t20 += v * b14;
+ t21 += v * b15;
+ v = a[7 + aoff];
+ t7 += v * b0;
+ t8 += v * b1;
+ t9 += v * b2;
+ t10 += v * b3;
+ t11 += v * b4;
+ t12 += v * b5;
+ t13 += v * b6;
+ t14 += v * b7;
+ t15 += v * b8;
+ t16 += v * b9;
+ t17 += v * b10;
+ t18 += v * b11;
+ t19 += v * b12;
+ t20 += v * b13;
+ t21 += v * b14;
+ t22 += v * b15;
+ v = a[8 + aoff];
+ t8 += v * b0;
+ t9 += v * b1;
+ t10 += v * b2;
+ t11 += v * b3;
+ t12 += v * b4;
+ t13 += v * b5;
+ t14 += v * b6;
+ t15 += v * b7;
+ t16 += v * b8;
+ t17 += v * b9;
+ t18 += v * b10;
+ t19 += v * b11;
+ t20 += v * b12;
+ t21 += v * b13;
+ t22 += v * b14;
+ t23 += v * b15;
+ v = a[9 + aoff];
+ t9 += v * b0;
+ t10 += v * b1;
+ t11 += v * b2;
+ t12 += v * b3;
+ t13 += v * b4;
+ t14 += v * b5;
+ t15 += v * b6;
+ t16 += v * b7;
+ t17 += v * b8;
+ t18 += v * b9;
+ t19 += v * b10;
+ t20 += v * b11;
+ t21 += v * b12;
+ t22 += v * b13;
+ t23 += v * b14;
+ t24 += v * b15;
+ v = a[10 + aoff];
+ t10 += v * b0;
+ t11 += v * b1;
+ t12 += v * b2;
+ t13 += v * b3;
+ t14 += v * b4;
+ t15 += v * b5;
+ t16 += v * b6;
+ t17 += v * b7;
+ t18 += v * b8;
+ t19 += v * b9;
+ t20 += v * b10;
+ t21 += v * b11;
+ t22 += v * b12;
+ t23 += v * b13;
+ t24 += v * b14;
+ t25 += v * b15;
+ v = a[11 + aoff];
+ t11 += v * b0;
+ t12 += v * b1;
+ t13 += v * b2;
+ t14 += v * b3;
+ t15 += v * b4;
+ t16 += v * b5;
+ t17 += v * b6;
+ t18 += v * b7;
+ t19 += v * b8;
+ t20 += v * b9;
+ t21 += v * b10;
+ t22 += v * b11;
+ t23 += v * b12;
+ t24 += v * b13;
+ t25 += v * b14;
+ t26 += v * b15;
+ v = a[12 + aoff];
+ t12 += v * b0;
+ t13 += v * b1;
+ t14 += v * b2;
+ t15 += v * b3;
+ t16 += v * b4;
+ t17 += v * b5;
+ t18 += v * b6;
+ t19 += v * b7;
+ t20 += v * b8;
+ t21 += v * b9;
+ t22 += v * b10;
+ t23 += v * b11;
+ t24 += v * b12;
+ t25 += v * b13;
+ t26 += v * b14;
+ t27 += v * b15;
+ v = a[13 + aoff];
+ t13 += v * b0;
+ t14 += v * b1;
+ t15 += v * b2;
+ t16 += v * b3;
+ t17 += v * b4;
+ t18 += v * b5;
+ t19 += v * b6;
+ t20 += v * b7;
+ t21 += v * b8;
+ t22 += v * b9;
+ t23 += v * b10;
+ t24 += v * b11;
+ t25 += v * b12;
+ t26 += v * b13;
+ t27 += v * b14;
+ t28 += v * b15;
+ v = a[14 + aoff];
+ t14 += v * b0;
+ t15 += v * b1;
+ t16 += v * b2;
+ t17 += v * b3;
+ t18 += v * b4;
+ t19 += v * b5;
+ t20 += v * b6;
+ t21 += v * b7;
+ t22 += v * b8;
+ t23 += v * b9;
+ t24 += v * b10;
+ t25 += v * b11;
+ t26 += v * b12;
+ t27 += v * b13;
+ t28 += v * b14;
+ t29 += v * b15;
+ v = a[15 + aoff];
+ t15 += v * b0;
+ t16 += v * b1;
+ t17 += v * b2;
+ t18 += v * b3;
+ t19 += v * b4;
+ t20 += v * b5;
+ t21 += v * b6;
+ t22 += v * b7;
+ t23 += v * b8;
+ t24 += v * b9;
+ t25 += v * b10;
+ t26 += v * b11;
+ t27 += v * b12;
+ t28 += v * b13;
+ t29 += v * b14;
+ t30 += v * b15;
+
+ t0 += 38 * t16;
+ t1 += 38 * t17;
+ t2 += 38 * t18;
+ t3 += 38 * t19;
+ t4 += 38 * t20;
+ t5 += 38 * t21;
+ t6 += 38 * t22;
+ t7 += 38 * t23;
+ t8 += 38 * t24;
+ t9 += 38 * t25;
+ t10 += 38 * t26;
+ t11 += 38 * t27;
+ t12 += 38 * t28;
+ t13 += 38 * t29;
+ t14 += 38 * t30;
+ // t15 left as is
+
+ // first car
+ c = 1;
+ v = t0 + c + 65535;
+ c = v >> 16;
+ t0 = v - c * 65536;
+ v = t1 + c + 65535;
+ c = v >> 16;
+ t1 = v - c * 65536;
+ v = t2 + c + 65535;
+ c = v >> 16;
+ t2 = v - c * 65536;
+ v = t3 + c + 65535;
+ c = v >> 16;
+ t3 = v - c * 65536;
+ v = t4 + c + 65535;
+ c = v >> 16;
+ t4 = v - c * 65536;
+ v = t5 + c + 65535;
+ c = v >> 16;
+ t5 = v - c * 65536;
+ v = t6 + c + 65535;
+ c = v >> 16;
+ t6 = v - c * 65536;
+ v = t7 + c + 65535;
+ c = v >> 16;
+ t7 = v - c * 65536;
+ v = t8 + c + 65535;
+ c = v >> 16;
+ t8 = v - c * 65536;
+ v = t9 + c + 65535;
+ c = v >> 16;
+ t9 = v - c * 65536;
+ v = t10 + c + 65535;
+ c = v >> 16;
+ t10 = v - c * 65536;
+ v = t11 + c + 65535;
+ c = v >> 16;
+ t11 = v - c * 65536;
+ v = t12 + c + 65535;
+ c = v >> 16;
+ t12 = v - c * 65536;
+ v = t13 + c + 65535;
+ c = v >> 16;
+ t13 = v - c * 65536;
+ v = t14 + c + 65535;
+ c = v >> 16;
+ t14 = v - c * 65536;
+ v = t15 + c + 65535;
+ c = v >> 16;
+ t15 = v - c * 65536;
+ t0 += c - 1 + 37 * (c - 1);
+
+ // second car
+ c = 1;
+ v = t0 + c + 65535;
+ c = v >> 16;
+ t0 = v - c * 65536;
+ v = t1 + c + 65535;
+ c = v >> 16;
+ t1 = v - c * 65536;
+ v = t2 + c + 65535;
+ c = v >> 16;
+ t2 = v - c * 65536;
+ v = t3 + c + 65535;
+ c = v >> 16;
+ t3 = v - c * 65536;
+ v = t4 + c + 65535;
+ c = v >> 16;
+ t4 = v - c * 65536;
+ v = t5 + c + 65535;
+ c = v >> 16;
+ t5 = v - c * 65536;
+ v = t6 + c + 65535;
+ c = v >> 16;
+ t6 = v - c * 65536;
+ v = t7 + c + 65535;
+ c = v >> 16;
+ t7 = v - c * 65536;
+ v = t8 + c + 65535;
+ c = v >> 16;
+ t8 = v - c * 65536;
+ v = t9 + c + 65535;
+ c = v >> 16;
+ t9 = v - c * 65536;
+ v = t10 + c + 65535;
+ c = v >> 16;
+ t10 = v - c * 65536;
+ v = t11 + c + 65535;
+ c = v >> 16;
+ t11 = v - c * 65536;
+ v = t12 + c + 65535;
+ c = v >> 16;
+ t12 = v - c * 65536;
+ v = t13 + c + 65535;
+ c = v >> 16;
+ t13 = v - c * 65536;
+ v = t14 + c + 65535;
+ c = v >> 16;
+ t14 = v - c * 65536;
+ v = t15 + c + 65535;
+ c = v >> 16;
+ t15 = v - c * 65536;
+ t0 += c - 1 + 37 * (c - 1);
+
+ o[0 + ooff] = t0;
+ o[1 + ooff] = t1;
+ o[2 + ooff] = t2;
+ o[3 + ooff] = t3;
+ o[4 + ooff] = t4;
+ o[5 + ooff] = t5;
+ o[6 + ooff] = t6;
+ o[7 + ooff] = t7;
+ o[8 + ooff] = t8;
+ o[9 + ooff] = t9;
+ o[10 + ooff] = t10;
+ o[11 + ooff] = t11;
+ o[12 + ooff] = t12;
+ o[13 + ooff] = t13;
+ o[14 + ooff] = t14;
+ o[15 + ooff] = t15;
+ }
+
+ private static void S(
+ long[] o,
+ long[] a) {
+ S(o, 0, a, 0);
+ }
+
+ private static void S(
+ long[] o, final int ooff,
+ long[] a, final int aoff) {
+ M(o, ooff, a, aoff, a, aoff);
+ }
+
+ private static void inv25519(
+ long[] o, final int ooff,
+ long[] i, final int ioff) {
+ long[] c = new long[16];
+ int a;
+ for (a = 0; a < 16; a++) c[a] = i[a + ioff];
+ for (a = 253; a >= 0; a--) {
+ S(c, 0, c, 0);
+ if (a != 2 && a != 4) M(c, 0, c, 0, i, ioff);
+ }
+ for (a = 0; a < 16; a++) o[a + ooff] = c[a];
+ }
+
+ private static void pow2523(long[] o, long[] i) {
+ long[] c = new long[16];
+ int a;
+
+ for (a = 0; a < 16; a++) c[a] = i[a];
+
+ for (a = 250; a >= 0; a--) {
+ S(c, 0, c, 0);
+ if (a != 1) M(c, 0, c, 0, i, 0);
+ }
+
+ for (a = 0; a < 16; a++) o[a] = c[a];
+ }
+
+ public static int crypto_scalarmult(byte[] q, byte[] n, byte[] p) {
+ byte[] z = new byte[32];
+ long[] x = new long[80];
+ int r, i;
+ long[] a = new long[16], b = new long[16], c = new long[16],
+ d = new long[16], e = new long[16], f = new long[16];
+ for (i = 0; i < 31; i++) z[i] = n[i];
+ z[31] = (byte) (((n[31] & 127) | 64) & 0xff);
+ z[0] &= 248;
+ unpack25519(x, p);
+ for (i = 0; i < 16; i++) {
+ b[i] = x[i];
+ d[i] = a[i] = c[i] = 0;
+ }
+ a[0] = d[0] = 1;
+ for (i = 254; i >= 0; --i) {
+ r = (z[i >>> 3] >>> (i & 7)) & 1;
+ sel25519(a, b, r);
+ sel25519(c, d, r);
+ A(e, a, c);
+ Z(a, a, c);
+ A(c, b, d);
+ Z(b, b, d);
+ S(d, e);
+ S(f, a);
+ M(a, c, a);
+ M(c, b, e);
+ A(e, a, c);
+ Z(a, a, c);
+ S(b, a);
+ Z(c, d, f);
+ M(a, c, _121665);
+ A(a, a, d);
+ M(c, c, a);
+ M(a, d, f);
+ M(d, b, x);
+ S(b, e);
+ sel25519(a, b, r);
+ sel25519(c, d, r);
+ }
+ for (i = 0; i < 16; i++) {
+ x[i + 16] = a[i];
+ x[i + 32] = c[i];
+ x[i + 48] = b[i];
+ x[i + 64] = d[i];
+ }
+ inv25519(x, 32, x, 32);
+ M(x, 16, x, 16, x, 32);
+ pack25519(q, x, 16);
+
+ return 0;
+ }
+
+ public static int crypto_scalarmult_base(byte[] q, byte[] n) {
+ return crypto_scalarmult(q, n, _9);
+ }
+
+ public static int crypto_box_keypair(byte[] y, byte[] x) {
+ randombytes(x, 32);
+ return crypto_scalarmult_base(y, x);
+ }
+
+ public static int crypto_box_beforenm(byte[] k, byte[] y, byte[] x) {
+ byte[] s = new byte[32];
+ crypto_scalarmult(s, x, y);
+
+ /*String dbgt = "";
+ for (int dbg = 0; dbg < s.length; dbg ++) dbgt += " "+s[dbg];
+ Log.d(TAG, "crypto_box_beforenm -> "+dbgt);
+
+ dbgt = "";
+ for (int dbg = 0; dbg < x.length; dbg ++) dbgt += " "+x[dbg];
+ Log.d(TAG, "crypto_box_beforenm, x -> "+dbgt);
+
+ dbgt = "";
+ for (int dbg = 0; dbg < y.length; dbg ++) dbgt += " "+y[dbg];
+ Log.d(TAG, "crypto_box_beforenm, y -> "+dbgt);
+ */
+
+ return crypto_core_hsalsa20(k, _0, s, sigma);
+ }
+
+ public static int crypto_box_afternm(byte[] c, byte[] m, int /*long*/ d, byte[] n, byte[] k) {
+ return crypto_secretbox(c, m, d, n, k);
+ }
+
+ public static int crypto_box_open_afternm(byte[] m, byte[] c, int /*long*/ d, byte[] n, byte[] k) {
+ return crypto_secretbox_open(m, c, d, n, k);
+ }
+
+ public static int crypto_box(byte[] c, byte[] m, int /*long*/ d, byte[] n, byte[] y, byte[] x) {
+ byte[] k = new byte[32];
+
+ ///L/og.d(TAG, "crypto_box start ...");
+
+ crypto_box_beforenm(k, y, x);
+ return crypto_box_afternm(c, m, d, n, k);
+ }
+
+ public static int crypto_box_open(byte[] m, byte[] c, int /*long*/ d, byte[] n, byte[] y, byte[] x) {
+ byte[] k = new byte[32];
+ crypto_box_beforenm(k, y, x);
+ return crypto_box_open_afternm(m, c, d, n, k);
+ }
+
+ private static final long K[] = {
+ 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
+ 0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
+ 0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+ 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
+ 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
+ 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+ 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
+ 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
+ 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+ 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
+ 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
+ 0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+ 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
+ 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
+ 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+ 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
+ 0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
+ 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+ 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
+ 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
+ };
+
+ private static int crypto_hashblocks_hl(int[] hh, int[] hl, byte[] m, final int moff, int n) {
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < n; dbg ++) dbgt += " "+m[dbg+moff];
+ ///Log.d(TAG, "crypto_hashblocks_hl m/"+n + "-> "+dbgt);
+
+ int[] wh = new int[16], wl = new int[16];
+ int bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7,
+ bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7,
+ th, tl, h, l, i, j, a, b, c, d;
+
+ int ah0 = hh[0],
+ ah1 = hh[1],
+ ah2 = hh[2],
+ ah3 = hh[3],
+ ah4 = hh[4],
+ ah5 = hh[5],
+ ah6 = hh[6],
+ ah7 = hh[7],
+
+ al0 = hl[0],
+ al1 = hl[1],
+ al2 = hl[2],
+ al3 = hl[3],
+ al4 = hl[4],
+ al5 = hl[5],
+ al6 = hl[6],
+ al7 = hl[7];
+
+ int pos = 0;
+ while (n >= 128) {
+ for (i = 0; i < 16; i++) {
+ j = 8 * i + pos;
+ wh[i] = ((m[j + 0 + moff] & 0xff) << 24) | ((m[j + 1 + moff] & 0xff) << 16) | ((m[j + 2 + moff] & 0xff) << 8) | ((m[j + 3 + moff] & 0xff) << 0);
+ wl[i] = ((m[j + 4 + moff] & 0xff) << 24) | ((m[j + 5 + moff] & 0xff) << 16) | ((m[j + 6 + moff] & 0xff) << 8) | ((m[j + 7 + moff] & 0xff) << 0);
+ }
+ for (i = 0; i < 80; i++) {
+ bh0 = ah0;
+ bh1 = ah1;
+ bh2 = ah2;
+ bh3 = ah3;
+ bh4 = ah4;
+ bh5 = ah5;
+ bh6 = ah6;
+ bh7 = ah7;
+
+ bl0 = al0;
+ bl1 = al1;
+ bl2 = al2;
+ bl3 = al3;
+ bl4 = al4;
+ bl5 = al5;
+ bl6 = al6;
+ bl7 = al7;
+
+ // add
+ h = ah7;
+ l = al7;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ // Sigma1
+ h = ((ah4 >>> 14) | (al4 << (32 - 14))) ^ ((ah4 >>> 18) | (al4 << (32 - 18))) ^ ((al4 >>> (41 - 32)) | (ah4 << (32 - (41 - 32))));
+ l = ((al4 >>> 14) | (ah4 << (32 - 14))) ^ ((al4 >>> 18) | (ah4 << (32 - 18))) ^ ((ah4 >>> (41 - 32)) | (al4 << (32 - (41 - 32))));
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // Ch
+ h = (ah4 & ah5) ^ (~ah4 & ah6);
+ l = (al4 & al5) ^ (~al4 & al6);
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // K
+ ///h = K[i*2];
+ ///l = K[i*2+1];
+ h = (int) ((K[i] >>> 32) & 0xffffffff);
+ l = (int) ((K[i] >>> 0) & 0xffffffff);
+
+ ///Log.d(TAG, "i"+i + ",h:0x"+Integer.toHexString(h) + ",l:0x"+Integer.toHexString(l));
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // w
+ h = wh[i % 16];
+ l = wl[i % 16];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ th = c & 0xffff | d << 16;
+ tl = a & 0xffff | b << 16;
+
+ // add
+ h = th;
+ l = tl;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ // Sigma0
+ h = ((ah0 >>> 28) | (al0 << (32 - 28))) ^ ((al0 >>> (34 - 32)) | (ah0 << (32 - (34 - 32)))) ^ ((al0 >>> (39 - 32)) | (ah0 << (32 - (39 - 32))));
+ l = ((al0 >>> 28) | (ah0 << (32 - 28))) ^ ((ah0 >>> (34 - 32)) | (al0 << (32 - (34 - 32)))) ^ ((ah0 >>> (39 - 32)) | (al0 << (32 - (39 - 32))));
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // Maj
+ h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2);
+ l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2);
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ bh7 = (c & 0xffff) | (d << 16);
+ bl7 = (a & 0xffff) | (b << 16);
+
+ // add
+ h = bh3;
+ l = bl3;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = th;
+ l = tl;
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ bh3 = (c & 0xffff) | (d << 16);
+ bl3 = (a & 0xffff) | (b << 16);
+
+ ah1 = bh0;
+ ah2 = bh1;
+ ah3 = bh2;
+ ah4 = bh3;
+ ah5 = bh4;
+ ah6 = bh5;
+ ah7 = bh6;
+ ah0 = bh7;
+
+ al1 = bl0;
+ al2 = bl1;
+ al3 = bl2;
+ al4 = bl3;
+ al5 = bl4;
+ al6 = bl5;
+ al7 = bl6;
+ al0 = bl7;
+
+ if (i % 16 == 15) {
+ for (j = 0; j < 16; j++) {
+ // add
+ h = wh[j];
+ l = wl[j];
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = wh[(j + 9) % 16];
+ l = wl[(j + 9) % 16];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // sigma0
+ th = wh[(j + 1) % 16];
+ tl = wl[(j + 1) % 16];
+ h = ((th >>> 1) | (tl << (32 - 1))) ^ ((th >>> 8) | (tl << (32 - 8))) ^ (th >>> 7);
+ l = ((tl >>> 1) | (th << (32 - 1))) ^ ((tl >>> 8) | (th << (32 - 8))) ^ ((tl >>> 7) | (th << (32 - 7)));
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ // sigma1
+ th = wh[(j + 14) % 16];
+ tl = wl[(j + 14) % 16];
+ h = ((th >>> 19) | (tl << (32 - 19))) ^ ((tl >>> (61 - 32)) | (th << (32 - (61 - 32)))) ^ (th >>> 6);
+ l = ((tl >>> 19) | (th << (32 - 19))) ^ ((th >>> (61 - 32)) | (tl << (32 - (61 - 32)))) ^ ((tl >>> 6) | (th << (32 - 6)));
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ wh[j] = (c & 0xffff) | (d << 16);
+ wl[j] = (a & 0xffff) | (b << 16);
+ }
+ }
+ }
+
+ // add
+ h = ah0;
+ l = al0;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[0];
+ l = hl[0];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[0] = ah0 = (c & 0xffff) | (d << 16);
+ hl[0] = al0 = (a & 0xffff) | (b << 16);
+
+ h = ah1;
+ l = al1;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[1];
+ l = hl[1];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[1] = ah1 = (c & 0xffff) | (d << 16);
+ hl[1] = al1 = (a & 0xffff) | (b << 16);
+
+ h = ah2;
+ l = al2;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[2];
+ l = hl[2];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[2] = ah2 = (c & 0xffff) | (d << 16);
+ hl[2] = al2 = (a & 0xffff) | (b << 16);
+
+ h = ah3;
+ l = al3;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[3];
+ l = hl[3];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[3] = ah3 = (c & 0xffff) | (d << 16);
+ hl[3] = al3 = (a & 0xffff) | (b << 16);
+
+ h = ah4;
+ l = al4;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[4];
+ l = hl[4];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[4] = ah4 = (c & 0xffff) | (d << 16);
+ hl[4] = al4 = (a & 0xffff) | (b << 16);
+
+ h = ah5;
+ l = al5;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[5];
+ l = hl[5];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[5] = ah5 = (c & 0xffff) | (d << 16);
+ hl[5] = al5 = (a & 0xffff) | (b << 16);
+
+ h = ah6;
+ l = al6;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[6];
+ l = hl[6];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[6] = ah6 = (c & 0xffff) | (d << 16);
+ hl[6] = al6 = (a & 0xffff) | (b << 16);
+
+ h = ah7;
+ l = al7;
+
+ a = l & 0xffff;
+ b = l >>> 16;
+ c = h & 0xffff;
+ d = h >>> 16;
+
+ h = hh[7];
+ l = hl[7];
+
+ a += l & 0xffff;
+ b += l >>> 16;
+ c += h & 0xffff;
+ d += h >>> 16;
+
+ b += a >>> 16;
+ c += b >>> 16;
+ d += c >>> 16;
+
+ hh[7] = ah7 = (c & 0xffff) | (d << 16);
+ hl[7] = al7 = (a & 0xffff) | (b << 16);
+
+ pos += 128;
+ n -= 128;
+
+ /*dbgt = "";
+ for (int dbg = 0; dbg < hh.length; dbg ++) dbgt += " "+hh[dbg];
+ Log.d(TAG, "\ncrypto_hashblocks_hl hh -> "+dbgt);
+
+ dbgt = "";
+ for (int dbg = 0; dbg < hl.length; dbg ++) dbgt += " "+hl[dbg];
+ Log.d(TAG, "\ncrypto_hashblocks_hl hl -> "+dbgt);*/
+ }
+
+ return n;
+ }
+
+ // TBD 64bits of n
+ ///int crypto_hash(byte [] out, byte [] m, long n)
+ public static int crypto_hash(byte[] out, byte[] m, final int moff, int n) {
+ int[] hh = new int[8],
+ hl = new int[8];
+ byte[] x = new byte[256];
+ int i, b = n;
+ long u;
+
+ hh[0] = 0x6a09e667;
+ hh[1] = 0xbb67ae85;
+ hh[2] = 0x3c6ef372;
+ hh[3] = 0xa54ff53a;
+ hh[4] = 0x510e527f;
+ hh[5] = 0x9b05688c;
+ hh[6] = 0x1f83d9ab;
+ hh[7] = 0x5be0cd19;
+
+ hl[0] = 0xf3bcc908;
+ hl[1] = 0x84caa73b;
+ hl[2] = 0xfe94f82b;
+ hl[3] = 0x5f1d36f1;
+ hl[4] = 0xade682d1;
+ hl[5] = 0x2b3e6c1f;
+ hl[6] = 0xfb41bd6b;
+ hl[7] = 0x137e2179;
+
+ if (n >= 128) {
+ crypto_hashblocks_hl(hh, hl, m, moff, n);
+ n %= 128;
+ }
+
+ for (i = 0; i < n; i++) x[i] = m[b - n + i + moff];
+ x[n] = (byte) 128;
+
+ n = 256 - 128 * (n < 112 ? 1 : 0);
+ x[n - 9] = 0;
+
+ ts64(x, n - 8, b << 3/*(b / 0x20000000) | 0, b << 3*/);
+
+ crypto_hashblocks_hl(hh, hl, x, 0, n);
+
+ for (i = 0; i < 8; i++) {
+ u = hh[i];
+ u <<= 32;
+ u |= hl[i] & 0xffffffffL;
+ ts64(out, 8 * i, u);
+ }
+
+ return 0;
+ }
+
+ public static int crypto_hash(byte[] out, byte[] m) {
+ return crypto_hash(out, m, 0, m != null ? m.length : 0);
+ }
+
+ // gf: long[16]
+ ///private static void add(gf p[4],gf q[4])
+ private static void add(long[] p[], long[] q[]) {
+ long[] a = new long[16];
+ long[] b = new long[16];
+ long[] c = new long[16];
+ long[] d = new long[16];
+ long[] t = new long[16];
+ long[] e = new long[16];
+ long[] f = new long[16];
+ long[] g = new long[16];
+ long[] h = new long[16];
+
+
+ long[] p0 = p[0];
+ long[] p1 = p[1];
+ long[] p2 = p[2];
+ long[] p3 = p[3];
+
+ long[] q0 = q[0];
+ long[] q1 = q[1];
+ long[] q2 = q[2];
+ long[] q3 = q[3];
+
+ Z(a, 0, p1, 0, p0, 0);
+ Z(t, 0, q1, 0, q0, 0);
+ M(a, 0, a, 0, t, 0);
+ A(b, 0, p0, 0, p1, 0);
+ A(t, 0, q0, 0, q1, 0);
+ M(b, 0, b, 0, t, 0);
+ M(c, 0, p3, 0, q3, 0);
+ M(c, 0, c, 0, D2, 0);
+ M(d, 0, p2, 0, q2, 0);
+
+ A(d, 0, d, 0, d, 0);
+ Z(e, 0, b, 0, a, 0);
+ Z(f, 0, d, 0, c, 0);
+ A(g, 0, d, 0, c, 0);
+ A(h, 0, b, 0, a, 0);
+
+ M(p0, 0, e, 0, f, 0);
+ M(p1, 0, h, 0, g, 0);
+ M(p2, 0, g, 0, f, 0);
+ M(p3, 0, e, 0, h, 0);
+ }
+
+ private static void cswap(long[] p[], long[] q[], byte b) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ sel25519(p[i], 0, q[i], 0, b);
+ }
+
+ private static void pack(byte[] r, long[] p[]) {
+ long[] tx = new long[16];
+ long[] ty = new long[16];
+ long[] zi = new long[16];
+
+ inv25519(zi, 0, p[2], 0);
+
+ M(tx, 0, p[0], 0, zi, 0);
+ M(ty, 0, p[1], 0, zi, 0);
+
+ pack25519(r, ty, 0);
+
+ r[31] ^= par25519(tx, 0) << 7;
+ }
+
+ private static void scalarmult(long[] p[], long[] q[], byte[] s, final int soff) {
+ int i;
+
+ set25519(p[0], gf0);
+ set25519(p[1], gf1);
+ set25519(p[2], gf1);
+ set25519(p[3], gf0);
+
+ for (i = 255; i >= 0; --i) {
+ byte b = (byte) ((s[i / 8 + soff] >>> (i & 7)) & 1);
+
+ cswap(p, q, b);
+ add(q, p);
+ add(p, p);
+ cswap(p, q, b);
+ }
+
+ ///String dbgt = "";
+ ///for (int dbg = 0; dbg < p.length; dbg ++) for (int dd = 0; dd < p[dbg].length; dd ++) dbgt += " "+p[dbg][dd];
+ ///L/og.d(TAG, "scalarmult -> "+dbgt);
+ }
+
+ private static void scalarbase(long[] p[], byte[] s, final int soff) {
+ long[][] q = new long[4][];
+
+ q[0] = new long[16];
+ q[1] = new long[16];
+ q[2] = new long[16];
+ q[3] = new long[16];
+
+ set25519(q[0], X);
+ set25519(q[1], Y);
+ set25519(q[2], gf1);
+ M(q[3], 0, X, 0, Y, 0);
+ scalarmult(p, q, s, soff);
+ }
+
+ public static int crypto_sign_keypair(byte[] pk, byte[] sk, boolean seeded) {
+ byte[] d = new byte[64];
+ long[][] p = new long[4][];
+
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ int i;
+
+ if (!seeded) randombytes(sk, 32);
+ crypto_hash(d, sk, 0, 32);
+ d[0] &= 248;
+ d[31] &= 127;
+ d[31] |= 64;
+
+ scalarbase(p, d, 0);
+ pack(pk, p);
+
+ for (i = 0; i < 32; i++) sk[i + 32] = pk[i];
+ return 0;
+ }
+
+ private static final long L[] = {
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x10
+ };
+
+ private static void modL(byte[] r, final int roff, long x[]) {
+ long carry;
+ int i, j;
+
+ for (i = 63; i >= 32; --i) {
+ carry = 0;
+ for (j = i - 32; j < i - 12; ++j) {
+ x[j] += carry - 16 * x[i] * L[j - (i - 32)];
+ carry = (x[j] + 128) >> 8;
+ x[j] -= carry << 8;
+ }
+ x[j] += carry;
+ x[i] = 0;
+ }
+ carry = 0;
+
+ for (j = 0; j < 32; j++) {
+ x[j] += carry - (x[31] >> 4) * L[j];
+ carry = x[j] >> 8;
+ x[j] &= 255;
+ }
+
+ for (j = 0; j < 32; j++) x[j] -= carry * L[j];
+
+ for (i = 0; i < 32; i++) {
+ x[i + 1] += x[i] >> 8;
+ r[i + roff] = (byte) (x[i] & 255);
+ }
+ }
+
+ private static void reduce(byte[] r) {
+ long[] x = new long[64];
+ int i;
+
+ for (i = 0; i < 64; i++) x[i] = (long) (r[i] & 0xff);
+
+ for (i = 0; i < 64; i++) r[i] = 0;
+
+ modL(r, 0, x);
+ }
+
+ // TBD... 64bits of n
+ ///int crypto_sign(byte [] sm, long * smlen, byte [] m, long n, byte [] sk)
+ public static int crypto_sign(byte[] sm, long dummy /* *smlen not used*/, byte[] m, final int moff, int/*long*/ n, byte[] sk) {
+ byte[] d = new byte[64], h = new byte[64], r = new byte[64];
+
+ int i, j;
+ long[] x = new long[64];
+
+ long[][] p = new long[4][];
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ crypto_hash(d, sk, 0, 32);
+ d[0] &= 248;
+ d[31] &= 127;
+ d[31] |= 64;
+
+ ///*smlen = n+64;
+
+ for (i = 0; i < n; i++) sm[64 + i] = m[i + moff];
+
+ for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
+
+ crypto_hash(r, sm, 32, n + 32);
+ reduce(r);
+ scalarbase(p, r, 0);
+ pack(sm, p);
+
+ for (i = 0; i < 32; i++) sm[i + 32] = sk[i + 32];
+ crypto_hash(h, sm, 0, n + 64);
+ reduce(h);
+
+ for (i = 0; i < 64; i++) x[i] = 0;
+
+ for (i = 0; i < 32; i++) x[i] = (long) (r[i] & 0xff);
+
+ for (i = 0; i < 32; i++) for (j = 0; j < 32; j++) x[i + j] += (h[i] & 0xff) * (long) (d[j] & 0xff);
+
+ modL(sm, 32, x);
+
+ return 0;
+ }
+
+ private static int unpackneg(long[] r[], byte p[]) {
+ long[] t = new long[16];
+ long[] chk = new long[16];
+ long[] num = new long[16];
+ long[] den = new long[16];
+ long[] den2 = new long[16];
+ long[] den4 = new long[16];
+ long[] den6 = new long[16];
+
+ set25519(r[2], gf1);
+ unpack25519(r[1], p);
+ S(num, r[1]);
+ M(den, num, D);
+ Z(num, num, r[2]);
+ A(den, r[2], den);
+
+ S(den2, den);
+ S(den4, den2);
+ M(den6, den4, den2);
+ M(t, den6, num);
+ M(t, t, den);
+
+ pow2523(t, t);
+ M(t, t, num);
+ M(t, t, den);
+ M(t, t, den);
+ M(r[0], t, den);
+
+ S(chk, r[0]);
+ M(chk, chk, den);
+ if (neq25519(chk, num) != 0) M(r[0], r[0], I);
+
+ S(chk, r[0]);
+ M(chk, chk, den);
+ if (neq25519(chk, num) != 0) return -1;
+
+ if (par25519(r[0]) == ((p[31] & 0xFF) >>> 7)) Z(r[0], gf0, r[0]);
+
+ M(r[3], r[0], r[1]);
+
+ return 0;
+ }
+
+ /// TBD 64bits of mlen
+ ///int crypto_sign_open(byte []m,long *mlen,byte []sm,long n,byte []pk)
+ public static int crypto_sign_open(byte[] m, long dummy /* *mlen not used*/, byte[] sm, final int smoff, int/*long*/ n, byte[] pk) {
+ int i;
+ byte[] t = new byte[32], h = new byte[64];
+
+ long[][] p = new long[4][];
+ p[0] = new long[16];
+ p[1] = new long[16];
+ p[2] = new long[16];
+ p[3] = new long[16];
+
+ long[][] q = new long[4][];
+ q[0] = new long[16];
+ q[1] = new long[16];
+ q[2] = new long[16];
+ q[3] = new long[16];
+
+ ///*mlen = -1;
+
+ if (n < 64) return -1;
+
+ if (unpackneg(q, pk) != 0) return -1;
+
+ for (i = 0; i < n; i++) m[i] = sm[i + smoff];
+
+ for (i = 0; i < 32; i++) m[i + 32] = pk[i];
+
+ crypto_hash(h, m, 0, n);
+
+ reduce(h);
+ scalarmult(p, q, h, 0);
+
+ scalarbase(q, sm, 32 + smoff);
+ add(p, q);
+ pack(t, p);
+
+ n -= 64;
+ if (crypto_verify_32(sm, smoff, t, 0) != 0) {
+ // optimizing it
+ ///for (i = 0; i < n; i ++) m[i] = 0;
+ return -1;
+ }
+
+ // TBD optimizing ...
+ ///for (i = 0; i < n; i ++) m[i] = sm[i + 64 + smoff];
+ ///*mlen = n;
+
+ return 0;
+ }
+
+ /*
+ * @description
+ * Java SecureRandom generator
+ * */
+ private static final SecureRandom jrandom = new SecureRandom();
+
+ public static byte[] randombytes(byte[] x) {
+ jrandom.nextBytes(x);
+ return x;
+ }
+
+ public static byte[] randombytes(int len) {
+ return randombytes(new byte[len]);
+ }
+
+ public static byte[] randombytes(byte[] x, int len) {
+ byte[] b = randombytes(len);
+ System.arraycopy(b, 0, x, 0, len);
+ return x;
+ }
+
+/*
+ public static byte[] randombytes(byte [] x, int len) {
+ int ret = len % 8;
+ long rnd;
+
+ for (int i = 0; i < len-ret; i += 8) {
+ rnd = jrandom.nextLong();
+
+ x[i+0] = (byte) (rnd >>> 0);
+ x[i+1] = (byte) (rnd >>> 8);
+ x[i+2] = (byte) (rnd >>> 16);
+ x[i+3] = (byte) (rnd >>> 24);
+ x[i+4] = (byte) (rnd >>> 32);
+ x[i+5] = (byte) (rnd >>> 40);
+ x[i+6] = (byte) (rnd >>> 48);
+ x[i+7] = (byte) (rnd >>> 56);
+ }
+
+ if (ret > 0) {
+ rnd = jrandom.nextLong();
+ for (int i = len-ret; i < len; i ++)
+ x[i] = (byte) (rnd >>> 8*i);
+ }
+ return x;
+ }
+*/
+
+ public static byte[] makeBoxNonce() {
+ return randombytes(Box.nonceLength);
+ }
+
+ public static byte[] makeSecretBoxNonce() {
+ return randombytes(SecretBox.nonceLength);
+ }
+
+ public static String hexEncodeToString(byte[] raw) {
+ String HEXES = "0123456789ABCDEF";
+ final StringBuilder hex = new StringBuilder(2 * raw.length);
+ for (final byte b : raw) {
+ hex.append(HEXES.charAt((b & 0xF0) >> 4))
+ .append(HEXES.charAt((b & 0x0F)));
+ }
+ return hex.toString();
+ }
+
+ public static byte[] hexDecode(String s) {
+ byte[] b = new byte[s.length() / 2];
+ for (int i = 0; i < s.length(); i += 2) {
+ b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i + 1), 16));
+ }
+ return b;
+ }
+
+ // public static boolean java.util.Arrays.equals(array1, array2);
+
+}
diff --git a/utils/pom.xml b/utils/pom.xml
index 11432e5e..a9548cd0 100644
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -50,11 +50,10 @@
- org.purejava
- tweetnacl-java
- 1.1.2
- system
- ${project.basedir}/../tweetnacl-java-1.1.2.jar
+ io.github.neodix42
+ tweetnacl-java-8
+ 1.1.12
+ compile