Bug
ltc_ecc_verify_key() Test 3 ("does nG = O?") is completely non-functional. It accepts both valid and invalid keys — providing zero additional validation.
Root Cause
Two interacting bugs:
Bug 1: map=1 destroys the point-at-infinity representation
ltc_ecc_verify_key.c line 43:
if ((err = ltc_ecc_mulmod(order, &(key->pubkey), point, a, prime, 1)) != CRYPT_OK) { goto done1; }
When map=1, ltc_ecc_mulmod calls ltc_ecc_map at the end, which converts a point-at-infinity (z=0) to (0,0,1):
ltc_ecc_map.c lines 29-30:
if (mp_iszero(P->z)) {
return ltc_ecc_set_point_xyz(0, 0, 1, P);
}
Bug 2: ltc_ecc_is_point_at_infinity() cannot detect (0,0,1)
ltc_ecc_is_point_at_infinity.c:
if (!mp_iszero(P->z)) { // z=1, not zero → short-circuit
*retval = 0; // returns "not infinity"
return CRYPT_OK;
}
Since z=1 after the map, the function immediately returns inf=0, never reaching the y²==x³ check.
Combined effect: inf is always 0 regardless of whether nG=O, so || inf at line 46 never triggers. Test 3 is dead code.
Fix
Both changes are required — neither alone is sufficient:
- if ((err = ltc_ecc_mulmod(order, &(key->pubkey), point, a, prime, 1)) != CRYPT_OK) { goto done1; }
+ if ((err = ltc_ecc_mulmod(order, &(key->pubkey), point, a, prime, 0)) != CRYPT_OK) { goto done1; }
err = ltc_ecc_is_point_at_infinity(point, prime, &inf);
- if (err != CRYPT_OK || inf) {
+ if (err != CRYPT_OK || !inf) {
err = CRYPT_ERROR;
}
Why both:
- Only changing
|| inf → || !inf without map=0: inf is still always 0, so !inf=1 always, rejecting ALL keys including valid ones.
- Only changing map=1 → map=0 without fixing the logic: with map=0, a valid key (nG=O) correctly gives inf=1, but
|| inf would then reject it — logic is inverted.
Impact
For cofactor=1 curves (SECP256R1, SECP384R1, etc. — the vast majority of deployed curves), Test 2 (point-on-curve) already prevents all invalid keys, so Test 3 adds no value.
For cofactor>1 curves (SECP112R2, SECP128R2, SECP160R2), small-subgroup points can pass Test 2 but should fail Test 3. The broken Test 3 means such invalid keys are incorrectly accepted.
Bug
ltc_ecc_verify_key()Test 3 ("does nG = O?") is completely non-functional. It accepts both valid and invalid keys — providing zero additional validation.Root Cause
Two interacting bugs:
Bug 1:
map=1destroys the point-at-infinity representationltc_ecc_verify_key.cline 43:When
map=1,ltc_ecc_mulmodcallsltc_ecc_mapat the end, which converts a point-at-infinity (z=0) to (0,0,1):ltc_ecc_map.clines 29-30:Bug 2:
ltc_ecc_is_point_at_infinity()cannot detect (0,0,1)ltc_ecc_is_point_at_infinity.c:Since z=1 after the map, the function immediately returns
inf=0, never reaching the y²==x³ check.Combined effect:
infis always 0 regardless of whether nG=O, so|| infat line 46 never triggers. Test 3 is dead code.Fix
Both changes are required — neither alone is sufficient:
Why both:
|| inf→|| !infwithout map=0:infis still always 0, so!inf=1 always, rejecting ALL keys including valid ones.|| infwould then reject it — logic is inverted.Impact
For cofactor=1 curves (SECP256R1, SECP384R1, etc. — the vast majority of deployed curves), Test 2 (point-on-curve) already prevents all invalid keys, so Test 3 adds no value.
For cofactor>1 curves (SECP112R2, SECP128R2, SECP160R2), small-subgroup points can pass Test 2 but should fail Test 3. The broken Test 3 means such invalid keys are incorrectly accepted.