20231302邱之钊密码系统设计实验二一

news/2025/11/2 17:43:01/文章来源:https://www.cnblogs.com/9q2z2z/p/19185167

《密码系统设计》实验二

在 Ubuntu或openEuler中(推荐 openEuler)中调试运⾏商⽤密码检测中⼼https://www.scctc.org.cn/xzzx/sfydm/ydmxz/提供的源代码,⾄少运⾏SM2,SM3,SM4代码。使⽤GmSSL命令验证你代码的正确性。使⽤Markdown记录详细记录实践过程,每完成⼀项功能或者⼀个函数git commit ⼀次。(14分)

(一)SM2的实践

由于miracl库存在问题,反复尝试无法编译,故参考链接进行实践:
https://github.com/lookingforfyf/SMX_Test/tree/master

qzz@qzz-virtual-machine:~/Desktop/sy2/sm2/SMX_Test-master/SMX_Test/miracl-lib-X86_64/SM2ALG$ make
qzz@qzz-virtual-machine:~/Desktop/sy2/sm2/SMX_Test-master/SMX_Test/miracl-lib-X86_64/SM2ALG$ ./sm2_test
==============================================================================
message  = 6D65737361676520646967657374 [for test sign]
data     = 656E6372797074696F6E207374616E64617264 [for test enc]
privkey  = 3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8
pubx     = 09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020
puby     = CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13
rand     = 59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21
ZA       = B2E14C5C79C6DF5B85F4FE7ED8DB7A262B9DA7E07CCB0EA9F4747B8CCDA8A4F3
sign_R   = F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3
sign_S   = B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA
cipher   = 04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF059983C18F809E262923C53AEC295D30383B54E39D609D160AFCB1908D0BD876621886CA989CA9C7D58087307CA93092D651EFA
==============================================================================generate privkey = 3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8 [pass]
generate pubx    = 09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020 [pass]
generate puby    = CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13 [pass]
generate ZA      = B2E14C5C79C6DF5B85F4FE7ED8DB7A262B9DA7E07CCB0EA9F4747B8CCDA8A4F3 [pass]
generate sign_r  = F5A03B0648D2C4630EEAC513E1BB81A15944DA3827D5B74143AC7EACEEE720B3 [pass]
generate sign_s  = B1B6AA29DF212FD8763182BC0D421CA1BB9038FD1F7F42D4840B69C485BBC1AA [pass]
generate cipher  = 04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73 [pass]E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF059983C18F809E262923C53AEC295D30383B54E39D609D160AFCB1908D0BD876621886CA989CA9C7D58087307CA93092D651EFA

截图如下:
image

(二)SM3的实践

sm3.h

//
// Created by He-Zh on 2024/10/27.
//#ifndef EXP2_SM3_H
#define EXP2_SM3_H
#include <string.h>
#define SM3_len 256
#define SM3_T1 0x79CC4519
#define SM3_T2 0x7A879D8A
#define SM3_IVA 0x7380166f
#define SM3_IVB 0x4914b2b9
#define SM3_IVC 0x172442d7
#define SM3_IVD 0xda8a0600
#define SM3_IVE 0xa96f30bc
#define SM3_IVF 0x163138aa
#define SM3_IVG 0xe38dee4d
#define SM3_IVH 0xb0fb0e4e
/* Various logical functions */
#define SM3_p1(x) (x^SM3_rotl32(x,15)^SM3_rotl32(x,23))
#define SM3_p0(x) (x^SM3_rotl32(x,9)^SM3_rotl32(x,17))
#define SM3_ff0(a,b,c) (a^b^c)
#define SM3_ff1(a,b,c) ((a&b)|(a&c)|(b&c))
#define SM3_gg0(e,f,g) (e^f^g)
#define SM3_gg1(e,f,g) ((e&f)|((~e)&g))
#define SM3_rotl32(x,n) ((((unsigned int) x) << n) | (((unsigned int) x) >> (32 - n)))
#define SM3_rotr32(x,n) ((((unsigned int) x) >> n) | (((unsigned int) x) << (32 - n)))
typedef struct {unsigned int state[8];unsigned int length;unsigned int curlen;unsigned char buf[64];
} SM3_STATE;
void BiToWj(unsigned int Bi[], unsigned int Wj[]);
void WjToWj1(unsigned int Wj[], unsigned int Wj1[]);
void CF(unsigned int Wj[], unsigned int Wj1[], unsigned int V[]);
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]);
void SM3_init(SM3_STATE *md);
void SM3_compress(SM3_STATE * md);
void SM3_process(SM3_STATE * md, unsigned char buf[], int len);
void SM3_done(SM3_STATE *md, unsigned char *hash);
void SM3_256(unsigned char buf[], int len, unsigned char hash[]);
int SM3_SelfTest();
#endif //EXP2_SM3_H

sm3.c

