org.polkadot.utils.crypto.TweetNaCl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of polkadot-java Show documentation
Show all versions of polkadot-java Show documentation
Java Polkadot API, this is a clone of https://github.com/polkadot-java/api
The newest version!
package org.polkadot.utils.crypto;
import java.security.*;
import java.util.Arrays;
import java.util.Random;
// https://github.com/ianopolous/tweetnacl-java
/* Ported from the original C by Ian Preston and Chris Boddy
* crypto_hash() is ported from TweetNaCl.js
* Released under GPL 2
*/
public class TweetNaCl {
public static final int crypto_auth_hmacsha512256_tweet_BYTES = 32;
public static final int crypto_auth_hmacsha512256_tweet_KEYBYTES = 32;
public static final int BOX_PUBLIC_KEY_BYTES = 32;
public static final int BOX_SECRET_KEY_BYTES = 32;
public static final int BOX_SHARED_KEY_BYTES = 32;
public static final int BOX_NONCE_BYTES = 24;
public static final int BOX_OVERHEAD_BYTES = 16;
public static final int SIGNATURE_SIZE_BYTES = 64;
public static final int SIGN_PUBLIC_KEY_BYTES = 32;
public static final int SIGN_SECRET_KEY_BYTES = 64;
public static final int SIGN_KEYPAIR_SEED_BYTES = 32;
public static final int SECRETBOX_KEY_BYTES = 32;
public static final int SECRETBOX_NONCE_BYTES = 24;
public static final int SECRETBOX_OVERHEAD_BYTES = 16;
public static final int HASH_SIZE_BYTES = 64; // SHA-512
private static final int SECRETBOX_INTERNAL_OVERHEAD_BYTES = 32;
public static class InvalidSignatureException extends RuntimeException {}
public static class InvalidCipherTextException extends RuntimeException {}
public static void crypto_sign_keypair(byte[] pk, byte[] sk, boolean isSeeded)
{
byte[] d = new byte[64];
long[][] /*gf*/ p = new long[4][GF_LEN];
int i;
if (!isSeeded)
randombytes(sk, 32);
crypto_hash(d, sk, 32);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
scalarbase(p,d, 0);
pack(pk,p);
for (i=0;i < 32;++i)sk[32 + i] = pk[i];
}
public static int crypto_box_keypair(byte[] y,byte[] x, boolean isSeeded)
{
if (!isSeeded)
randombytes(x,32);
return crypto_scalarmult_base(y,x);
}
public static int crypto_scalarmult_base(byte[] q,byte[] n)
{
return crypto_scalarmult(q, n, _9);
}
public static byte[] crypto_sign(byte[] message, byte[] secretSigningKey) {
byte[] signedMessage = new byte[message.length + TweetNaCl.SIGNATURE_SIZE_BYTES];
TweetNaCl.crypto_sign(signedMessage, message, message.length, secretSigningKey);
return signedMessage;
}
public static byte[] crypto_sign_open(byte[] signed, byte[] publicSigningKey) {
byte[] message = new byte[signed.length];
int res = TweetNaCl.crypto_sign_open(message, signed, signed.length, publicSigningKey);
if (res != 0)
throw new InvalidSignatureException();
return Arrays.copyOfRange(message, 64, message.length);
}
public static byte[] crypto_box(byte[] message, byte[] nonce, byte[] theirPublicBoxingKey, byte[] ourSecretBoxingKey) {
if (nonce.length != BOX_NONCE_BYTES)
throw new IllegalStateException("Illegal nonce length: "+nonce.length);
byte[] cipherText = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + message.length];
byte[] paddedMessage = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + message.length];
System.arraycopy(message, 0, paddedMessage, SECRETBOX_INTERNAL_OVERHEAD_BYTES, message.length);
TweetNaCl.crypto_box(cipherText, paddedMessage, paddedMessage.length, nonce, theirPublicBoxingKey, ourSecretBoxingKey);
return Arrays.copyOfRange(cipherText, 16, cipherText.length);
}
public static byte[] crypto_box_open(byte[] cipher, byte[] nonce, byte[] theirPublicBoxingKey, byte[] secretBoxingKey) {
byte[] paddedCipher = new byte[cipher.length + 16];
System.arraycopy(cipher, 0, paddedCipher, 16, cipher.length);
byte[] rawText = new byte[paddedCipher.length];
int res = TweetNaCl.crypto_box_open(rawText, paddedCipher, paddedCipher.length, nonce, theirPublicBoxingKey, secretBoxingKey);
if (res != 0)
throw new InvalidCipherTextException();
return Arrays.copyOfRange(rawText, 32, rawText.length);
}
public static byte[] secretbox(byte[] mesage, byte[] nonce, byte[] key) {
byte[] m = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + mesage.length];
byte[] c = new byte[m.length];
System.arraycopy(mesage, 0, m, SECRETBOX_INTERNAL_OVERHEAD_BYTES, mesage.length);
crypto_secretbox(c, m, m.length, nonce, key);
return Arrays.copyOfRange(c, SECRETBOX_OVERHEAD_BYTES, c.length);
}
public static byte[] secretbox_open(byte[] cipher, byte[] nonce, byte[] key) {
byte[] c = new byte[SECRETBOX_OVERHEAD_BYTES + cipher.length];
byte[] m = new byte[c.length];
System.arraycopy(cipher, 0, c, SECRETBOX_OVERHEAD_BYTES, cipher.length);
if (c.length < 32) throw new IllegalStateException("Cipher too small!");
if (crypto_secretbox_open(m, c, c.length, nonce, key) != 0) throw new IllegalStateException("Invalid encryption!");
return Arrays.copyOfRange(m, SECRETBOX_INTERNAL_OVERHEAD_BYTES, m.length);
}
private static byte[] _0 = new byte[16], _9 = new byte[32];
static {
_9[0] = 9;
}
private static final int GF_LEN = 16;
private static long[] gf0 = new long[GF_LEN];
private static long[] gf1 = new long[GF_LEN]; static{gf1[0] = 1;}
private static long[] _121665 = new long[GF_LEN]; static{_121665[0] = 0xDB41; _121665[1] =1;}
private static long[] D = new long[]{0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
D2 = new long[]{0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
X = new long[]{0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
Y = new long[]{0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666},
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 >>> (32 - c)); }
public static int ld32(byte[] x, int off)
{
int u = x[off + 3] & 0xff;
u = (u<<8)|(x[off + 2] & 0xff);
u = (u<<8)|(x[off + 1] & 0xff);
return (u<<8)|(x[off + 0] & 0xff);
}
private static void st32(byte[] x, int off, int u)
{
int i;
for (i=0;i < 4;++i){ x[off + i] = (byte)u; u >>= 8; }
}
private static int vn(byte[] x, int xOff, byte[] y,int n)
{
int i,d = 0;
for (i=0;i < n;++i)d |= 0xff & (x[xOff + i]^y[i]);
return (1 & ((d - 1) >> 8)) - 1;
}
private static int crypto_verify_16(byte[] x, int xOff, byte[] y)
{
return vn(x, xOff, y, 16);
}
private static int crypto_verify_32(byte[] x,byte[] y)
{
return vn(x, 0, y,32);
}
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);
x[1+i] = ld32(k,4*i);
x[6+i] = ld32(in,4*i);
x[11+i] = ld32(k,16+4*i);
}
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);
x[6+i] -= ld32(in,4*i);
}
for (i=0;i < 4;++i){
st32(out, 4*i,x[5*i]);
st32(out, 16+4*i,x[6+i]);
}
} else
for (i=0;i < 16;++i)st32(out, 4 * i,x[i] + y[i]);
}
private static int crypto_core_salsa20(byte[] out,byte[] in,byte[] k,byte[] c)
{
core(out,in,k,c,0);
return 0;
}
private static int crypto_core_hsalsa20(byte[] out,byte[] in,byte[] k,byte[] c)
{
core(out,in,k,c,1);
return 0;
}
private static byte[] sigma = { 101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107 };
private static int crypto_stream_salsa20_xor(byte[] c,byte[] m,long b,byte[] n, int nOff, byte[] k)
{
byte[] z = new byte[16],x = new byte[64];
int u,i;
if (b == 0) return 0;
for (i=0;i < 16;++i)z[i] = 0;
for (i=0;i < 8;++i)z[i] = n[nOff + i];
int cOff = 0;
int mOff = 0;
while (b >= 64) {
crypto_core_salsa20(x,z,k,sigma);
for (i=0;i < 64; ++i) c[cOff + i] = (byte)((m != null ? m[mOff + i]:0)^ x[i]);
u = 1;
for (i = 8;i < 16;++i) {
u += 0xff & z[i];
z[i] = (byte)u;
u >>= 8;
}
b -= 64;
cOff += 64;
if (m != null) mOff += 64;
}
if (b != 0) {
crypto_core_salsa20(x,z,k,sigma);
for (i=0;i < b; i++) c[cOff + i] = (byte)((m != null ? m[mOff + i]:0)^ x[i]);
}
return 0;
}
private static int crypto_stream_salsa20(byte[] c,long d,byte[] n, int nOff, byte[] k)
{
return crypto_stream_salsa20_xor(c,null,d,n, nOff, k);
}
private 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, s);
}
private 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, s);
}
private static void add1305(int[] h,int[] c)
{
int j,u = 0;
for (j=0;j < 17;++j){
u += h[j] + c[j];
h[j] = u & 255;
u >>= 8;
}
}
private static int[] minusp = new int[] {
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
} ;
private static int crypto_onetimeauth(byte[] out, int outOff, byte[] m, int mOff, long n,byte[] k)
{
int s,i,j,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] = 0xff & k[j];
r[3]&=15;
r[4]&=252;
r[7]&=15;
r[8]&=252;
r[11]&=15;
r[12]&=252;
r[15]&=15;
while (n > 0) {
for (j=0;j < 17;++j)
c[j] = 0;
for (j = 0;(j < 16) && (j < n);++j)
c[j] = 0xff & m[mOff + j];
c[j] = 1;
mOff += 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 (i=0;i < 17;++i)
h[i] = x[i];
u = 0;
for (j=0;j < 16;++j){
u += h[j];
h[j] = u & 255;
u >>= 8;
}
u += h[16]; h[16] = u & 3;
u = 5 * (u >> 2);
for (j=0;j < 16;++j){
u += h[j];
h[j] = u & 255;
u >>= 8;
}
u += h[16]; h[16] = u;
}
for (j=0;j < 17;++j)g[j] = h[j];
add1305(h,minusp);
s = -(h[16] >> 7);
for (j=0;j < 17;++j)h[j] ^= s & (g[j] ^ h[j]);
for (j=0;j < 16;++j)
c[j] = 0xff & k[j + 16];
c[16] = 0;
add1305(h,c);
for (j=0;j < 16;++j)out[outOff + j] = (byte)h[j];
return 0;
}
private static int crypto_onetimeauth_verify(byte[] h, int hOff, byte[] m, int mOff, long n,byte[] k)
{
byte[] x = new byte[16];
crypto_onetimeauth(x, 0, m, mOff, n,k);
return crypto_verify_16(h, hOff, x);
}
private static int crypto_secretbox(byte[] c,byte[] m,long 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, 32, d - 32, c);
for (i=0;i < 16;++i)c[i] = 0;
return 0;
}
private static int crypto_secretbox_open(byte[] m,byte[] c,long 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,c, 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[] /*gf*/ r, long[] /*gf*/ a)
{
int i;
for (i=0;i < 16;++i)r[i]=a[i];
}
private static void car25519(long[] /*gf*/ o, int oOff)
{
for (int i=0;i < 16;++i){
o[oOff + i]+=(1<<16);
long c=o[oOff + i]>>16;
o[oOff + (i+1) * (i<15 ? 1:0)] += c - 1 + 37 * (c-1) * (i==15 ? 1 : 0);
o[oOff + i]-=c<<16;
}
}
private static void sel25519(long[] /*gf*/ p,long[] /*gf*/ q,int b)
{
long t,c=~(b-1);
int i;
for (i=0;i < 16;++i){
t= c&(p[i]^q[i]);
p[i]^=t;
q[i]^=t;
}
}
private static void pack25519(byte[] o,long[] /*gf*/ n, int nOff)
{
int i,j,b;
long[] /*gf*/ m = new long[GF_LEN],t = new long[GF_LEN];
for (i=0;i < 16;++i)t[i]=n[nOff+i];
car25519(t, 0);
car25519(t, 0);
car25519(t, 0);
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,m,1-b);
}
for (i=0;i < 16;++i){
o[2*i]=(byte)t[i];
o[2*i+1]=(byte)(t[i]>>8);
}
}
private static int neq25519(long[] /*gf*/ a, long[] /*gf*/ b)
{
byte[] c = new byte[32],d = new byte[32];
pack25519(c,a, 0);
pack25519(d,b, 0);
return crypto_verify_32(c,d);
}
private static byte par25519(long[] /*gf*/ a)
{
byte[] d = new byte[32];
pack25519(d,a, 0);
return (byte)(d[0]&1);
}
private static void unpack25519(long[] /*gf*/ o, byte[] n)
{
int i;
for (i=0;i < 16;++i)
o[i] = (0xff & n[2*i])+((0xffL & n[2*i+1])<<8);
o[15]&=0x7fff;
}
private static void A(long[] /*gf*/ o,long[] /*gf*/ a,long[] /*gf*/ b)
{
int i;
for (i=0;i < 16;++i)o[i]=a[i]+b[i];
}
private static void Z(long[] /*gf*/ o,long[] /*gf*/ a,long[] /*gf*/ b)
{
int i;
for (i=0;i < 16;++i)o[i]=a[i]-b[i];
}
private static void M(long[] /*gf*/ o, int oOff, long[] /*gf*/ a, int aOff, long[] /*gf*/ b, int bOff)
{
long[] t = new long[31];
for (int i=0;i < 31;++i)t[i]=0;
for (int i=0;i < 16; ++i) for(int j=0; j <16;++j)t[i+j]+=a[aOff + i]*b[bOff + j];
for (int i=0;i < 15;++i)t[i]+=38*t[i+16];
for (int i=0;i < 16;++i)o[oOff + i]=t[i];
car25519(o, oOff);
car25519(o, oOff);
}
private static void S(long[] /*gf*/ o,long[] /*gf*/ a)
{
M(o, 0, a, 0, a, 0);
}
private static void inv25519(long[] /*gf*/ o, int oOff, long[] /*gf*/ i, int iOff)
{
long[] /*gf*/ c = new long[GF_LEN];
int a;
for (a=0;a < 16;++a)c[a]=i[iOff + a];
for(a=253;a>=0;a--) {
S(c,c);
if(a!=2&&a!=4) M(c, 0, c, 0, i, iOff);
}
for (a=0;a < 16;++a)o[oOff + a]=c[a];
}
private static void pow2523(long[] /*gf*/ o,long[] /*gf*/ i)
{
long[] /*gf*/ c = new long[GF_LEN];
int a;
for (a=0;a < 16;++a)c[a]=i[a];
for(a=250;a>=0;a--) {
S(c,c);
if(a!=1) M(c, 0, c, 0, i, 0);
}
for (a=0;a < 16;++a)o[a]=c[a];
}
private static int crypto_scalarmult(byte[] q,byte[] n,byte[] p)
{
byte[] z = new byte[32];
long[] x = new long[80];
int r;
int i;
long[] /*gf*/ a = new long[GF_LEN],b = new long[GF_LEN],c = new long[GF_LEN],
d = new long[GF_LEN],e = new long[GF_LEN],f = new long[GF_LEN];
for (i=0;i < 31;++i)
z[i] = n[i];
z[31] = (byte)((n[31]&127)|64);
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=( (0xff & 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, 0, c, 0, a, 0);
M(c, 0, b, 0, e, 0);
A(e,a,c);
Z(a,a,c);
S(b, a);
Z(c,d,f);
M(a, 0, c, 0, _121665, 0);
A(a, a, d);
M(c, 0, c, 0, a, 0);
M(a, 0, d, 0, f, 0);
M(d, 0, b, 0, x, 0);
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;
}
private static int crypto_box_beforenm(byte[] k,byte[] y,byte[] x)
{
byte[] s = new byte[32];
crypto_scalarmult(s, x, y);
return crypto_core_hsalsa20(k,_0,s,sigma);
}
private static int crypto_box_afternm(byte[] c,byte[] m,long d,byte[] n,byte[] k)
{
return crypto_secretbox(c, m, d, n, k);
}
private static int crypto_box_open_afternm(byte[] m,byte[] c,long d,byte[] n,byte[] k)
{
return crypto_secretbox_open(m, c, d, n, k);
}
private static int crypto_box(byte[] c,byte[] m,long d,byte[] nonce, byte[] theirPublicBoxingKey, byte[] ourSecretBoxingKey)
{
byte[] k = new byte[32];
crypto_box_beforenm(k, theirPublicBoxingKey, ourSecretBoxingKey);
return crypto_box_afternm(c, m, d, nonce, k);
}
private static int crypto_box_open(byte[] m,byte[] c,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 int crypto_hash(byte[] out, byte[] m, int n) {
int[] hh = new int[8], hl = new int[8];
byte[] x = new byte[256];
int i, b = n;
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;
crypto_hashblocks_hl(hh, hl, m, n);
n %= 128;
for (i = 0; i < n; i++) x[i] = m[b-n+i];
x[n] = (byte)128;
n = 256-128*(n<112?1:0);
x[n-9] = 0;
jsts64(x, n - 8, (b / 0x20000000), b << 3);
crypto_hashblocks_hl(hh, hl, x, n);
for (i = 0; i < 8; i++) jsts64(out, 8 * i, hh[i], hl[i]);
return 0;
}
private static void jsts64(byte[] x, int i, int h, int l) {
x[i] = (byte)(h >> 24);
x[i+1] = (byte)(h >> 16);
x[i+2] = (byte)(h >> 8);
x[i+3] = (byte)h;
x[i+4] = (byte)(l >> 24);
x[i+5] = (byte)(l >> 16);
x[i+6] = (byte)(l >> 8);
x[i+7] = (byte)l;
}
private static int[] jsK = new int[]{
0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
};
private static int crypto_hashblocks_hl(int[] hh, int[] hl, byte[] m, int n) {
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, i, j, h, l, 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] & 0xff) << 24) | ((m[j+1] & 0xff) << 16) | ((m[j+2] & 0xff) << 8) | (m[j+3] & 0xff);
wl[i] = ((m[j+4] & 0xff) << 24) | ((m[j+5] & 0xff) << 16) | ((m[j+6] & 0xff) << 8) | (m[j+7] & 0xff);
}
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 = jsK[i*2];
l = jsK[i*2+1];
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;
}
return n;
}
private static void add(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/)
{
long[] /*gf*/ a=new long[GF_LEN],b=new long[GF_LEN],c=new long[GF_LEN],
d=new long[GF_LEN],t=new long[GF_LEN],e=new long[GF_LEN],
f=new long[GF_LEN],g=new long[GF_LEN],h=new long[GF_LEN];
Z(a, p[1], p[0]);
Z(t, q[1], q[0]);
M(a, 0, a, 0, t, 0);
A(b, p[0], p[1]);
A(t, q[0], q[1]);
M(b, 0, b, 0, t, 0);
M(c, 0, p[3], 0, q[3], 0);
M(c, 0, c, 0, D2, 0);
M(d, 0, p[2], 0, q[2], 0);
A(d, d, d);
Z(e, b, a);
Z(f, d, c);
A(g, d, c);
A(h, b, a);
M(p[0], 0, e, 0, f, 0);
M(p[1], 0, h, 0, g, 0);
M(p[2], 0, g, 0, f, 0);
M(p[3], 0, e, 0, h, 0);
}
private static void cswap(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/,byte b)
{
int i;
for(i=0; i < 4; i++)
sel25519(p[i],q[i],b & 0xff);
}
private static void pack(byte[] r,long[][] /*gf*/ p/*[4]*/)
{
long[] /*gf*/ tx = new long[GF_LEN], ty = new long[GF_LEN], zi = new long[GF_LEN];
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) << 7;
}
private static void scalarmult(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/,byte[] s, 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)(( (0xff & s[sOff + i/8]) >> (i&7))&1);
cswap(p,q,b);
add(q,p);
add(p,p);
cswap(p,q,b);
}
}
private static void scalarbase(long[][] /*gf*/ p/*[4]*/,byte[] s, int sOff)
{
long[][] /*gf*/ q = new long[4][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);
}
private static 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, int rOff, long[] x/*[64]*/)
{
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[rOff + i] = (byte)(x[i] & 255);
}
}
private static void reduce(byte[] r)
{
long[] x = new long[64];
for (int i=0;i < 64; i++) x[i] = 0xff & r[i];
for (int i=0;i < 64;++i)r[i] = 0;
modL(r, 0, x);
}
private static int crypto_sign(byte[] sm, byte[] m,int n,byte[] sk)
{
byte[] d = new byte[64],h = new byte[64],r = new byte[64];
long[] x = new long[64];
long[][] /*gf*/ p/*[4]*/ = new long[4][GF_LEN];
crypto_hash(d, sk, 32);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
// smlen[0] = n+64;
for (int i=0;i < n;++i)sm[64 + i] = m[i];
for (int i=0;i < 32;++i)sm[32 + i] = d[32 + i];
crypto_hash(r, Arrays.copyOfRange(sm, 32, sm.length), n + 32);
reduce(r);
scalarbase(p, r, 0);
pack(sm, p);
for (int i=0;i < 32;++i)sm[i+32] = sk[i+32];
crypto_hash(h, sm, n + 64);
reduce(h);
for (int i=0;i < 64;++i) x[i] = 0;
for (int i=0;i < 32; ++i) x[i] = 0xff & r[i];
for (int i=0;i < 32; ++i) for(int j=0; j < 32; ++j) x[i+j] += (0xff & h[i]) * (0xff & d[j]);
modL(sm, 32,x);
return 0;
}
private static int unpackneg(long[][] /*gf*/ r/*[4]*/,byte[] p/*[32]*/)
{
long[] /*gf*/ t = new long[GF_LEN], chk = new long[GF_LEN], num = new long[GF_LEN], den = new long[GF_LEN],
den2 = new long[GF_LEN], den4 = new long[GF_LEN], den6 = new long[GF_LEN];
set25519(r[2],gf1);
unpack25519(r[1],p);
S(num, r[1]);
M(den, 0, num, 0, D, 0);
Z(num,num,r[2]);
A(den,r[2],den);
S(den2,den);
S(den4,den2);
M(den6, 0, den4, 0, den2, 0);
M(t, 0, den6, 0, num, 0);
M(t, 0, t, 0, den, 0);
pow2523(t, t);
M(t, 0, t, 0, num, 0);
M(t, 0, t, 0, den, 0);
M(t, 0, t, 0, den, 0);
M(r[0], 0, t, 0, den, 0);
S(chk,r[0]);
M(chk, 0, chk, 0, den, 0);
if (neq25519(chk, num) != 0) M(r[0], 0, r[0], 0, I, 0);
S(chk, r[0]);
M(chk, 0, chk, 0, den, 0);
if (neq25519(chk, num) != 0) return -1;
if (par25519(r[0]) == ( (0xff & p[31]) >> 7)) Z(r[0],gf0,r[0]);
M(r[3], 0, r[0], 0, r[1], 0);
return 0;
}
private static int crypto_sign_open(byte[] m, byte[] sm, int n, byte[] pk)
{
int i;
byte[] t = new byte[32],h = new byte[64];
long[][] /*gf*/ p = new long[4][GF_LEN],q = new long[4][GF_LEN];
// mlen[0] = -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, n);
reduce(h);
scalarmult(p, q, h, 0);
scalarbase(q, sm, 32);
add(p, q);
pack(t, p);
n -= 64;
if (crypto_verify_32(sm, t) != 0) {
for (i=0;i < n;++i)m[i] = 0;
return -1;
}
for (i=0;i < n;++i)m[64 + i] = sm[i + 64];
// mlen[0] = n;
return 0;
}
private static SecureRandom getStrongCSPRNG() {
try {
return SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
private static Random prng = getStrongCSPRNG();
public static void randombytes(byte[] b, int len) {
byte[] r = new byte[len];
prng.nextBytes(r);
System.arraycopy(r, 0, b, 0, len);
}
}