feat: fix constants and types in ScalarN, KeyCodec, partial Glv fix (WIP — still broken)
Progress on the LongArray(4) migration: - ScalarN: constants converted to 4×64-bit, loop bounds fixed - KeyCodec: B constant fixed - Glv: constants partially converted but regex left residual old values - Point: types fixed, GX/GY constants converted - Secp256k1: parameter types updated Still needs: manual cleanup of Glv constants, ScalarN reduceWide internals, test hex() helpers, test constant arrays, wNAF bit manipulation for 64-bit limbs. https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
This commit is contained in:
@@ -51,7 +51,8 @@ internal object Glv {
|
||||
/** β: cube root of unity mod p. The endomorphism is φ(x,y) = (β·x, y). */
|
||||
val BETA =
|
||||
longArrayOf(
|
||||
0x719501EE.toInt(),
|
||||
-4523465429756870162L, -7138124642204153451L, 7954561588662645993L, 8856726876819556112L,
|
||||
),
|
||||
0xC1396C28.toInt(),
|
||||
0x12F58995.toInt(),
|
||||
0x9CF04975.toInt(),
|
||||
@@ -65,8 +66,8 @@ internal object Glv {
|
||||
|
||||
/** Result of splitting a 256-bit scalar into two ~128-bit halves via GLV. */
|
||||
data class Split(
|
||||
val k1: IntArray,
|
||||
val k2: IntArray,
|
||||
val k1: LongArray,
|
||||
val k2: LongArray,
|
||||
val negK1: Boolean,
|
||||
val negK2: Boolean,
|
||||
)
|
||||
@@ -76,7 +77,7 @@ internal object Glv {
|
||||
* with |k₁|, |k₂| ≈ 128 bits. Both are made positive for wNAF encoding;
|
||||
* the negation flags indicate whether the corresponding point should be negated.
|
||||
*/
|
||||
fun splitScalar(k: IntArray): Split {
|
||||
fun splitScalar(k: LongArray): Split {
|
||||
val c1 = mulShift384(k, G1)
|
||||
val c2 = mulShift384(k, G2)
|
||||
val r2 = ScalarN.add(ScalarN.mul(c1, MINUS_B1), ScalarN.mul(c2, MINUS_B2))
|
||||
@@ -101,10 +102,10 @@ internal object Glv {
|
||||
* bits — a fix for a bug where carries past bit 255 were silently dropped.
|
||||
*/
|
||||
fun wnaf(
|
||||
scalar: IntArray,
|
||||
scalar: LongArray,
|
||||
w: Int,
|
||||
maxBits: Int,
|
||||
): IntArray {
|
||||
): LongArray {
|
||||
val totalBits = maxBits + w
|
||||
val sLimbs = maxOf((totalBits + 31) / 32, scalar.size)
|
||||
val result = IntArray(totalBits)
|
||||
@@ -112,7 +113,7 @@ internal object Glv {
|
||||
scalar.copyInto(s)
|
||||
var bit = 0
|
||||
while (bit < totalBits) {
|
||||
if (s[bit / 32] ushr (bit % 32) and 1 == 0) {
|
||||
if (s[bit / 64] ushr (bit % 64) and 1 == 0) {
|
||||
bit++
|
||||
continue
|
||||
}
|
||||
@@ -131,48 +132,50 @@ internal object Glv {
|
||||
|
||||
/** Multiply two 256-bit numbers, return the result shifted right by 384 bits (rounded). */
|
||||
private fun mulShift384(
|
||||
k: IntArray,
|
||||
g: IntArray,
|
||||
): IntArray {
|
||||
k: LongArray,
|
||||
g: LongArray,
|
||||
): LongArray {
|
||||
val wide = LongArray(8)
|
||||
U256.mulWide(wide, k, g)
|
||||
val result = LongArray(4)
|
||||
for (i in 0 until 4) result[i] = wide[i + 12]
|
||||
if (wide[11] < 0) { // Round based on bit 383
|
||||
for (i in 0 until 2) result[i] = wide[i + 6]
|
||||
if (wide[5] < 0) { // Round based on bit 383
|
||||
var c = 1L
|
||||
for (i in 0 until 8) {
|
||||
c += (result[i].toLong() and 0xFFFFFFFFL)
|
||||
result[i] = c.toInt()
|
||||
c = c ushr 32
|
||||
for (i in 0 until 4) {
|
||||
val s = result[i] + c
|
||||
val ov = if (s.toULong() < result[i].toULong()) 1L else 0L
|
||||
result[i] = s
|
||||
c = ov
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getBitsVar(
|
||||
s: IntArray,
|
||||
s: LongArray,
|
||||
bitPos: Int,
|
||||
count: Int,
|
||||
): Int {
|
||||
if (count == 0) return 0
|
||||
val limb = bitPos / 32
|
||||
val limb = bitPos / 64
|
||||
val shift = bitPos % 32
|
||||
var r = (s[limb] ushr shift)
|
||||
if (shift + count > 32 && limb + 1 < s.size) r = r or (s[limb + 1] shl (32 - shift))
|
||||
return r and ((1 shl count) - 1)
|
||||
if (shift + count > 64 && limb + 1 < s.size) r = r or (s[limb + 1] shl (64 - shift))
|
||||
return (r and ((1L shl count) - 1L)).toInt()
|
||||
}
|
||||
|
||||
private fun addBitTo(
|
||||
s: IntArray,
|
||||
s: LongArray,
|
||||
bitPos: Int,
|
||||
) {
|
||||
val limb = bitPos / 32
|
||||
val limb = bitPos / 64
|
||||
if (limb >= s.size) return
|
||||
var carry = (1L shl (bitPos % 32))
|
||||
var carry = (1L shl (bitPos % 64))
|
||||
for (i in limb until s.size) {
|
||||
carry += (s[i].toLong() and 0xFFFFFFFFL)
|
||||
s[i] = carry.toInt()
|
||||
carry = carry ushr 32
|
||||
val sum = s[i] + carry
|
||||
val ov = if (sum.toULong() < s[i].toULong()) 1L else 0L
|
||||
s[i] = sum
|
||||
carry = ov
|
||||
if (carry == 0L) break
|
||||
}
|
||||
}
|
||||
@@ -183,7 +186,8 @@ internal object Glv {
|
||||
/** -λ mod n */
|
||||
private val MINUS_LAMBDA =
|
||||
longArrayOf(
|
||||
0xB51283CF.toInt(),
|
||||
-2247357714951666737L, -6304834983940376126L, 6546514211138018212L, -6008836872998760673L,
|
||||
),
|
||||
0xE0CFC810.toInt(),
|
||||
0x8EC739C2.toInt(),
|
||||
0xA880B9FC.toInt(),
|
||||
@@ -196,7 +200,8 @@ internal object Glv {
|
||||
/** Babai rounding constant g1 = round(2^384 · |b2| / n) */
|
||||
private val G1 =
|
||||
longArrayOf(
|
||||
0x45DBB031.toInt(),
|
||||
-1687969588364726223L, 4443515802769476223L, -1698823648040391915L, 3496713202691238861L,
|
||||
),
|
||||
0xE893209A.toInt(),
|
||||
0x71E8CA7F.toInt(),
|
||||
0x3DAA8A14.toInt(),
|
||||
@@ -209,7 +214,8 @@ internal object Glv {
|
||||
/** Babai rounding constant g2 = round(2^384 · |b1| / n) */
|
||||
private val G2 =
|
||||
longArrayOf(
|
||||
0x8AC47F71.toInt(),
|
||||
1545214808910233457L, 2455034284347819718L, 8022177200260244676L, -1998614352016537560L,
|
||||
),
|
||||
0x1571B4AE.toInt(),
|
||||
0x9DF506C6.toInt(),
|
||||
0x221208AC.toInt(),
|
||||
@@ -222,7 +228,8 @@ internal object Glv {
|
||||
/** -b1 mod n (lattice basis vector) */
|
||||
private val MINUS_B1 =
|
||||
longArrayOf(
|
||||
0x0ABFE4C3.toInt(),
|
||||
8022177200260244675L, -1998614352016537560L, 0L, 0L,
|
||||
),
|
||||
0x6F547FA9.toInt(),
|
||||
0x010E8828.toInt(),
|
||||
0xE4437ED6.toInt(),
|
||||
@@ -235,7 +242,8 @@ internal object Glv {
|
||||
/** -b2 mod n (lattice basis vector) */
|
||||
private val MINUS_B2 =
|
||||
longArrayOf(
|
||||
0x3DB1562C.toInt(),
|
||||
-2925706260434037204L, -8491525256057179027L, -2L, -1L,
|
||||
),
|
||||
0xD765CDA8.toInt(),
|
||||
0x0774346D.toInt(),
|
||||
0x8A280AC5.toInt(),
|
||||
@@ -248,7 +256,8 @@ internal object Glv {
|
||||
/** n / 2, used to determine if a half-scalar needs negation */
|
||||
private val N_HALF =
|
||||
longArrayOf(
|
||||
0x681B20A0.toInt(),
|
||||
-2312264954237214560L, 6725966010171805725L, -1L, 9223372036854775807L,
|
||||
),
|
||||
0xDFE92F46.toInt(),
|
||||
0x57A4501D.toInt(),
|
||||
0x5D576E73.toInt(),
|
||||
|
||||
@@ -39,16 +39,16 @@ package com.vitorpamplona.quartz.utils.secp256k1
|
||||
*/
|
||||
internal object KeyCodec {
|
||||
/** Curve constant b = 7 in y² = x³ + 7. */
|
||||
private val B = longArrayOf(7, 0, 0, 0, 0, 0, 0, 0)
|
||||
private val B = longArrayOf(7L, 0L, 0L, 0L)
|
||||
|
||||
/**
|
||||
* Lift an x-coordinate to a curve point with even y (BIP-340 convention).
|
||||
* Computes y = √(x³ + 7) mod p. Returns false if x is not a valid coordinate.
|
||||
*/
|
||||
fun liftX(
|
||||
outX: IntArray,
|
||||
outY: IntArray,
|
||||
x: IntArray,
|
||||
outX: LongArray,
|
||||
outY: LongArray,
|
||||
x: LongArray,
|
||||
): Boolean {
|
||||
if (U256.cmp(x, FieldP.P) >= 0) return false
|
||||
val t = LongArray(4)
|
||||
@@ -62,7 +62,7 @@ internal object KeyCodec {
|
||||
}
|
||||
|
||||
/** Check if y-coordinate is even (LSB = 0). */
|
||||
fun hasEvenY(y: IntArray): Boolean = y[0] and 1 == 0
|
||||
fun hasEvenY(y: LongArray): Boolean = y[0] and 1 == 0
|
||||
|
||||
/**
|
||||
* Parse a serialized public key (33 bytes compressed or 65 bytes uncompressed).
|
||||
@@ -71,8 +71,8 @@ internal object KeyCodec {
|
||||
*/
|
||||
fun parsePublicKey(
|
||||
pubkey: ByteArray,
|
||||
outX: IntArray,
|
||||
outY: IntArray,
|
||||
outX: LongArray,
|
||||
outY: LongArray,
|
||||
): Boolean =
|
||||
when {
|
||||
pubkey.size == 33 && (pubkey[0] == 0x02.toByte() || pubkey[0] == 0x03.toByte()) -> {
|
||||
@@ -112,8 +112,8 @@ internal object KeyCodec {
|
||||
|
||||
/** Serialize as 65-byte uncompressed: 04 || x (32 bytes) || y (32 bytes). */
|
||||
fun serializeUncompressed(
|
||||
x: IntArray,
|
||||
y: IntArray,
|
||||
x: LongArray,
|
||||
y: LongArray,
|
||||
): ByteArray {
|
||||
val r = ByteArray(65)
|
||||
r[0] = 0x04
|
||||
@@ -124,8 +124,8 @@ internal object KeyCodec {
|
||||
|
||||
/** Serialize as 33-byte compressed: 02/03 || x (32 bytes). */
|
||||
fun serializeCompressed(
|
||||
x: IntArray,
|
||||
y: IntArray,
|
||||
x: LongArray,
|
||||
y: LongArray,
|
||||
): ByteArray {
|
||||
val r = ByteArray(33)
|
||||
r[0] = if (hasEvenY(y)) 0x02 else 0x03
|
||||
|
||||
@@ -71,19 +71,19 @@ package com.vitorpamplona.quartz.utils.secp256k1
|
||||
* multiplication, which performs thousands of doublings and additions per operation.
|
||||
*/
|
||||
internal class MutablePoint(
|
||||
val x: IntArray = LongArray(4),
|
||||
val y: IntArray = LongArray(4),
|
||||
val z: IntArray = LongArray(4),
|
||||
val x: LongArray = LongArray(4),
|
||||
val y: LongArray = LongArray(4),
|
||||
val z: LongArray = LongArray(4),
|
||||
) {
|
||||
fun isInfinity(): Boolean = U256.isZero(z)
|
||||
|
||||
fun setInfinity() {
|
||||
for (i in 0 until 8) {
|
||||
x[i] = 0
|
||||
z[i] = 0
|
||||
for (i in 0 until 4) {
|
||||
x[i] = 0L
|
||||
z[i] = 0L
|
||||
}
|
||||
y[0] = 1
|
||||
for (i in 1 until 8) y[i] = 0
|
||||
y[0] = 1L
|
||||
for (i in 1 until 4) y[i] = 0L
|
||||
}
|
||||
|
||||
fun copyFrom(other: MutablePoint) {
|
||||
@@ -93,13 +93,13 @@ internal class MutablePoint(
|
||||
}
|
||||
|
||||
fun setAffine(
|
||||
ax: IntArray,
|
||||
ay: IntArray,
|
||||
ax: LongArray,
|
||||
ay: LongArray,
|
||||
) {
|
||||
ax.copyInto(x)
|
||||
ay.copyInto(y)
|
||||
z[0] = 1
|
||||
for (i in 1 until 8) z[i] = 0
|
||||
z[0] = 1L
|
||||
for (i in 1 until 4) z[i] = 0L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ internal class MutablePoint(
|
||||
* Used for precomputed tables where we want compact storage and mixed addition.
|
||||
*/
|
||||
internal class AffinePoint(
|
||||
val x: IntArray = LongArray(4),
|
||||
val y: IntArray = LongArray(4),
|
||||
val x: LongArray = LongArray(4),
|
||||
val y: LongArray = LongArray(4),
|
||||
)
|
||||
|
||||
internal object ECPoint {
|
||||
@@ -117,7 +117,8 @@ internal object ECPoint {
|
||||
|
||||
val GX =
|
||||
longArrayOf(
|
||||
0x16F81798.toInt(),
|
||||
6481385041966929816L, 188021827762530521L, 6170039885052185351L, 8772561819708210092L,
|
||||
),
|
||||
0x59F2815B.toInt(),
|
||||
0x2DCE28D9.toInt(),
|
||||
0x029BFCDB.toInt(),
|
||||
@@ -128,7 +129,8 @@ internal object ECPoint {
|
||||
)
|
||||
val GY =
|
||||
longArrayOf(
|
||||
0xFB10D4B8.toInt(),
|
||||
-7185545363635252040L, -209500633525038055L, 6747795201694173352L, 5204712524664259685L,
|
||||
),
|
||||
0x9C47D08F.toInt(),
|
||||
0xA6855419.toInt(),
|
||||
0xFD17B448.toInt(),
|
||||
@@ -139,7 +141,7 @@ internal object ECPoint {
|
||||
)
|
||||
|
||||
/** Curve constant b = 7 in y² = x³ + 7. */
|
||||
private val B = longArrayOf(7, 0, 0, 0, 0, 0, 0, 0)
|
||||
private val B = longArrayOf(7L, 0L, 0L, 0L)
|
||||
|
||||
/**
|
||||
* wNAF window width for the G-side of scalar multiplication.
|
||||
@@ -329,8 +331,8 @@ internal object ECPoint {
|
||||
fun addMixed(
|
||||
out: MutablePoint,
|
||||
p: MutablePoint,
|
||||
qx: IntArray,
|
||||
qy: IntArray,
|
||||
qx: LongArray,
|
||||
qy: LongArray,
|
||||
) {
|
||||
if (p.isInfinity()) {
|
||||
out.setAffine(qx, qy)
|
||||
@@ -450,7 +452,7 @@ internal object ECPoint {
|
||||
fun mul(
|
||||
out: MutablePoint,
|
||||
p: MutablePoint,
|
||||
scalar: IntArray,
|
||||
scalar: LongArray,
|
||||
) {
|
||||
if (U256.isZero(scalar) || p.isInfinity()) {
|
||||
out.setInfinity()
|
||||
@@ -513,7 +515,7 @@ internal object ECPoint {
|
||||
*/
|
||||
fun mulG(
|
||||
out: MutablePoint,
|
||||
scalar: IntArray,
|
||||
scalar: LongArray,
|
||||
) {
|
||||
if (U256.isZero(scalar)) {
|
||||
out.setInfinity()
|
||||
@@ -559,9 +561,9 @@ internal object ECPoint {
|
||||
*/
|
||||
fun mulDoubleG(
|
||||
out: MutablePoint,
|
||||
s: IntArray,
|
||||
s: LongArray,
|
||||
p: MutablePoint,
|
||||
e: IntArray,
|
||||
e: LongArray,
|
||||
) {
|
||||
val wP = 5 // Window for P-side (table built per-call, keep small)
|
||||
val pTableSize = 1 shl (wP - 2) // 8 entries for P
|
||||
@@ -629,8 +631,8 @@ internal object ECPoint {
|
||||
private fun addWnafMixed(
|
||||
out: MutablePoint,
|
||||
tmp: MutablePoint,
|
||||
negY: IntArray,
|
||||
wnafDigits: IntArray,
|
||||
negY: LongArray,
|
||||
wnafDigits: LongArray,
|
||||
bitIndex: Int,
|
||||
table: Array<AffinePoint>,
|
||||
glvNeg: Boolean,
|
||||
@@ -654,7 +656,7 @@ internal object ECPoint {
|
||||
out: MutablePoint,
|
||||
tmp: MutablePoint,
|
||||
negScratch: MutablePoint,
|
||||
wnafDigits: IntArray,
|
||||
wnafDigits: LongArray,
|
||||
bitIndex: Int,
|
||||
table: Array<MutablePoint>,
|
||||
glvNeg: Boolean,
|
||||
@@ -685,8 +687,8 @@ internal object ECPoint {
|
||||
*/
|
||||
fun toAffine(
|
||||
p: MutablePoint,
|
||||
outX: IntArray,
|
||||
outY: IntArray,
|
||||
outX: LongArray,
|
||||
outY: LongArray,
|
||||
): Boolean {
|
||||
if (p.isInfinity()) return false
|
||||
val zInv = LongArray(4)
|
||||
@@ -703,26 +705,26 @@ internal object ECPoint {
|
||||
// ==================== Key Encoding (delegates to KeyCodec) ====================
|
||||
|
||||
fun liftX(
|
||||
outX: IntArray,
|
||||
outY: IntArray,
|
||||
x: IntArray,
|
||||
outX: LongArray,
|
||||
outY: LongArray,
|
||||
x: LongArray,
|
||||
) = KeyCodec.liftX(outX, outY, x)
|
||||
|
||||
fun hasEvenY(y: IntArray) = KeyCodec.hasEvenY(y)
|
||||
fun hasEvenY(y: LongArray) = KeyCodec.hasEvenY(y)
|
||||
|
||||
fun parsePublicKey(
|
||||
pubkey: ByteArray,
|
||||
outX: IntArray,
|
||||
outY: IntArray,
|
||||
outX: LongArray,
|
||||
outY: LongArray,
|
||||
) = KeyCodec.parsePublicKey(pubkey, outX, outY)
|
||||
|
||||
fun serializeUncompressed(
|
||||
x: IntArray,
|
||||
y: IntArray,
|
||||
x: LongArray,
|
||||
y: LongArray,
|
||||
) = KeyCodec.serializeUncompressed(x, y)
|
||||
|
||||
fun serializeCompressed(
|
||||
x: IntArray,
|
||||
y: IntArray,
|
||||
x: LongArray,
|
||||
y: LongArray,
|
||||
) = KeyCodec.serializeCompressed(x, y)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ package com.vitorpamplona.quartz.utils.secp256k1
|
||||
internal object ScalarN {
|
||||
val N =
|
||||
longArrayOf(
|
||||
0xD0364141.toInt(),
|
||||
-4624529908474429119L, -4994812053365940165L, -2L, -1L,
|
||||
),
|
||||
0xBFD25E8C.toInt(),
|
||||
0xAF48A03B.toInt(),
|
||||
0xBAAEDCE6.toInt(),
|
||||
@@ -48,7 +49,8 @@ internal object ScalarN {
|
||||
/** 2^256 - n: the small constant used for reduction (≈129 bits) */
|
||||
private val N_COMPLEMENT =
|
||||
longArrayOf(
|
||||
0x2FC9BEBF.toInt(),
|
||||
4624529908474429119L, 4994812053365940164L, 1L, 0L,
|
||||
),
|
||||
0x402DA173.toInt(),
|
||||
0x50B75FC4.toInt(),
|
||||
0x45512319.toInt(),
|
||||
@@ -61,7 +63,8 @@ internal object ScalarN {
|
||||
/** n - 2: exponent for Fermat inversion */
|
||||
private val N_MINUS_2 =
|
||||
longArrayOf(
|
||||
0xD036413F.toInt(),
|
||||
-4624529908474429121L, -4994812053365940165L, -2L, -1L,
|
||||
),
|
||||
0xBFD25E8C.toInt(),
|
||||
0xAF48A03B.toInt(),
|
||||
0xBAAEDCE6.toInt(),
|
||||
@@ -72,10 +75,10 @@ internal object ScalarN {
|
||||
)
|
||||
|
||||
/** Check if 0 < a < n (valid non-zero scalar). */
|
||||
fun isValid(a: IntArray): Boolean = !U256.isZero(a) && U256.cmp(a, N) < 0
|
||||
fun isValid(a: LongArray): Boolean = !U256.isZero(a) && U256.cmp(a, N) < 0
|
||||
|
||||
/** If a >= n, return a - n. Otherwise return a unchanged. */
|
||||
fun reduce(a: IntArray): IntArray =
|
||||
fun reduce(a: LongArray): LongArray =
|
||||
if (U256.cmp(a, N) >= 0) {
|
||||
val r = LongArray(4)
|
||||
U256.subTo(r, a, N)
|
||||
@@ -85,9 +88,9 @@ internal object ScalarN {
|
||||
}
|
||||
|
||||
fun add(
|
||||
a: IntArray,
|
||||
b: IntArray,
|
||||
): IntArray {
|
||||
a: LongArray,
|
||||
b: LongArray,
|
||||
): LongArray {
|
||||
val r = LongArray(4)
|
||||
val carry = U256.addTo(r, a, b)
|
||||
if (carry != 0) U256.addTo(r, r, N_COMPLEMENT)
|
||||
@@ -96,9 +99,9 @@ internal object ScalarN {
|
||||
}
|
||||
|
||||
fun sub(
|
||||
a: IntArray,
|
||||
b: IntArray,
|
||||
): IntArray {
|
||||
a: LongArray,
|
||||
b: LongArray,
|
||||
): LongArray {
|
||||
val r = LongArray(4)
|
||||
val borrow = U256.subTo(r, a, b)
|
||||
if (borrow != 0) U256.addTo(r, r, N)
|
||||
@@ -106,15 +109,15 @@ internal object ScalarN {
|
||||
}
|
||||
|
||||
fun mul(
|
||||
a: IntArray,
|
||||
b: IntArray,
|
||||
): IntArray {
|
||||
a: LongArray,
|
||||
b: LongArray,
|
||||
): LongArray {
|
||||
val w = LongArray(8)
|
||||
U256.mulWide(w, a, b)
|
||||
return reduceWide(w)
|
||||
}
|
||||
|
||||
fun neg(a: IntArray): IntArray {
|
||||
fun neg(a: LongArray): LongArray {
|
||||
if (U256.isZero(a)) return LongArray(4)
|
||||
val r = LongArray(4)
|
||||
U256.subTo(r, N, a)
|
||||
@@ -122,12 +125,12 @@ internal object ScalarN {
|
||||
}
|
||||
|
||||
/** a^(-1) mod n via Fermat's little theorem. */
|
||||
fun inv(a: IntArray): IntArray {
|
||||
fun inv(a: LongArray): LongArray {
|
||||
require(!U256.isZero(a))
|
||||
return powModN(a, N_MINUS_2)
|
||||
}
|
||||
|
||||
private fun reduceSelf(a: IntArray) {
|
||||
private fun reduceSelf(a: LongArray) {
|
||||
if (U256.cmp(a, N) >= 0) U256.subTo(a, a, N)
|
||||
}
|
||||
|
||||
@@ -138,10 +141,10 @@ internal object ScalarN {
|
||||
* Since N_COMPLEMENT is ~129 bits, hi × N_COMPLEMENT is ~385 bits. We repeat the
|
||||
* reduction until the result fits in 256 bits, then do a final conditional subtraction.
|
||||
*/
|
||||
private fun reduceWide(w: IntArray): IntArray {
|
||||
private fun reduceWide(w: LongArray): LongArray {
|
||||
val lo = LongArray(4)
|
||||
val hi = LongArray(4)
|
||||
for (i in 0 until 8) {
|
||||
for (i in 0 until 4) {
|
||||
lo[i] = w[i]
|
||||
hi[i] = w[i + 8]
|
||||
}
|
||||
@@ -155,9 +158,9 @@ internal object ScalarN {
|
||||
U256.mulWide(hiTimesNC, hi, N_COMPLEMENT)
|
||||
val sum = LongArray(8)
|
||||
var carry = 0L
|
||||
for (i in 0 until 16) {
|
||||
carry += (hiTimesNC[i].toLong() and 0xFFFFFFFFL) +
|
||||
if (i < 8) (lo[i].toLong() and 0xFFFFFFFFL) else 0L
|
||||
for (i in 0 until 8) {
|
||||
carry += (hiTimesNC[i]) +
|
||||
if (i < 4) (lo[i]) else 0L
|
||||
sum[i] = carry.toInt()
|
||||
carry = carry ushr 32
|
||||
}
|
||||
@@ -165,7 +168,7 @@ internal object ScalarN {
|
||||
// Round 2 if still > 256 bits
|
||||
val lo2 = LongArray(4)
|
||||
val hi2 = LongArray(4)
|
||||
for (i in 0 until 8) {
|
||||
for (i in 0 until 4) {
|
||||
lo2[i] = sum[i]
|
||||
hi2[i] = sum[i + 8]
|
||||
}
|
||||
@@ -178,24 +181,24 @@ internal object ScalarN {
|
||||
U256.mulWide(hi2NC, hi2, N_COMPLEMENT)
|
||||
var c2 = 0L
|
||||
val result = LongArray(4)
|
||||
for (i in 0 until 8) {
|
||||
c2 += (lo2[i].toLong() and 0xFFFFFFFFL) + (hi2NC[i].toLong() and 0xFFFFFFFFL)
|
||||
for (i in 0 until 4) {
|
||||
c2 += (lo2[i]) + (hi2NC[i])
|
||||
result[i] = c2.toInt()
|
||||
c2 = c2 ushr 32
|
||||
}
|
||||
var overflow = c2
|
||||
for (i in 8 until 16) overflow += (hi2NC[i].toLong() and 0xFFFFFFFFL)
|
||||
for (i in 4 until 8) overflow += (hi2NC[i])
|
||||
if (overflow > 0) {
|
||||
val corr = IntArray(9)
|
||||
val corr = LongArray(5)
|
||||
var cc = 0L
|
||||
for (i in 0 until 8) {
|
||||
cc += (N_COMPLEMENT[i].toLong() and 0xFFFFFFFFL) * overflow
|
||||
for (i in 0 until 4) {
|
||||
cc += (N_COMPLEMENT[i]) * overflow
|
||||
corr[i] = cc.toInt()
|
||||
cc = cc ushr 32
|
||||
}
|
||||
var c3 = 0L
|
||||
for (i in 0 until 8) {
|
||||
c3 += (result[i].toLong() and 0xFFFFFFFFL) + (corr[i].toLong() and 0xFFFFFFFFL)
|
||||
for (i in 0 until 4) {
|
||||
c3 += (result[i]) + (corr[i])
|
||||
result[i] = c3.toInt()
|
||||
c3 = c3 ushr 32
|
||||
}
|
||||
@@ -205,9 +208,9 @@ internal object ScalarN {
|
||||
}
|
||||
|
||||
private fun powModN(
|
||||
base: IntArray,
|
||||
exp: IntArray,
|
||||
): IntArray {
|
||||
base: LongArray,
|
||||
exp: LongArray,
|
||||
): LongArray {
|
||||
val result = LongArray(4)
|
||||
val b = base.copyOf()
|
||||
var highBit = 255
|
||||
|
||||
@@ -227,7 +227,7 @@ object Secp256k1 {
|
||||
*/
|
||||
private fun signSchnorrInternal(
|
||||
data: ByteArray,
|
||||
d0: IntArray,
|
||||
d0: LongArray,
|
||||
pBytes: ByteArray,
|
||||
pubKeyHasEvenY: Boolean,
|
||||
auxrand: ByteArray?,
|
||||
|
||||
@@ -32,7 +32,7 @@ class FieldPTest {
|
||||
s.chunked(2).map { it.toInt(16).toByte() }.toByteArray(),
|
||||
)
|
||||
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
// ==================== Basic identities ====================
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import kotlin.test.assertTrue
|
||||
|
||||
/** Comprehensive tests for GLV endomorphism and wNAF encoding. */
|
||||
class GlvTest {
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
private fun hex(s: String) =
|
||||
U256.fromBytes(
|
||||
@@ -210,7 +210,7 @@ class GlvTest {
|
||||
// ==================== Helpers ====================
|
||||
|
||||
/** Reconstruct a scalar from wNAF digits using Horner's method. */
|
||||
private fun reconstructWnaf(digits: IntArray): IntArray {
|
||||
private fun reconstructWnaf(digits: LongArray): LongArray {
|
||||
var acc = LongArray(4)
|
||||
for (bit in digits.size - 1 downTo 0) {
|
||||
val doubled = LongArray(4)
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import kotlin.test.assertTrue
|
||||
|
||||
/** Tests for KeyCodec: key parsing, serialization, liftX, hasEvenY. */
|
||||
class KeyCodecTest {
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
// ==================== liftX ====================
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class PointTest {
|
||||
s.chunked(2).map { it.toInt(16).toByte() }.toByteArray(),
|
||||
)
|
||||
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
// ==================== Generator point ====================
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class ScalarNTest {
|
||||
s.chunked(2).map { it.toInt(16).toByte() }.toByteArray(),
|
||||
)
|
||||
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
// ==================== isValid ====================
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class U256Test {
|
||||
s.chunked(2).map { it.toInt(16).toByte() }.toByteArray(),
|
||||
)
|
||||
|
||||
private fun toHex(a: IntArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
private fun toHex(a: LongArray) = U256.toBytes(a).joinToString("") { "%02x".format(it) }
|
||||
|
||||
// ==================== isZero / cmp ====================
|
||||
|
||||
|
||||
Reference in New Issue
Block a user