fix: correct GLV MINUS_LAMBDA constant and fe_cmp normalization bug

Two critical bugs fixed:

1. GLV MINUS_LAMBDA d[1] and d[2] were wrong (0xC8B936E903BCBCBE vs
   correct 0xA880B9FC8EC739C2, and 0x5AD9E3FD77ED9BA3 vs correct
   0x5AD9E3FD77ED9BA4). This caused the GLV scalar decomposition to
   produce wrong k1 values for all large scalars, making ecmult give
   wrong results. Verified by checking lambda^3 mod n == 1.

2. fe_cmp normalized both inputs before comparing, which reduced P
   itself to 0 (since P is in the range [P, 2^256) that normalize
   handles). This caused the "r < p" check in verify to fail for ALL
   valid signatures. Fixed by comparing raw limb values.

Sign + verify + verify_fast now work correctly for small keys (1-3).
Some keys with larger nonces still fail in the ecmult path — likely
one more GLV/wNAF edge case remaining.

https://claude.ai/code/session_011KVZhDcV2G7idNWEBz12GY
This commit is contained in:
Claude
2026-04-11 04:03:55 +00:00
parent 09fb48e75c
commit fefbb243f0
6 changed files with 36 additions and 33 deletions
@@ -105,15 +105,16 @@ class MarmotSubscriptionManagerTest {
}
@Test
fun testGiftWrapFilter() {
val manager = MarmotSubscriptionManager(userPubKey)
val filter = manager.giftWrapFilter()
fun testGiftWrapFilter() =
runTest {
val manager = MarmotSubscriptionManager(userPubKey)
val filter = manager.giftWrapFilter()
assertEquals(listOf(GiftWrapEvent.KIND), filter.kinds)
assertNotNull(filter.tags)
assertEquals(listOf(userPubKey), filter.tags["p"])
assertNull(filter.since)
}
assertEquals(listOf(GiftWrapEvent.KIND), filter.kinds)
assertNotNull(filter.tags)
assertEquals(listOf(userPubKey), filter.tags["p"])
assertNull(filter.since)
}
@Test
fun testGiftWrapFilterWithSince() =
@@ -154,14 +155,15 @@ class MarmotSubscriptionManagerTest {
}
@Test
fun testBuildFiltersWithNoGroupsHasGiftWrapAndKeyPackage() {
val manager = MarmotSubscriptionManager(userPubKey)
val allFilters = manager.buildFilters()
fun testBuildFiltersWithNoGroupsHasGiftWrapAndKeyPackage() =
runTest {
val manager = MarmotSubscriptionManager(userPubKey)
val allFilters = manager.buildFilters()
// Gift wrap filter + own key package filter
assertEquals(2, allFilters.size)
assertEquals(listOf(GiftWrapEvent.KIND), allFilters[0].kinds)
}
// Gift wrap filter + own key package filter
assertEquals(2, allFilters.size)
assertEquals(listOf(GiftWrapEvent.KIND), allFilters[0].kinds)
}
@Test
fun testKeyPackageFilter() {