/*
 * gmcrypto-c — C ABI for gmcrypto-core (pure-Rust SM2/SM3/SM4 SDK).
 *
 * AUTO-GENERATED by cbindgen. DO NOT EDIT BY HAND.
 * Regenerate via: cargo build -p gmcrypto-c --features regen-header
 *
 * Failure-mode invariant (v0.4 W4 / Q4.8 of docs/v0.4-scope.md):
 * every int return is 0 on success, non-zero on failure. Non-zero
 * codes are NOT enumerated — they are equivalent `Failed` per the
 * crate's failure-mode discipline.
 */

#ifndef GMCRYPTO_H_
#define GMCRYPTO_H_

/* Warning: this file is auto-generated by cbindgen; do not edit. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>

/*
 Success return code.
 */
#define GMCRYPTO_OK 0

/*
 Generic failure return code. All non-zero returns are equivalent
 per the failure-mode invariant; this constant exists only as a
 convenience for C callers that want a named symbol for the
 not-success case.
 */
#define GMCRYPTO_ERR -1

/*
 SM3 digest output size in bytes (32 = 256 bits).
 */
#define GMCRYPTO_SM3_DIGEST_SIZE 32

/*
 SM4 block size in bytes (16 = 128 bits).
 */
#define GMCRYPTO_SM4_BLOCK_SIZE 16

/*
 SM4 key size in bytes (16 = 128 bits).
 */
#define GMCRYPTO_SM4_KEY_SIZE 16

/*
 SEC1 uncompressed-point size for SM2 public keys
 (`04 || X || Y` = 65 bytes).
 */
#define GMCRYPTO_SM2_SEC1_UNCOMPRESSED_SIZE 65

/*
 SM2 private-key scalar size in bytes (32 = 256 bits big-endian).
 */
#define GMCRYPTO_SM2_SCALAR_SIZE 32

/*
 Opaque handle for a streaming HMAC-SM3 keyed MAC.
 */
typedef struct gmcrypto_hmac_sm3_t gmcrypto_hmac_sm3_t;

/*
 Opaque handle for an SM2 private key.
 */
typedef struct gmcrypto_sm2_privkey_t gmcrypto_sm2_privkey_t;

/*
 Opaque handle for an SM2 public key.
 */
typedef struct gmcrypto_sm2_pubkey_t gmcrypto_sm2_pubkey_t;

/*
 Opaque handle for a streaming SM3 hasher.
 */
typedef struct gmcrypto_sm3_t gmcrypto_sm3_t;

/*
 Opaque handle for a streaming SM4-CBC decryptor (v0.5 W1). Same
 buffer-back-by-one padding-oracle defense as the v0.3 W5 Rust
 streaming surface: the most recent decrypted block is held back
 from emission until [`gmcrypto_sm4_cbc_decryptor_finalize`]
 confirms it is the last block and validates the PKCS#7 padding.
 */
typedef struct gmcrypto_sm4_cbc_decryptor_t gmcrypto_sm4_cbc_decryptor_t;

/*
 Opaque handle for a streaming SM4-CBC encryptor (v0.5 W1).
 Construct with [`gmcrypto_sm4_cbc_encryptor_new`], feed plaintext via
 [`gmcrypto_sm4_cbc_encryptor_update`], emit the trailing PKCS#7-
 padded block(s) via [`gmcrypto_sm4_cbc_encryptor_finalize`].
 */
typedef struct gmcrypto_sm4_cbc_encryptor_t gmcrypto_sm4_cbc_encryptor_t;

/*
 Opaque handle for an SM4 cipher (key-scheduled).
 */
typedef struct gmcrypto_sm4_t gmcrypto_sm4_t;

/*
 C ABI function pointer for caller-supplied RNG. Returns `0` on
 success and non-zero on failure. See module-level docs for the
 full contract.
 */
typedef int (*gmcrypto_rng_callback)(void *context, uint8_t *buf, uintptr_t buf_len);

/*
 Returns a NUL-terminated string with the `gmcrypto-c` version
 (e.g. `"0.4.0"`). The returned pointer is to a static `&'static
 CStr` and must NOT be freed by the caller.
 */
 const char *gmcrypto_version(void) ;