//
// Created by He-Zh on 2024/10/27.
//#include "sm3.h"
#include <stdio.h>
void BiToW(unsigned int Bi[], unsigned int W[])
{int i;unsigned int tmp;for(i=0;i<=15;i++){W[i]=Bi[i];}for(i=16;i<=67;i++){tmp=W[i-16]^ W[i-9]^ SM3_rotl32(W[i-3],15);W[i]=SM3_p1(tmp)^ (SM3_rotl32(W[i-13],7))^ W[i-6];}
}
void WToW1(unsigned int W[], unsigned int W1[])
{int i;for(i=0;i<=63;i++){W1[i]=W[i]^W[i+4];}
}
void CF(unsigned int W[], unsigned int W1[], unsigned int V[])
{unsigned int SS1;unsigned int SS2;unsigned int TT1;unsigned int TT2;unsigned int A,B,C,D,E,F,G,H;unsigned int T=SM3_T1;unsigned int FF;unsigned int GG;int j;
//reg init,set ABCDEFGH=V0A=V[0];B=V[1];C=V[2];D=V[3];E=V[4];F=V[5];G=V[6];H=V[7];for(j=0;j<=63;j++){//SS1if(j==0){T=SM3_T1;}else if(j==16){T=SM3_rotl32(SM3_T2,16);}else{T=SM3_rotl32(T,1);}SS1=SM3_rotl32((SM3_rotl32(A,12)+E+T),7);//SS2SS2=SS1^SM3_rotl32(A,12);//TT1if(j<=15){FF=SM3_ff0(A,B,C);}else{FF=SM3_ff1(A,B,C);}TT1=FF+D+SS2+*W1;W1++;//TT2if(j<=15){GG=SM3_gg0(E,F,G);}else{GG=SM3_gg1(E,F,G);}TT2=GG+H+SS1+*W;W++;//DD=C;//CC=SM3_rotl32(B,9);//BB=A;//AA=TT1;//HH=G;//GG=SM3_rotl32(F,19);//FF=E;//EE=SM3_p0(TT2);}//update VV[0]=A^V[0];V[1]=B^V[1];V[2]=C^V[2];V[3]=D^V[3];V[4]=E^V[4];V[5]=F^V[5];V[6]=G^V[6];V[7]=H^V[7];
}
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[])
{unsigned char tmp = 0;unsigned int i = 0;for(i=0; i<bytelen/4; i++){tmp = des[4*i];des[4*i] = src[4*i+3];src[4*i+3] = tmp;tmp = des[4*i+1];des[4*i+1] = src[4*i+2];des[4*i+2] = tmp;}
}
void SM3_init(SM3_STATE *md)
{md->curlen = md->length = 0;md->state[0] = SM3_IVA;md->state[1] = SM3_IVB;md->state[2] = SM3_IVC;md->state[3] = SM3_IVD;md->state[4] = SM3_IVE;md->state[5] = SM3_IVF;md->state[6] = SM3_IVG;md->state[7] = SM3_IVH;
}
void SM3_compress(SM3_STATE * md)
{unsigned int W[68];unsigned int W1[64];//if CPU uses little-endian, BigEndian function is a necessary callBigEndian(md->buf, 64, md->buf);BiToW((unsigned int *)md->buf,W);WToW1(W,W1);CF(W, W1, md->state);
}
void SM3_process(SM3_STATE * md, unsigned char *buf, int len)
{while (len--){/* copy byte */md->buf[md->curlen] = *buf++;md->curlen++;/* is 64 bytes full? */if (md->curlen == 64){SM3_compress(md);md->length += 512;md->curlen = 0;}}
}
void SM3_done(SM3_STATE *md, unsigned char hash[])
{int i;unsigned char tmp = 0;/* increase the bit length of the message */md->length += md->curlen <<3;/* append the '1' bit */md->buf[md->curlen] = 0x80;md->curlen++;/* if the length is currently above 56 bytes, appends zeros tillit reaches 64 bytes, compress the current block, creat a newblock by appending zeros and length,and then compress it*/if (md->curlen >56){for (; md->curlen < 64;){md->buf[md->curlen] = 0;md->curlen++;}SM3_compress(md);md->curlen = 0;}/* if the length is less than 56 bytes, pad upto 56 bytes of zeroes */for (; md->curlen < 56;){md->buf[md->curlen] = 0;md->curlen++;}/* since all messages are under 2^32 bits we mark the top bits zero */for (i = 56; i < 60; i++){md->buf[i] = 0;}/* append length */md->buf[63] = md->length & 0xff;md->buf[62] = (md->length >> 8) & 0xff;md->buf[61] = (md->length >> 16) & 0xff;md->buf[60] = (md->length >> 24) & 0xff;SM3_compress(md);/* copy output */memcpy(hash,md->state,SM3_len/8);BigEndian(hash,SM3_len/8,hash);//if CPU uses little-endian, BigEndian function is a necessary call
}
void SM3_256(unsigned char buf[], int len, unsigned char hash[])
{SM3_STATE md;SM3_init(&md);SM3_process(&md, buf, len);SM3_done(&md, hash);
}
int SM3_SelfTest()
{unsigned int i=0,a=1,b=1;// 测试用例1:字符串 "20231302邱之钊"unsigned char Msg1[] = "20231302邱之钊";int MsgLen1 = strlen((char*)Msg1);unsigned char MsgHash1[32] = {0};// 测试用例2:原来的长字符串测试(可选保留)unsigned char Msg2[64] = {0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64};int MsgLen2 = 64;unsigned char MsgHash2[32] = {0};unsigned char StdHash2[32] = {0xde,0xbe,0x9f,0xf9,0x22,0x75,0xb8,0xa1,0x38,0x60,0x48,0x89,0xc1,0x8e,0x5a,0x4d,0x6f,0xdb,0x70,0xe5,0x38,0x7e,0x57,0x65,0x29,0x3d,0xcb,0xa3,0x9c,0x0c,0x57,0x32};// 计算 "20231302邱之钊" 的哈希值SM3_256(Msg1, MsgLen1, MsgHash1);printf("SM3 hash of '20231302邱之钊': ");for(int i = 0; i < 32; i++){printf("%02x", MsgHash1[i]);}printf("\n");// 可选:计算第二个测试用例SM3_256(Msg2, MsgLen2, MsgHash2);// 由于我们没有 "20231302邱之钊" 的标准哈希值,这里只验证第二个测试用例b = memcmp(MsgHash2, StdHash2, SM3_len/8);// 如果第二个测试用例通过,就返回0(成功)if (b == 0){return 0;}else{return 1;}
}
int main(){printf("%d\n",SM3_SelfTest());return 0;
}

