fix: correct GLV constants and scalar_mul modular reduction
- Fix GLV_MINUS_LAMBDA constant (d[1] and d[2] were incorrectly computed from Kotlin signed-to-unsigned conversion) - Fix scalar_mul reduction: the carry from folding high limbs was silently dropped when the target position exceeded 4 limbs. Use proper row-based fold with carry propagation into higher positions - Fix in-place gej_double aliasing: when r == p, the output overwrites the input during computation. Added explicit copy-on-alias Verified working: pubkeyCreate, 2*G, (n-1)*G, ecmult for all scalar sizes. Verify path still needs debugging (ecmult_double_g gives correct result for simple cases but the full sign→verify round-trip has a hash/nonce mismatch). https://claude.ai/code/session_011KVZhDcV2G7idNWEBz12GY
This commit is contained in:
@@ -120,40 +120,59 @@ void scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Reduce 512-bit product mod n.
|
/* Reduce 512-bit product mod n using 2^256 mod n = MOD_C.
|
||||||
* Method: fold high limbs using 2^256 mod n = 0x14551231950B75FC4402DA1732FC9BEBF.
|
* For inputs < n (< 2^256), the product is < 2^512.
|
||||||
* For the crypto operations we use (challenge * secret_key), inputs are < n,
|
* We fold the high 256 bits using: hi * 2^256 ≡ hi * MOD_C (mod n).
|
||||||
* so the product is < n^2 < 2^512. We reduce by subtracting n repeatedly.
|
* The result may still exceed 256 bits, so we do a second fold. */
|
||||||
* This is simple and correct; a Barrett reduction could be added for speed. */
|
static const uint64_t MOD_C[4] = {
|
||||||
r->d[0] = t[0]; r->d[1] = t[1]; r->d[2] = t[2]; r->d[3] = t[3];
|
0x402DA1732FC9BEBFULL, 0x4551231950B75FC4ULL, 1, 0
|
||||||
|
};
|
||||||
|
|
||||||
/* Fold high limbs: for each non-zero high limb, the product is too large.
|
|
||||||
* Simple approach: reduce by subtracting n while result >= n. */
|
|
||||||
if (t[4] | t[5] | t[6] | t[7]) {
|
|
||||||
/* High part is non-zero: use the modular constant c = 2^256 mod n.
|
|
||||||
* c = {0x402DA1732FC9BEBF, 0x4551231950B75FC4, 0x1, 0x0} */
|
|
||||||
static const uint64_t MOD_C[4] = {
|
|
||||||
0x402DA1732FC9BEBFULL, 0x4551231950B75FC4ULL, 1, 0
|
|
||||||
};
|
|
||||||
#if HAVE_INT128
|
#if HAVE_INT128
|
||||||
/* Accumulate: r += t[i+4] * c * 2^(64*i) for i=0..3 */
|
{
|
||||||
for (int i = 0; i < 4; i++) {
|
/* Fold: r = t[0..3] + t[4..7] * MOD_C, row-based (same as fe mul_wide) */
|
||||||
if (t[i + 4] == 0) continue;
|
uint64_t mid[8] = {0};
|
||||||
|
mid[0] = t[0]; mid[1] = t[1]; mid[2] = t[2]; mid[3] = t[3];
|
||||||
|
|
||||||
|
/* Add t[4] * MOD_C at position 0 */
|
||||||
|
for (int i = 4; i < 8; i++) {
|
||||||
|
if (t[i] == 0) continue;
|
||||||
uint128_t carry = 0;
|
uint128_t carry = 0;
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
int k = i + j;
|
int k = (i - 4) + j;
|
||||||
if (k < 4) {
|
carry += (uint128_t)t[i] * MOD_C[j] + mid[k];
|
||||||
carry += (uint128_t)t[i + 4] * MOD_C[j] + r->d[k];
|
mid[k] = (uint64_t)carry;
|
||||||
r->d[k] = (uint64_t)carry;
|
carry >>= 64;
|
||||||
carry >>= 64;
|
}
|
||||||
|
/* Propagate carry into higher positions */
|
||||||
|
for (int k = (i - 4) + 4; carry && k < 8; k++) {
|
||||||
|
carry += mid[k];
|
||||||
|
mid[k] = (uint64_t)carry;
|
||||||
|
carry >>= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Second fold: mid[4..7] * MOD_C */
|
||||||
|
r->d[0] = mid[0]; r->d[1] = mid[1]; r->d[2] = mid[2]; r->d[3] = mid[3];
|
||||||
|
if (mid[4] | mid[5] | mid[6] | mid[7]) {
|
||||||
|
for (int i = 4; i < 8; i++) {
|
||||||
|
if (mid[i] == 0) continue;
|
||||||
|
uint128_t carry = 0;
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
int k = (i - 4) + j;
|
||||||
|
if (k < 4) {
|
||||||
|
carry += (uint128_t)mid[i] * MOD_C[j] + r->d[k];
|
||||||
|
r->d[k] = (uint64_t)carry;
|
||||||
|
carry >>= 64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
(void)MOD_C;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/* Final reduction */
|
#else
|
||||||
|
r->d[0] = t[0]; r->d[1] = t[1]; r->d[2] = t[2]; r->d[3] = t[3];
|
||||||
|
#endif
|
||||||
|
/* Final reduction: subtract n while >= n */
|
||||||
while (scalar_cmp(r, &SCALAR_N) >= 0) {
|
while (scalar_cmp(r, &SCALAR_N) >= 0) {
|
||||||
sub256(r->d, r->d, SCALAR_N.d);
|
sub256(r->d, r->d, SCALAR_N.d);
|
||||||
}
|
}
|
||||||
@@ -205,8 +224,8 @@ static const secp256k1_scalar GLV_MINUS_B2 = {{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
static const secp256k1_scalar GLV_MINUS_LAMBDA = {{
|
static const secp256k1_scalar GLV_MINUS_LAMBDA = {{
|
||||||
0xE0CFC810B51283CFULL, 0xA880B9FC8EC739C2ULL,
|
0xE0CFC810B51283CFULL, 0xC8B936E903BCBCBEULL,
|
||||||
0x5AD9E3FD77ED9BA4ULL, 0xAC9C52B33FA3CF1FULL
|
0x5AD9E3FD77ED9BA3ULL, 0xAC9C52B33FA3CF1FULL
|
||||||
}};
|
}};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user