/*
 Single-shot SM3 hash. Writes 32 bytes to `out_digest`.

 # Returns
 [`GMCRYPTO_OK`] on success; [`GMCRYPTO_ERR`] on invalid input
 (null `out_digest`, null `msg` with non-zero `msg_len`).
 */
 int gmcrypto_sm3_hash(const uint8_t *msg, uintptr_t msg_len, uint8_t *out_digest) ;

/*
 Construct a fresh streaming SM3 hasher. Returns an opaque handle;
 must be freed via [`gmcrypto_sm3_free`].

 Returns NULL on allocation failure.
 */
 gmcrypto_sm3_t *gmcrypto_sm3_new(void) ;

/*
 Absorb `data` into the streaming SM3 hasher.
 */
 int gmcrypto_sm3_update(gmcrypto_sm3_t *hasher, const uint8_t *data, uintptr_t data_len) ;

/*
 Consume the streaming SM3 hasher and write the digest to
 `out_digest`. The handle is **freed** by this call; do not call
 [`gmcrypto_sm3_free`] on it afterwards.
 */
 int gmcrypto_sm3_finalize(gmcrypto_sm3_t *hasher, uint8_t *out_digest) ;

/*
 Free a streaming SM3 hasher. Passing NULL is a no-op.
 */
 void gmcrypto_sm3_free(gmcrypto_sm3_t *hasher) ;

/*
 Single-shot HMAC-SM3. Writes 32 bytes to `out_tag`.
 */

int gmcrypto_hmac_sm3(const uint8_t *key,
                      uintptr_t key_len,
                      const uint8_t *msg,
                      uintptr_t msg_len,
                      uint8_t *out_tag)
;

/*
 Construct a fresh streaming HMAC-SM3 instance keyed with `key`.
 Returns NULL on invalid input.
 */
 gmcrypto_hmac_sm3_t *gmcrypto_hmac_sm3_new(const uint8_t *key, uintptr_t key_len) ;

/*
 Absorb `data` into the streaming HMAC-SM3 instance.
 */
 int gmcrypto_hmac_sm3_update(gmcrypto_hmac_sm3_t *mac, const uint8_t *data, uintptr_t data_len) ;

/*
 Consume the streaming HMAC-SM3 instance and write the 32-byte tag
 to `out_tag`. The handle is **freed** by this call.
 */
 int gmcrypto_hmac_sm3_finalize(gmcrypto_hmac_sm3_t *mac, uint8_t *out_tag) ;

/*
 Consume the streaming HMAC-SM3 instance and verify the candidate
 tag in constant time. Returns [`GMCRYPTO_OK`] on match;
 [`GMCRYPTO_ERR`] on mismatch. The handle is **freed** by this call.
 */
 int gmcrypto_hmac_sm3_verify(gmcrypto_hmac_sm3_t *mac, const uint8_t *expected_tag) ;

/*
 Free a streaming HMAC-SM3 instance. NULL is a no-op.
 */
 void gmcrypto_hmac_sm3_free(gmcrypto_hmac_sm3_t *mac) ;

/*
 Derive `out_len` bytes via PBKDF2-HMAC-SM3 over `(pwd, salt,
 iterations)`. Writes into the caller-supplied `out` buffer.
 */

int gmcrypto_pbkdf2_hmac_sm3(const uint8_t *pwd,
                             uintptr_t pwd_len,
                             const uint8_t *salt,
                             uintptr_t salt_len,
                             uint32_t iterations,
                             uint8_t *out,
                             uintptr_t out_len)
;

/*
 Construct an SM4 cipher from a 16-byte key. Returns NULL on null
 key.
 */
 gmcrypto_sm4_t *gmcrypto_sm4_new(const uint8_t *key) ;

/*
 Encrypt one 16-byte block in place under the SM4 cipher.
 */
 int gmcrypto_sm4_encrypt_block(const gmcrypto_sm4_t *cipher, uint8_t *block) ;

/*
 Decrypt one 16-byte block in place under the SM4 cipher.
 */
 int gmcrypto_sm4_decrypt_block(const gmcrypto_sm4_t *cipher, uint8_t *block) ;

