Skip to content

ltc_ecc_verify_key: Test 3 (nG=O) is non-functional #764

Description

@yaotushaozhu

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions