SM2 #733

Open
karel-m wants to merge 2 commits from pr/sm2 into develop
karel-m commented 2026-04-21 14:00:20 -05:00 (Migrated from github.com)

Added SM2 (Chinese public key algorithm) support.

It depends on the not-yet-merged SM3 hash support.

SM2 uses the existing ECC curve code where possible (it is just another curve). However, its signing/encryption work differently enough, so this patch adds separate SM2-specific functions.

Checklist

  • documentation is added or updated
  • tests are added or updated
Added SM2 (Chinese public key algorithm) support. It depends on the not-yet-merged SM3 hash support. SM2 uses the existing ECC curve code where possible (it is just another curve). However, its signing/encryption work differently enough, so this patch adds separate SM2-specific functions. ### Checklist * [x] documentation is added or updated * [x] tests are added or updated
sjaeckel (Migrated from github.com) reviewed 2026-05-19 09:19:29 -05:00
@ -474,0 +481,4 @@
const unsigned char *msg, unsigned long msglen,
const unsigned char *sig, unsigned long siglen,
int hash_idx, int *stat, const ecc_key *key);
sjaeckel (Migrated from github.com) commented 2026-05-19 09:17:10 -05:00

Would it maybe make sense to introduce a new generic API?

Add LTC_ECCSIG_SM2 to ecc_signature_type and hash_idx to ltc_ecc_sig_opts and then have the following:

int ecc_sign_data(const unsigned char    *data,
                           unsigned long     datalen,
                           unsigned char    *sig,
                           unsigned long    *siglen,
                           ltc_ecc_sig_opts *opts,
                     const       ecc_key    *key);

int ecc_verify_data(const unsigned char *sig,
                             unsigned long  siglen,
                       const unsigned char *data,
                             unsigned long  datalen,
                          ltc_ecc_sig_opts *opts,
                                       int *stat,
                       const       ecc_key *key);
Would it maybe make sense to introduce a new generic API? Add `LTC_ECCSIG_SM2` to `ecc_signature_type` and `hash_idx` to `ltc_ecc_sig_opts` and then have the following: ``` int ecc_sign_data(const unsigned char *data, unsigned long datalen, unsigned char *sig, unsigned long *siglen, ltc_ecc_sig_opts *opts, const ecc_key *key); int ecc_verify_data(const unsigned char *sig, unsigned long siglen, const unsigned char *data, unsigned long datalen, ltc_ecc_sig_opts *opts, int *stat, const ecc_key *key); ```
@ -0,0 +534,4 @@
LTC_ARGCHK(key != NULL);
if ((err = s_sm2_only_curve(key)) != CRYPT_OK) return err;
if ((hash_idx = s_sm2_hash_idx(hash_idx)) < 0) return hash_idx;
sjaeckel (Migrated from github.com) commented 2026-05-19 07:10:07 -05:00

This error check won't work.

I'd say we can remove the hash_idx in the API. This also applies to ecc_decrypt_key_sm2().

This error check won't work. I'd say we can remove the `hash_idx` in the API. This also applies to `ecc_decrypt_key_sm2()`.
karel-m (Migrated from github.com) reviewed 2026-05-20 05:31:48 -05:00
@ -474,0 +481,4 @@
const unsigned char *msg, unsigned long msglen,
const unsigned char *sig, unsigned long siglen,
int hash_idx, int *stat, const ecc_key *key);
karel-m (Migrated from github.com) commented 2026-05-20 05:31:48 -05:00
you mean something similar to https://github.com/libtom/libtomcrypt/issues/724#issuecomment-4252844286 ?
karel-m commented 2026-05-20 07:11:01 -05:00 (Migrated from github.com)

I am not sure if it is a nice piece of code.