我的命令:

qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ vi sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ vi sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ gcc -o sm3 sm3.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ ./sm3
SM3 hash of '20231302邱之钊': ab3b4e68cfc076f2c08df9a44f32077d618014aafafffe650f2bbc9c970b51fe
0qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.h
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gcc -o sm4 sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check successqzz@qzz-virtual-machine:~/Desktop/sy2/sm4$

使用GmSSL命令验证代码正确性。和SM3代码运行结果完全一致:

qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ echo -n "20231302邱之钊" | gmssl sm3
ab3b4e68cfc076f2c08df9a44f32077d618014aafafffe650f2bbc9c970b51fe

屏幕截图 2025-10-26 193326

(三)SM4的实践

sm4.h

#include<stdio.h> //rotate n bits to the left in a 32bit buffer 
#define SM4_Rotl32(buf, n) (((buf)<<n)|((buf)>>(32-n))) unsigned int SM4_CK[32] ={0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279}; unsigned char SM4_Sbox[256] = {0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,  
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}; unsigned int SM4_FK[4] = {0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC}; /************************************************************ 
Function: void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]); 
Description: Generate round keys 
Calls: 
Called By: SM4_Encrypt; SM4_Decrypt; 
Input: MK[]: Master key 
Output: rk[]: round keys 
Return:null Others: 
************************************************************/ 
void SM4_KeySchedule(unsigned char MK[], unsigned int rk[]); /************************************************************ 
Function: void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char 
CipherText[]); 
Description: Encryption function 
Calls: SM4_KeySchedule 
Called By: 
Input: MK[]: Master key PlainText[]: input text 
Output: CipherText[]: output text 
Return:null 
Others: 
************************************************************/ 
void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char CipherText[]); /************************************************************ 
Function: void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[], unsigned char PlainText[]); 
Description: Decryption function 
Calls: SM4_KeySchedule 
Called By: 
Input: MK[]: Master key CipherText[]: input text 
Output: PlainText[]: output text 
Return:null 
Others: 
************************************************************/ 
void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[], unsigned char PlainText[]); /************************************************************ 
Function: int SM4_SelfCheck() 
Description: Self-check with standard data 
Calls: SM4_Encrypt; SM4_Decrypt; 
Called By: 
Input: 
Output: 
Return: 1 fail ; 0 success 
Others: 
************************************************************/ 
int SM4_SelfCheck(); 

sm4.c

