#![doc(html_no_source)]
//! 此密码库实现了中华人民共和国国家密码管理局发布的商用密码算法。\
//! This cryptographic library implements the ShangMi algorithms
//! which issued by the State Cryptography Administration of the People's Republic of China.
//!
//! # 支持列表（Available Algoruthms Table）
//!
//! * 密码杂凑算法（Cryptographic Hash Algoruthms）
//!
//!   * [SM3](self::cryptographic_hashs::SM3) - SM3密码杂凑算法（ShangMi 3 Cryptographic Hash Algoruthm）
//!   * [SHA-1](self::cryptographic_hashs::SHA1) - 安全散列算法1（Secure Hash Algorithm 1）
//!   * [SHA-2](self::cryptographic_hashs::SHA2) - 安全散列算法2（Secure Hash Algorithm 2）
//!
//! * 分组密码算法（Block Cipher Algoruthms）
//!
//!   * [SM4](self::block_ciphers::SM4) - SM4分组密码算法（ShangMi 4 Block Cipher Algoruthm）
//!
//! * 消息鉴别码算法（Message Authentication Code Algoruthms）
//!
//!   * [HMAC](self::mac::HMAC) - 密钥杂凑消息鉴别码（Keyed-Hash Message Authentication Code）
//!
//! * 分组工作模式（Operation Modes for Block Cipher）
//!
//!   * [ECB](self::block_ciphers::OperationMode::ECB) - 电码本（Electronic Codebook）
//!   * [CBC](self::block_ciphers::OperationMode::CBC) - 密文分组链接（Cipher Block Chaining）
//!   * [CFB](self::block_ciphers::OperationMode::CFB) - 密文反馈（Cipher Feedback）
//!   * [OFB](self::block_ciphers::OperationMode::OFB) - 输出反馈（Output Feedback）
//!
//! # 示例（Examples）
//!
//!   * 使用密文分组链接工作模式的SM4分组密码算法的流式加密计算（SM4-CBC Encryption Stream Mode Calculate）
//!
//! ```rust
//! # fn main() -> Result<(), ()> {
//! use neuedu_cryptos::common::PaddingMethod;
//! use neuedu_cryptos::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};
//!
//! # const KEY: [u8; 16] = [
//! #     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
//! #     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
//! # ];
//! # const IV: [u8; 16] = [
//! #     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
//! #     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
//! # ];
//! # const PLAIN_MESSAGE: [u8; 16] = [
//! #     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
//! #     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
//! # ];
//! #
//! let mut instance = SM4::new(
//!     KEY,
//!     Operation::Encrypt,
//!     Some(OperationMode::CBC(IV.into())),
//!     Some(PaddingMethod::Method1),
//! )?;
//!
//! let mut cipher = Vec::<u8>::new();
//! cipher.append(&mut instance.update(&PLAIN_MESSAGE)?);
//! cipher.append(&mut instance.r#final()?);
//! #
//! # assert_eq!(cipher, [
//! #     0x26, 0x77, 0xF4, 0x6B, 0x09, 0xC1, 0x22, 0xCC,
//! #     0x97, 0x55, 0x33, 0x10, 0x5B, 0xD4, 0xA2, 0x2A,
//! #     0x3B, 0x88, 0x0E, 0x68, 0x67, 0x77, 0x25, 0x22,
//! #     0xAE, 0x55, 0xD2, 0xF0, 0xAE, 0x74, 0x78, 0xAE,
//! # ]);
//! #
//! #     Ok(())
//! # }
//! ```
//!
//! * 基于SM3密码杂凑算法的密钥杂凑消息鉴别码的块式计算（HMAC-SM3 Block Mode Calculate）
//! ```rust
//! # fn main() -> Result<(), ()> {
//! use neuedu_cryptos::mac::hmac_sm3;
//!
//! let mac = hmac_sm3(b"key", b"message")?;
//! #
//! # assert_eq!(mac, [
//! #     0x34, 0xC9, 0x0B, 0x29, 0x1A, 0x80, 0xB7, 0xFD,
//! #     0x7F, 0x2B, 0xE4, 0x3D, 0x68, 0x39, 0x35, 0xBA,
//! #     0xB9, 0xD1, 0x49, 0x16, 0x46, 0x66, 0xC4, 0xEF,
//! #     0x88, 0x57, 0xC8, 0x15, 0xCF, 0x2E, 0xF8, 0x32,
//! # ]);
//! #
//! #     Ok(())
//! # }
//! ```

pub mod block_ciphers;
pub mod common;
pub mod cryptographic_hashs;
pub mod mac;
mod libs;


#[cfg(test)]
mod tests {

    use crate::common::bytes_to_hexstring;
    use crate::cryptographic_hashs::CryptographicHashImpl;