int ecc_sign_data(const unsigned char     *in,
                        unsigned long      inlen,
                        unsigned char     *out,
                        unsigned long     *outlen,
                        ltc_ecc_sign_opts *opts,
                  const ecc_key           *key)
{
   unsigned char digest[MAXBLOCKSIZE];
   unsigned long digestlen;
   ltc_ecc_sig_opts v2;
   int err;

   LTC_ARGCHK(in     != NULL);
   LTC_ARGCHK(out    != NULL);
   LTC_ARGCHK(outlen != NULL);
   LTC_ARGCHK(opts   != NULL);
   LTC_ARGCHK(key    != NULL);

   if (opts->type == LTC_ECCSIG_SM2) {
      LTC_ARGCHK(opts->id != NULL || opts->idlen == 0);
      return ecc_sign_sm2(opts->id, opts->idlen, in, inlen, out, outlen, opts->prng, opts->wprng, opts->hash_idx, key);
   }

   if ((err = hash_is_valid(opts->hash_idx)) != CRYPT_OK) return err;
   digestlen = sizeof(digest);
   if ((err = hash_memory(opts->hash_idx, in, inlen, digest, &digestlen)) != CRYPT_OK) return err;

   XMEMSET(&v2, 0, sizeof(v2));
   v2.type               = opts->type;
   v2.prng               = opts->prng;
   v2.wprng              = opts->wprng;
   v2.enable_recovery_id = opts->want_recovery_id;
   if (opts->nonce_mode == LTC_ECC_NONCE_RFC6979) {
      v2.rfc6979_hash_alg = hash_descriptor[opts->hash_idx].name;
   }

   err = ecc_sign_hash_v2(digest, digestlen, out, outlen, &v2, key);

   if (err == CRYPT_OK && opts->want_recovery_id) {
      opts->recovery_id = v2.recovery_id;
   }

   zeromem(digest, sizeof(digest));
   return err;
}
I am not sure if it is a nice piece of code. ```c int ecc_sign_data(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, ltc_ecc_sign_opts *opts, const ecc_key *key) { unsigned char digest[MAXBLOCKSIZE]; unsigned long digestlen; ltc_ecc_sig_opts v2; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(opts != NULL); LTC_ARGCHK(key != NULL); if (opts->type == LTC_ECCSIG_SM2) { LTC_ARGCHK(opts->id != NULL || opts->idlen == 0); return ecc_sign_sm2(opts->id, opts->idlen, in, inlen, out, outlen, opts->prng, opts->wprng, opts->hash_idx, key); } if ((err = hash_is_valid(opts->hash_idx)) != CRYPT_OK) return err; digestlen = sizeof(digest); if ((err = hash_memory(opts->hash_idx, in, inlen, digest, &digestlen)) != CRYPT_OK) return err; XMEMSET(&v2, 0, sizeof(v2)); v2.type = opts->type; v2.prng = opts->prng; v2.wprng = opts->wprng; v2.enable_recovery_id = opts->want_recovery_id; if (opts->nonce_mode == LTC_ECC_NONCE_RFC6979) { v2.rfc6979_hash_alg = hash_descriptor[opts->hash_idx].name; } err = ecc_sign_hash_v2(digest, digestlen, out, outlen, &v2, key); if (err == CRYPT_OK && opts->want_recovery_id) { opts->recovery_id = v2.recovery_id; } zeromem(digest, sizeof(digest)); return err; } ```
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'pr/sm2:pr/sm2'
git switch 'pr/sm2'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'develop'
git merge --no-ff 'pr/sm2'
git switch 'pr/sm2'
git rebase 'develop'
git switch 'develop'
git merge --ff-only 'pr/sm2'
git switch 'pr/sm2'
git rebase 'develop'
git switch 'develop'
git merge --no-ff 'pr/sm2'
git switch 'develop'
git merge --squash 'pr/sm2'
git switch 'develop'
git merge --ff-only 'pr/sm2'
git switch 'develop'
git merge 'pr/sm2'
git push origin 'develop'
Sign in to join this conversation.
No reviewers
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-libtom/libtomcrypt!733
No description provided.