# SM2 SM2 can be used in digital signature. Algorithms below are related: - Key generation - Sign - Verify - Encrypt - Decrypt - Key exchange - Serialization and deserialization ## Create a New Contex By creating a context, libsm will initialize all the parameters used in those algorithms, including ECC parameters. ```rust use libsm::sm2::signature::{Pubkey, Seckey, Signature, SigCtx}; let ctx = SigCtx::new(); ``` ## Generate a Key pair ```rust let (pk, sk) = ctx.new_keypair(); ``` `pk` is a public key use for verifying. `sk` is a secret key used for signing. The public key can be derived from the secret key. ```rust let pk = ctx.pk_from_sk(&sk).unwrap(); ``` ## Sign and Verify ```rust let signature = ctx.sign(msg, &sk, &pk); let result: bool = ctx.verify(msg, &pk, &signature); ``` ## Encrypt and Decrypt ```rust let encrypt_ctx = EncryptCtx::new(klen, pk); let cipher_text = encrypt_ctx.encrypt(msg); let decrypt_ctx = DecryptCtx::new(klen, sk); let plain_text = decrypt_ctx.decrypt(&cipher); ``` ## Key Exchange ```rust let mut ctx1 = ExchangeCtxA::new(klen, id_a, id_b, pk_a, pk_b, sk_a); let mut ctx2 = ExchangeCtxB::new(klen, id_a, id_b, pk_a, pk_b, sk_b); let r_a_point = ctx1.exchange1(); let (r_b_point, s_b) = ctx2.exchange2(&r_a_point); let s_a = ctx1.exchange3(&r_b_point, s_b); let succ: bool = ctx2.exchange4(s_a, &r_a_point); ``` ## Serialization and Deserialization Keys and Signatures can be serialized to ``Vec``. ### Public Key ```rust let pk_raw = ctx.serialize_pubkey(&pk, true); let new_pk = ctx.load_pubkey(&pk_raw[..])?; ``` if you want to compress the public key, set the second parameter of `serialize_pubkey()` to `true`. An uncompressed public key will be 65 bytes, and the compressed key is 33 bytes. The return value of `load_pubkey()` is ``Result``. If the public key is invalid, an error will be returned. ### Secret Key ```rust let sk_raw = ctx.serialize_seckey(&sk); let new_sk = ctx.load_seckey(&sk_raw[..])?; ``` The output size of `serialize_seckey()` is 32 bytes. The return value of `load_seckey()` is `Result`. An error will be returned if the secret key is invalid. ### Signature Signatures can be encoded to DER format. ```rust let der = signature.der_encode(); let parsed_sig = Signature::der_decode(&der[..])?; ``` ## Details of How the Signature is Generated ### 1. Calculate Z_A First, an `ID` is needed. But in certification applications, no ID is given. So according to the standard, we use the default value, which is "1234567812345678". Then we calculate the length of ID in bits, which is 16 * 8 = 128, and name it as `ID_LEN`. `ID_LEN` should be a 16-bit number in big-endian. Then, the parameters of the elliptic curve should be given, include `a` and `b` in the curve eqution, and the coordinate of EC group generator, which is `x_G` and `y_G`. For details, see [the standard](http://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b965ce832cc34bc191cb1cde446b860d.pdf). And the coordinate of the public key should be appended, which is `x_A` and `y_A`. All of them are 32-byte big-endian numbers. Hash the concatenation using SM3, and we can get Z_A. ``` Z_A = SM3(ID_LEN || ID || a || b || x_G || y_G || x_A || y_A) ``` Z_A is a 32-byte big-endian number. ### 2. Calculate the Final Hash Prepend Z_A before the message, and hash again using SM3, then we can get `e`. ``` e = SM3(Z_A || M) ``` ### 3. Verify the Message Finally, `e` is verified by SM2 algorithm. See section 6.2 and 7.2 of the second part of [this documentation](http://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b791a9f908bb4803875ab6aeeb7b4e03.pdf). ``` isValid = SM2_Verify(e, signature, publicKey) ``` Signatures generated by this library is compatible with [GmSSL](https://github.com/guanzhi/GmSSL). Be careful, in SM2, we **cannot** recover the public key using the message and the signature, like what Ethereum did. Because before the verification, the public key must be provided to calculate `e`. To solve this, append the public key after the signature, and extract it before the verification. ![sm2 graph](./images/sm2.png)