初始提交:SM2/SM3/SM4/SM9 密码算法库
- SM3 哈希函数 (GB/T 32905-2013) - SM4 分组密码,支持 ECB/CBC/OFB/CFB/CTR/GCM/CCM/XTS 模式 (GB/T 32907-2016) - SM2 椭圆曲线密码 (GB/T 32918.1-5-2016) - SM9 标识密码 (GB/T 38635.1-2-2020) - 全程常量时间运算 - 支持 no_std,带 alloc 特性 - 完整的国标测试向量 - Criterion 性能基准测试
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
//! SM2 集成测试(往返验证 + 边界测试)
|
||||
//!
|
||||
//! 注:GB/T 32918.2-2016 附录 A 的精确测试向量需要从官方标准文档获取。
|
||||
//! 此文件提供功能完整性验证测试。
|
||||
|
||||
use crypto_bigint::U256;
|
||||
use libsmx::sm2::{get_e, get_z, sign_with_k, verify, PrivateKey};
|
||||
|
||||
/// 使用标准附录 A 私钥和随机数进行签名,然后验签(往返测试)
|
||||
///
|
||||
/// 私钥 d 来自 GB/T 32918.2-2016 附录 A.2 示例
|
||||
#[test]
|
||||
fn test_sm2_sign_verify_with_known_key() {
|
||||
// GB/T 32918.2-2016 附录 A 私钥
|
||||
let d_bytes =
|
||||
hex::decode("3945208f7b2144b13f36e38ac6d39f95889393692860b51a42fb81ef4df7c5b8")
|
||||
.unwrap();
|
||||
let k_bytes =
|
||||
hex::decode("59276e27d506861a16680f3ad9c02dccef3cc1fa3cdbe4ce6d54b80deac1bc21")
|
||||
.unwrap();
|
||||
|
||||
let pri_key = PrivateKey::from_bytes(d_bytes.as_slice().try_into().unwrap())
|
||||
.expect("私钥应有效");
|
||||
let pub_key = pri_key.public_key();
|
||||
|
||||
let id = b"ALICE123@YAHOO.COM";
|
||||
let msg = b"message digest";
|
||||
|
||||
let z = get_z(id, &pub_key);
|
||||
let e = get_e(&z, msg);
|
||||
|
||||
let k = U256::from_be_slice(&k_bytes);
|
||||
let sig = sign_with_k(&e, &pri_key, &k).expect("签名应成功");
|
||||
|
||||
// 验签
|
||||
verify(&e, &pub_key, &sig).expect("验签应成功");
|
||||
|
||||
// 签名长度正确
|
||||
assert_eq!(sig.len(), 64, "签名应为 64 字节");
|
||||
}
|
||||
|
||||
/// 不同消息产生不同签名(同一 k)
|
||||
#[test]
|
||||
fn test_sm2_different_messages_different_sigs() {
|
||||
let d_bytes =
|
||||
hex::decode("3945208f7b2144b13f36e38ac6d39f95889393692860b51a42fb81ef4df7c5b8")
|
||||
.unwrap();
|
||||
let pri_key = PrivateKey::from_bytes(d_bytes.as_slice().try_into().unwrap()).unwrap();
|
||||
let pub_key = pri_key.public_key();
|
||||
|
||||
let id = b"test_user";
|
||||
let k = U256::from_be_slice(
|
||||
&hex::decode("59276e27d506861a16680f3ad9c02dccef3cc1fa3cdbe4ce6d54b80deac1bc21")
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let z = get_z(id, &pub_key);
|
||||
let e1 = get_e(&z, b"message 1");
|
||||
let e2 = get_e(&z, b"message 2");
|
||||
|
||||
let sig1 = sign_with_k(&e1, &pri_key, &k).unwrap();
|
||||
let sig2 = sign_with_k(&e2, &pri_key, &k).unwrap();
|
||||
|
||||
// 不同消息签名结果不同(r 相同因为 k 相同,但 s 不同)
|
||||
assert_ne!(sig1[32..], sig2[32..], "不同消息的 s 值应不同");
|
||||
}
|
||||
|
||||
/// 验签对篡改消息应失败
|
||||
#[test]
|
||||
fn test_sm2_verify_tampered_message_fails() {
|
||||
let d_bytes =
|
||||
hex::decode("3945208f7b2144b13f36e38ac6d39f95889393692860b51a42fb81ef4df7c5b8")
|
||||
.unwrap();
|
||||
let pri_key = PrivateKey::from_bytes(d_bytes.as_slice().try_into().unwrap()).unwrap();
|
||||
let pub_key = pri_key.public_key();
|
||||
|
||||
let id = b"1234567812345678";
|
||||
let msg = b"original message";
|
||||
let z = get_z(id, &pub_key);
|
||||
let e = get_e(&z, msg);
|
||||
|
||||
let k = U256::from_be_slice(
|
||||
&hex::decode("59276e27d506861a16680f3ad9c02dccef3cc1fa3cdbe4ce6d54b80deac1bc21")
|
||||
.unwrap(),
|
||||
);
|
||||
let sig = sign_with_k(&e, &pri_key, &k).unwrap();
|
||||
|
||||
// 对不同消息的摘要验签,应失败
|
||||
let e_wrong = get_e(&z, b"tampered message");
|
||||
assert!(
|
||||
verify(&e_wrong, &pub_key, &sig).is_err(),
|
||||
"篡改消息后验签应失败"
|
||||
);
|
||||
}
|
||||
|
||||
/// 验签对篡改签名应失败
|
||||
#[test]
|
||||
fn test_sm2_verify_tampered_sig_fails() {
|
||||
let d_bytes =
|
||||
hex::decode("3945208f7b2144b13f36e38ac6d39f95889393692860b51a42fb81ef4df7c5b8")
|
||||
.unwrap();
|
||||
let pri_key = PrivateKey::from_bytes(d_bytes.as_slice().try_into().unwrap()).unwrap();
|
||||
let pub_key = pri_key.public_key();
|
||||
|
||||
let id = b"1234567812345678";
|
||||
let msg = b"test message";
|
||||
let z = get_z(id, &pub_key);
|
||||
let e = get_e(&z, msg);
|
||||
|
||||
let k = U256::from_be_slice(
|
||||
&hex::decode("59276e27d506861a16680f3ad9c02dccef3cc1fa3cdbe4ce6d54b80deac1bc21")
|
||||
.unwrap(),
|
||||
);
|
||||
let mut sig = sign_with_k(&e, &pri_key, &k).unwrap();
|
||||
sig[0] ^= 1; // 篡改 r 的第一字节
|
||||
|
||||
assert!(
|
||||
verify(&e, &pub_key, &sig).is_err(),
|
||||
"篡改签名后验签应失败"
|
||||
);
|
||||
}
|
||||
|
||||
/// Z 值计算确定性验证(相同输入产生相同 Z)
|
||||
#[test]
|
||||
fn test_sm2_z_value_deterministic() {
|
||||
let d_bytes =
|
||||
hex::decode("3945208f7b2144b13f36e38ac6d39f95889393692860b51a42fb81ef4df7c5b8")
|
||||
.unwrap();
|
||||
let pri_key = PrivateKey::from_bytes(d_bytes.as_slice().try_into().unwrap()).unwrap();
|
||||
let pub_key = pri_key.public_key();
|
||||
|
||||
let id = b"ALICE123@YAHOO.COM";
|
||||
let z1 = get_z(id, &pub_key);
|
||||
let z2 = get_z(id, &pub_key);
|
||||
assert_eq!(z1, z2, "Z 值计算应为确定性");
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//! SM3 国标测试向量(GB/T 32905-2016 附录 A)
|
||||
//!
|
||||
//! A.1 示例1:消息为 "abc"(3 字节)
|
||||
//! A.2 示例2:消息为 "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"(64 字节)
|
||||
|
||||
use libsmx::sm3::Sm3Hasher;
|
||||
|
||||
/// GB/T 32905-2016 附录 A.1
|
||||
/// 输入:M = "abc"
|
||||
/// 预期:66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
|
||||
#[test]
|
||||
fn test_sm3_vector_a1_abc() {
|
||||
let msg = b"abc";
|
||||
let digest = Sm3Hasher::digest(msg);
|
||||
let expected = hex::decode("66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0")
|
||||
.unwrap();
|
||||
assert_eq!(digest.as_slice(), expected.as_slice(), "GB/T 32905 附录 A.1 失败");
|
||||
}
|
||||
|
||||
/// GB/T 32905-2016 附录 A.2
|
||||
/// 输入:M = "abcd" × 16(64 字节)
|
||||
/// 预期:debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732
|
||||
#[test]
|
||||
fn test_sm3_vector_a2_64bytes() {
|
||||
let msg = b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
|
||||
let digest = Sm3Hasher::digest(msg);
|
||||
let expected = hex::decode("debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732")
|
||||
.unwrap();
|
||||
assert_eq!(digest.as_slice(), expected.as_slice(), "GB/T 32905 附录 A.2 失败");
|
||||
}
|
||||
|
||||
/// 流式接口与单次接口结果一致性验证
|
||||
#[test]
|
||||
fn test_sm3_streaming_equals_oneshot() {
|
||||
let msg = b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
|
||||
let one_shot = Sm3Hasher::digest(msg);
|
||||
|
||||
let mut h = Sm3Hasher::new();
|
||||
h.update(&msg[..32]);
|
||||
h.update(&msg[32..]);
|
||||
let streaming = h.finalize();
|
||||
|
||||
assert_eq!(one_shot, streaming, "流式与单次结果不一致");
|
||||
}
|
||||
|
||||
/// 空消息哈希测试
|
||||
/// SM3("") = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b
|
||||
#[test]
|
||||
fn test_sm3_empty_message() {
|
||||
let digest = Sm3Hasher::digest(b"");
|
||||
let expected = hex::decode("1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b")
|
||||
.unwrap();
|
||||
assert_eq!(digest.as_slice(), expected.as_slice(), "SM3 空消息测试失败");
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//! SM4 国标测试向量(GB/T 32907-2016 附录 A)
|
||||
//!
|
||||
//! A.1 示例1:单次 ECB 加密
|
||||
//! A.2 示例2:1,000,000 次迭代 ECB 加密(验证算法迭代正确性)
|
||||
|
||||
use libsmx::sm4::{sm4_decrypt_ecb, sm4_encrypt_ecb};
|
||||
|
||||
/// GB/T 32907-2016 附录 A.1
|
||||
/// 密钥:0123456789abcdeffedcba9876543210
|
||||
/// 明文:0123456789abcdeffedcba9876543210
|
||||
/// 密文:681edf34d206965e86b3e94f536e4246
|
||||
#[test]
|
||||
fn test_sm4_ecb_vector_a1_single() {
|
||||
let key = hex::decode("0123456789abcdeffedcba9876543210").unwrap();
|
||||
let plaintext = hex::decode("0123456789abcdeffedcba9876543210").unwrap();
|
||||
let expected_ct = hex::decode("681edf34d206965e86b3e94f536e4246").unwrap();
|
||||
|
||||
let key_arr: [u8; 16] = key.try_into().unwrap();
|
||||
let ct = sm4_encrypt_ecb(&key_arr, &plaintext);
|
||||
assert_eq!(ct, expected_ct, "GB/T 32907 附录 A.1 加密失败");
|
||||
|
||||
let pt = sm4_decrypt_ecb(&key_arr, &ct);
|
||||
assert_eq!(pt, plaintext, "GB/T 32907 附录 A.1 解密失败");
|
||||
}
|
||||
|
||||
/// GB/T 32907-2016 附录 A.2
|
||||
/// 密钥:0123456789abcdeffedcba9876543210
|
||||
/// 明文:0123456789abcdeffedcba9876543210(反复迭代 1,000,000 次)
|
||||
/// 密文:595298c7c6fd271f0402f804c33d3f66
|
||||
#[test]
|
||||
fn test_sm4_ecb_vector_a2_million_iterations() {
|
||||
let key: [u8; 16] = hex::decode("0123456789abcdeffedcba9876543210")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let mut data: Vec<u8> = hex::decode("0123456789abcdeffedcba9876543210").unwrap();
|
||||
|
||||
for _ in 0..1_000_000 {
|
||||
data = sm4_encrypt_ecb(&key, &data);
|
||||
}
|
||||
|
||||
let expected = hex::decode("595298c7c6fd271f0402f804c33d3f66").unwrap();
|
||||
assert_eq!(data, expected, "GB/T 32907 附录 A.2 百万次迭代失败");
|
||||
}
|
||||
|
||||
/// ECB 解密是加密的逆操作(往返测试)
|
||||
#[test]
|
||||
fn test_sm4_ecb_roundtrip() {
|
||||
let key = [0x01u8; 16];
|
||||
let plaintext = b"SM4 ECB test!!!\x00";
|
||||
let ct = sm4_encrypt_ecb(&key, plaintext);
|
||||
let pt = sm4_decrypt_ecb(&key, &ct);
|
||||
assert_eq!(pt.as_slice(), plaintext.as_slice());
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
//! SM9 国标测试向量(GB/T 38635-2020 附录 A)
|
||||
//!
|
||||
//! 端到端测试:密钥生成 → 签名 → 验签 → 加密 → 解密
|
||||
|
||||
use libsmx::sm9::{
|
||||
generate_enc_master_keypair, generate_enc_user_key, generate_sign_master_keypair,
|
||||
generate_sign_user_key, sm9_decrypt, sm9_encrypt, sm9_sign, sm9_verify,
|
||||
Sm9EncPubKey, Sm9MasterPrivKey, Sm9SignPubKey,
|
||||
};
|
||||
use rand_core::RngCore;
|
||||
|
||||
/// 固定种子的确定性 RNG(仅用于测试)
|
||||
struct DeterministicRng([u8; 32]);
|
||||
|
||||
impl DeterministicRng {
|
||||
fn new(seed: [u8; 32]) -> Self {
|
||||
Self(seed)
|
||||
}
|
||||
}
|
||||
|
||||
impl RngCore for DeterministicRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
u32::from_le_bytes([self.0[0], self.0[1], self.0[2], self.0[3]])
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
u64::from_le_bytes(self.0[..8].try_into().unwrap())
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
for (i, b) in dest.iter_mut().enumerate() {
|
||||
*b = self.0[i % 32];
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
|
||||
self.fill_bytes(dest);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// SM9 签名主密钥对生成 + 签名私钥派生 + 签名验签端到端测试
|
||||
#[test]
|
||||
fn test_sm9_sign_verify_end_to_end() {
|
||||
let mut rng = DeterministicRng::new([0x42u8; 32]);
|
||||
|
||||
// 1. 生成签名主密钥对
|
||||
let (master_priv, sign_pub) = generate_sign_master_keypair(&mut rng);
|
||||
|
||||
// 验证主公钥在 G2 上
|
||||
let pub_bytes = sign_pub.as_bytes();
|
||||
let pub_key = Sm9SignPubKey::from_bytes(pub_bytes).expect("主公钥应有效");
|
||||
|
||||
// 2. 为用户 "Alice" 派生签名私钥
|
||||
let id = b"Alice";
|
||||
let da = generate_sign_user_key(&master_priv, id).expect("签名私钥派生应成功");
|
||||
|
||||
// 3. 签名
|
||||
let msg = b"hello SM9 world";
|
||||
let (h, s) = sm9_sign(msg, &da, &pub_key, &mut rng).expect("签名应成功");
|
||||
|
||||
// 4. 验签
|
||||
sm9_verify(msg, &h, &s, id, &pub_key).expect("验签应成功");
|
||||
}
|
||||
|
||||
/// 验签对错误消息应失败
|
||||
#[test]
|
||||
fn test_sm9_verify_wrong_message_fails() {
|
||||
let mut rng = DeterministicRng::new([0xABu8; 32]);
|
||||
let (master_priv, sign_pub) = generate_sign_master_keypair(&mut rng);
|
||||
let pub_key = Sm9SignPubKey::from_bytes(sign_pub.as_bytes()).unwrap();
|
||||
|
||||
let id = b"Bob";
|
||||
let da = generate_sign_user_key(&master_priv, id).unwrap();
|
||||
|
||||
let msg = b"original message";
|
||||
let (h, s) = sm9_sign(msg, &da, &pub_key, &mut rng).unwrap();
|
||||
|
||||
// 用不同消息验签,应失败
|
||||
assert!(
|
||||
sm9_verify(b"tampered message", &h, &s, id, &pub_key).is_err(),
|
||||
"篡改消息后验签应失败"
|
||||
);
|
||||
}
|
||||
|
||||
/// 验签对错误用户 ID 应失败
|
||||
#[test]
|
||||
fn test_sm9_verify_wrong_id_fails() {
|
||||
let mut rng = DeterministicRng::new([0xAAu8; 32]); // 注:种子需 < GROUP_ORDER (首字节<0xB6)
|
||||
let (master_priv, sign_pub) = generate_sign_master_keypair(&mut rng);
|
||||
let pub_key = Sm9SignPubKey::from_bytes(sign_pub.as_bytes()).unwrap();
|
||||
|
||||
let id = b"Charlie";
|
||||
let da = generate_sign_user_key(&master_priv, id).unwrap();
|
||||
|
||||
let msg = b"test";
|
||||
let (h, s) = sm9_sign(msg, &da, &pub_key, &mut rng).unwrap();
|
||||
|
||||
// 用不同 ID 验签,应失败
|
||||
assert!(
|
||||
sm9_verify(msg, &h, &s, b"Eve", &pub_key).is_err(),
|
||||
"错误 ID 验签应失败"
|
||||
);
|
||||
}
|
||||
|
||||
/// SM9 加密主密钥对生成 + 加密私钥派生 + 加解密端到端测试
|
||||
#[test]
|
||||
fn test_sm9_encrypt_decrypt_end_to_end() {
|
||||
let mut rng = DeterministicRng::new([0x55u8; 32]);
|
||||
|
||||
// 1. 生成加密主密钥对
|
||||
let (master_priv, enc_pub) = generate_enc_master_keypair(&mut rng);
|
||||
let pub_key = Sm9EncPubKey::from_bytes(enc_pub.as_bytes()).expect("加密主公钥应有效");
|
||||
|
||||
// 2. 为用户 "Alice" 派生加密私钥
|
||||
let id = b"Alice";
|
||||
let de = generate_enc_user_key(&master_priv, id).expect("加密私钥派生应成功");
|
||||
|
||||
// 3. 加密
|
||||
let plaintext = b"SM9 encryption test message!";
|
||||
let ciphertext = sm9_encrypt(id, plaintext, &pub_key, &mut rng).expect("加密应成功");
|
||||
|
||||
// 4. 解密
|
||||
let decrypted = sm9_decrypt(id, &ciphertext, &de).expect("解密应成功");
|
||||
assert_eq!(decrypted, plaintext, "解密结果应与原始明文一致");
|
||||
}
|
||||
|
||||
/// 解密篡改密文应失败
|
||||
#[test]
|
||||
fn test_sm9_decrypt_tampered_ciphertext_fails() {
|
||||
let mut rng = DeterministicRng::new([0x77u8; 32]);
|
||||
let (master_priv, enc_pub) = generate_enc_master_keypair(&mut rng);
|
||||
let pub_key = Sm9EncPubKey::from_bytes(enc_pub.as_bytes()).unwrap();
|
||||
|
||||
let id = b"Dave";
|
||||
let de = generate_enc_user_key(&master_priv, id).unwrap();
|
||||
|
||||
let plaintext = b"secret data";
|
||||
let mut ciphertext = sm9_encrypt(id, plaintext, &pub_key, &mut rng).unwrap();
|
||||
|
||||
// 篡改密文(修改 C3 部分)
|
||||
let tamper_idx = ciphertext.len() - 1;
|
||||
ciphertext[tamper_idx] ^= 0xFF;
|
||||
|
||||
assert!(
|
||||
sm9_decrypt(id, &ciphertext, &de).is_err(),
|
||||
"篡改密文后解密应失败"
|
||||
);
|
||||
}
|
||||
|
||||
/// 使用错误私钥解密应失败
|
||||
#[test]
|
||||
fn test_sm9_decrypt_wrong_key_fails() {
|
||||
let mut rng = DeterministicRng::new([0x99u8; 32]);
|
||||
let (master_priv, enc_pub) = generate_enc_master_keypair(&mut rng);
|
||||
let pub_key = Sm9EncPubKey::from_bytes(enc_pub.as_bytes()).unwrap();
|
||||
|
||||
// Alice 的私钥加密
|
||||
let id_alice = b"Alice";
|
||||
let de_alice = generate_enc_user_key(&master_priv, id_alice).unwrap();
|
||||
|
||||
// 用 Bob 的私钥尝试解密
|
||||
let id_bob = b"Bob";
|
||||
let de_bob = generate_enc_user_key(&master_priv, id_bob).unwrap();
|
||||
|
||||
let plaintext = b"only Alice should read this";
|
||||
let ciphertext = sm9_encrypt(id_alice, plaintext, &pub_key, &mut rng).unwrap();
|
||||
|
||||
// Bob 的私钥不能解密 Alice 的密文
|
||||
assert!(
|
||||
sm9_decrypt(id_alice, &ciphertext, &de_bob).is_err(),
|
||||
"错误私钥解密应失败"
|
||||
);
|
||||
let _ = de_alice; // 确保 Alice 私钥存在
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod pairing_reference_tests {
|
||||
/// Compare our pairing output against sm9_core reference
|
||||
/// This tests with a hardcoded known-good pairing value
|
||||
#[test]
|
||||
fn test_pairing_against_sm9core() {
|
||||
use sm9_core::{G1, G2, Group};
|
||||
use libsmx::sm9::groups::g1::G1Affine;
|
||||
use libsmx::sm9::groups::g2::G2Affine;
|
||||
use libsmx::sm9::pairing::pairing;
|
||||
use libsmx::sm9::fields::fp12::fp12_to_bytes;
|
||||
|
||||
// Get sm9_core reference pairing of generators
|
||||
let g1_ref = G1::one();
|
||||
let g2_ref = G2::one();
|
||||
let gt_ref = sm9_core::pairing(g1_ref, g2_ref);
|
||||
let ref_bytes = gt_ref.to_slice();
|
||||
|
||||
// Get our pairing of generators
|
||||
let g1 = G1Affine::generator();
|
||||
let g2 = G2Affine::generator();
|
||||
let gt = pairing(&g1, &g2);
|
||||
let our_bytes = fp12_to_bytes(>);
|
||||
|
||||
// Print both for debugging
|
||||
println!("sm9_core ref bytes[0..32]: {:02x?}", &ref_bytes[0..32]);
|
||||
println!("our bytes[0..32]: {:02x?}", &our_bytes[0..32]);
|
||||
|
||||
// They can't be directly compared due to different tower structures
|
||||
// But we can verify by checking if our e(G1,G2)^order == 1
|
||||
// For now, just print to help diagnose
|
||||
println!("sm9_core ref bytes (full):");
|
||||
for chunk in ref_bytes.chunks(32) {
|
||||
println!(" {:02x?}", chunk);
|
||||
}
|
||||
println!("our bytes (full):");
|
||||
for chunk in our_bytes.chunks(32) {
|
||||
println!(" {:02x?}", chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user