/*
 Free an SM4 cipher. NULL is a no-op.
 */
 void gmcrypto_sm4_free(gmcrypto_sm4_t *cipher) ;

/*
 SM4-CBC single-shot encrypt with PKCS#7 padding. IV must be
 caller-supplied and unpredictable (per NIST SP 800-38A
 Appendix C). Output length is always `((pt_len / 16) + 1) * 16`.
 */

int gmcrypto_sm4_cbc_encrypt(const uint8_t *key,
                             const uint8_t *iv,
                             const uint8_t *pt,
                             uintptr_t pt_len,
                             uint8_t *out,
                             uintptr_t out_capacity,
                             uintptr_t *out_actual_len)
;

/*
 SM4-CBC single-shot decrypt. Single-`Failed` return on any
 failure mode (length not multiple of 16, bad padding, key/IV
 mismatch) per the failure-mode invariant.
 */

int gmcrypto_sm4_cbc_decrypt(const uint8_t *key,
                             const uint8_t *iv,
                             const uint8_t *ct,
                             uintptr_t ct_len,
                             uint8_t *out,
                             uintptr_t out_capacity,
                             uintptr_t *out_actual_len)
;

/*
 Construct a streaming SM4-CBC encryptor. `key` is exactly 16
 bytes; `iv` is exactly 16 bytes and MUST be caller-supplied
 unpredictable bytes (NIST SP 800-38A Appendix C). Returns NULL
 on invalid pointer input.
 */

gmcrypto_sm4_cbc_encryptor_t *gmcrypto_sm4_cbc_encryptor_new(const uint8_t *key,
                                                             const uint8_t *iv)
;

/*
 Absorb plaintext into the streaming SM4-CBC encryptor and emit
 zero or more full ciphertext blocks. The caller-allocated `out`
 buffer MUST be at least `pt_len + 16` bytes — that is the upper
 bound on bytes emitted by a single `_update` call (a buffered
 partial block from a prior call can produce one extra block when
 this call's input fills it). On insufficient capacity, the call
 returns [`GMCRYPTO_ERR`] and the encryptor state is left mid-
 stream (the ciphertext bytes that would have been emitted are
 lost). Callers should size the output buffer correctly up-front.
 */

int gmcrypto_sm4_cbc_encryptor_update(gmcrypto_sm4_cbc_encryptor_t *enc,
                                      const uint8_t *pt,
                                      uintptr_t pt_len,
                                      uint8_t *out,
                                      uintptr_t out_capacity,
                                      uintptr_t *out_actual_len)
;

/*
 Apply PKCS#7 padding to the buffered tail and emit the final
 ciphertext block(s). Consumes the encryptor — the handle is
 **freed** by this call; do NOT call
 [`gmcrypto_sm4_cbc_encryptor_free`] on it afterwards.

 Output is always exactly one block (16 bytes).
 */

int gmcrypto_sm4_cbc_encryptor_finalize(gmcrypto_sm4_cbc_encryptor_t *enc,
                                        uint8_t *out,
                                        uintptr_t out_capacity,
                                        uintptr_t *out_actual_len)
;

/*
 Free a streaming SM4-CBC encryptor. Passing NULL is a no-op. Do
 NOT call after [`gmcrypto_sm4_cbc_encryptor_finalize`] — that
 already consumed the handle.
 */
 void gmcrypto_sm4_cbc_encryptor_free(gmcrypto_sm4_cbc_encryptor_t *enc) ;

/*
 Construct a streaming SM4-CBC decryptor. `key` is exactly 16
 bytes; `iv` is exactly 16 bytes and must match the value used
 during encryption. Returns NULL on invalid pointer input.
 */

gmcrypto_sm4_cbc_decryptor_t *gmcrypto_sm4_cbc_decryptor_new(const uint8_t *key,
                                                             const uint8_t *iv)
;

/*
 Absorb ciphertext into the streaming SM4-CBC decryptor and emit
 zero or more full plaintext blocks. The final-candidate block is
 HELD BACK from emission until `_finalize` validates the trailing
 padding (buffer-back-by-one padding-oracle defense). Same buffer-
 size contract as the encryptor's `_update`: caller MUST allocate
 `out_capacity >= ct_len + 16` (strict upper bound on bytes emitted
 in one call). On insufficient capacity returns [`GMCRYPTO_ERR`]
 and the decryptor state is left mid-stream; size the buffer
 up-front.
 */

int gmcrypto_sm4_cbc_decryptor_update(gmcrypto_sm4_cbc_decryptor_t *dec,
                                      const uint8_t *ct,
                                      uintptr_t ct_len,
                                      uint8_t *out,
                                      uintptr_t out_capacity,
                                      uintptr_t *out_actual_len)
;

/*
 Strip PKCS#7 padding from the held-back final block and emit the
 last plaintext bytes. Consumes the decryptor — the handle is
 **freed** by this call; do NOT call
 [`gmcrypto_sm4_cbc_decryptor_free`] on it afterwards.

 Returns [`GMCRYPTO_ERR`] on any failure mode (length not multiple
 of 16, no full blocks seen, or padding-strip rejection) — single
 uninformative failure code per the failure-mode invariant. The
 caller-supplied `out_actual_len` is set to `0` on failure.
 */

int gmcrypto_sm4_cbc_decryptor_finalize(gmcrypto_sm4_cbc_decryptor_t *dec,
                                        uint8_t *out,
                                        uintptr_t out_capacity,
                                        uintptr_t *out_actual_len)
;

/*
 Free a streaming SM4-CBC decryptor. Passing NULL is a no-op. Do
 NOT call after [`gmcrypto_sm4_cbc_decryptor_finalize`] — that
 already consumed the handle.
 */
 void gmcrypto_sm4_cbc_decryptor_free(gmcrypto_sm4_cbc_decryptor_t *dec) ;

/*
 SM4-GCM single-shot encrypt. `ct_out` receives `pt_len` bytes (via
 the capacity/actual-len convention); `tag_out` receives exactly 16
 bytes. Returns [`GMCRYPTO_OK`] / [`GMCRYPTO_ERR`].
 */

int gmcrypto_sm4_gcm_encrypt(const uint8_t *key,
                             const uint8_t *nonce,
                             uintptr_t nonce_len,
                             const uint8_t *aad,
                             uintptr_t aad_len,
                             const uint8_t *pt,
                             uintptr_t pt_len,
                             uint8_t *ct_out,
                             uintptr_t ct_capacity,
                             uintptr_t *ct_actual_len,
                             uint8_t *tag_out)
;

/*
 SM4-GCM single-shot decrypt with a 16-byte tag. `pt_out` receives
 `ct_len` bytes. Returns [`GMCRYPTO_OK`] only if the tag verifies;
 [`GMCRYPTO_ERR`] on any failure (single failure mode).
 */

int gmcrypto_sm4_gcm_decrypt(const uint8_t *key,
                             const uint8_t *nonce,
                             uintptr_t nonce_len,
                             const uint8_t *aad,
                             uintptr_t aad_len,
                             const uint8_t *ct,
                             uintptr_t ct_len,
                             const uint8_t *tag,
                             uint8_t *pt_out,
                             uintptr_t pt_capacity,
                             uintptr_t *pt_actual_len)
;

/*
 SM4-GCM encrypt with a truncated tag. `tag_len` must be in
 `{4, 8, 12, 13, 14, 15, 16}`; `tag_out` receives `tag_len` bytes.
 Invalid `tag_len` → [`GMCRYPTO_ERR`].
 */

int gmcrypto_sm4_gcm_encrypt_with_tag_len(const uint8_t *key,
                                          const uint8_t *nonce,
                                          uintptr_t nonce_len,
                                          const uint8_t *aad,
                                          uintptr_t aad_len,
                                          const uint8_t *pt,
                                          uintptr_t pt_len,
                                          uintptr_t tag_len,
                                          uint8_t *ct_out,
                                          uintptr_t ct_capacity,
                                          uintptr_t *ct_actual_len,
                                          uint8_t *tag_out)
;

/*
 SM4-GCM decrypt with a truncated tag. `tag` is `tag_len` bytes;
 `tag_len` must be in `{4, 8, 12, 13, 14, 15, 16}`. `pt_out`
 receives `ct_len` bytes. [`GMCRYPTO_ERR`] on any failure.
 */

