gchq/CyberChef · error · OperationError

Invalid Public Key

Error message

Invalid Public Key

What it means

SM2's setPublicKey() builds an uncompressed point '04'+X+Y, decodes it via the elliptic curve, then at SM2.mjs:62 rejects the result if it is the point at infinity. The decode may succeed on syntactically valid hex that is mathematically not on the curve or evaluates to the identity element, so this is a semantic validity check, not just a parse check.

Source

Thrown at src/core/lib/SM2.mjs:62

        this.format = format;
    }

    /**
     * Set the public key coordinates for the SM2 class
     *
     * @param {string} publicKeyX
     * @param {string} publicKeyY
     */
    setPublicKey(publicKeyX, publicKeyY) {
        /*
        * TODO: This needs some additional length validation; and checking for errors in the decoding process
        * TODO: Can probably support other public key encoding methods here as well in the future
        */
        this.publicKey = this.ecParams.curve.decodePointHex("04" + publicKeyX + publicKeyY);

        if (this.publicKey.isInfinity()) {
            throw new OperationError("Invalid Public Key");
        }
    }

    /**
     * Set the private key value for the SM2 class
     *
     * @param {string} privateKey
     */
    setPrivateKey(privateKeyHex) {
        this.privateKey = new r.BigInteger(privateKeyHex, 16);
    }

    /**
     * Main encryption function; takes user input, processes encryption and returns the result in hex (with the components arranged as configured by the user args)
     *
     * @param {*} input
     * @returns {string}
     */

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm the X and Y coordinates are correct, in the right order, and at the expected length (32 bytes / 64 hex chars each for SM2 P-256).
  2. Verify the SM2 curve parameters object (ecParams) is the standard SM2 curve, not a secp256k1/P-256 stand-in.
  3. Check endianness matches the decoder's expectation (big-endian hex).
  4. Reject zero/all-zero coordinates in caller code before invoking setPublicKey.

Example fix

// before
sm2.setPublicKey(coordB, coordA); // X/Y swapped
// after
sm2.setPublicKey(coordA, coordB);
Defensive patterns

Strategy: validation

Validate before calling

// Validate X/Y hex before calling setPublicKey.
function validateSm2PubKeyHex(x, y) {
  const re = /^[0-9a-fA-F]{64}$/;
  if (!re.test(x) || !re.test(y))
    throw new TypeError("SM2 public key coordinates must be 64 hex chars each");
  if (/^0+$/.test(x) || /^0+$/.test(y))
    throw new TypeError("SM2 public key coordinates must be non-zero");
}

Type guard

function looksLikeSm2PublicKeyCoords(x, y) {
  return typeof x === "string" && typeof y === "string" &&
    /^[0-9a-fA-F]{64}$/.test(x) && /^[0-9a-fA-F]{64}$/.test(y) &&
    !/^0+$/.test(x) && !/^0+$/.test(y);
}

Try / catch

import OperationError from "../errors/OperationError.mjs";
try {
  validateSm2PubKeyHex(x, y);
  sm2.setPublicKey(x, y);
} catch (e) {
  if (e instanceof OperationError && /Invalid Public Key/.test(e.message)) {
    // coordinates decoded but point is on-curve degenerate; re-check curve params
  } else throw e;
}

Prevention

When it happens

Trigger: setPublicKey(publicKeyX, publicKeyY) is called with X/Y hex coordinates that decode to the identity element (point at infinity). Causes: wrong curve parameters loaded, X/Y swapped, coordinates that do not satisfy the SM2 curve equation y^2 = x^3 + ax + b, or a malformed/truncated hex string that decodes to a degenerate point.

Common situations: Public key copied from a different curve (e.g. secp256k1 vs SM2); hex endianness mismatch (big-endian vs little-endian); X and Y swapped during manual transcription; truncated key where one coordinate is all zeros.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/50040827dafef0a3. Report an issue: GitHub.