SM2 support through the PSA API II #896

Open
opened 2026-09-04 09:36:37 -05:00 by ronald-cron-arm · 2 comments
ronald-cron-arm commented 2026-09-04 09:36:37 -05:00 (Migrated from github.com)

Freely available English translation of the Chinese SM2 signature standard: http://www.gmbz.org.cn/upload/2024-11-18/1731899583359013934.pdf

Referenced by RFC 9563:
[GMT-0003.2]
Cryptography Standardization Technical Committee of China, "SM2 Public Key Cryptographic Algorithms Based on Elliptic Curves Part 2: Digital Signature Algorithm", [In Chinese], GM/T 0003.2-2012, March 2012. English translation available at: http://www.gmbz.org.cn/upload/2024-11-18/1731899583359013934.pdf

PSA cryptography API specification:

  • The PSA cryptography API 1.5 specification does not specify support for SM2.
  • The specification of the support does not look completely straightforward. SM2 does not sign a hash of the message alone. Before hashing the message, SM2 computes the value ZA, which binds a user identity (IDA) to the elliptic-curve domain parameters and the signer's public key. The value that is signed is then derived from ZA || message. The specification needs to define how IDA is handled when using the signing and verifying APIs.
  • do we accept to combine SM2 with any hash, mathematically possible it seems? Only 256 bits hashes like SM3?
  • do we support SM2-DETERMINISTIC?

Note: While researching about IDA and ZA it seems that a default IDA of 1234567812345678 is used in real life.

An implementation has been proposed for SM2 in Mbed TLS: https://github.com/Mbed-TLS/mbedtls/pull/1620. A CLA valid label was added to the PR thus we should be allowed to use it.

Scope of the initial implementation:
Generic support in ecp.c like for the BRAINPOOL_P_R1_256 curve. No optimizations like:

  • optimized point-doubling formula (a=-3) (we need the value of a for the computation of ZA). This could be enabled at low cost though but we need to change how we detect (-3).
  • specialized reduction for the SM2 prime

Two main steps for the implementation