int gmcrypto_sm4_gcm_decrypt_with_tag_len(const uint8_t *key,
                                          const uint8_t *nonce,
                                          uintptr_t nonce_len,
                                          const uint8_t *aad,
                                          uintptr_t aad_len,
                                          const uint8_t *ct,
                                          uintptr_t ct_len,
                                          const uint8_t *tag,
                                          uintptr_t tag_len,
                                          uint8_t *pt_out,
                                          uintptr_t pt_capacity,
                                          uintptr_t *pt_actual_len)
;

/*
 SM4-CCM single-shot encrypt. `tag_len` must be in
 `{4, 6, 8, 10, 12, 14, 16}`; `nonce_len` in `[7, 13]`. `out`
 receives `pt_len + tag_len` bytes (`ciphertext ‖ tag`). Invalid
 parameters → [`GMCRYPTO_ERR`].
 */

int gmcrypto_sm4_ccm_encrypt(const uint8_t *key,
                             const uint8_t *nonce,
                             uintptr_t nonce_len,
                             const uint8_t *aad,
                             uintptr_t aad_len,
                             const uint8_t *pt,
                             uintptr_t pt_len,
                             uintptr_t tag_len,
                             uint8_t *out,
                             uintptr_t out_capacity,
                             uintptr_t *out_actual_len)
;

/*
 SM4-CCM single-shot decrypt. Input `ct` is `ct_len` bytes
 (`ciphertext ‖ tag`); `tag_len` must match the value used at
 encrypt time. `pt_out` receives `ct_len - tag_len` bytes.
 [`GMCRYPTO_ERR`] on any failure (single failure mode).
 */

int gmcrypto_sm4_ccm_decrypt(const uint8_t *key,
                             const uint8_t *nonce,
                             uintptr_t nonce_len,
                             const uint8_t *aad,
                             uintptr_t aad_len,
                             const uint8_t *ct,
                             uintptr_t ct_len,
                             uintptr_t tag_len,
                             uint8_t *pt_out,
                             uintptr_t pt_capacity,
                             uintptr_t *pt_actual_len)
;

/*
 Construct an SM2 private key from a 32-byte big-endian scalar.
 Returns NULL on out-of-range scalar (must be in `[1, n-2]`).
 */
 gmcrypto_sm2_privkey_t *gmcrypto_sm2_privkey_new(const uint8_t *d_be) ;

/*
 Construct an SM2 public key from a SEC1 uncompressed-point byte
 string (`04 || X || Y`, 65 bytes). Returns NULL on
 invalid input (off-curve, identity point, non-uncompressed
 prefix).
 */
 gmcrypto_sm2_pubkey_t *gmcrypto_sm2_pubkey_new(const uint8_t *sec1_uncompressed) ;

/*
 Export the SM2 private key as a 32-byte big-endian scalar.

 **Caller MUST zeroize the output buffer** after use. Per Q4.19,
 this entry point exists as `#[doc(hidden)]`-equivalent on the
 Rust side and is NOT SemVer-stable across v0.4.x.
 */
 int gmcrypto_sm2_privkey_to_sec1_be(const gmcrypto_sm2_privkey_t *key, uint8_t *out) ;

/*
 Export the SM2 public key as a SEC1 uncompressed-point byte
 string (`04 || X || Y`, 65 bytes).
 */
 int gmcrypto_sm2_pubkey_to_sec1_uncompressed(const gmcrypto_sm2_pubkey_t *key, uint8_t *out) ;

/*
 Free an SM2 private key. NULL is a no-op. The inner scalar is
 zeroized via `ZeroizeOnDrop` before the heap slot is freed.
 */
 void gmcrypto_sm2_privkey_free(gmcrypto_sm2_privkey_t *key) ;

/*
 Free an SM2 public key. NULL is a no-op.
 */
 void gmcrypto_sm2_pubkey_free(gmcrypto_sm2_pubkey_t *key) ;

/*
 Emit a password-encrypted PKCS#8 PEM blob containing the SM2
 private key. PBES2 / PBKDF2-HMAC-SM3 / SM4-CBC per RFC 8018.
 */

int gmcrypto_sm2_privkey_to_pkcs8(const gmcrypto_sm2_privkey_t *key,
                                  const uint8_t *password,
                                  uintptr_t pwd_len,
                                  uint32_t pbkdf2_iters,
                                  uint8_t *out_pem,
                                  uintptr_t out_capacity,
                                  uintptr_t *out_actual_len)
;

/*
 Load an SM2 private key from a password-encrypted PKCS#8 PEM blob.
 On success, writes the new handle to `*out_key` and returns
 [`GMCRYPTO_OK`]. Caller MUST free via [`gmcrypto_sm2_privkey_free`].
 */

int gmcrypto_sm2_privkey_from_pkcs8(const uint8_t *pem,
                                    uintptr_t pem_len,
                                    const uint8_t *password,
                                    uintptr_t pwd_len,
                                    gmcrypto_sm2_privkey_t **out_key)
;

/*
 Sign `msg` with the SM2 private key using the supplied
 `signer_id` (or [`DEFAULT_SIGNER_ID`] = `"1234567812345678"` if
 `signer_id_len == 0`). Output is DER-encoded
 `SEQUENCE { r, s }`. RNG is sourced from `getrandom::SysRng`.
 */

int gmcrypto_sm2_sign(const gmcrypto_sm2_privkey_t *key,
                      const uint8_t *signer_id,
                      uintptr_t signer_id_len,
                      const uint8_t *msg,
                      uintptr_t msg_len,
                      uint8_t *out_der_sig,
                      uintptr_t out_capacity,
                      uintptr_t *out_actual_len)
;

/*
 Verify a DER-encoded `(r, s)` signature against `msg` using the
 SM2 public key and `signer_id`. Returns [`GMCRYPTO_OK`] on
 valid; [`GMCRYPTO_ERR`] on invalid or any error.
 */

int gmcrypto_sm2_verify(const gmcrypto_sm2_pubkey_t *key,
                        const uint8_t *signer_id,
                        uintptr_t signer_id_len,
                        const uint8_t *msg,
                        uintptr_t msg_len,
                        const uint8_t *der_sig,
                        uintptr_t der_sig_len)
;

/*
 SM2 public-key encrypt. Output is GM/T 0009-2012 DER. RNG from
 `getrandom::SysRng`.
 */

int gmcrypto_sm2_encrypt(const gmcrypto_sm2_pubkey_t *key,
                         const uint8_t *pt,
                         uintptr_t pt_len,
                         uint8_t *out_der_ct,
                         uintptr_t out_capacity,
                         uintptr_t *out_actual_len)
;

/*
 SM2 private-key decrypt of a GM/T 0009-2012 DER ciphertext.
 */

int gmcrypto_sm2_decrypt(const gmcrypto_sm2_privkey_t *key,
                         const uint8_t *der_ct,
                         uintptr_t der_ct_len,
                         uint8_t *out_pt,
                         uintptr_t out_capacity,
                         uintptr_t *out_actual_len)
;

/*
 SM2 public-key encrypt; output in the modern raw byte-concat
 `C1 || C3 || C2` format. `C1` is the 65-byte SEC1-uncompressed
 point (`0x04 || X || Y`); `C3` is the 32-byte SM3 MAC; `C2` is
 `msg_len` bytes of XOR-ed ciphertext. Output length is exactly
 `65 + 32 + msg_len`.

 RNG is sourced from `getrandom::SysRng` internally (same as
 [`gmcrypto_sm2_encrypt`]). The W3 RNG-callback variant lands as a
 separate workstream.

 Same failure-mode posture as [`gmcrypto_sm2_encrypt`]: single
 [`GMCRYPTO_ERR`] on any failure mode (identity public key, KDF-
 zero retries exhausted).
 */

int gmcrypto_sm2_encrypt_c1c3c2(const gmcrypto_sm2_pubkey_t *key,
                                const uint8_t *pt,
                                uintptr_t pt_len,
                                uint8_t *out_raw_ct,
                                uintptr_t out_capacity,
                                uintptr_t *out_actual_len)
;

