co.topl.crypto.signatures.eddsa.X25519Field.scala Maven / Gradle / Ivy
The newest version!
package co.topl.crypto.signatures.eddsa
/**
* AMS 2021:
* Curve point operations ported from BouncyCastle used in all EC primitives in crypto.primitives.eddsa
* Licensing: https://www.bouncycastle.org/licence.html
* Copyright (c) 2000 - 2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
private[crypto] class X25519Field {
val SIZE = 10
val M24 = 0x00ffffff
val M25 = 0x01ffffff
val M26 = 0x03ffffff
val ROOT_NEG_ONE: Array[Int] = Array[Int](0x020ea0b0, 0x0386c9d2, 0x00478c4e, 0x0035697f, 0x005e8630, 0x01fbd7a7,
0x0340264f, 0x01f0b2b4, 0x00027e0e, 0x00570649)
def add(x: Array[Int], y: Array[Int], z: Array[Int]): Unit =
for (i <- 0 until SIZE)
z(i) = x(i) + y(i)
def addOne(z: Array[Int]): Unit =
z(0) += 1
def addOne(z: Array[Int], zOff: Int): Unit =
z(zOff) += 1
def apm(x: Array[Int], y: Array[Int], zp: Array[Int], zm: Array[Int]): Unit =
for (i <- 0 until SIZE) {
val xi = x(i)
val yi = y(i)
zp(i) = xi + yi
zm(i) = xi - yi
}
def carry(z: Array[Int]): Unit = {
var z0 = z(0)
var z1 = z(1)
var z2 = z(2)
var z3 = z(3)
var z4 = z(4)
var z5 = z(5)
var z6 = z(6)
var z7 = z(7)
var z8 = z(8)
var z9 = z(9)
z3 += (z2 >> 25)
z2 &= M25
z5 += (z4 >> 25)
z4 &= M25
z8 += (z7 >> 25)
z7 &= M25
z0 += (z9 >> 25) * 38
z9 &= M25
z1 += (z0 >> 26)
z0 &= M26
z6 += (z5 >> 26)
z5 &= M26
z2 += (z1 >> 26)
z1 &= M26
z4 += (z3 >> 26)
z3 &= M26
z7 += (z6 >> 26)
z6 &= M26
z9 += (z8 >> 26)
z8 &= M26
z(0) = z0
z(1) = z1
z(2) = z2
z(3) = z3
z(4) = z4
z(5) = z5
z(6) = z6
z(7) = z7
z(8) = z8
z(9) = z9
}
def cmov(cond: Int, x: Array[Int], xOff: Int, z: Array[Int], zOff: Int): Unit =
for (i <- 0 until SIZE) {
var z_i = z(zOff + i)
val diff = z_i ^ x(xOff + i)
z_i ^= (diff & cond)
z(zOff + i) = z_i
}
def cnegate(negate: Int, z: Array[Int]): Unit = {
val mask = 0 - negate
for (i <- 0 until SIZE)
z(i) = (z(i) ^ mask) - mask
}
def copy(x: Array[Int], xOff: Int, z: Array[Int], zOff: Int): Unit =
for (i <- 0 until SIZE)
z(zOff + i) = x(xOff + i)
def create = new Array[Int](SIZE)
def createTable(n: Int) = new Array[Int](SIZE * n)
def cswap(swap: Int, a: Array[Int], b: Array[Int]): Unit = {
val mask = 0 - swap
for (i <- 0 until SIZE) {
val ai = a(i)
val bi = b(i)
val dummy = mask & (ai ^ bi)
a(i) = ai ^ dummy
b(i) = bi ^ dummy
}
}
def decode(x: Array[Byte], xOff: Int, z: Array[Int]): Unit = {
decode128(x, xOff, z, 0)
decode128(x, xOff + 16, z, 5)
z(9) &= M24
}
def decode128(bs: Array[Byte], off: Int, z: Array[Int], zOff: Int): Unit = {
val t0 = decode32(bs, off + 0)
val t1 = decode32(bs, off + 4)
val t2 = decode32(bs, off + 8)
val t3 = decode32(bs, off + 12)
z(zOff + 0) = t0 & M26
z(zOff + 1) = ((t1 << 6) | (t0 >>> 26)) & M26
z(zOff + 2) = ((t2 << 12) | (t1 >>> 20)) & M25
z(zOff + 3) = ((t3 << 19) | (t2 >>> 13)) & M26
z(zOff + 4) = t3 >>> 7
}
def decode32(bs: Array[Byte], off: Int): Int = {
var n = bs(off) & 0xff
n |= (bs(off + 1) & 0xff) << 8
n |= (bs(off + 2) & 0xff) << 16
n |= bs(off + 3) << 24
n
}
def encode(x: Array[Int], z: Array[Byte], zOff: Int): Unit = {
encode128(x, 0, z, zOff)
encode128(x, 5, z, zOff + 16)
}
def encode128(x: Array[Int], xOff: Int, bs: Array[Byte], off: Int): Unit = {
val x0 = x(xOff + 0)
val x1 = x(xOff + 1)
val x2 = x(xOff + 2)
val x3 = x(xOff + 3)
val x4 = x(xOff + 4)
val t0 = x0 | (x1 << 26)
encode32(t0, bs, off + 0)
val t1 = (x1 >>> 6) | (x2 << 20)
encode32(t1, bs, off + 4)
val t2 = (x2 >>> 12) | (x3 << 13)
encode32(t2, bs, off + 8)
val t3 = (x3 >>> 19) | (x4 << 7)
encode32(t3, bs, off + 12)
}
def encode32(n: Int, bs: Array[Byte], off: Int): Unit = {
bs(off) = n.toByte
bs(off + 1) = (n >>> 8).toByte
bs(off + 2) = (n >>> 16).toByte
bs(off + 3) = (n >>> 24).toByte
}
def inv(x: Array[Int], z: Array[Int]): Unit = {
// (250 1s) (1 0s) (1 1s) (1 0s) (2 1s)
// Addition chain: [1] [2] 3 5 10 15 25 50 75 125 [250]
val x2 = create
val t = create
powPm5d8(x, x2, t)
sqr(t, 3, t)
mul(t, x2, z)
}
def isZero(x: Array[Int]): Int = {
var d = 0
for (i <- 0 until SIZE)
d |= x(i)
d = (d >>> 1) | (d & 1)
(d - 1) >> 31
}
def isZeroVar(x: Array[Int]): Boolean = 0 != isZero(x)
def mul(x: Array[Int], y: Int, z: Array[Int]): Unit = {
val x0 = x(0)
val x1 = x(1)
var x2 = x(2)
val x3 = x(3)
var x4 = x(4)
val x5 = x(5)
val x6 = x(6)
var x7 = x(7)
val x8 = x(8)
var x9 = x(9)
var c0 = 0L
var c1 = 0L
var c2 = 0L
var c3 = 0L
c0 = x2.toLong * y
x2 = c0.toInt & M25
c0 >>= 25
c1 = x4.toLong * y
x4 = c1.toInt & M25
c1 >>= 25
c2 = x7.toLong * y
x7 = c2.toInt & M25
c2 >>= 25
c3 = x9.toLong * y
x9 = c3.toInt & M25
c3 >>= 25
c3 *= 38
c3 += x0.toLong * y
z(0) = c3.toInt & M26
c3 >>= 26
c1 += x5.toLong * y
z(5) = c1.toInt & M26
c1 >>= 26
c3 += x1.toLong * y
z(1) = c3.toInt & M26
c3 >>= 26
c0 += x3.toLong * y
z(3) = c0.toInt & M26
c0 >>= 26
c1 += x6.toLong * y
z(6) = c1.toInt & M26
c1 >>= 26
c2 += x8.toLong * y
z(8) = c2.toInt & M26
c2 >>= 26
z(2) = x2 + c3.toInt
z(4) = x4 + c0.toInt
z(7) = x7 + c1.toInt
z(9) = x9 + c2.toInt
}
def mul(x: Array[Int], y: Array[Int], z: Array[Int]): Unit = {
var x0 = x(0)
var y0 = y(0)
var x1 = x(1)
var y1 = y(1)
var x2 = x(2)
var y2 = y(2)
var x3 = x(3)
var y3 = y(3)
var x4 = x(4)
var y4 = y(4)
val u0 = x(5)
val v0 = y(5)
val u1 = x(6)
val v1 = y(6)
val u2 = x(7)
val v2 = y(7)
val u3 = x(8)
val v3 = y(8)
val u4 = x(9)
val v4 = y(9)
var a0 = x0.toLong * y0
var a1 = x0.toLong * y1 + x1.toLong * y0
var a2 = x0.toLong * y2 + x1.toLong * y1 + x2.toLong * y0
var a3 = x1.toLong * y2 + x2.toLong * y1
a3 <<= 1
a3 += x0.toLong * y3 + x3.toLong * y0
var a4 = x2.toLong * y2
a4 <<= 1
a4 += x0.toLong * y4 + x1.toLong * y3 + x3.toLong * y1 + x4.toLong * y0
var a5 = x1.toLong * y4 + x2.toLong * y3 + x3.toLong * y2 + x4.toLong * y1
a5 <<= 1
var a6 = x2.toLong * y4 + x4.toLong * y2
a6 <<= 1
a6 += x3.toLong * y3
var a7 = x3.toLong * y4 + x4.toLong * y3
var a8 = x4.toLong * y4
a8 <<= 1
val b0 = u0.toLong * v0
val b1 = u0.toLong * v1 + u1.toLong * v0
val b2 = u0.toLong * v2 + u1.toLong * v1 + u2.toLong * v0
var b3 = u1.toLong * v2 + u2.toLong * v1
b3 <<= 1
b3 += u0.toLong * v3 + u3.toLong * v0
var b4 = u2.toLong * v2
b4 <<= 1
b4 += u0.toLong * v4 + u1.toLong * v3 + u3.toLong * v1 + u4.toLong * v0
val b5 = u1.toLong * v4 + u2.toLong * v3 + u3.toLong * v2 + u4.toLong * v1
var b6 = u2.toLong * v4 + u4.toLong * v2
b6 <<= 1
b6 += u3.toLong * v3
val b7 = u3.toLong * v4 + u4.toLong * v3
val b8 = u4.toLong * v4
a0 -= b5 * 76
a1 -= b6 * 38
a2 -= b7 * 38
a3 -= b8 * 76
a5 -= b0
a6 -= b1
a7 -= b2
a8 -= b3
x0 += u0
y0 += v0
x1 += u1
y1 += v1
x2 += u2
y2 += v2
x3 += u3
y3 += v3
x4 += u4
y4 += v4
val c0 = x0.toLong * y0
val c1 = x0.toLong * y1 + x1.toLong * y0
val c2 = x0.toLong * y2 + x1.toLong * y1 + x2.toLong * y0
var c3 = x1.toLong * y2 + x2.toLong * y1
c3 <<= 1
c3 += x0.toLong * y3 + x3.toLong * y0
var c4 = x2.toLong * y2
c4 <<= 1
c4 += x0.toLong * y4 + x1.toLong * y3 + x3.toLong * y1 + x4.toLong * y0
var c5 = x1.toLong * y4 + x2.toLong * y3 + x3.toLong * y2 + x4.toLong * y1
c5 <<= 1
var c6 = x2.toLong * y4 + x4.toLong * y2
c6 <<= 1
c6 += x3.toLong * y3
val c7 = x3.toLong * y4 + x4.toLong * y3
var c8 = x4.toLong * y4
c8 <<= 1
var z8 = 0
var z9 = 0
var t = 0L
t = a8 + (c3 - a3)
z8 = t.toInt & M26
t >>= 26
t += (c4 - a4) - b4
z9 = t.toInt & M25
t >>= 25
t = a0 + (t + c5 - a5) * 38
z(0) = t.toInt & M26
t >>= 26
t += a1 + (c6 - a6) * 38
z(1) = t.toInt & M26
t >>= 26
t += a2 + (c7 - a7) * 38
z(2) = t.toInt & M25
t >>= 25
t += a3 + (c8 - a8) * 38
z(3) = t.toInt & M26
t >>= 26
t += a4 + b4 * 38
z(4) = t.toInt & M25
t >>= 25
t += a5 + (c0 - a0)
z(5) = t.toInt & M26
t >>= 26
t += a6 + (c1 - a1)
z(6) = t.toInt & M26
t >>= 26
t += a7 + (c2 - a2)
z(7) = t.toInt & M25
t >>= 25
t += z8
z(8) = t.toInt & M26
t >>= 26
z(9) = z9 + t.toInt
}
def negate(x: Array[Int], z: Array[Int]): Unit =
for (i <- 0 until SIZE)
z(i) = -x(i)
def normalize(z: Array[Int]): Unit = {
val x = (z(9) >>> 23) & 1
reduce(z, x)
reduce(z, -x)
}
def one(z: Array[Int]): Unit = {
z(0) = 1
for (i <- 1 until SIZE)
z(i) = 0
}
def powPm5d8(x: Array[Int], rx2: Array[Int], rz: Array[Int]): Unit = {
// (250 1s) (1 0s) (1 1s)
// Addition chain: [1] 2 3 5 10 15 25 50 75 125 [250]
val x2 = rx2
sqr(x, x2)
mul(x, x2, x2)
val x3 = create
sqr(x2, x3)
mul(x, x3, x3)
val x5 = x3
sqr(x3, 2, x5)
mul(x2, x5, x5)
val x10 = create
sqr(x5, 5, x10)
mul(x5, x10, x10)
val x15 = create
sqr(x10, 5, x15)
mul(x5, x15, x15)
val x25 = x5
sqr(x15, 10, x25)
mul(x10, x25, x25)
val x50 = x10
sqr(x25, 25, x50)
mul(x25, x50, x50)
val x75 = x15
sqr(x50, 25, x75)
mul(x25, x75, x75)
val x125 = x25
sqr(x75, 50, x125)
mul(x50, x125, x125)
val x250 = x50
sqr(x125, 125, x250)
mul(x125, x250, x250)
val t = x125
sqr(x250, 2, t)
mul(t, x, rz)
}
def reduce(z: Array[Int], c: Int): Unit = {
var z9 = z(9)
var t = z9
z9 = t & M24
t >>= 24
t += c
t *= 19
t += z(0)
z(0) = t & M26
t >>= 26
t += z(1)
z(1) = t & M26
t >>= 26
t += z(2)
z(2) = t & M25
t >>= 25
t += z(3)
z(3) = t & M26
t >>= 26
t += z(4)
z(4) = t & M25
t >>= 25
t += z(5)
z(5) = t & M26
t >>= 26
t += z(6)
z(6) = t & M26
t >>= 26
t += z(7)
z(7) = t & M25
t >>= 25
t += z(8)
z(8) = t & M26
t >>= 26
t += z9
z(9) = t
}
def sqr(x: Array[Int], z: Array[Int]): Unit = {
var x0 = x(0)
var x1 = x(1)
var x2 = x(2)
var x3 = x(3)
var x4 = x(4)
val u0 = x(5)
val u1 = x(6)
val u2 = x(7)
val u3 = x(8)
val u4 = x(9)
var x1_2 = x1 * 2
var x2_2 = x2 * 2
var x3_2 = x3 * 2
var x4_2 = x4 * 2
var a0 = x0.toLong * x0
var a1 = x0.toLong * x1_2
var a2 = x0.toLong * x2_2 + x1.toLong * x1
var a3 = x1_2.toLong * x2_2 + x0.toLong * x3_2
val a4 = x2.toLong * x2_2 + x0.toLong * x4_2 + x1.toLong * x3_2
var a5 = x1_2.toLong * x4_2 + x2_2.toLong * x3_2
var a6 = x2_2.toLong * x4_2 + x3.toLong * x3
var a7 = x3.toLong * x4_2
var a8 = x4.toLong * x4_2
val u1_2 = u1 * 2
val u2_2 = u2 * 2
val u3_2 = u3 * 2
val u4_2 = u4 * 2
val b0 = u0.toLong * u0
val b1 = u0.toLong * u1_2
val b2 = u0.toLong * u2_2 + u1.toLong * u1
val b3 = u1_2.toLong * u2_2 + u0.toLong * u3_2
val b4 = u2.toLong * u2_2 + u0.toLong * u4_2 + u1.toLong * u3_2
val b5 = u1_2.toLong * u4_2 + u2_2.toLong * u3_2
val b6 = u2_2.toLong * u4_2 + u3.toLong * u3
val b7 = u3.toLong * u4_2
val b8 = u4.toLong * u4_2
a0 -= b5 * 38
a1 -= b6 * 38
a2 -= b7 * 38
a3 -= b8 * 38
a5 -= b0
a6 -= b1
a7 -= b2
a8 -= b3
x0 += u0
x1 += u1
x2 += u2
x3 += u3
x4 += u4
x1_2 = x1 * 2
x2_2 = x2 * 2
x3_2 = x3 * 2
x4_2 = x4 * 2
val c0 = x0.toLong * x0
val c1 = x0.toLong * x1_2
val c2 = x0.toLong * x2_2 + x1.toLong * x1
val c3 = x1_2.toLong * x2_2 + x0.toLong * x3_2
val c4 = x2.toLong * x2_2 + x0.toLong * x4_2 + x1.toLong * x3_2
val c5 = x1_2.toLong * x4_2 + x2_2.toLong * x3_2
val c6 = x2_2.toLong * x4_2 + x3.toLong * x3
val c7 = x3.toLong * x4_2
val c8 = x4.toLong * x4_2
var z8 = 0
var z9 = 0
var t = 0L
t = a8 + (c3 - a3)
z8 = t.toInt & M26
t >>= 26
t += (c4 - a4) - b4
z9 = t.toInt & M25
t >>= 25
t = a0 + (t + c5 - a5) * 38
z(0) = t.toInt & M26
t >>= 26
t += a1 + (c6 - a6) * 38
z(1) = t.toInt & M26
t >>= 26
t += a2 + (c7 - a7) * 38
z(2) = t.toInt & M25
t >>= 25
t += a3 + (c8 - a8) * 38
z(3) = t.toInt & M26
t >>= 26
t += a4 + b4 * 38
z(4) = t.toInt & M25
t >>= 25
t += a5 + (c0 - a0)
z(5) = t.toInt & M26
t >>= 26
t += a6 + (c1 - a1)
z(6) = t.toInt & M26
t >>= 26
t += a7 + (c2 - a2)
z(7) = t.toInt & M25
t >>= 25
t += z8
z(8) = t.toInt & M26
t >>= 26
z(9) = z9 + t.toInt
}
def sqr(x: Array[Int], n: Int, z: Array[Int]): Unit = {
var nv = n
sqr(x, z)
while ({ nv -= 1; nv } > 0) sqr(z, z)
}
def sqrtRatioVar(u: Array[Int], v: Array[Int], z: Array[Int]): Boolean = {
val uv3 = create
val uv7 = create
mul(u, v, uv3)
sqr(v, uv7)
mul(uv3, uv7, uv3)
sqr(uv7, uv7)
mul(uv7, uv3, uv7)
val t = create
val x = create
powPm5d8(uv7, t, x)
mul(x, uv3, x)
val vx2 = create
sqr(x, vx2)
mul(vx2, v, vx2)
sub(vx2, u, t)
normalize(t)
if (isZeroVar(t)) {
copy(x, 0, z, 0)
return true
}
add(vx2, u, t)
normalize(t)
if (isZeroVar(t)) {
mul(x, ROOT_NEG_ONE, z)
return true
}
false
}
def sub(x: Array[Int], y: Array[Int], z: Array[Int]): Unit =
for (i <- 0 until SIZE)
z(i) = x(i) - y(i)
def subOne(z: Array[Int]): Unit =
z(0) -= 1
def zero(z: Array[Int]): Unit =
for (i <- 0 until SIZE)
z(i) = 0
}