See https://github.com/ronald-cron-arm/TF-PSA-Crypto/tree/sm2-prototype

  • Add support for SM2 curve. Choose Brainpool P256 as the primary integration analogue because it follows the generic 256-bit short-Weierstrass path while having its own PSA family, configuration, and OID. Useful regex: rg -n '(BRAINPOOL_P_R1|BP(256|384|512)R1|brainpoolP(256|384|512)r1)'. The support for secp256r1 has more specific parts (specialized modular reduction, dedicated driver, required for EC J-PAKE).

    • Public PSA representation. Add the ECC family, feature switch, and size handling (include/psa/crypto_values.h, include/psa/crypto_config.h, include/psa/crypto_sizes.h)
    • Internal ECP representation. Add the group ID, curve registration, domain parameters, and group loader (drivers/builtin/include/mbedtls/private/ecp.h, drivers/builtin/src/ecp.c and drivers/builtin/src/ecp_curves.c)
    • PSA/ECP bridge. Validate supported sizes and implement conversions in both directions (drivers/builtin/src/psa_crypto_ecp.c and drivers/builtin/src/psa_util_internal.c)
    • Build and configuration plumbing. Connect PSA_WANT_*, builtin fallback, and accelerator support (core/tf_psa_crypto_check_config.h, drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h and scripts/data_files/config-options-current.txt)
    • Encoding support. Add the standard curve OID and its group mapping (utilities/crypto_oid.h and utilities/oid.c).
    • Tests. Cover curve discovery, exact domain parameters, PSA conversions, and metadata (tests/suites/test_suite_ecp.data, tests/suites/test_suite_psa_crypto.data and tests/suites/test_suite_psa_crypto_metadata.data)
  • Add MVP SM2 signature algorithm support

    • Implement tf_psa_crypto_sm2_sign_hash() and tf_psa_crypto_sm2_verify_hash() in drivers/builtin/src/sm2.c (not in psa_crypto_ecp.c as done for ECDSA for historical reasons).

      • Validate that PSA signing uses a 256-bit curveSM2 key pair and verification uses a 256-bit curveSM2 public key or key pair.
      • Encode signatures using PSA’s fixed-width r || s representation.
      • Declare internal interfaces in drivers/builtin/src/sm2_internal.h.
    • Add the TF-PSA-Crypto-specific tf_psa_crypto_sm2_compute_z() API.
      - The caller computes ZA, then hashes ZA || message, and finally calls psa_sign_hash() or psa_verify_hash().

      • Add self-testing using GM/T 0003.2-2012 Annex A.2 vectors.
        • tests/suites/test_suite_sm2.data
        • tests/suites/test_suite_sm2.function
        • Note that these vectors test the SM2 algorithm using a different elliptic curve, not the standardized curveSM2 parameters.
    • Use ECDSA as the guide for:

      • PSA registration and algorithm classification: include/psa/crypto_values.h
        • Add PSA_ALG_SM2DSA() (?) and PSA_ALG_IS_SM2DSA().
        • Classify it as SIGN_HASH.
        • Explicitly exclude it from SIGN_MESSAGE and HASH_AND_SIGN to start with, since those APIs cannot carry the SM2 identity.
        • Support extracting its associated hash with PSA_ALG_SIGN_GET_HASH().
        • Use vendor-defined values because PSA has no official SM2 identifiers yet.
      • Additional vendor API: include/psa/crypto_extra.h
      • Configuration: Enable the required hash, ECP, bignum, and accelerator-fallback dependencies (include/psa/crypto_config.h, drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h, and scripts/data_files/config-options-current.txt.
      • Dispatch: core/psa_crypto.c
      • Signature sizing: include/psa/crypto_sizes.h
      • Shared ECC key loading: drivers/builtin/src/psa_crypto_ecp.c (compilation guard).
    • Add PSA-level tests:

      • tests/suites/test_suite_psa_crypto.data
      • tests/suites/test_suite_psa_crypto.function
      • tests/suites/test_suite_psa_crypto_metadata.data
      • Cover ZA, algorithm metadata, sign/verify round trips, published verification vectors.
Freely available English translation of the Chinese SM2 signature standard: http://www.gmbz.org.cn/upload/2024-11-18/1731899583359013934.pdf Referenced by RFC 9563: [GMT-0003.2] Cryptography Standardization Technical Committee of China, "SM2 Public Key Cryptographic Algorithms Based on Elliptic Curves Part 2: Digital Signature Algorithm", [In Chinese], GM/T 0003.2-2012, March 2012. English translation available at: http://www.gmbz.org.cn/upload/2024-11-18/1731899583359013934.pdf PSA cryptography API specification: - The PSA cryptography API 1.5 specification does not specify support for SM2. - The specification of the support does not look completely straightforward. SM2 does not sign a hash of the message alone. Before hashing the message, SM2 computes the value `ZA`, which binds a user identity (`IDA`) to the elliptic-curve domain parameters and the signer's public key. The value that is signed is then derived from `ZA || message`. The specification needs to define how `IDA` is handled when using the signing and verifying APIs. - do we accept to combine SM2 with any hash, mathematically possible it seems? Only 256 bits hashes like SM3? - do we support SM2-DETERMINISTIC? Note: While researching about IDA and ZA it seems that a default IDA of `1234567812345678` is used in real life. An implementation has been proposed for SM2 in Mbed TLS: https://github.com/Mbed-TLS/mbedtls/pull/1620. A `CLA valid` label was added to the PR thus we should be allowed to use it. Scope of the initial implementation: Generic support in ecp.c like for the BRAINPOOL_P_R1_256 curve. No optimizations like: - optimized point-doubling formula (a=-3) (we need the value of a for the computation of ZA). This could be enabled at low cost though but we need to change how we detect (-3). - specialized reduction for the SM2 prime ### Two main steps for the implementation See https://github.com/ronald-cron-arm/TF-PSA-Crypto/tree/sm2-prototype - Add support for SM2 curve. Choose Brainpool P256 as the primary integration analogue because it follows the generic 256-bit short-Weierstrass path while having its own PSA family, configuration, and OID. Useful regex: rg -n '(BRAINPOOL_P_R1|BP(256|384|512)R1|brainpoolP(256|384|512)r1)'. The support for `secp256r1` has more specific parts (specialized modular reduction, dedicated driver, required for EC J-PAKE). - Public PSA representation. Add the ECC family, feature switch, and size handling (include/psa/crypto_values.h, include/psa/crypto_config.h, include/psa/crypto_sizes.h) - Internal ECP representation. Add the group ID, curve registration, domain parameters, and group loader (drivers/builtin/include/mbedtls/private/ecp.h, drivers/builtin/src/ecp.c and drivers/builtin/src/ecp_curves.c) - PSA/ECP bridge. Validate supported sizes and implement conversions in both directions (drivers/builtin/src/psa_crypto_ecp.c and drivers/builtin/src/psa_util_internal.c) - Build and configuration plumbing. Connect PSA_WANT_*, builtin fallback, and accelerator support (core/tf_psa_crypto_check_config.h, drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h and scripts/data_files/config-options-current.txt) - Encoding support. Add the standard curve OID and its group mapping (utilities/crypto_oid.h and utilities/oid.c). - Tests. Cover curve discovery, exact domain parameters, PSA conversions, and metadata (tests/suites/test_suite_ecp.data, tests/suites/test_suite_psa_crypto.data and tests/suites/test_suite_psa_crypto_metadata.data) - Add MVP SM2 signature algorithm support - Implement tf_psa_crypto_sm2_sign_hash() and tf_psa_crypto_sm2_verify_hash() in drivers/builtin/src/sm2.c (not in `psa_crypto_ecp.c` as done for ECDSA for historical reasons). - Validate that PSA signing uses a 256-bit curveSM2 key pair and verification uses a 256-bit curveSM2 public key or key pair. - Encode signatures using PSA’s fixed-width r || s representation. - Declare internal interfaces in drivers/builtin/src/sm2_internal.h. - Add the TF-PSA-Crypto-specific tf_psa_crypto_sm2_compute_z() API. - The caller computes ZA, then hashes ZA || message, and finally calls psa_sign_hash() or psa_verify_hash(). - Add self-testing using GM/T 0003.2-2012 Annex A.2 vectors. - tests/suites/test_suite_sm2.data - tests/suites/test_suite_sm2.function - Note that these vectors test the SM2 algorithm using a different elliptic curve, not the standardized curveSM2 parameters. - Use ECDSA as the guide for: - PSA registration and algorithm classification: include/psa/crypto_values.h - Add PSA_ALG_SM2DSA() (?) and PSA_ALG_IS_SM2DSA(). - Classify it as SIGN_HASH. - Explicitly exclude it from SIGN_MESSAGE and HASH_AND_SIGN to start with, since those APIs cannot carry the SM2 identity. - Support extracting its associated hash with PSA_ALG_SIGN_GET_HASH(). - Use vendor-defined values because PSA has no official SM2 identifiers yet. - Additional vendor API: include/psa/crypto_extra.h - Configuration: Enable the required hash, ECP, bignum, and accelerator-fallback dependencies (include/psa/crypto_config.h, drivers/builtin/include/mbedtls/private/crypto_adjust_config_enable_builtins.h, and scripts/data_files/config-options-current.txt. - Dispatch: core/psa_crypto.c - Signature sizing: include/psa/crypto_sizes.h - Shared ECC key loading: drivers/builtin/src/psa_crypto_ecp.c (compilation guard). - Add PSA-level tests: - tests/suites/test_suite_psa_crypto.data - tests/suites/test_suite_psa_crypto.function - tests/suites/test_suite_psa_crypto_metadata.data - Cover ZA, algorithm metadata, sign/verify round trips, published verification vectors.
gilles-peskine-arm commented 2026-09-29 04:29:11 -05:00 (Migrated from github.com)

We should go forward with adding SM2 in PSA: https://github.com/GlobalPlatform/psa-api/issues/22

We should go forward with adding SM2 in PSA: https://github.com/GlobalPlatform/psa-api/issues/22
mpg commented 2026-09-29 05:54:25 -05:00 (Migrated from github.com)

Scope of the initial implementation: Generic support in ecp.c like for the BRAINPOOL_P_R1_256 curve. No optimizations like:

For the record, as discussed verbally, I think a non-optimized version is a great first step, but before we ship SM2 support we want to follow with some optimizations (that can be done in parallel with other work, once we have a working non-optimized version).

* optimized point-doubling formula (a=-3) (we need the value of a for the computation of ZA). This could be enabled at low cost though but we need to change how we detect (-3).

If we need the value of a for something, we can easily compute it as p - 3. I don't think we should need to change how "a = -3" is represented.

* specialized reduction for the SM2 prime

This has a very significant impact on performance.

There's also another optimisation to consider (that is actually also done for brainpool curves, it's done for all Short Weierstrass curves): pre-computed multiples of the base point, controlled by MBEDTLS_ECP_FIXED_POINT_OPTIM (speeding up signature generation by about 3-4x, and signature verification to a lesser extend).

