Skip to content

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

@yaotushaozhu

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions