Pure Elixir SM2 cryptographic operations (GM/T 0003-2012).
SM2 is a Chinese commercial cryptographic algorithm standard for:
- Key pair generation (ECDH)
- Digital signature (ECDSA with SM3 pre-hash)
- Encryption/decryption (ECDH + SM3 KDF + XOR + SM3 MAC)
This is a pure Elixir implementation with no external dependencies.
The explicit sign_standard/3, verify_standard/4, encrypt_standard/2, and
decrypt_standard/2 APIs implement ZA-aware signatures and the standard SM3
KDF. The shorter legacy APIs retain the historical Guomi-specific format;
legacy encryption repeats a 32-byte XOR mask and must not protect sensitive
data or be used as part of a production protocol.
Summary
Functions
Decrypts the legacy Guomi-specific compatibility ciphertext format.
Decrypts standard raw SM2 C1 || C3 || C2 ciphertext.
Encrypts with the legacy Guomi-specific C1 || C2 || C3 compatibility format.
Encrypts a non-empty message using the standard SM2 KDF and C1 || C3 || C2.
Generates an SM2 key pair.
Signs message with a 32-byte private key and returns raw r || s bytes.
Produces a standards-compatible raw SM2 signature using an explicit user ID.
Returns true; the current SM2 primitives are implemented entirely in Elixir.
Calculates the SM2 user identity digest ZA for user_id and public_key.
Verifies a raw 64-byte r || s compatibility signature.
Verifies a standards-compatible raw SM2 signature using the same user ID.
Types
Functions
@spec decrypt(binary(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Decrypts the legacy Guomi-specific compatibility ciphertext format.
Returns :invalid_ciphertext for malformed framing, :invalid_key for an
invalid private key, or :decryption_failed when authentication fails.
@spec decrypt_standard(binary(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Decrypts standard raw SM2 C1 || C3 || C2 ciphertext.
This function never falls back to the legacy Guomi format. Integrity failure,
an invalid ephemeral point, or an all-zero KDF returns :decryption_failed.
@spec encrypt(binary() | iodata(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Encrypts with the legacy Guomi-specific C1 || C2 || C3 compatibility format.
This format repeats a 32-byte XOR mask for longer messages and must not be used
for sensitive data or production protocols. Invalid iodata returns
{:error, :invalid_input}.
@spec encrypt_standard(binary() | iodata(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Encrypts a non-empty message using the standard SM2 KDF and C1 || C3 || C2.
C1 is a 65-byte uncompressed point, C3 is the 32-byte SM3 integrity digest, and C2 has the same length as the plaintext. This API has not undergone an independent security audit.
Generates an SM2 key pair.
The private key is a 32-byte big-endian integer. The public key is a 65-byte
uncompressed point encoded as 0x04 || x || y.
@spec sign(binary() | iodata(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Signs message with a 32-byte private key and returns raw r || s bytes.
This compatibility API signs SM3(message) and does not calculate the SM2
user identity digest ZA. Do not assume interoperability with standard SM2
signing APIs. Invalid iodata returns {:error, :invalid_input}.
@spec sign_standard(binary() | iodata(), binary(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Produces a standards-compatible raw SM2 signature using an explicit user ID.
The signed digest is SM3(ZA || message). The result is 64-byte raw
r || s; DER encoding is intentionally not implicit.
@spec supported?() :: boolean()
Returns true; the current SM2 primitives are implemented entirely in Elixir.
@spec user_identity_digest(binary(), binary()) :: {:ok, binary()} | {:error, error_reason()}
Calculates the SM2 user identity digest ZA for user_id and public_key.
The user ID must be a binary no longer than 8191 bytes so its bit length fits
the standard 16-bit ENTLA field.
@spec verify(binary() | iodata(), binary(), binary()) :: {:ok, boolean()} | {:error, error_reason()}
Verifies a raw 64-byte r || s compatibility signature.
Returns {:ok, false} for a well-formed but invalid signature and an error for
malformed keys, signatures, or message input. This API does not calculate ZA.
@spec verify_standard(binary() | iodata(), binary(), binary(), binary()) :: {:ok, boolean()} | {:error, error_reason()}
Verifies a standards-compatible raw SM2 signature using the same user ID.
Returns {:ok, false} when the inputs are well formed but the signature or
user ID does not match.