This is the tables like brainpoolP256r1_T that are present in ecp_curves.c. They are generated by framework/scripts/ecp_comb_table.py. Unfortunately that script was broken by the repo script: it builds a helper program, which currently fails to build as it's using out-of-date paths, names, etc.

I have a PR that entirely removes ecp_comb_table.py and replaces it with something new (while making other improvements), but it is quite out of date as well - still lives on the wrong side of the split for example: https://github.com/Mbed-TLS/mbedtls/pull/7623

I'm not sure what the easiest way is here. FWIW, asking codex to fix framework/scripts/ecp_comb_table.py seems to produce plausible results. I have not tried to evaluate how hard it would be to update my PR.

Btw, even if we don't revive my PR for the occasion, you might still be interested in this bit of documentation I wrote: https://github.com/Mbed-TLS/mbedtls/pull/7623/changes/fc456345703f26ab36c5a8085b242269f0ea1eb6 (step 4 is assuming my PR is merged, and should be changed to using framework/scripts/ecp_comb_table.py if not, but the other steps should be valid either way).

> Scope of the initial implementation: Generic support in ecp.c like for the BRAINPOOL_P_R1_256 curve. No optimizations like: For the record, as discussed verbally, I think a non-optimized version is a great first step, but before we ship SM2 support we want to follow with some optimizations (that can be done in parallel with other work, once we have a working non-optimized version). > * optimized point-doubling formula (a=-3) (we need the value of a for the computation of ZA). This could be enabled at low cost though but we need to change how we detect (-3). > If we need the value of `a` for something, we can easily compute it as `p - 3`. I don't think we should need to change how "a = -3" is represented. > * specialized reduction for the SM2 prime This has a very significant impact on performance. There's also another optimisation to consider (that is actually also done for brainpool curves, it's done for all Short Weierstrass curves): pre-computed multiples of the base point, controlled by `MBEDTLS_ECP_FIXED_POINT_OPTIM` (speeding up signature generation by about 3-4x, and signature verification to a lesser extend). This is the tables like `brainpoolP256r1_T` that are present in `ecp_curves.c`. They are generated by `framework/scripts/ecp_comb_table.py`. Unfortunately that script was broken by the repo script: it builds a helper program, which currently fails to build as it's using out-of-date paths, names, etc. I have a PR that entirely removes `ecp_comb_table.py` and replaces it with something new (while making other improvements), but it is quite out of date as well - still lives on the wrong side of the split for example: https://github.com/Mbed-TLS/mbedtls/pull/7623 I'm not sure what the easiest way is here. FWIW, asking codex to fix `framework/scripts/ecp_comb_table.py` seems to produce plausible results. I have not tried to evaluate how hard it would be to update my PR. Btw, even if we don't revive my PR for the occasion, you might still be interested in this bit of documentation I wrote: https://github.com/Mbed-TLS/mbedtls/pull/7623/changes/fc456345703f26ab36c5a8085b242269f0ea1eb6 (step 4 is assuming my PR is merged, and should be changed to using `framework/scripts/ecp_comb_table.py` if not, but the other steps should be valid either way).
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-Mbed-TLS/TF-PSA-Crypto#896
No description provided.