    #[test]
    fn sm3_3() {
        use crate::cryptographic_hashs::SM3;

        let mut sm3 = SM3::default();
        sm3.update(b"abc").unwrap();
        let digest = sm3.r#final().unwrap();

        assert_eq!(digest, [
            0x66, 0xC7, 0xF0, 0xF4, 0x62, 0xEE, 0xED, 0xD9, 0xD1, 0xF2, 0xD4, 0x6B, 0xDC, 0x10, 0xE4, 0xE2,
            0x41, 0x67, 0xC4, 0x87, 0x5C, 0xF2, 0xF7, 0xA2, 0x29, 0x7D, 0xA0, 0x2B, 0x8F, 0x4B, 0xA8, 0xE0,
        ]);
        assert_eq!(bytes_to_hexstring(&digest), "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0");
    }

    #[test]
    fn sm3_31() {
        use crate::cryptographic_hashs::sm3;

        let digest = sm3(b"abcdabcdabcdabcdabcdabcdabcdabc").unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "632a65359991cd20ac31a7d5d174dd83bf2bc906c2c20a59a722f366d1a4d93d");
    }

    #[test]
    fn sm3_64() {
        use crate::cryptographic_hashs::SM3;

        const MESSAGE: &[u8] = b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";

        let mut sm3 = SM3::default();
        sm3.update(MESSAGE).unwrap();
        let digest = sm3.r#final().unwrap();
        assert_eq!(digest, [
            222, 190, 159, 249, 34, 117, 184, 161, 56, 96, 72, 137, 193, 142, 90, 77,
            111, 219, 112, 229, 56, 126, 87, 101, 41, 61, 203, 163, 156, 12, 87, 50,
        ]);
    }

    #[test]
    fn sha1_0() {
        use crate::cryptographic_hashs::SHA1;

        let mut sha1 = SHA1::default();
        sha1.update(b"").unwrap();
        let digest = sha1.r#final().unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "da39a3ee5e6b4b0d3255bfef95601890afd80709");
    }

    #[test]
    fn sha224_0() {
        use crate::cryptographic_hashs::{CryptographicHash, SHA2};

        let mut sha2 = SHA2::new(CryptographicHash::SHA224);
        sha2.update(b"").unwrap();
        let digest = sha2.r#final().unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f");
    }

    #[test]
    fn sha256_0() {
        use crate::cryptographic_hashs::{CryptographicHash, SHA2};

        let mut sha2 = SHA2::new(CryptographicHash::SHA256);
        sha2.update(b"").unwrap();
        let digest = sha2.r#final().unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
    }

    #[test]
    fn sha384_0() {
        use crate::cryptographic_hashs::{CryptographicHash, SHA2};

        let mut sha2 = SHA2::new(CryptographicHash::SHA384);
        sha2.update(b"").unwrap();
        let digest = sha2.r#final().unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b");
    }

    #[test]
    fn sha512_0() {
        use crate::cryptographic_hashs::{CryptographicHash, SHA2};

        let mut sha2 = SHA2::new(CryptographicHash::SHA512);
        sha2.update(b"").unwrap();
        let digest = sha2.r#final().unwrap();

        assert_eq!(bytes_to_hexstring(&digest), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
    }

    #[test]
    fn hmac_sm3_3() {
        use crate::cryptographic_hashs::CryptographicHash;
        use crate::mac::HMAC;

        const M3: &[u8] = b"abc";

        let mut hmac_sm3 = HMAC::new(M3, CryptographicHash::SM3);
        hmac_sm3.update(M3).unwrap();
        let mac = hmac_sm3.r#final().unwrap();
        assert_eq!(mac, [
            129, 18, 210, 74, 9, 238, 218, 67, 234, 89, 95, 60, 254, 251, 42, 52,
            133, 105, 119, 206, 74, 193, 208, 63, 204, 32, 103, 174, 100, 197, 227, 241,
        ]);
    }

    #[test]
    fn hmac_sm3_64() {
        use crate::mac::hmac_sm3;

        const M64: &[u8] = b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";

        let mac = hmac_sm3(M64, M64).unwrap();

        assert_eq!(mac, [
            220, 54, 122, 224, 123, 151, 172, 158, 180, 229, 118, 45, 91, 133, 224, 26,
            133, 139, 9, 19, 146, 54, 90, 145, 60, 193, 122, 96, 163, 228, 121, 200,
        ]);
    }

    #[test]
    fn sm4_ecb_padding_none() {
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), None).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(encrypt_result, [
            0x68, 0x1E, 0xDF, 0x34, 0xD2, 0x06, 0x96, 0x5E, 0x86, 0xB3, 0xE9, 0x4F, 0x53, 0x6E, 0x42, 0x46,
            0x68, 0x1E, 0xDF, 0x34, 0xD2, 0x06, 0x96, 0x5E, 0x86, 0xB3, 0xE9, 0x4F, 0x53, 0x6E, 0x42, 0x46,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), None).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);
    }

    #[test]
    fn sm4_ecb_padding_pkcs7() {
        use crate::common::PaddingMethod;
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_ALIGN: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_UNALIGN: [u8; 15] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method1)).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
            0, 42, 138, 78, 250, 134, 60, 202, 208, 36, 172, 3, 0, 187, 64, 210,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method1)).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method1)).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE_UNALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
            236, 33, 220, 50, 174, 93, 235, 26, 85, 223, 83, 247, 213, 117, 161, 33
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method1)).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32,
        ]);
    }

    #[test]
    fn sm4_ecb_padding_bit() {
        use crate::common::PaddingMethod;
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_ALIGN: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_UNALIGN: [u8; 15] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method2)).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
            140, 51, 142, 90, 39, 227, 73, 190, 174, 57, 33, 79, 237, 169, 112, 153,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method2)).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method2)).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE_UNALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
            213, 115, 115, 28, 246, 131, 231, 82, 134, 205, 123, 10, 160, 214, 47, 172,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method2)).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32,
        ]);
    }

    #[test]
    fn sm4_ecb_padding_zero() {
        use crate::common::PaddingMethod;
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_ALIGN: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE_UNALIGN: [u8; 15] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method3(Some(16)))).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            255, 243, 176, 128, 169, 64, 199, 147, 175, 127, 77, 40, 173, 209, 21, 34,
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method3(None))).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method3(Some(31)))).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE_ALIGN).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE_UNALIGN).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());

        assert_eq!(encrypt_result, [
            61, 248, 63, 100, 42, 49, 85, 19, 230, 215, 221, 221, 206, 181, 117, 72,
            104, 30, 223, 52, 210, 6, 150, 94, 134, 179, 233, 79, 83, 110, 66, 70,
            201, 182, 145, 178, 19, 105, 17, 254, 68, 57, 146, 28, 163, 250, 129, 95,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::ECB), Some(PaddingMethod::Method3(None))).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32,
        ]);
    }

    #[test]
    fn sm4_cbc_padding_none() {
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const IV: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::CBC(IV.into())), None).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(encrypt_result, [
            0x26, 0x77, 0xF4, 0x6B, 0x09, 0xC1, 0x22, 0xCC, 0x97, 0x55, 0x33, 0x10, 0x5B, 0xD4, 0xA2, 0x2A,
            0xF6, 0x12, 0x5F, 0x72, 0x75, 0xCE, 0x55, 0x2C, 0x3A, 0x2B, 0xBC, 0xF5, 0x33, 0xDE, 0x8A, 0x3B,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::CBC(IV.into())), None).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);
    }

    #[test]
    fn sm4_cfb_padding_none() {
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const IV: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::CFB(IV.into())), None).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(encrypt_result, [
            0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1, 0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
            0x9E, 0xD2, 0x58, 0xA8, 0x5A, 0x04, 0x67, 0xCC, 0x92, 0xAA, 0xB3, 0x93, 0xDD, 0x97, 0x89, 0x95,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::CFB(IV.into())), None).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);
    }

    #[test]
    fn sm4_ofb_padding_none() {
        use crate::block_ciphers::{BlockCipherImpl, Operation, OperationMode, SM4};

        const KEY: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const IV: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];
        const MESSAGE: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10];

        let mut sm4 = SM4::new(KEY, Operation::Encrypt, Some(OperationMode::OFB(IV.into())), None).unwrap();
        let mut encrypt_result = Vec::<u8>::new();
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.update(&MESSAGE).unwrap());
        encrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(encrypt_result, [
            0x69, 0x3D, 0x9A, 0x53, 0x5B, 0xAD, 0x5B, 0xB1, 0x78, 0x6F, 0x53, 0xD7, 0x25, 0x3A, 0x70, 0x56,
            0xF2, 0x07, 0x5D, 0x28, 0xB5, 0x23, 0x5F, 0x58, 0xD5, 0x00, 0x27, 0xE4, 0x17, 0x7D, 0x2B, 0xCE,
        ]);

        let mut sm4 = SM4::new(KEY, Operation::Decrypt, Some(OperationMode::OFB(IV.into())), None).unwrap();
        let mut decrypt_result = Vec::<u8>::new();
        decrypt_result.extend(&sm4.update(&encrypt_result).unwrap());
        decrypt_result.extend(&sm4.r#final().unwrap());
        assert_eq!(decrypt_result, [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
        ]);
    }
}
