perf: eliminate ULong.constructor-impl NOOP calls in unsigned comparisons
Bytecode analysis revealed that every `a.toULong() < b.toULong()`
comparison generates 2 invokestatic calls to ULong.constructor-impl
(NOOPs that return the input unchanged) plus Long.compareUnsigned.
Across all secp256k1 hot paths, this produced 554 NOOP invokestatic
calls in the bytecode, translating to ~18,000 wasted calls per verify.
Replace all toULong() comparisons with an inline uLt() helper that
uses the XOR-with-MIN_VALUE trick directly:
(a xor Long.MIN_VALUE) < (b xor Long.MIN_VALUE)
This produces pure arithmetic bytecode (lxor, lcmp, ifge) with ZERO
method calls, eliminating all ULong.constructor-impl overhead.
Before: lload, invokestatic ULong.constructor-impl, lload,
invokestatic ULong.constructor-impl, invokestatic
Long.compareUnsigned, ifge (6 bytecodes, 3 method calls)
After: lload, ldc MIN_VALUE, lxor, lload, ldc MIN_VALUE, lxor,
lcmp, ifge (8 bytecodes, 0 method calls)
https://claude.ai/code/session_01EMY5RnXb9rnsyU2KbXrSaY
This commit is contained in:
+53
-53
@@ -110,19 +110,19 @@ internal inline fun fieldMulReduceWith(
|
||||
|
||||
lo = a0 * b1
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
w[1] = s
|
||||
carry = umulh(a0, b1) + c1
|
||||
|
||||
lo = a0 * b2
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
w[2] = s
|
||||
carry = umulh(a0, b2) + c1
|
||||
|
||||
lo = a0 * b3
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
w[3] = s
|
||||
w[4] = umulh(a0, b3) + c1
|
||||
|
||||
@@ -131,7 +131,7 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a1, b0)
|
||||
prev = w[1]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
w[1] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -139,9 +139,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a1, b1)
|
||||
prev = w[2]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[2] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -149,9 +149,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a1, b2)
|
||||
prev = w[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[3] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -159,9 +159,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a1, b3)
|
||||
prev = w[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[4] = s
|
||||
w[5] = hi + c1 + c2
|
||||
|
||||
@@ -170,7 +170,7 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a2, b0)
|
||||
prev = w[2]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
w[2] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -178,9 +178,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a2, b1)
|
||||
prev = w[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[3] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -188,9 +188,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a2, b2)
|
||||
prev = w[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[4] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -198,9 +198,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a2, b3)
|
||||
prev = w[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[5] = s
|
||||
w[6] = hi + c1 + c2
|
||||
|
||||
@@ -209,7 +209,7 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a3, b0)
|
||||
prev = w[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
w[3] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -217,9 +217,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a3, b1)
|
||||
prev = w[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[4] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -227,9 +227,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a3, b2)
|
||||
prev = w[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[5] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -237,9 +237,9 @@ internal inline fun fieldMulReduceWith(
|
||||
hi = umulh(a3, b3)
|
||||
prev = w[6]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[6] = s
|
||||
w[7] = hi + c1 + c2
|
||||
|
||||
@@ -280,13 +280,13 @@ internal inline fun fieldSqrReduceWith(
|
||||
|
||||
lo = a0 * a2
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
w[2] = s
|
||||
carry = umulh(a0, a2) + c1
|
||||
|
||||
lo = a0 * a3
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
w[3] = s
|
||||
w[4] = umulh(a0, a3) + c1
|
||||
|
||||
@@ -294,7 +294,7 @@ internal inline fun fieldSqrReduceWith(
|
||||
hi = umulh(a1, a2)
|
||||
prev = w[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
w[3] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -302,9 +302,9 @@ internal inline fun fieldSqrReduceWith(
|
||||
hi = umulh(a1, a3)
|
||||
prev = w[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
w[4] = s
|
||||
w[5] = hi + c1 + c2
|
||||
|
||||
@@ -312,7 +312,7 @@ internal inline fun fieldSqrReduceWith(
|
||||
hi = umulh(a2, a3)
|
||||
prev = w[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
w[5] = s
|
||||
w[6] = hi + c1
|
||||
|
||||
@@ -342,44 +342,44 @@ internal inline fun fieldSqrReduceWith(
|
||||
hi = umulh(a0, a0)
|
||||
w[0] = lo
|
||||
s = w[1] + hi
|
||||
c1 = if (s.toULong() < w[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, w[1])) 1L else 0L
|
||||
w[1] = s
|
||||
var dCarry = c1
|
||||
|
||||
lo = a1 * a1
|
||||
hi = umulh(a1, a1)
|
||||
s = w[2] + lo
|
||||
c1 = if (s.toULong() < w[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, w[2])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
w[2] = s
|
||||
prev = w[3] + hi
|
||||
val c3a = if (prev.toULong() < w[3].toULong()) 1L else 0L
|
||||
val c3a = if (uLt(prev, w[3])) 1L else 0L
|
||||
prev += c1 + c2
|
||||
val c4a = if (prev.toULong() < (c1 + c2).toULong()) 1L else 0L
|
||||
val c4a = if (uLt(prev, c1 + c2)) 1L else 0L
|
||||
w[3] = prev
|
||||
dCarry = c3a + c4a
|
||||
|
||||
lo = a2 * a2
|
||||
hi = umulh(a2, a2)
|
||||
s = w[4] + lo
|
||||
c1 = if (s.toULong() < w[4].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, w[4])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
w[4] = s
|
||||
prev = w[5] + hi
|
||||
val c3b = if (prev.toULong() < w[5].toULong()) 1L else 0L
|
||||
val c3b = if (uLt(prev, w[5])) 1L else 0L
|
||||
prev += c1 + c2
|
||||
val c4b = if (prev.toULong() < (c1 + c2).toULong()) 1L else 0L
|
||||
val c4b = if (uLt(prev, c1 + c2)) 1L else 0L
|
||||
w[5] = prev
|
||||
dCarry = c3b + c4b
|
||||
|
||||
lo = a3 * a3
|
||||
hi = umulh(a3, a3)
|
||||
s = w[6] + lo
|
||||
c1 = if (s.toULong() < w[6].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, w[6])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
w[6] = s
|
||||
prev = w[7] + hi
|
||||
prev += c1 + c2
|
||||
@@ -412,34 +412,34 @@ internal inline fun reduceWideInline(
|
||||
hcLo = w[4] * c
|
||||
hcHi = umulh(w[4], c)
|
||||
s1 = w[0] + hcLo
|
||||
c1 = if (s1.toULong() < w[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
var carry = hcHi + c1
|
||||
|
||||
hcLo = w[5] * c
|
||||
hcHi = umulh(w[5], c)
|
||||
s1 = w[1] + hcLo
|
||||
c1 = if (s1.toULong() < w[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[1])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[1] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
hcLo = w[6] * c
|
||||
hcHi = umulh(w[6], c)
|
||||
s1 = w[2] + hcLo
|
||||
c1 = if (s1.toULong() < w[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[2])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[2] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
hcLo = w[7] * c
|
||||
hcHi = umulh(w[7], c)
|
||||
s1 = w[3] + hcLo
|
||||
c1 = if (s1.toULong() < w[3].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[3])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[3] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
@@ -448,27 +448,27 @@ internal inline fun reduceWideInline(
|
||||
val ccLo = carry * c
|
||||
val ccHi = umulh(carry, c)
|
||||
s1 = out[0] + ccLo
|
||||
c1 = if (s1.toULong() < out[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, out[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
var prop = ccHi + c1
|
||||
if (prop != 0L) {
|
||||
s1 = out[1] + prop
|
||||
prop = if (s1.toULong() < out[1].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[1])) 1L else 0L
|
||||
out[1] = s1
|
||||
if (prop != 0L) {
|
||||
s1 = out[2] + prop
|
||||
prop = if (s1.toULong() < out[2].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[2])) 1L else 0L
|
||||
out[2] = s1
|
||||
if (prop != 0L) {
|
||||
s1 = out[3] + prop
|
||||
prop = if (s1.toULong() < out[3].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[3])) 1L else 0L
|
||||
out[3] = s1
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prop != 0L) {
|
||||
s1 = out[0] + c
|
||||
c1 = if (s1.toULong() < out[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, out[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
if (c1 != 0L) {
|
||||
out[1]++
|
||||
|
||||
@@ -68,7 +68,7 @@ internal object FieldP {
|
||||
if (carry != 0) {
|
||||
// Overflow past 2^256: add 2^256 mod p = 2^32 + 977 = 0x1000003D1
|
||||
val s1 = out[0] + 4294968273L
|
||||
val c1 = if (s1.toULong() < out[0].toULong()) 1L else 0L
|
||||
val c1 = if (uLt(s1, out[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
if (c1 != 0L) {
|
||||
out[1]++
|
||||
@@ -95,7 +95,7 @@ internal object FieldP {
|
||||
if (borrow != 0) {
|
||||
// Add P = [P0, -1, -1, -1].
|
||||
val s0 = out[0] + P0
|
||||
val c0 = if (s0.toULong() < out[0].toULong()) 1L else 0L
|
||||
val c0 = if (uLt(s0, out[0])) 1L else 0L
|
||||
out[0] = s0
|
||||
// For limbs 1-3: adding P[i]=-1 with carry c:
|
||||
// c=1 → result unchanged, carry out=1 (identity propagation)
|
||||
@@ -173,7 +173,7 @@ internal object FieldP {
|
||||
}
|
||||
// P - a: limb 0 is P0 - a[0], limbs 1-3 are (-1) - a[i] = ~a[i]
|
||||
out[0] = P0 - a[0]
|
||||
val borrow = if (a[0].toULong() > P0.toULong()) 1L else 0L
|
||||
val borrow = if (uLt(P0, a[0])) 1L else 0L
|
||||
// ~a[i] - borrow. New borrow only if ~a[i] == 0 (i.e., a[i] == -1) and borrow == 1
|
||||
out[1] = a[1].inv() - borrow
|
||||
val b1 = if (a[1] == -1L && borrow != 0L) 1L else 0L
|
||||
@@ -200,28 +200,28 @@ internal object FieldP {
|
||||
// Conditional add: out = a + (P & mask), unrolled
|
||||
// Limb 0
|
||||
s1 = a[0] + p0
|
||||
c1 = if (s1.toULong() < a[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
var carry = c1
|
||||
// Limb 1
|
||||
s1 = a[1] + mask
|
||||
c1 = if (s1.toULong() < a[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[1])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[1] = s2
|
||||
carry = c1 + c2
|
||||
// Limb 2
|
||||
s1 = a[2] + mask
|
||||
c1 = if (s1.toULong() < a[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[2])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[2] = s2
|
||||
carry = c1 + c2
|
||||
// Limb 3
|
||||
s1 = a[3] + mask
|
||||
c1 = if (s1.toULong() < a[3].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[3])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[3] = s2
|
||||
carry = c1 + c2
|
||||
|
||||
@@ -405,7 +405,7 @@ internal object FieldP {
|
||||
hcLo = w[4] * c
|
||||
hcHi = unsignedMultiplyHigh(w[4], c)
|
||||
s1 = w[0] + hcLo
|
||||
c1 = if (s1.toULong() < w[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
var carry = hcHi + c1
|
||||
|
||||
@@ -413,9 +413,9 @@ internal object FieldP {
|
||||
hcLo = w[5] * c
|
||||
hcHi = unsignedMultiplyHigh(w[5], c)
|
||||
s1 = w[1] + hcLo
|
||||
c1 = if (s1.toULong() < w[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[1])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[1] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
@@ -423,9 +423,9 @@ internal object FieldP {
|
||||
hcLo = w[6] * c
|
||||
hcHi = unsignedMultiplyHigh(w[6], c)
|
||||
s1 = w[2] + hcLo
|
||||
c1 = if (s1.toULong() < w[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[2])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[2] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
@@ -433,9 +433,9 @@ internal object FieldP {
|
||||
hcLo = w[7] * c
|
||||
hcHi = unsignedMultiplyHigh(w[7], c)
|
||||
s1 = w[3] + hcLo
|
||||
c1 = if (s1.toULong() < w[3].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, w[3])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[3] = s2
|
||||
carry = hcHi + c1 + c2
|
||||
|
||||
@@ -444,21 +444,21 @@ internal object FieldP {
|
||||
val ccLo = carry * c
|
||||
val ccHi = unsignedMultiplyHigh(carry, c)
|
||||
s1 = out[0] + ccLo
|
||||
c1 = if (s1.toULong() < out[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, out[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
// Propagate carry (unrolled, with early exit)
|
||||
var prop = ccHi + c1
|
||||
if (prop != 0L) {
|
||||
s1 = out[1] + prop
|
||||
prop = if (s1.toULong() < out[1].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[1])) 1L else 0L
|
||||
out[1] = s1
|
||||
if (prop != 0L) {
|
||||
s1 = out[2] + prop
|
||||
prop = if (s1.toULong() < out[2].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[2])) 1L else 0L
|
||||
out[2] = s1
|
||||
if (prop != 0L) {
|
||||
s1 = out[3] + prop
|
||||
prop = if (s1.toULong() < out[3].toULong()) 1L else 0L
|
||||
prop = if (uLt(s1, out[3])) 1L else 0L
|
||||
out[3] = s1
|
||||
}
|
||||
}
|
||||
@@ -466,7 +466,7 @@ internal object FieldP {
|
||||
// Overflow past 256 bits: 2^256 ≡ C (mod p)
|
||||
if (prop != 0L) {
|
||||
s1 = out[0] + c
|
||||
c1 = if (s1.toULong() < out[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, out[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
if (c1 != 0L) {
|
||||
out[1]++
|
||||
|
||||
@@ -224,7 +224,7 @@ internal object Glv {
|
||||
for (i in limb until s.size) {
|
||||
val old = s[i]
|
||||
s[i] = old + if (i == limb) addVal else 1L
|
||||
if (s[i].toULong() >= old.toULong() || (i == limb && addVal == 0L)) break
|
||||
if (!uLt(s[i], old) || (i == limb && addVal == 0L)) break
|
||||
// overflowed — carry to next limb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,9 +198,9 @@ internal object ScalarN {
|
||||
0L
|
||||
}
|
||||
val s1 = hiTimesNC[i] + loVal
|
||||
val c1 = if (s1.toULong() < hiTimesNC[i].toULong()) 1L else 0L
|
||||
val c1 = if (uLt(s1, hiTimesNC[i])) 1L else 0L
|
||||
val s2 = s1 + carry
|
||||
val c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
val c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
w[i] = s2
|
||||
carry = c1 + c2
|
||||
}
|
||||
@@ -238,9 +238,9 @@ internal object ScalarN {
|
||||
saved3
|
||||
}
|
||||
val s1 = loVal + hi2NC[i]
|
||||
val c1 = if (s1.toULong() < loVal.toULong()) 1L else 0L
|
||||
val c1 = if (uLt(s1, loVal)) 1L else 0L
|
||||
val s2 = s1 + c2
|
||||
val cc = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
val cc = if (uLt(s2, s1)) 1L else 0L
|
||||
out[i] = s2
|
||||
c2 = c1 + cc
|
||||
}
|
||||
@@ -252,13 +252,13 @@ internal object ScalarN {
|
||||
val c1lo = ov * N_COMPLEMENT[1]
|
||||
val c1hi = unsignedMultiplyHigh(ov, N_COMPLEMENT[1])
|
||||
val s0 = out[0] + c0lo
|
||||
val carry0 = if (s0.toULong() < out[0].toULong()) 1L else 0L
|
||||
val carry0 = if (uLt(s0, out[0])) 1L else 0L
|
||||
out[0] = s0
|
||||
val s1 = out[1] + c0hi + c1lo + carry0
|
||||
val carry1 = if (s1.toULong() < out[1].toULong()) 1L else 0L
|
||||
val carry1 = if (uLt(s1, out[1])) 1L else 0L
|
||||
out[1] = s1
|
||||
val s2 = out[2] + c1hi + ov + carry1
|
||||
val carry2 = if (s2.toULong() < out[2].toULong()) 1L else 0L
|
||||
val carry2 = if (uLt(s2, out[2])) 1L else 0L
|
||||
out[2] = s2
|
||||
out[3] += carry2
|
||||
}
|
||||
|
||||
@@ -45,6 +45,28 @@ package com.vitorpamplona.quartz.utils.secp256k1
|
||||
// Package structure: U256 → FieldP/ScalarN → Glv/KeyCodec → Point → Secp256k1
|
||||
// =====================================================================================
|
||||
|
||||
/**
|
||||
* Unsigned less-than comparison without ULong inline class overhead.
|
||||
*
|
||||
* Kotlin's `uLt(a, b)` generates 2 invokestatic calls to
|
||||
* ULong.constructor-impl (NOOPs that return the input unchanged) plus
|
||||
* Long.compareUnsigned per comparison. On ART, these extra invokestatic
|
||||
* calls add ~2-3ns each × ~18,000 comparisons per verify = ~36-54μs.
|
||||
*
|
||||
* This inline function uses the XOR-with-MIN_VALUE trick directly,
|
||||
* producing pure arithmetic bytecode with ZERO method calls:
|
||||
* lload a, ldc MIN_VALUE, lxor, lload b, ldc MIN_VALUE, lxor, lcmp, ifge
|
||||
*
|
||||
* vs the toULong() path:
|
||||
* lload a, invokestatic ULong.constructor-impl, lload b,
|
||||
* invokestatic ULong.constructor-impl, invokestatic Long.compareUnsigned, ifge
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun uLt(
|
||||
a: Long,
|
||||
b: Long,
|
||||
): Boolean = (a xor Long.MIN_VALUE) < (b xor Long.MIN_VALUE)
|
||||
|
||||
/**
|
||||
* Raw 256-bit unsigned integer arithmetic using 4×64-bit limbs.
|
||||
*/
|
||||
@@ -58,7 +80,7 @@ internal object U256 {
|
||||
): Int {
|
||||
for (i in 3 downTo 0) {
|
||||
if (a[i] != b[i]) {
|
||||
return if (a[i].toULong() < b[i].toULong()) -1 else 1
|
||||
return if (uLt(a[i], b[i])) -1 else 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
@@ -77,31 +99,31 @@ internal object U256 {
|
||||
|
||||
// Limb 0 (no carry input)
|
||||
s1 = a[0] + b[0]
|
||||
c1 = if (s1.toULong() < a[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[0])) 1L else 0L
|
||||
out[0] = s1
|
||||
var carry = c1
|
||||
|
||||
// Limb 1
|
||||
s1 = a[1] + b[1]
|
||||
c1 = if (s1.toULong() < a[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[1])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[1] = s2
|
||||
carry = c1 + c2
|
||||
|
||||
// Limb 2
|
||||
s1 = a[2] + b[2]
|
||||
c1 = if (s1.toULong() < a[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[2])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[2] = s2
|
||||
carry = c1 + c2
|
||||
|
||||
// Limb 3
|
||||
s1 = a[3] + b[3]
|
||||
c1 = if (s1.toULong() < a[3].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s1, a[3])) 1L else 0L
|
||||
s2 = s1 + carry
|
||||
c2 = if (s2.toULong() < s1.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s2, s1)) 1L else 0L
|
||||
out[3] = s2
|
||||
carry = c1 + c2
|
||||
|
||||
@@ -121,31 +143,31 @@ internal object U256 {
|
||||
|
||||
// Limb 0 (no borrow input)
|
||||
d1 = a[0] - b[0]
|
||||
c1 = if (a[0].toULong() < b[0].toULong()) 1L else 0L
|
||||
c1 = if (uLt(a[0], b[0])) 1L else 0L
|
||||
out[0] = d1
|
||||
var borrow = c1
|
||||
|
||||
// Limb 1
|
||||
d1 = a[1] - b[1]
|
||||
c1 = if (a[1].toULong() < b[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(a[1], b[1])) 1L else 0L
|
||||
d2 = d1 - borrow
|
||||
c2 = if (d1.toULong() < borrow.toULong()) 1L else 0L
|
||||
c2 = if (uLt(d1, borrow)) 1L else 0L
|
||||
out[1] = d2
|
||||
borrow = c1 + c2
|
||||
|
||||
// Limb 2
|
||||
d1 = a[2] - b[2]
|
||||
c1 = if (a[2].toULong() < b[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(a[2], b[2])) 1L else 0L
|
||||
d2 = d1 - borrow
|
||||
c2 = if (d1.toULong() < borrow.toULong()) 1L else 0L
|
||||
c2 = if (uLt(d1, borrow)) 1L else 0L
|
||||
out[2] = d2
|
||||
borrow = c1 + c2
|
||||
|
||||
// Limb 3
|
||||
d1 = a[3] - b[3]
|
||||
c1 = if (a[3].toULong() < b[3].toULong()) 1L else 0L
|
||||
c1 = if (uLt(a[3], b[3])) 1L else 0L
|
||||
d2 = d1 - borrow
|
||||
c2 = if (d1.toULong() < borrow.toULong()) 1L else 0L
|
||||
c2 = if (uLt(d1, borrow)) 1L else 0L
|
||||
out[3] = d2
|
||||
borrow = c1 + c2
|
||||
|
||||
@@ -187,19 +209,19 @@ internal object U256 {
|
||||
|
||||
lo = a0 * b1
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
out[1] = s
|
||||
carry = unsignedMultiplyHigh(a0, b1) + c1
|
||||
|
||||
lo = a0 * b2
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
out[2] = s
|
||||
carry = unsignedMultiplyHigh(a0, b2) + c1
|
||||
|
||||
lo = a0 * b3
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
out[3] = s
|
||||
out[4] = unsignedMultiplyHigh(a0, b3) + c1
|
||||
|
||||
@@ -208,7 +230,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, b0)
|
||||
prev = out[1]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
out[1] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -216,9 +238,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, b1)
|
||||
prev = out[2]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[2] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -226,9 +248,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, b2)
|
||||
prev = out[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[3] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -236,9 +258,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, b3)
|
||||
prev = out[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[4] = s
|
||||
out[5] = hi + c1 + c2
|
||||
|
||||
@@ -247,7 +269,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a2, b0)
|
||||
prev = out[2]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
out[2] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -255,9 +277,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a2, b1)
|
||||
prev = out[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[3] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -265,9 +287,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a2, b2)
|
||||
prev = out[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[4] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -275,9 +297,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a2, b3)
|
||||
prev = out[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[5] = s
|
||||
out[6] = hi + c1 + c2
|
||||
|
||||
@@ -286,7 +308,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a3, b0)
|
||||
prev = out[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
out[3] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -294,9 +316,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a3, b1)
|
||||
prev = out[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[4] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -304,9 +326,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a3, b2)
|
||||
prev = out[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[5] = s
|
||||
carry = hi + c1 + c2
|
||||
|
||||
@@ -314,9 +336,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a3, b3)
|
||||
prev = out[6]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[6] = s
|
||||
out[7] = hi + c1 + c2
|
||||
}
|
||||
@@ -353,13 +375,13 @@ internal object U256 {
|
||||
|
||||
lo = a0 * a2
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
out[2] = s
|
||||
carry = unsignedMultiplyHigh(a0, a2) + c1
|
||||
|
||||
lo = a0 * a3
|
||||
s = lo + carry
|
||||
c1 = if (s.toULong() < lo.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, lo)) 1L else 0L
|
||||
out[3] = s
|
||||
out[4] = unsignedMultiplyHigh(a0, a3) + c1
|
||||
|
||||
@@ -368,7 +390,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, a2)
|
||||
prev = out[3]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
out[3] = s
|
||||
carry = hi + c1
|
||||
|
||||
@@ -376,9 +398,9 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a1, a3)
|
||||
prev = out[4]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
s += carry
|
||||
c2 = if (s.toULong() < carry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, carry)) 1L else 0L
|
||||
out[4] = s
|
||||
out[5] = hi + c1 + c2
|
||||
|
||||
@@ -387,7 +409,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a2, a3)
|
||||
prev = out[5]
|
||||
s = prev + lo
|
||||
c1 = if (s.toULong() < prev.toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, prev)) 1L else 0L
|
||||
out[5] = s
|
||||
out[6] = hi + c1
|
||||
|
||||
@@ -419,7 +441,7 @@ internal object U256 {
|
||||
hi = unsignedMultiplyHigh(a0, a0)
|
||||
out[0] = lo // out[0] was 0
|
||||
s = out[1] + hi
|
||||
c1 = if (s.toULong() < out[1].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, out[1])) 1L else 0L
|
||||
out[1] = s
|
||||
var dCarry = c1
|
||||
|
||||
@@ -427,14 +449,14 @@ internal object U256 {
|
||||
lo = a1 * a1
|
||||
hi = unsignedMultiplyHigh(a1, a1)
|
||||
s = out[2] + lo
|
||||
c1 = if (s.toULong() < out[2].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, out[2])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
out[2] = s
|
||||
prev = out[3] + hi
|
||||
val c3a = if (prev.toULong() < out[3].toULong()) 1L else 0L
|
||||
val c3a = if (uLt(prev, out[3])) 1L else 0L
|
||||
prev += c1 + c2
|
||||
val c4a = if (prev.toULong() < (c1 + c2).toULong()) 1L else 0L
|
||||
val c4a = if (uLt(prev, c1 + c2)) 1L else 0L
|
||||
out[3] = prev
|
||||
dCarry = c3a + c4a
|
||||
|
||||
@@ -442,14 +464,14 @@ internal object U256 {
|
||||
lo = a2 * a2
|
||||
hi = unsignedMultiplyHigh(a2, a2)
|
||||
s = out[4] + lo
|
||||
c1 = if (s.toULong() < out[4].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, out[4])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
out[4] = s
|
||||
prev = out[5] + hi
|
||||
val c3b = if (prev.toULong() < out[5].toULong()) 1L else 0L
|
||||
val c3b = if (uLt(prev, out[5])) 1L else 0L
|
||||
prev += c1 + c2
|
||||
val c4b = if (prev.toULong() < (c1 + c2).toULong()) 1L else 0L
|
||||
val c4b = if (uLt(prev, c1 + c2)) 1L else 0L
|
||||
out[5] = prev
|
||||
dCarry = c3b + c4b
|
||||
|
||||
@@ -457,12 +479,12 @@ internal object U256 {
|
||||
lo = a3 * a3
|
||||
hi = unsignedMultiplyHigh(a3, a3)
|
||||
s = out[6] + lo
|
||||
c1 = if (s.toULong() < out[6].toULong()) 1L else 0L
|
||||
c1 = if (uLt(s, out[6])) 1L else 0L
|
||||
s += dCarry
|
||||
c2 = if (s.toULong() < dCarry.toULong()) 1L else 0L
|
||||
c2 = if (uLt(s, dCarry)) 1L else 0L
|
||||
out[6] = s
|
||||
prev = out[7] + hi
|
||||
val c3c = if (prev.toULong() < out[7].toULong()) 1L else 0L
|
||||
val c3c = if (uLt(prev, out[7])) 1L else 0L
|
||||
prev += c1 + c2
|
||||
out[7] = prev
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user