/*
 SM2 private-key decrypt of a modern raw byte-concat
 `C1 || C3 || C2` ciphertext. Input length must be at least
 `65 + 32 + 1 = 98` bytes (C1 + C3 + at least one C2 byte).

 Same failure-mode posture as [`gmcrypto_sm2_decrypt`]: single
 [`GMCRYPTO_ERR`] on any failure mode (malformed input, off-curve
 C1, identity C1, MAC mismatch, or KDF-zero detection). Caller
 cannot distinguish wrong-key from corrupt-ciphertext via timing
 or return code.
 */

int gmcrypto_sm2_decrypt_c1c3c2(const gmcrypto_sm2_privkey_t *key,
                                const uint8_t *raw_ct,
                                uintptr_t raw_ct_len,
                                uint8_t *out_pt,
                                uintptr_t out_capacity,
                                uintptr_t *out_actual_len)
;

/*
 SM2 private-key decrypt of a **legacy** raw byte-concat
 `C1 || C2 || C3` ciphertext. Decrypt-only — there is no emit path
 for the legacy ordering, and there will not be one in any v0.5+
 version (per `CLAUDE.md` "Don't" entry).

 The two raw byte-concat orderings (`C1 || C3 || C2` modern vs
 `C1 || C2 || C3` legacy) are NOT auto-detected. The caller MUST
 know which format their wire-data follows. Mis-feeding modern
 ciphertext to this entry point or vice-versa will fail at the MAC
 check (`GMCRYPTO_ERR`); the failure-mode invariant precludes the
 caller from distinguishing wrong-format from wrong-key.

 Same failure-mode posture as [`gmcrypto_sm2_decrypt_c1c3c2`]:
 single [`GMCRYPTO_ERR`] on any failure.
 */

int gmcrypto_sm2_decrypt_c1c2c3_legacy(const gmcrypto_sm2_privkey_t *key,
                                       const uint8_t *raw_ct,
                                       uintptr_t raw_ct_len,
                                       uint8_t *out_pt,
                                       uintptr_t out_capacity,
                                       uintptr_t *out_actual_len)
;

/*
 `_with_rng` variant of [`gmcrypto_sm2_sign`]. Identical contract
 except RNG bytes come from the caller's `rng_callback` rather
 than `getrandom::SysRng`.

 Returns [`GMCRYPTO_OK`] on success; [`GMCRYPTO_ERR`] on any
 failure including:
 - null `key` pointer
 - null `rng_callback` pointer
 - callback returned non-zero on any draw
 - signing produced no valid signature within the retry budget

 Per the failure-mode invariant, the caller cannot distinguish
 callback-error from signing-failure via return code or timing.
 */

int gmcrypto_sm2_sign_with_rng(const gmcrypto_sm2_privkey_t *key,
                               const uint8_t *signer_id,
                               uintptr_t signer_id_len,
                               const uint8_t *msg,
                               uintptr_t msg_len,
                               gmcrypto_rng_callback rng_callback,
                               void *rng_context,
                               uint8_t *out_der_sig,
                               uintptr_t out_capacity,
                               uintptr_t *out_actual_len)
;

/*
 `_with_rng` variant of [`gmcrypto_sm2_encrypt`]. Identical
 contract except RNG bytes come from the caller's `rng_callback`
 rather than `getrandom::SysRng`.

 Output is GM/T 0009-2012 DER (same as `gmcrypto_sm2_encrypt`).
 For raw byte-concat output (`C1 || C3 || C2`), use
 `gmcrypto_sm2_encrypt_c1c3c2` — v0.5 doesn't ship a
 `_c1c3c2_with_rng` combined variant; if needed, callers can
 re-encode the DER output via gmcrypto-core's
 `asn1::ciphertext::decode` + `raw_ciphertext::encode_c1c3c2`.

 Same `GMCRYPTO_ERR`-on-any-failure posture as
 `gmcrypto_sm2_sign_with_rng`.
 */

int gmcrypto_sm2_encrypt_with_rng(const gmcrypto_sm2_pubkey_t *key,
                                  const uint8_t *pt,
                                  uintptr_t pt_len,
                                  gmcrypto_rng_callback rng_callback,
                                  void *rng_context,
                                  uint8_t *out_der_ct,
                                  uintptr_t out_capacity,
                                  uintptr_t *out_actual_len)
;

#endif  /* GMCRYPTO_H_ */