//
// Created by He-Zh on 2024/10/27.
//#include "sm4.h"
void SM4_KeySchedule(unsigned char MK[],unsigned int rk[])
{unsigned int tmp,buf,K[36];int i;for(i=0;i<4;i++){K[i]=SM4_FK[i]^( (MK[4*i]<<24) | (MK[4*i+1]<<16)|(MK[4*i+2]<<8) | (MK[4*i+3]) );}for(i=0;i<32;i++){tmp =K[i+1]^K[i+2]^K[i+3]^ SM4_CK[i];//nonlinear operationbuf= (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);
//linear operationK[i+4]=K[i]^((buf)^(SM4_Rotl32((buf),13))^(SM4_Rotl32((buf),23)));rk[i]=K[i+4];}
}
void SM4_Encrypt(unsigned char MK[],unsigned char PlainText[],unsigned char CipherText[])
{unsigned int rk[32],X[36],tmp,buf;int i,j;SM4_KeySchedule(MK,rk);for(j=0;j<4;j++){X[j]=(PlainText[j*4]<<24) |(PlainText[j*4+1]<<16)|(PlainText[j*4+2]<<8)|(PlainText[j*4+3]);}for(i=0;i<32;i++){tmp = X[i+1]^X[i+2]^X[i+3]^rk[i];//nonlinear operationbuf= ( SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);//linear operationX[i+4]=X[i]^(buf^SM4_Rotl32((buf),2)^ SM4_Rotl32((buf),10)^ SM4_Rotl32((buf),18)^ SM4_Rotl32((buf),24));}for(j=0;j<4;j++){CipherText[4*j]=(X[35-j]>> 24)& 0xFF;CipherText[4*j+1]=(X[35-j]>> 16)& 0xFF;CipherText[4*j+2]=(X[35-j]>> 8)& 0xFF;CipherText[4*j+3]=(X[35-j])& 0xFF;}
}
void SM4_Decrypt(unsigned char MK[],unsigned char CipherText[],unsigned char PlainText[])
{unsigned int rk[32],X[36],tmp,buf;int i,j;SM4_KeySchedule(MK,rk);for(j=0;j<4;j++){X[j]=(CipherText[j*4]<<24) |(CipherText[j*4+1]<<16)|(CipherText[j*4+2]<<8)|(CipherText[j*4+3]);}for(i=0;i<32;i++){tmp = X[i+1]^X[i+2]^X[i+3]^rk[31-i];//nonlinear operationbuf= (SM4_Sbox[(tmp >> 24) & 0xFF]) << 24|(SM4_Sbox[(tmp >> 16) & 0xFF]) << 16|(SM4_Sbox[(tmp >> 8) & 0xFF]) << 8|(SM4_Sbox[tmp & 0xFF]);//linear operationX[i+4]=X[i]^(buf^SM4_Rotl32((buf),2)^ SM4_Rotl32((buf),10)^ SM4_Rotl32((buf),18)^ SM4_Rotl32((buf),24));}for(j=0;j<4;j++){PlainText[4*j]=(X[35-j]>> 24)& 0xFF;PlainText[4*j+1]=(X[35-j]>>16)& 0xFF;PlainText[4*j+2]=(X[35-j]>> 8)& 0xFF;PlainText[4*j+3]=(X[35-j])& 0xFF;}
}
int SM4_SelfCheck()
{int i;//Standard dataunsigned char key[16] ={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};unsigned char plain[16]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};unsigned charcipher[16]={0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46};unsigned char En_output[16];unsigned char De_output[16];SM4_Encrypt(key,plain,En_output);SM4_Decrypt(key,cipher,De_output);for(i=0;i<16;i++){if ( (En_output[i]!=cipher[i]) | (De_output[i]!=plain[i]) ){printf("Self-check error");return 1;}}printf("Self-check success");return 0;
}
int main(){SM4_SelfCheck();return 0;
}

我的运行:

qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.h
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gcc -o sm4 sm4.c
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check successqzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ 

使用GmSSL命令验证代码正确性。使用相同明文和密钥进行加密所得到的结果和SM4代码中的运行结果完全一致:

qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ echo -ne "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10" > key.binx32\x10" > key.bin
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ echo -ne "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10" > plain.txt 
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ gmssl sm4_ecb -encrypt -in plain.txt -key $(xxd -p -c 32 key.bin) -out enc.bin
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ od -tc -tx1 enc.bin 
0000000   h 036 337   4 322 006 226   ^ 206 263 351   O   S   n   B   F68  1e  df  34  d2  06  96  5e  86  b3  e9  4f  53  6e  42  46
0000020

gmssl命令得出的结果是681edf34d206965e86b3e94f536e4246:
屏幕截图 2025-10-26 193952

在 SM4_SelfCheck() 函数中,预期结果为681edf34d206965e86b3e94f536e4246,又因为运行函数结果显示运行结果与预期一致,故gmssl命令结果验证得到sm4代码结果正确:
image

在密标委⽹站http://www.gmbz.org.cn/main/bzlb.html查找SM2,SM3,SM4相关标准,分析代码实现与标准的对应关系。(6分)

SM2加解密

标准 函数实现 备注
常数与符号 一一对应
辅助函数 KDF
加密算法 SM2_Encrypt 函数
解密算法 SM2_Decrypt 函数
椭圆曲线系统参数 SM2_Init 函数
用户密钥对 Test_PubKey 函数,SM2_KeyGeneration 函数 SM2_KeyGeneration 函数作用:该函数用于从给定的私钥生成相应的公钥。在椭圆曲线密码学中,公钥是通过对基点(G)进行私钥的标量乘法得到的。即公钥 pubKey = [priKey]G,其中 priKey 是私钥,G 是椭圆曲线上的基点,[priKey]G 表示将基点G进行私钥对应的标量乘法操作。输入:私钥 priKey,这是一个大整数,通常在 [1, n-2] 范围内,其中n是椭圆曲线的基点G的阶。输出:公钥 pubKey,这是一个椭圆曲线上的点,表示为 (x, y) 坐标。返回:函数返回0表示成功生成公钥,返回1表示生成公钥过程中出现错误,比如私钥不在有效范围内或者公钥点不在椭圆曲线上。Test_PubKey 函数作用:该函数用于验证给定的公钥是否有效。有效性检查包括:公钥点是否在无穷远点(点在椭圆曲线上的定义之外),公钥点的坐标是否在有限域内,以及公钥点是否在椭圆曲线上,最后还要检查公钥点的阶是否等于n。输入:公钥点 pubKey,这是一个椭圆曲线上的点。输出:无。返回:函数返回0表示公钥有效,返回1表示公钥点是无穷远点,返回2表示公钥点的X或Y坐标超出了有限域的范围,返回3表示公钥点不在椭圆曲线上,返回4表示公钥点的阶不等于n。

SM2密钥协商

标准 函数实现 备注
常数与符号 一一对应
辅助函数 KDF
用户密钥对 SM2_KeyGeneration 函数
密钥交换协议 SM2_KeyEx_Init_I 函数,SM2_KeyEx_Re_I 函数,SM2_KeyEx_Init_II 函数,SM2_KeyEx_Re_II 函数 SM2_KeyEx_Init_I 函数:作用:密钥交换的初始化步骤,由发起方(例如Alice)生成一个随机数rA并计算点RA,这是密钥交换的第一步。SM2_KeyEx_Re_I 函数:作用:密钥交换的响应步骤,由响应方(例如Bob)生成RB,并计算一个共享的秘密密钥。Bob将RB发送给Alice。SM2_KeyEx_Init_II 函数:作用:密钥交换的完成步骤,由发起方Alice计算共享的秘密密钥,并计算一个哈希值供响应方Bob验证。SM2_KeyEx_Re_II 函数: 作用:(可选)响应方Bob验证从发起方Alice接收到的哈希值,以确保密钥交换的完整性和安全性

SM2签名验签

标准 函数实现 备注
常数与符号 一一对应
辅助函数 KDF
用户密钥对 SM2_KeyGeneration
数字签名生成算法 SM2_Sign
数字签名验证算法 SM2_Verify
其他 SM2_Init、Test_Point、Test_PubKey、Test_Zero、Test_n、Test_Range和SM3_256 持上述签名生成和验证过程中的辅助函数。它们用于初始化曲线参数、验证点是否在曲线上、验证公钥的有效性、检查大整数是否为零或等于n、以及计算哈希值

SM3

标准 函数实现 详细解释
常数 一一对应
消息扩展 BiToW 函数,WToW1 函数 BiToW 函数:这个函数将输入的512位消息块(分割成16个32位字)扩展到一个512位的W数组,分成68个32位字。这个过程涉及到位操作和与SM3算法的固定参数相结合。WToW1 函数:这个函数进一步扩展消息,通过将W数组的每个元素与其后第四个元素进行异或操作,生成新的W1数组。这个数组将用于后续的压缩函数。
压缩函数 CF 函数,SM3_compress 函数 CF 函数:这个函数执行SM3算法的核心压缩操作,它使用W和W1数组以及一系列非线性和线性变换来更新哈希值。这个过程涉及到多轮迭代,每轮使用不同的参数和操作。SM3_compress 函数:这个函数执行实际的压缩操作,它调用BigEndian函数进行字节序转换,然后调用BiToW和WToW1函数进行消息扩展,最后调用CF函数执行压缩操作。
迭代过程 CF 函数,SM3_compress 函数 在CF函数中:这个函数通过64轮迭代,使用W和W1数组以及一系列非线性和线性变换来更新哈希值。每轮迭代都涉及到消息的加权、压缩和哈希状态的更新。在SM3_process函数中:这个函数处理输入的消息,将其分割成512位的块,并重复调用SM3_compress函数来压缩每个块,直到所有消息都被处理。

SM4

标准 函数实现
轮函数F SM4_KeySchedule 函数
加密算法 SM4_Encrypt 函数
解密算法 SM4_Decrypt 函数
密钥扩展算法 SM4_KeySchedule 函数

3.使用Rust完成SM2,SM3,SM4算法的实现(选做,10分)

(一)SM3
sm3.rs

use std::mem::transmute;const SM3_LEN: usize = 256;
const SM3_T1: u32 = 0x79CC4519;
const SM3_T2: u32 = 0x7A879D8A;
const SM3_IVA: u32 = 0x7380166f;
const SM3_IVB: u32 = 0x4914b2b9;
const SM3_IVC: u32 = 0x172442d7;
const SM3_IVD: u32 = 0xda8a0600;
const SM3_IVE: u32 = 0xa96f30bc;
const SM3_IVF: u32 = 0x163138aa;
const SM3_IVG: u32 = 0xe38dee4d;
const SM3_IVH: u32 = 0xb0fb0e4e;#[derive(Clone)]
struct Sm3State {state: [u32; 8],length: u64,curlen: usize,buf: [u8; 64],
}impl Sm3State {fn new() -> Self {Self {state: [SM3_IVA, SM3_IVB, SM3_IVC, SM3_IVD, SM3_IVE, SM3_IVF, SM3_IVG, SM3_IVH],length: 0,curlen: 0,buf: [0u8; 64],}}fn p1(x: u32) -> u32 {x ^ Sm3State::rotl(x, 15) ^ Sm3State::rotl(x, 23)}fn p0(x: u32) -> u32 {x ^ Sm3State::rotl(x, 9) ^ Sm3State::rotl(x, 17)}fn ff0(a: u32, b: u32, c: u32) -> u32 {a ^ b ^ c}fn ff1(a: u32, b: u32, c: u32) -> u32 {(a & b) | (a & c) | (b & c)}fn gg0(e: u32, f: u32, g: u32) -> u32 {e ^ f ^ g}fn gg1(e: u32, f: u32, g: u32) -> u32 {(e & f) | (!e & g)}fn rotl(x: u32, n: u32) -> u32 {(x << n) | (x >> (32 - n))}fn big_endian(src: &[u8], bytelen: usize, des: &mut [u8]) {for i in 0..(bytelen / 4) {des[4 * i] = src[4 * i + 3];des[4 * i + 1] = src[4 * i + 2];des[4 * i + 2] = src[4 * i + 1];des[4 * i + 3] = src[4 * i];}}fn bi_to_w(bi: &[u32; 16], w: &mut [u32; 68]) {w[0..16].copy_from_slice(bi);for i in 16..68 {let tmp = w[i - 16] ^ w[i - 9] ^ Sm3State::rotl(w[i - 3], 15);w[i] = Sm3State::p1(tmp) ^ Sm3State::rotl(w[i - 13], 7) ^ w[i - 6];}}fn w_to_w1(w: &[u32; 68], w1: &mut [u32; 64]) {for i in 0..64 {w1[i] = w[i] ^ w[i + 4];}}fn cf(w: &[u32; 68], w1: &[u32; 64], v: &mut [u32; 8]) {let mut a = v[0];let mut b = v[1];let mut c = v[2];let mut d = v[3];let mut e = v[4];let mut f = v[5];let mut g = v[6];let mut h = v[7];let mut t = SM3_T1;for j in 0..64 {if j == 16 {t = Sm3State::rotl(SM3_T2, 16);} else if j > 0 {t = Sm3State::rotl(t, 1);}let ss1 = Sm3State::rotl(Sm3State::rotl(a, 12).wrapping_add(e).wrapping_add(t), 7);let ss2 = ss1 ^ Sm3State::rotl(a, 12);let tt1 = if j <= 15 {Sm3State::ff0(a, b, c)} else {Sm3State::ff1(a, b, c)}.wrapping_add(d).wrapping_add(ss2).wrapping_add(w1[j]);let tt2 = if j <= 15 {Sm3State::gg0(e, f, g)} else {Sm3State::gg1(e, f, g)}.wrapping_add(h).wrapping_add(ss1).wrapping_add(w[j]);d = c;c = Sm3State::rotl(b, 9);b = a;a = tt1;h = g;g = Sm3State::rotl(f, 19);f = e;e = Sm3State::p0(tt2);}v[0] ^= a;v[1] ^= b;v[2] ^= c;v[3] ^= d;v[4] ^= e;v[5] ^= f;v[6] ^= g;v[7] ^= h;}fn compress(&mut self) {let mut w = [0u32; 68];let mut w1 = [0u32; 64];let mut buf = [0u32; 16];for i in 0..16 {buf[i] = u32::from_be_bytes([self.buf[4 * i], self.buf[4 * i + 1], self.buf[4 * i + 2], self.buf[4 * i + 3]]);}Sm3State::bi_to_w(&buf, &mut w);Sm3State::w_to_w1(&w, &mut w1);Sm3State::cf(&w, &w1, &mut self.state);}fn process(&mut self, buf: &[u8]) {for &b in buf {self.buf[self.curlen] = b;self.curlen += 1;if self.curlen == 64 {self.compress();self.length += 512;self.curlen = 0;}}}fn done(&mut self, hash: &mut [u8; 32]) {self.length += (self.curlen as u64) << 3;self.buf[self.curlen] = 0x80;self.curlen += 1;if self.curlen > 56 {self.buf[self.curlen..64].fill(0);self.compress();self.curlen = 0;}self.buf[self.curlen..56].fill(0);self.buf[56..64].copy_from_slice(&self.length.to_be_bytes());self.compress();for (i, &s) in self.state.iter().enumerate() {hash[i * 4..i * 4 + 4].copy_from_slice(&s.to_be_bytes());}}
}fn sm3_256(buf: &[u8], hash: &mut [u8; 32]) {let mut state = Sm3State::new();state.process(buf);state.done(hash);
}fn main() {let mut hash = [0u8; 32];sm3_256(b"abc", &mut hash);for byte in &hash {print!("{:02x}", byte);}println!();
}

运行结果:

qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ rustc sm3.rs
warning: unused import: `std::mem::transmute`--> sm3.rs:1:5|
1 | use std::mem::transmute;|     ^^^^^^^^^^^^^^^^^^^|= note: `#[warn(unused_imports)]` on by defaultwarning: constant `SM3_LEN` is never used--> sm3.rs:3:7|
3 | const SM3_LEN: usize = 256;|       ^^^^^^^|= note: `#[warn(dead_code)]` on by defaultwarning: associated function `big_endian` is never used--> sm3.rs:61:8|
23 | impl Sm3State {| ------------- associated function in this implementation
...
61 |     fn big_endian(src: &[u8], bytelen: usize, des: &mut [u8]) {|        ^^^^^^^^^^warning: 3 warnings emittedqzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ ./sm3
66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
qzz@qzz-virtual-machine:~/Desktop/sy2/sm3$ 

image
(二)SM4
sm4.rs

const SM4_CK: [u32; 32] = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
];const SM4_SBOX: [u8; 256] = [0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
];const SM4_FK: [u32; 4] = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];fn sm4_rotl32(buf: u32, n: u32) -> u32 {(buf << n) | (buf >> (32 - n))
}fn sm4_key_schedule(mk: &[u8], rk: &mut [u32; 32]) {let mut k = [0u32; 36];for i in 0..4 {k[i] = SM4_FK[i]^ ((mk[4 * i] as u32) << 24| (mk[4 * i + 1] as u32) << 16| (mk[4 * i + 2] as u32) << 8| (mk[4 * i + 3] as u32));}for i in 0..32 {let tmp = k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ SM4_CK[i];let buf = (SM4_SBOX[(tmp >> 24) as usize & 0xFF] as u32) << 24| (SM4_SBOX[(tmp >> 16) as usize & 0xFF] as u32) << 16| (SM4_SBOX[(tmp >> 8) as usize & 0xFF] as u32) << 8| SM4_SBOX[tmp as usize & 0xFF] as u32;k[i + 4] = k[i] ^ (buf ^ sm4_rotl32(buf, 13) ^ sm4_rotl32(buf, 23));rk[i] = k[i + 4];}
}
fn sm4_substitute(input: u32) -> u32 {// 使用S盒来替代输入字节let mut buf = 0u32;buf |= (SM4_SBOX[(input >> 24) as usize & 0xFF] as u32) << 24;buf |= (SM4_SBOX[(input >> 16) as usize & 0xFF] as u32) << 16;buf |= (SM4_SBOX[(input >> 8) as usize & 0xFF] as u32) << 8;buf |= SM4_SBOX[input as usize & 0xFF] as u32;buf
}fn sm4_round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {let tmp = x1 ^ x2 ^ x3 ^ rk;let buf = sm4_substitute(tmp);x0 ^ buf ^ sm4_rotl32(buf, 2) ^ sm4_rotl32(buf, 10) ^ sm4_rotl32(buf, 18) ^ sm4_rotl32(buf, 24)
}fn sm4_encrypt(input: &[u8], output: &mut [u8], rk: &[u32; 32]) {let mut x = [0u32; 36];for i in 0..4 {x[i] = (input[4 * i] as u32) << 24| (input[4 * i + 1] as u32) << 16| (input[4 * i + 2] as u32) << 8| input[4 * i + 3] as u32;}for i in 0..32 {x[i + 4] = sm4_round_function(x[i], x[i + 1], x[i + 2], x[i + 3], rk[i]);}for i in 0..4 {output[4 * i] = (x[35 - i] >> 24) as u8;output[4 * i + 1] = (x[35 - i] >> 16) as u8;output[4 * i + 2] = (x[35 - i] >> 8) as u8;output[4 * i + 3] = x[35 - i] as u8;}
}fn sm4_decrypt(input: &[u8], output: &mut [u8], rk: &[u32; 32]) {let mut x = [0u32; 36];for i in 0..4 {x[i] = (input[4 * i] as u32) << 24| (input[4 * i + 1] as u32) << 16| (input[4 * i + 2] as u32) << 8| input[4 * i + 3] as u32;}for i in 0..32 {x[i + 4] = sm4_round_function(x[i], x[i + 1], x[i + 2], x[i + 3], rk[31 - i]);}for i in 0..4 {output[4 * i] = (x[35 - i] >> 24) as u8;output[4 * i + 1] = (x[35 - i] >> 16) as u8;output[4 * i + 2] = (x[35 - i] >> 8) as u8;output[4 * i + 3] = x[35 - i] as u8;}
}
fn sm4_self_check() -> bool {// 标准测试数据let key: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,];let plain: [u8; 16] = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,];let expected_cipher: [u8; 16] = [0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e,0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46,];// 结果缓冲区let mut rk = [0u32; 32];let mut cipher = [0u8; 16];let mut decrypted = [0u8; 16];// 生成轮密钥sm4_key_schedule(&key, &mut rk);// 加密sm4_encrypt(&plain, &mut cipher, &rk);// 检查加密结果是否与期望值相同if cipher != expected_cipher {println!("Self-check error: encryption failed.");return false;}// 解密sm4_decrypt(&cipher, &mut decrypted, &rk);// 检查解密结果是否恢复为原始明文if decrypted != plain {println!("Self-check error: decryption failed.");return false;}println!("Self-check success.");true
}fn main() {if sm4_self_check() {println!("SM4 encryption and decryption passed the self-check.");} else {println!("SM4 encryption and decryption failed the self-check.");}
}

运行结果

qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ vi sm4.rs
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ rustc sm4.rs
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ ./sm4
Self-check success.
SM4 encryption and decryption passed the self-check.
qzz@qzz-virtual-machine:~/Desktop/sy2/sm4$ 

image

代码,文档托管到gitee或github等,推荐gitclone

https://gitee.com/q9z2z2/922.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/953709.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年 11 月运动木地板厂家最新推荐,成分精纯与效能升级!—— 产能、专利、环保三维数据透视

体育场馆建设对运动木地板的成分精纯度与综合效能要求不断提高,市场上部分产品存在原材杂质多、环保不达标等问题,影响使用安全与场馆寿命。为筛选优质品牌,本次推荐从产能、专利、环保三维度开展测评。产能维度核查…

2025 年 11 月运动木地板厂家最新推荐,配方精研与效能焕新!—— 实力品牌深度解析采购无忧之选!

运动木地板的配方设计与效能表现,直接决定体育场馆的使用体验与安全系数。当前市场部分品牌存在木材配方不合理、性能参数不达标等问题,增加采购风险。为挖掘实力品牌,本次测评从品牌实力核心维度开展:核查品牌成立…

2025 年 11 月运动木地板厂家最新推荐,成分焕新与效能强化!—— 精准检测与稳定性能深度解析

当下体育场馆对运动木地板的成分品质与性能稳定性要求持续提升,市场中部分产品存在木材纤维结构松散、减震效能衰减等问题,给运动安全与场馆运营带来隐患。为筛选优质品牌,本次推荐联合专业检测机构,依据国际运动地…

【软考】信安中级密码学专题

针对信安中级里,密码学相关案例题的知识点和真题密码学的三大目标 ‌Confidentiality 机密性(保密性):确保信息未经非授权的访问,避免信息泄露。 Integrity 完整性:防止信息非法的修改和毁坏,…

算法 第二次作业

算法 第二次作业找第k小的数的分治算法(快速选择算法) 自然语言描述: 选择一个元素作为“基准”:从数组中选择一个元素作为基准,选择的方法可以有多种,例如随机选择、选择数组的第一个元素、选择数组的中间元素等…

JavaScript异步编程:从回调地狱到优雅解决方案

异步编程是JavaScript的核心能力,但回调嵌套易导致"回调地狱"。本文将介绍现代JS异步处理的演进之路,助你写出更简洁高效的代码。1. Promise:异步操作的基石 Promise 通过链式调用解决回调嵌套问题: fet…

使用JavaScript和Node.js构建简单的RESTful API

引言:本文将指导你如何使用JavaScript和Node.js的Express框架构建一个简单的RESTful API。我们将创建一个简单的用户管理系统,包括获取用户列表、添加新用户以及删除用户。 正文与代码演示:设置项目:首先,创建一个…

JavaScript中的闭包:原理、应用与代码

在JavaScript的众多概念中,闭包(Closure)无疑是一个既深奥又强大的特性。闭包不仅能够帮助我们封装私有变量,实现模块化编程,还能在函数之间传递状态,使得函数的行为更加丰富和灵活。本文将深入探讨闭包的原理,…

2025 年 11 月 PVC 地板厂家最新推荐,聚焦原料安全与功效稳定的专业产品解析

PVC 地板因适用场景广泛,全球市场需求逐年攀升,但原料安全不达标、功效随使用波动等问题,让采购方面临决策难题。为解决这一痛点,国际地材专业测评协会联合材料安全机构,参照氨糖行业对原料安全、功效稳定的专业评…

2025 年 11 月 PVC 地板厂家最新推荐,聚焦原料合规与功效持久的专业产品解析

PVC 地板全球市场需求旺盛,但原料不合规、功效随使用周期快速衰退等问题,成为采购方核心顾虑。为提供科学选购依据,国际地材合规测评协会联合材料性能机构,参照氨糖行业对原料合规、功效持久的专业评估标准,开展 …

2025 年 11 月 PVC 地板厂家最新推荐,聚焦成分安全与功效持续的优质产品解析

PVC 地板在全球各场景广泛应用,但成分安全隐患、功效随使用衰减等问题频发。为解决采购痛点,国际地材安全测评协会联合材料研究机构,参照氨糖行业对成分安全、功效持续的严格标准,开展 2025 年 11 月 PVC 地板专项…

2025 年 11 月 PVC 地板厂家最新推荐,聚焦原料品质与功效长效性的优质产品解析

PVC 地板市场规模持续扩大,但原料品质参差不齐、功效随使用周期衰退等问题,成为采购方核心顾虑。为提供科学选购依据,国际地材品质认证协会联合材料检测机构,参照氨糖行业对原料纯度、功效稳定性的严苛评估体系,开…

React Hooks:提升前端开发效率的关键

在现代前端开发中,React作为最受欢迎的JavaScript库之一,其生态系统不断演进,带来了许多创新和优化。其中,React Hooks的出现无疑是一个革命性的里程碑。自React 16.8版本引入以来,Hooks已经成为了前端开发者们提…

网络设备命令行

1. 命令行视图进入设备时是用户视图 用户视图:查看运行状态和统计信息等功能 系统视图:配置系统参数以及进入其他功能配置视图 其他视图:用户可以进行接口参数和协议参数配置用户视图切成系统视图命令 system-view …

基于BESO方法实现MBB梁一体化拓扑优化

一、MBB梁拓扑优化问题定义 设计目标:在满足刚度约束下实现质量最小化(或刚度最大化下的质量约束) 设计变量:材料密度分布(0-1离散变量) 约束条件:总质量 ≤ 目标质量(体积分数约束) 关键节点位移 ≤ 允许值 …

究极干货 —— 用最纯粹的语言,解析 DeepSeek OCR

究极干货 —— 用最纯粹的语言,解析 DeepSeek OCR这是一篇 “纯干货” 文章,用 8500 字的最纯粹的语言,解析 DeepSeek OCR,与大家探讨 AI 记忆系统的各种可能性~楔子 最近看到了一篇极具启发性的论文:《DeepSeek-…

【图文详细】用HBuilder X写PHP并且能够在浏览器运行打开 - 昵

【图文详细】用HBuilder X写PHP并且能够在浏览器运行打开 今天教大家如何使用HBuilder X写PHP。 用到的工具: HBuilder X,配置phpstudy端口和url、登录账号下载php语言服务 phpStudy,仅仅查看端口,启动apache、mysq…

可视化水表数据并实现用水量超标警报的技术方案

本文详细介绍如何通过S0脉冲模块连接水表,使用NodeMCU采集数据,结合InfluxDB时序数据库实现用水量可视化监控和警报系统的完整技术方案。如何可视化水表数据并在用水量过多时获得警报 在我居住的村庄,水表每5年更换…

闲话 25.11.2

一个 bgf 对角线提取技巧的拓展闲话 前几周(?)打了 us-tc。puzzle hunt 真好玩 😋 悠悠博客上更新了完赛记录 怎么快两个月没写鲜花了 /jk 前几月(?)写了点东西,发一下! 推歌: Weier Schnee by regulus ft. 初音…

题解:uoj695 【候选队互测2022】毛估估就行

题意:给出一个无向无权图,\(q\) 次询问两点距离,但是假设真实距离为 \(d\),输出 \([d-1,d+1]\) 都视为正确。\(n\le 8000,q\le 10^6,m\le n^2\)。 做法: 正常的最短路肯定是没法做,做出来就得图灵奖了。注意到输…