commonMain.io.eqoty.secretk.utils.AxlSign.kt Maven / Gradle / Ivy
// Curve25519 signatures (and also key agreement)
// like in the early Axolotl.
//
// Ported to Kotlin by Miguel Sandro Lucero. [email protected]. 2017.05.31
// You can use it under MIT or CC0 license.
//
// Curve25519 signatures idea and math by Trevor Perrin
// https://moderncrypto.org/mail-archive/curves/2014/000205.html
//
// Derived from axlsign.js written by Dmitry Chestnykh. https://github.com/wavesplatform/curve25519-js
package io.eqoty.secretk.utils
import com.ionspin.kotlin.crypto.util.LibsodiumRandom
import kotlin.math.floor
// *** R val _0 = IntArray(16)
val _9 = intArrayOf(
0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
)
val gf0 = gf()
val gf1 = gf(longArrayOf(1))
val _121665 = gf(longArrayOf(0xdb41, 1))
val D = gf(
longArrayOf(
0x78a3, 0x1359, 0x4dca, 0x75eb,
0xd8ab, 0x4141, 0x0a4d, 0x0070,
0xe898, 0x7779, 0x4079, 0x8cc7,
0xfe73, 0x2b6f, 0x6cee, 0x5203
)
)
val D2 = gf(
longArrayOf(
0xf159, 0x26b2, 0x9b94, 0xebd6,
0xb156, 0x8283, 0x149a, 0x00e0,
0xd130, 0xeef3, 0x80f2, 0x198e,
0xfce7, 0x56df, 0xd9dc, 0x2406
)
)
val X = gf(
longArrayOf(
0xd51a, 0x8f25, 0x2d60, 0xc956,
0xa7b2, 0x9525, 0xc760, 0x692c,
0xdc5c, 0xfdd6, 0xe231, 0xc0a4,
0x53fe, 0xcd6e, 0x36d3, 0x2169
)
)
val Y = gf(
longArrayOf(
0x6658, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666,
0x6666, 0x6666, 0x6666, 0x6666
)
)
val I = gf(
longArrayOf(
0xa0b0, 0x4a0e, 0x1b27, 0xc4ee,
0xe478, 0xad2f, 0x1806, 0x2f43,
0xd7a7, 0x3dfb, 0x0099, 0x2b4d,
0xdf0b, 0x4fc1, 0x2480, 0x2b83
)
)
private fun floorLng(v: Double): Long {
return floor(v).toLong()
}
private fun gf(): LongArray {
return gf(longArrayOf(0))
}
private fun gf(init: LongArray): LongArray {
val r = LongArray(16)
for (i in 0..init.size - 1) {
r[i] = init[i]
}
return r
}
private fun ts64(x: IntArray, i: Int, h: Int, l: Int) {
x[i] = ((h shr 24) and 0xff)
x[i + 1] = ((h shr 16) and 0xff)
x[i + 2] = ((h shr 8) and 0xff)
x[i + 3] = (h and 0xff)
x[i + 4] = ((l shr 24) and 0xff)
x[i + 5] = ((l shr 16) and 0xff)
x[i + 6] = ((l shr 8) and 0xff)
x[i + 7] = (l and 0xff)
}
private fun vn(x: IntArray, xi: Int, y: IntArray, yi: Int, n: Int): Int {
var d = 0
for (i in 0..n - 1) {
d = d or (x[xi + i] xor y[yi + i])
}
return (1 and ((d - 1) ushr 8)) - 1
}
private fun crypto_verify_32(x: IntArray, xi: Int, y: IntArray, yi: Int): Int {
return vn(x, xi, y, yi, 32)
}
private fun set25519(r: LongArray, a: LongArray) {
for (i in 0..15) {
r[i] = a[i] or 0
}
}
private fun car25519(o: LongArray) {
var v: Long
var c = 1L
for (i in 0..15) {
v = o[i] + c + 65535
c = floorLng(v / 65536.0)
o[i] = v - c * 65536
}
o[0] += c - 1 + 37 * (c - 1)
}
private fun sel25519(p: LongArray, q: LongArray, b: Int) {
var t: Long
val invb = (b - 1).inv()
val c: Long = invb.toLong()
for (i in 0..15) {
t = c and (p[i] xor q[i])
p[i] = p[i] xor t
q[i] = q[i] xor t
}
}
private fun pack25519(o: IntArray, n: LongArray) {
var b: Long
val m = gf()
val t = gf()
for (i in 0..15) {
t[i] = n[i]
}
car25519(t)
car25519(t)
car25519(t)
for (j in 0..1) {
m[0] = t[0] - 0xffed
for (i in 1..14) {
m[i] = t[i] - 0xffff - ((m[i - 1] shr 16) and 1)
m[i - 1] = m[i - 1] and 0xffff
}
m[15] = t[15] - 0x7fff - ((m[14] shr 16) and 1)
b = (m[15] shr 16) and 1
m[14] = m[14] and 0xffff
sel25519(t, m, 1 - b.toInt())
}
for (i in 0..15) {
o[2 * i] = (t[i]).toInt() and 0xff
o[2 * i + 1] = (t[i]).toInt() shr 8
}
}
private fun neq25519(a: LongArray, b: LongArray): Int {
val c = IntArray(32)
val d = IntArray(32)
pack25519(c, a)
pack25519(d, b)
return crypto_verify_32(c, 0, d, 0)
}
private fun par25519(a: LongArray): Int {
val d = IntArray(32)
pack25519(d, a)
return d[0] and 1
}
private fun unpack25519(o: LongArray, n: IntArray) {
for (i in 0..15) {
val value: Int = n[2 * i] + (n[2 * i + 1] shl 8)
o[i] = value.toLong()
}
o[15] = o[15] and 0x7fff
}
private fun A(o: LongArray, a: LongArray, b: LongArray) {
for (i in 0..15) {
o[i] = a[i] + b[i]
}
}
private fun Z(o: LongArray, a: LongArray, b: LongArray) {
for (i in 0..15) {
o[i] = a[i] - b[i]
}
}
// optimized by Miguel
private fun M(o: LongArray, a: LongArray, b: LongArray) {
val at = LongArray(32)
val ab = LongArray(16)
for (i in 0..15) {
ab[i] = b[i]
}
var v: Long
for (i in 0..15) {
v = a[i]
for (j in 0..15) {
at[j + i] += v * ab[j]
}
}
for (i in 0..14) {
at[i] += 38 * at[i + 16]
}
// t15 left as is
// first car
var c: Long = 1
for (i in 0..15) {
v = at[i] + c + 65535
c = floorLng(v / 65536.0)
at[i] = v - c * 65536
}
at[0] += c - 1 + 37 * (c - 1)
// second car
c = 1
for (i in 0..15) {
v = at[i] + c + 65535
c = floorLng(v / 65536.0)
at[i] = v - c * 65536
}
at[0] += c - 1 + 37 * (c - 1)
for (i in 0..15) {
o[i] = at[i]
}
}
private fun S(o: LongArray, a: LongArray) {
M(o, a, a)
}
private fun inv25519(o: LongArray, i: LongArray) {
val c = gf()
for (a in 0..15) {
c[a] = i[a]
}
for (a in 253 downTo 0) {
S(c, c)
if (a != 2 && a != 4) {
M(c, c, i)
}
}
for (a in 0..15) {
o[a] = c[a]
}
}
private fun pow2523(o: LongArray, i: LongArray) {
val c = gf()
for (a in 0..15) {
c[a] = i[a]
}
for (a in 250 downTo 0) {
S(c, c)
if (a != 1) {
M(c, c, i)
}
}
for (a in 0..15) {
o[a] = c[a]
}
}
private fun crypto_scalarmult(q: IntArray, n: IntArray, p: IntArray): Int {
val z = IntArray(32)
val x = LongArray(80)
var r: Int
val a = gf()
val b = gf()
val c = gf()
val d = gf()
val e = gf()
val f = gf()
for (i in 0..30) {
z[i] = n[i]
}
z[31] = (n[31] and 127) or 64
z[0] = z[0] and 248
unpack25519(x, p)
for (i in 0..15) {
b[i] = x[i]
d[i] = 0
a[i] = 0
c[i] = 0
}
a[0] = 1
d[0] = 1
for (i in 254 downTo 0) {
r = (z[i ushr 3] ushr (i and 7)) and 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 in 0..15) {
x[i + 16] = a[i]
x[i + 32] = c[i]
x[i + 48] = b[i]
x[i + 64] = d[i]
}
val x32 = x.copyOfRange(32, x.size) // from 32
val x16 = x.copyOfRange(16, x.size) // from 16
inv25519(x32, x32)
M(x16, x16, x32)
pack25519(q, x16)
return 0
}
private fun crypto_scalarmult_base(q: IntArray, n: IntArray): Int {
return crypto_scalarmult(q, n, _9)
}
// Constantes de cada ronda del SHA-512
var K = longArrayOf(
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
)
// optimized by miguel
private fun crypto_hashblocks_hl(hh: IntArray, hl: IntArray, m: IntArray, _n: Int): Int {
val wh = IntArray(16)
val wl = IntArray(16)
val bh = IntArray(8)
val bl = IntArray(8)
var th: Int
var tl: Int
var h: Int
var l: Int
var a: Int
var b: Int
var c: Int
var d: Int
val ah = IntArray(8)
val al = IntArray(8)
for (i in 0..7) {
ah[i] = hh[i]
al[i] = hl[i]
}
var pos = 0
var n = _n
while (n >= 128) {
for (i in 0..15) {
val j = 8 * i + pos
wh[i] = (m[j + 0] shl 24) or (m[j + 1] shl 16) or (m[j + 2] shl 8) or m[j + 3]
wl[i] = (m[j + 4] shl 24) or (m[j + 5] shl 16) or (m[j + 6] shl 8) or m[j + 7]
}
for (i in 0..79) {
for (j in 0..6) {
bh[j] = ah[j]
bl[j] = al[j]
}
// add
h = ah[7]
l = al[7]
a = l and 0xffff; b = l ushr 16
c = h and 0xffff; d = h ushr 16
// Sigma1
h =
((ah[4] ushr 14) or (al[4] shl (32 - 14))) xor ((ah[4] ushr 18) or (al[4] shl (32 - 18))) xor ((al[4] ushr (41 - 32)) or (ah[4] shl (32 - (41 - 32))))
l =
((al[4] ushr 14) or (ah[4] shl (32 - 14))) xor ((al[4] ushr 18) or (ah[4] shl (32 - 18))) xor ((ah[4] ushr (41 - 32)) or (al[4] shl (32 - (41 - 32))))
a += l and 0xffff
b += l ushr 16
c += h and 0xffff
d += h ushr 16
// Ch
h = (ah[4] and ah[5]) xor (ah[4].inv() and ah[6])
l = (al[4] and al[5]) xor (al[4].inv() and al[6])
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
// K
h = K[i * 2].toInt()
l = K[i * 2 + 1].toInt()
a += l and 0xffff
b += l ushr 16
c += h and 0xffff
d += h ushr 16
// w
h = wh[i % 16]
l = wl[i % 16]
a += l and 0xffff
b += l ushr 16
c += h and 0xffff
d += h ushr 16
b += a ushr 16
c += b ushr 16
d += c ushr 16
// *** R
th = c and 0xffff or (d shl 16)
tl = a and 0xffff or (b shl 16)
// add
h = th
l = tl
a = l and 0xffff
b = l ushr 16
c = h and 0xffff
d = h ushr 16
// Sigma0
h =
((ah[0] ushr 28) or (al[0] shl (32 - 28))) xor ((al[0] ushr (34 - 32)) or (ah[0] shl (32 - (34 - 32)))) xor ((al[0] ushr (39 - 32)) or (ah[0] shl (32 - (39 - 32))))
l =
((al[0] ushr 28) or (ah[0] shl (32 - 28))) xor ((ah[0] ushr (34 - 32)) or (al[0] shl (32 - (34 - 32)))) xor ((ah[0] ushr (39 - 32)) or (al[0] shl (32 - (39 - 32))))
a += l and 0xffff
b += l ushr 16
c += h and 0xffff
d += h ushr 16
// Maj
h = (ah[0] and ah[1]) xor (ah[0] and ah[2]) xor (ah[1] and ah[2])
l = (al[0] and al[1]) xor (al[0] and al[2]) xor (al[1] and al[2])
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
b += a ushr 16
c += b ushr 16
d += c ushr 16
bh[7] = (c and 0xffff) or (d shl 16)
bl[7] = (a and 0xffff) or (b shl 16)
// add
h = bh[3]
l = bl[3]
a = l and 0xffff
b = l ushr 16
c = h and 0xffff
d = h ushr 16
h = th
l = tl
a += l and 0xffff
b += l ushr 16
c += h and 0xffff
d += h ushr 16
b += a ushr 16
c += b ushr 16
d += c ushr 16
bh[3] = (c and 0xffff) or (d shl 16)
bl[3] = (a and 0xffff) or (b shl 16)
for (j in 0..7) {
val k = (j + 1) % 8
ah[k] = bh[j]
al[k] = bl[j]
}
if (i % 16 == 15) {
for (j in 0..15) {
// add
h = wh[j]
l = wl[j]
a = l and 0xffff; b = l ushr 16
c = h and 0xffff; d = h ushr 16
h = wh[(j + 9) % 16]
l = wl[(j + 9) % 16]
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
// sigma0
th = wh[(j + 1) % 16]
tl = wl[(j + 1) % 16]
h = ((th ushr 1) or (tl shl (32 - 1))) xor ((th ushr 8) or (tl shl (32 - 8))) xor (th ushr 7)
l =
((tl ushr 1) or (th shl (32 - 1))) xor ((tl ushr 8) or (th shl (32 - 8))) xor ((tl ushr 7) or (th shl (32 - 7)))
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
// sigma1
th = wh[(j + 14) % 16]
tl = wl[(j + 14) % 16]
h =
((th ushr 19) or (tl shl (32 - 19))) xor ((tl ushr (61 - 32)) or (th shl (32 - (61 - 32)))) xor (th ushr 6)
l =
((tl ushr 19) or (th shl (32 - 19))) xor ((th ushr (61 - 32)) or (tl shl (32 - (61 - 32)))) xor ((tl ushr 6) or (th shl (32 - 6)))
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
b += a ushr 16
c += b ushr 16
d += c ushr 16
wh[j] = ((c and 0xffff) or (d shl 16))
wl[j] = ((a and 0xffff) or (b shl 16))
}
}
}
// add
a = 0; b = 0; c = 0; d = 0
for (k in 0..7) {
if (k == 0) {
h = ah[0]
l = al[0]
a = l and 0xffff; b = l ushr 16
c = h and 0xffff; d = h ushr 16
}
h = hh[k]
l = hl[k]
a += l and 0xffff; b += l ushr 16
c += h and 0xffff; d += h ushr 16
b += a ushr 16
c += b ushr 16
d += c ushr 16
hh[k] = (c and 0xffff) or (d shl 16)
ah[k] = (c and 0xffff) or (d shl 16)
hl[k] = (a and 0xffff) or (b shl 16)
al[k] = (a and 0xffff) or (b shl 16)
if (k < 7) {
h = ah[k + 1]
l = al[k + 1]
a = l and 0xffff; b = l ushr 16
c = h and 0xffff; d = h ushr 16
}
}
pos += 128
n -= 128
}
return n
}
val _HH = longArrayOf(0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
val _HL = longArrayOf(0xf3bcc908, 0x84caa73b, 0xfe94f82b, 0x5f1d36f1, 0xade682d1, 0x2b3e6c1f, 0xfb41bd6b, 0x137e2179)
fun LongArray.toIntArray(): IntArray {
val v = IntArray(this.size)
for (i in 0..this.size - 1) {
v[i] = this[i].toInt()
}
return v
}
private fun crypto_hash(out: IntArray, m: IntArray, _n: Int): Int {
val hh = _HH.toIntArray()
val hl = _HL.toIntArray()
val x = IntArray(256)
var n = _n
val b = n
crypto_hashblocks_hl(hh, hl, m, n)
n %= 128
for (i in 0..n - 1) {
x[i] = m[b - n + i]
}
x[n] = 128
// *** R n = 256-128 * (n<112?1:0);
if (n < 112) {
n = 256 - 128 * 1
} else {
n = 256 - 128 * 0
}
x[n - 9] = 0
ts64(x, n - 8, ((b / 0x20000000) or 0), (b shl 3))
crypto_hashblocks_hl(hh, hl, x, n)
for (i in 0..7) {
ts64(out, 8 * i, hh[i], hl[i])
}
return 0
}
private fun add(p: Array, q: Array) {
val a = gf()
val b = gf()
val c = gf()
val d = gf()
val e = gf()
val f = gf()
val g = gf()
val h = gf()
val t = gf()
Z(a, p[1], p[0])
Z(t, q[1], q[0])
M(a, a, t)
A(b, p[0], p[1])
A(t, q[0], q[1])
M(b, b, t)
M(c, p[3], q[3])
M(c, c, D2)
M(d, p[2], q[2])
A(d, d, d)
Z(e, b, a)
Z(f, d, c)
A(g, d, c)
A(h, b, a)
M(p[0], e, f)
M(p[1], h, g)
M(p[2], g, f)
M(p[3], e, h)
}
private fun cswap(p: Array, q: Array, b: Int) {
for (i in 0..3) {
sel25519(p[i], q[i], b)
}
}
private fun pack(r: IntArray, p: Array) {
val tx = gf()
val ty = gf()
val zi = gf()
inv25519(zi, p[2])
M(tx, p[0], zi)
M(ty, p[1], zi)
pack25519(r, ty)
r[31] = r[31] xor (par25519(tx) shl 7)
}
private fun scalarmult(p: Array, q: Array, s: IntArray) {
var b: Int
set25519(p[0], gf0)
set25519(p[1], gf1)
set25519(p[2], gf1)
set25519(p[3], gf0)
for (i in 255 downTo 0) {
b = (s[(i / 8) or 0] shr (i and 7)) and 1
cswap(p, q, b)
add(q, p)
add(p, p)
cswap(p, q, b)
}
}
private fun scalarbase(p: Array, s: IntArray) {
val q = arrayOf(gf(), gf(), gf(), gf())
set25519(q[0], X)
set25519(q[1], Y)
set25519(q[2], gf1)
M(q[3], X, Y)
scalarmult(p, q, s)
}
var L = intArrayOf(
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 fun modL(r: IntArray, x: IntArray) {
var carry: Int
for (i in 63 downTo 32) {
carry = 0
var j = i - 32
val k = i - 12
while (j < k) {
x[j] += carry - 16 * x[i] * L[j - (i - 32)]
carry = (x[j] + 128) shr 8
x[j] -= carry * 256
++j
}
x[j] += carry
x[i] = 0
}
carry = 0
for (j in 0..31) {
x[j] += carry - (x[31] shr 4) * L[j]
carry = x[j] shr 8
x[j] = x[j] and 255
}
for (j in 0..31) {
x[j] -= carry * L[j]
}
for (i in 0..31) {
x[i + 1] += x[i] shr 8
r[i] = x[i] and 255
}
}
private fun reduce(r: IntArray) {
val x = IntArray(64)
for (i in 0..63) {
x[i] = r[i]
}
for (i in 0..63) {
r[i] = 0
}
modL(r, x)
}
// Like crypto_sign, but uses secret key directly in hash.
private fun crypto_sign_direct(sm: IntArray, m: IntArray, n: Int, sk: IntArray): Int {
val h = IntArray(64)
val r = IntArray(64)
val x = IntArray(64)
val p = arrayOf(gf(), gf(), gf(), gf())
for (i in 0..n - 1) {
sm[64 + i] = m[i]
}
for (i in 0..31) {
sm[32 + i] = sk[i]
}
crypto_hash(r, sm.copyOfRange(32, sm.size), n + 32)
reduce(r)
scalarbase(p, r)
pack(sm, p)
for (i in 0..31) {
sm[i + 32] = sk[32 + i]
}
crypto_hash(h, sm, n + 64)
reduce(h)
for (i in 0..63) {
x[i] = 0
}
for (i in 0..31) {
x[i] = r[i]
}
for (i in 0..31) {
for (j in 0..31) {
x[i + j] += h[i] * sk[j]
}
}
val tmp = sm.copyOfRange(32, sm.size)
modL(tmp, x)
for (i in 0..tmp.size - 1) {
sm[32 + i] = tmp[i]
}
return n + 64
}
// Note: sm must be n+128.
private fun crypto_sign_direct_rnd(sm: IntArray, m: IntArray, n: Int, sk: IntArray, rnd: IntArray): Int {
val h = IntArray(64)
val r = IntArray(64)
val x = IntArray(64)
val p = arrayOf(gf(), gf(), gf(), gf())
// Hash separation.
sm[0] = 0xfe
for (i in 1..31) {
sm[i] = 0xff
}
// Secret key.
for (i in 0..31) {
sm[32 + i] = sk[i]
}
// Message.
for (i in 0..n - 1) {
sm[64 + i] = m[i]
}
// Random suffix.
for (i in 0..63) {
sm[n + 64 + i] = rnd[i]
}
crypto_hash(r, sm, n + 128)
reduce(r)
scalarbase(p, r)
pack(sm, p)
for (i in 0..31) {
sm[i + 32] = sk[32 + i]
}
crypto_hash(h, sm, n + 64)
reduce(h)
// Wipe out random suffix.
for (i in 0..63) {
sm[n + 64 + i] = 0
}
for (i in 0..63) {
x[i] = 0
}
for (i in 0..31) {
x[i] = r[i]
}
for (i in 0..31) {
for (j in 0..31) {
x[i + j] += h[i] * sk[j]
}
}
val tmp = sm.copyOfRange(32, n + 64)
modL(tmp, x)
for (i in 0..tmp.size - 1) {
sm[32 + i] = tmp[i]
}
return n + 64
}
private fun curve25519_sign(sm: IntArray, m: IntArray, n: Int, sk: IntArray, opt_rnd: IntArray?): Int {
// If opt_rnd is provided, sm must have n + 128,
// otherwise it must have n + 64 bytes.
// Convert Curve25519 secret key into Ed25519 secret key (includes pub key).
val edsk = IntArray(64)
val p = arrayOf(gf(), gf(), gf(), gf())
for (i in 0..31) {
edsk[i] = sk[i]
}
// Ensure private key is in the correct format.
edsk[0] = edsk[0] and 248
edsk[31] = edsk[31] and 127
edsk[31] = edsk[31] or 64
scalarbase(p, edsk)
val tmp = edsk.copyOfRange(32, edsk.size)
pack(tmp, p)
for (i in 0..tmp.size - 1) {
edsk[32 + i] = tmp[i]
}
// Remember sign bit.
val signBit = edsk[63] and 128
val smlen: Int
if (opt_rnd != null) {
smlen = crypto_sign_direct_rnd(sm, m, n, edsk, opt_rnd)
} else {
smlen = crypto_sign_direct(sm, m, n, edsk)
}
// Copy sign bit from public key into signature.
sm[63] = sm[63] or signBit
return smlen
}
private fun unpackneg(r: Array, p: IntArray): Int {
val t = gf()
val chk = gf()
val num = gf()
val den = gf()
val den2 = gf()
val den4 = gf()
val den6 = gf()
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] shr 7)) {
Z(r[0], gf0, r[0])
}
M(r[3], r[0], r[1])
return 0
}
private fun crypto_sign_open(m: IntArray, sm: IntArray, _n: Int, pk: IntArray): Int {
val t = IntArray(32)
val h = IntArray(64)
val p = arrayOf(gf(), gf(), gf(), gf())
val q = arrayOf(gf(), gf(), gf(), gf())
var n = _n
var mlen = -1
if (n < 64) {
return mlen
}
if (unpackneg(q, pk) != 0) {
return mlen
}
for (i in 0..n - 1) {
m[i] = sm[i]
}
for (i in 0..31) {
m[i + 32] = pk[i]
}
crypto_hash(h, m, n)
reduce(h)
scalarmult(p, q, h)
scalarbase(q, sm.copyOfRange(32, sm.size))
add(p, q)
pack(t, p)
n -= 64
if (crypto_verify_32(sm, 0, t, 0) != 0) {
for (i in 0..n - 1) {
m[i] = 0
}
return -1
}
for (i in 0..n - 1) {
m[i] = sm[i + 64]
}
mlen = n
return mlen
}
// Converts Curve25519 public key back to Ed25519 public key.
// edwardsY = (montgomeryX - 1) / (montgomeryX + 1)
private fun convertPublicKey(pk: IntArray): IntArray {
val z = IntArray(32)
val x = gf()
val a = gf()
val b = gf()
unpack25519(x, pk)
A(a, x, gf1)
Z(b, x, gf1)
inv25519(a, a)
M(a, a, b)
pack25519(z, a)
return z
}
private fun curve25519_sign_open(m: IntArray, sm: IntArray, n: Int, pk: IntArray): Int {
// Convert Curve25519 public key into Ed25519 public key.
val edpk = convertPublicKey(pk)
// Restore sign bit from signature.
edpk[31] = edpk[31] or (sm[63] and 128)
// Remove sign bit from signature.
sm[63] = sm[63] and 127
// Verify signed message.
return crypto_sign_open(m, sm, n, edpk)
}
// Class
object AxlSign {
fun sharedKey(secretKey: IntArray, publicKey: IntArray): IntArray {
val sharedKey = IntArray(32)
crypto_scalarmult(sharedKey, secretKey, publicKey)
return sharedKey
}
fun signMessage(secretKey: IntArray, msg: IntArray, opt_random: IntArray?): IntArray {
if (opt_random != null) {
val buf = IntArray(128 + msg.size)
curve25519_sign(buf, msg, msg.size, secretKey, opt_random)
return buf.copyOfRange(0, 64 + msg.size)
} else {
val signedMsg = IntArray(64 + msg.size)
curve25519_sign(signedMsg, msg, msg.size, secretKey, null)
return signedMsg
}
}
// add by Miguel
fun openMessageStr(publicKey: IntArray, signedMsg: IntArray): String {
val m = openMessage(publicKey, signedMsg)
if (m != null) {
var msg = ""
for (i in 0..m.size - 1) {
msg += m[i].toChar()
}
return msg
} else {
return ""
}
}
fun openMessage(publicKey: IntArray, signedMsg: IntArray): IntArray? {
val tmp = IntArray(signedMsg.size)
val mlen = curve25519_sign_open(tmp, signedMsg, signedMsg.size, publicKey)
if (mlen < 0) {
return null
}
val m = IntArray(mlen)
for (i in 0..m.size - 1) {
m[i] = tmp[i]
}
return m
}
fun sign(secretKey: IntArray, msg: IntArray, opt_random: IntArray?): IntArray {
var len = 64
if (opt_random != null) {
len = 128
}
val buf = IntArray(len + msg.size)
curve25519_sign(buf, msg, msg.size, secretKey, opt_random)
val signature = IntArray(64)
for (i in 0..signature.size - 1) {
signature[i] = buf[i]
}
return signature
}
fun verify(publicKey: IntArray, msg: IntArray, signature: IntArray): Int {
val sm = IntArray(64 + msg.size)
val m = IntArray(64 + msg.size)
for (i in 0..63) {
sm[i] = signature[i]
}
for (i in 0..msg.size - 1) {
sm[i + 64] = msg[i]
}
if (curve25519_sign_open(m, sm, sm.size, publicKey) >= 0) {
return 1
} else {
return 0
}
}
class Keys(pk: IntArray, sk: IntArray) {
var publicKey = pk
var privateKey = sk
}
fun generateKeyPair(seed: IntArray): Keys {
val sk = IntArray(32)
val pk = IntArray(32)
for (i in 0..31) {
sk[i] = seed[i]
}
crypto_scalarmult_base(pk, sk)
// Turn secret key into the correct format.
sk[0] = sk[0] and 248
sk[31] = sk[31] and 127
sk[31] = sk[31] or 64
// Remove sign bit from public key.
pk[31] = pk[31] and 127
return Keys(pk, sk)
}
fun randomBytes(size: Int): IntArray {
val High: Int = 255
val Low: Int = 0
val seed = IntArray(size)
for (i in 0..seed.size - 1) {
seed[i] = LibsodiumRandom.uniform((High - Low).toUInt()).toInt() + Low
}
return seed
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy