天天看點

SM3雜湊算法的C、python和go實作Github注意點參考資料

文章目錄

  • Github
  • 注意點
    • Python
    • Python代碼
    • Go
    • Go代碼
    • C
    • C代碼
  • 參考資料
    • Python
    • C
    • Go

Github

https://github.com/Tyrone-Zhao/Algorithm/tree/master/sm3

注意點

Python

1.python中的非為補碼非,需要自己編寫按位非

2.算法為大端運算,用python編寫算法時需要在把輸入資料轉換成bytes後,從bytes讀取大端資料,使用int.from_bytes(data, “big”)方法

3.因為是采用寄存器機制,是以在python中需要使用list類型來實作, 并且設定最大值為2 ** 32,在做加法運算時需要取餘

Python代碼

SM3雜湊算法的C、python和go實作Github注意點參考資料
import binascii
import sys
import pysnooper


class SM3:
    MAX = 2 ** 32
    IV = "7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e"

    def __init__(self, string):
        self.input = string
        self.b_input = bytes(self.input, "utf-8")
        self.hex_input = hex(int.from_bytes(self.b_input, "big"))[2:]  # 按照大端計算

    @property
    def hash(self):
        """
        擷取結果Hash值
        :return: 256位16進制hash值
        """
        return self.iterationCourse(self.fill(self.hexToBin(self.hex_input)))[-1]

    def getT(self, j):
        """
        常量
        :param j:
        :return: 79cc4519 (0 <= j <= 15), 7a879d8a (16 <= j <= 63)
        """
        if 0 <= j <= 15:
            return int("79cc4519", 16)
        elif 16 <= j <= 63:
            return int("7a879d8a", 16)

    def FF(self, X, Y, Z, j):
        """
        布爾函數
        :param X: 16進制string
        :param Y: 16進制string
        :param Z: 16進制string
        :return: X ^ Y ^ Z (0 <= j <= 15), (X & Y) | (X & Z) | (Y & Z) (16 <= j <= 63)
        """
        if 0 <= j <= 15:
            return X ^ Y ^ Z
        elif 16 <= j <= 63:
            return (X & Y) | (X & Z) | (Y & Z)
        else:
            return 0

    def GG(self, X, Y, Z, j):
        """
        布爾函數
        :param X: 16進制string
        :param Y: 16進制string
        :param Z: 16進制string
        :return: X ^ Y ^ Z (0 <= j <= 15), (X & Y) | (~X & Z) (16 <= j <= 63)
        """
        if 0 <= j <= 15:
            return X ^ Y ^ Z
        elif 16 <= j <= 63:
            return (X & Y) | (self.non(X) & Z)
        else:
            return 0

    def P0(self, X):
        """
        置換函數
        :param X: 整數值
        :return: X ^ (X <<< 9) ^ (X <<< 17)
        """
        return X ^ self.leftRotate(X, 9) ^ self.leftRotate(X, 17)

    def P1(self, X):
        """
        置換函數
        :param X: 整數值
        :return: X ^ (X <<< 15) ^ (X <<< 23)
        """
        return X ^ self.leftRotate(X, 15) ^ self.leftRotate(X, 23)

    def leftRotate(self, X, k):
        """
        循環左移
        :param X: 整數值
        :param k: 位移的位數
        :param bit: 整數對應二進制的位數
        :return: 二進制左移k位的整數值
        """
        res = list(self.intToBin(X))
        for i in range(k):
            temp = res.pop(0)
            res.append(temp)
        return int("".join(res), 2)

    def fill(self, bin_string):
        """
        填充二進制消息string
        :param bin_string: 對任意消息使用self.msgToBin()得到的結果
        :return: 填充後的二進制消息m',其比特長度為512的倍數
        """
        tail = "{:064b}".format(len(bin_string))
        bin_string += "1"
        div, mod = divmod(len(bin_string), 512)
        if mod >= 448:
            bin_string += "0" * (512 - mod + 448)
        else:
            bin_string += "0" * (448 - mod)

        return bin_string + tail

    def iterationCourse(self, msg):
        """
        疊代壓縮消息
        :param msg: 填充後的二進制消息m', self.fill(msg)
        :return: Hash值(雜湊值)
        """
        # 将填充消息m'按512比特進行分組
        n = len(msg) // 512
        m = [msg[i * 512:(i + 1) * 512] for i in range(n)]
        # 對m[i]進行壓縮疊代, msg = self.bigLittleEndianConvert(Vi, "big")  # 小端資料轉換為大端
        V = [self.IV]
        for i in range(n):
            V.append(hex(int(self.intToBin(self.CF(V[-1], m[i]), 256), 2))[2:])

        return V

    def CF(self, Vi, mi):
        """
        壓縮函數
        :param Vi: 512比特16進制資料
        :param mi: 512比特二進制資料
        :return: 512比特16進制資料
        """
        # 将Vi存儲到字寄存器
        msg = Vi
        A = [int(msg[i * 8: (i + 1) * 8], 16) for i in range(len(msg) // 8)]
        # 消息擴充,得到W和W'
        W1, W2 = self.informationExtend(mi)
        # 壓縮消息
        for j in range(64):
            factor1 = self.leftRotate(A[0], 12)
            factor2 = self.leftRotate(self.getT(j), j % 32)
            SS1 = self.leftRotate((factor1 + A[4] + factor2) % self.MAX, 7)
            factor3 = self.leftRotate(A[0], 12)
            SS2 = SS1 ^ factor3
            TT1 = (self.FF(A[0], A[1], A[2], j) + A[3] + SS2 + W2[j]) % self.MAX
            TT2 = (self.GG(A[4], A[5], A[6], j) + A[7] + SS1 + W1[j]) % self.MAX
            A[3] = A[2]
            A[2] = self.leftRotate(A[1], 9)
            A[1] = A[0]
            A[0] = TT1
            A[7] = A[6]
            A[6] = self.leftRotate(A[5], 19)
            A[5] = A[4]
            A[4] = self.P0(TT2)
        temp = self.intToBin(A[0], 32) + self.intToBin(A[1], 32) + self.intToBin(A[2], 32) + \
               self.intToBin(A[3], 32) + self.intToBin(A[4], 32) + self.intToBin(A[5], 32) + \
               self.intToBin(A[6], 32) + self.intToBin(A[7], 32)
        temp = int(temp, 2)
        return temp ^ int(Vi, 16)


    def informationExtend(self, mi):
        """
        消息擴充, 将512比特二進制消息擴充為132個字
        :param mi: Bi,512比特二進制資料
        :return: W -> 68個16進制消息字, W' -> 64個16進制消息字
        """
        # 第一步,将消息Bi劃分為16個字W0~W15
        mi = self.binToHex(mi)
        W1 = [int(mi[i * 8: (i + 1) * 8], 16) for i in range(len(mi) // 8)]
        # 第二步
        for j in range(16, 68):
            p = self.P1(W1[j - 16] ^ W1[j - 9] ^ self.leftRotate(W1[j - 3], 15))
            W1.append(p ^ self.leftRotate(W1[j - 13], 7) ^ W1[j - 6])
        # 第三步
        W2 = [W1[j] ^ W1[j + 4] for j in range(64)]

        return W1, W2

    def bigLittleEndianConvert(self, data, need="big"):
        """
        大小端16進制資料轉換
        :param data: 16進制小端string
        :param need: 轉換為大端還是小端
        :return: 轉換後16進制string
        """
        if sys.byteorder != need:
            return binascii.hexlify(binascii.unhexlify(data)[::-1])
        return data

    def hexToBin(self, hex_string):
        """
        十六進制string轉換為二進制string
        :param hex: 十六進制string
        :return: 二進制string
        """
        res = ""
        for h in hex_string:
            res += '{:04b}'.format(int(h, 16))
        return res

    def binToHex(self, bin_string):
        """
        二進制string轉換為十六進制string
        :param bin_string: 二進制string
        :return: 十六進制string
        """
        res = ""
        for i in range(len(bin_string) // 4):
            s = bin_string[i * 4: (i + 1) * 4]
            res += '{:x}'.format(int(s, 2))
        return res

    def msgToHex(self, msg):
        """
        字元串轉換為16進制字元串
        :param msg: string
        :return: msg.encode("utf-8").hex()
        """
        return msg.encode("utf-8").hex()

    def msgToBin(self, msg):
        """
        字元串轉換為二進制字元串
        :param msg: string
        :return: self.hexToBin(self.msgToHex(msg))
        """
        return self.hexToBin(self.msgToHex(msg))

    def intToBin(self, X, bits=32):
        """
        整數值轉二進制
        :param X: 整數值
        :return: 32位二進制字元串
        """
        return ('{:0%db}' % bits).format(X)

    def non(self, X):
        """
        按位非
        :param X: 整數值
        :return: 按位非後的整數值
        """
        X = self.intToBin(X)
        Y = ""
        for i in X:
            if i == "0":
                Y += "1"
            else:
                Y += "0"
        return int(Y, 2)


if __name__ == "__main__":
    print(SM3("abc").hash)
    print(SM3("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd").hash)

           

Go

1.要注意大小端轉換問題,實際上就是byte位的倒序。

2.strconv.ParseInt(x, 16, 33),這裡ParseInt的比特位要設定為33,因為要轉換為uint32類型,而int有一個符号位。

3.W1和W2在疊代壓縮消息的for循環中重置。

4.每次調用Hash()函數時,都要預設重置struct中的内容

Go代碼

SM3雜湊算法的C、python和go實作Github注意點參考資料
package main

import (
	"bytes"
	"fmt"
	"strconv"
	"unsafe"
)

type SM3 struct {
	Input string
	IV    string
	V     []string
	B     []string
	W1    []uint32
	W2    []uint32
	A     []uint32
	MAX   uint32
}

// 初始化IV值
func (s *SM3) Init() {
	s.IV = "7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e"
	s.V = append(s.V, s.IV)
	s.MAX = 0xffffffff
}

// 輸入字元補齊32位
func (s *SM3) CharToBin(char uint32) string {
	r := strconv.FormatUint(uint64(char), 2) // byte轉為無符号整型
	// 	補充到32位
	if len(r) < 32 {
		r = fmt.Sprintf("%032s", r)
	}
	return r
}

// byte轉8位二進制
func (s *SM3) ByteToBin(char byte) string {
	r := strconv.FormatUint(uint64(char), 2) // byte轉為無符号整型
	// 	補充到32位
	if len(r) < 8 {
		r = fmt.Sprintf("%08s", r)
	}
	return r
}

// int轉二進制32位
func (s *SM3) DecimalToBin(n int) string {
	return s.CharToBin(uint32(n))
}

// uint32轉16進制
func (s *SM3) Uint32ToHex(i uint32) string {
	return fmt.Sprintf("%02x", i)
}

// 十六進制轉二進制32位
func (s *SM3) HexToBin(x string) string {
	base, _ := strconv.ParseInt(x, 16, 33)
	return s.CharToBin(uint32(base))
}

// 十六進制轉int
func (s *SM3) HexToInt(x string) int {
	var num int
	l := len(x)
	for i := l - 1; i >= 0; i-- {
		num += (int(x[l-i-1]) & 0xf) << uint8(i)
	}
	return num
}

// 8位十六進制轉uint32
func (s *SM3) HexToUint32(x string) uint32 {
	base, _ := strconv.ParseInt(x, 16, 33)
	return uint32(base)
}

// 二進制轉uint32
func (s *SM3) BinToUint32(b string) uint32 {
	base, _ := strconv.ParseInt(b, 2, 33)
	return uint32(base)
}

// 擷取T值
func (s *SM3) GetT(j uint8) uint32 {
	var r uint32
	if j < 16 {
		base, _ := strconv.ParseInt("79cc4519", 16, 32)
		r = uint32(base)
	} else if j <= 63 {
		base, _ := strconv.ParseInt("7a879d8a", 16, 32)
		r = uint32(base)
	}
	return r
}

// 布爾函數FFj
func (s *SM3) FF(X uint32, Y uint32, Z uint32, j uint8) uint32 {
	var r uint32
	if j < 16 {
		r = X ^ Y ^ Z
	} else if j <= 63 {
		r = (X & Y) | (X & Z) | (Y & Z)
	}
	return r
}

// 布爾函數GGj
func (s *SM3) GG(X uint32, Y uint32, Z uint32, j uint8) uint32 {
	var r uint32
	if j < 16 {
		r = X ^ Y ^ Z
	} else if j <= 63 {
		r = (X & Y) | ((^X) & Z)
	}
	return r
}

// 循環左移, k代表左移的位數
func (s *SM3) LeftRotate(X uint32, k uint8) uint32 {
	X = (X << k) | (X >> (32 - k))
	return X
}

// 置換函數P0
func (s *SM3) P0(X uint32) uint32 {
	return X ^ s.LeftRotate(X, 9) ^ s.LeftRotate(X, 17)
}

// 置換函數P1
func (s *SM3) P1(X uint32) uint32 {
	return X ^ s.LeftRotate(X, 15) ^ s.LeftRotate(X, 23)
}

// 填充函數
func (s *SM3) FillInput() string {
	s.Init()
	var res string
	res += s.BigLittleEndianConvert()
	res += "1" // 将1添加到消息末尾
	temp := len(res) % 512
	if temp < 448 {
		res += s.SameString("0", 448 - temp) // (l + 1 + k) mod 512餘448
	} else {
		res += s.SameString("0", 512 - temp + 448)
	}

	tail := fmt.Sprintf("%064s", s.DecimalToBin(len(s.Input)*8))
	res += tail
	return res
}

// 大小端資料轉換, 實際上就是位元組序反轉
func (s *SM3) BigLittleEndianConvert() string {
	var temp string
	if s.IsLittleEndian() {
		for i := 0; i < len(s.Input); i++ { // 小端轉大端
			temp += s.ByteToBin(s.Input[i])
		}
	} else {
		for i := len(s.Input) - 1; i >= 0; i-- {
			temp += s.ByteToBin(s.Input[i]) // 大端保持原狀
		}
	}

	return temp
}

// 判斷目前系統環境是否是小端
func (s *SM3) IsLittleEndian() bool {
	var i int32 = 0x01020304
	u := unsafe.Pointer(&i)
	pb := (*byte)(u)
	b := *pb
	return (b == 0x04)
}

// 傳回固定長度相同字元的字元串
func (s *SM3) SameString(str string, n int) string {
	var buffer bytes.Buffer
	for i := 0; i < n; i++ {
		buffer.WriteString(str)
	}
	return buffer.String()
}

// 疊代壓縮消息函數,傳回64位16進制hash值
func (s *SM3) IterationCourse() string {
	str := s.FillInput()
	n := len(str) / 512
	for i := 0; i < n; i++ {
		s.B = append(s.B, str[i*512:(i+1)*512])
	}
	for i := 0; i < n; i++ {
		s.V = append(s.V, s.CF(s.V[i], s.B[i]))
		// 重置s.W1和s.W2
		s.W1 = []uint32{}
		s.W2 = []uint32{}
	}
	return s.V[len(s.V)-1:][0]
}

// 壓縮函數
func (s *SM3) CF(Vi string, Bi string) string {
	// Vi按字存到A
	for i := 0; i < len(Vi)/8; i++ {
		s.A = append(s.A, s.HexToUint32(Vi[i*8:(i+1)*8]))
	}

	// 消息擴充,得到W1和W2
	s.informationExtend(Bi)

	for j := 0; j < 64; j++ {
		factor1 := s.LeftRotate(s.A[0], 12)
		factor2 := s.LeftRotate(s.GetT(uint8(j)), uint8(j%32))
		SS1 := s.LeftRotate((factor1 + s.A[4] + factor2), 7)
		factor3 := s.LeftRotate(s.A[0], 12)
		SS2 := SS1 ^ factor3
		TT1 := (s.FF(s.A[0], s.A[1], s.A[2], uint8(j)) + s.A[3] + SS2 + s.W2[j])
		TT2 := (s.GG(s.A[4], s.A[5], s.A[6], uint8(j)) + s.A[7] + SS1 + s.W1[j])
		s.A[3] = s.A[2]
		s.A[2] = s.LeftRotate(s.A[1], 9)
		s.A[1] = s.A[0]
		s.A[0] = TT1
		s.A[7] = s.A[6]
		s.A[6] = s.LeftRotate(s.A[5], 19)
		s.A[5] = s.A[4]
		s.A[4] = s.P0(TT2)
	}

	var res string
	for i := 0; i < len(Vi)/8; i++ {
		s.A[i] ^= s.HexToUint32(Vi[i*8 : (i+1)*8])
		res += s.Uint32ToHex(s.A[i])
	}
	return res
}

// 消息擴充函數
func (s *SM3) informationExtend(Bi string) {
	for i := 0; i < 16; i++ {
		s.W1 = append(s.W1, s.BinToUint32(Bi[i*32:(i+1)*32]))
	}
	for j := 16; j < 68; j++ {
		p := s.P1(s.W1[j-16] ^ s.W1[j-9] ^ s.LeftRotate(s.W1[j-3], 15))
		s.W1 = append(s.W1, p^s.LeftRotate(s.W1[j-13], 7)^s.W1[j-6])
	}

	for j := 0; j < 64; j++ {
		s.W2 = append(s.W2, s.W1[j]^s.W1[j+4])
	}
}

// 生成hash值
func (s *SM3) Hash(str string) string {
	s.Input = str
	s.Reset()
	return s.IterationCourse()
}

// 重置struct為零值
func (s *SM3) Reset() {
	s.V = []string{}
	s.B = []string{}
	s.A = []uint32{}
}

func main() {
	// 擷取輸入字元串
	var s SM3

	// "abc"測試
	fmt.Println(s.Hash("abc"))

	// 512bit測試
	fmt.Println(s.Hash("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"))
}
           

C

C代碼

SM3雜湊算法的C、python和go實作Github注意點參考資料

sm3.h

/*
 * sm3.h
 * 為使此算法相容32位、64位下Linux或Windows系統,
 * 選擇 int 來表示 32 位整數。
 * 消息長度最大限定為 2**32 - 1(機關:比特),
 * 且為 8 的倍數(消息的最小單元為位元組)。
*/

#ifndef C_SM3_H
#define C_SM3_H


/*
* SM3算法産生的哈希值大小(機關:位元組)
*/
#define SM3_HASH_SIZE 32

/*
* SM3上下文
*/
typedef struct SM3Context {
    unsigned int intermediateHash[SM3_HASH_SIZE / 4];
    unsigned char messageBlock[64];
} SM3Context;

/*
* SM3計算函數
*/
unsigned char *SM3Calc(const unsigned char *message,
                       unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE]);

#endif //C_SM3_H
           

sm3.cpp

/*
 * sm3.c
*/
#include <stdio.h>
#include <memory.h>
#include "sm3.h"

/*
* 判斷運作環境是否為小端
*/
static const int endianTest = 1;
#define IsLittleEndian() (*(char *)&endianTest == 1)

/*
* 向左循環移位
*/
#define LeftRotate(word, bits) ( (word) << (bits) | (word) >> (32 - (bits)) )

/*
* 反轉四位元組整型位元組序
*/
unsigned int *ReverseWord(unsigned int *word)
{
    unsigned char *byte, temp;

    byte = (unsigned char *)word;
    temp = byte[0];
    byte[0] = byte[3];
    byte[3] = temp;

    temp = byte[1];
    byte[1] = byte[2];
    byte[2] = temp;
    return word;

}

/*
* T
*/
unsigned int T(int i)
{
    if (i >= 0 && i <= 15)
        return 0x79CC4519;
    else if (i >= 16 && i <= 63)
        return 0x7A879D8A;
    else
        return 0;
}

/*
* FF
*/
unsigned int FF(unsigned int X, unsigned int Y, unsigned int Z, int i)
{
    if (i >= 0 && i <= 15)
        return X ^ Y ^ Z;
    else if (i >= 16 && i <= 63)
        return (X & Y) | (X & Z) | (Y & Z);
    else
        return 0;
}

/*
* GG
*/
unsigned int GG(unsigned int X, unsigned int Y, unsigned int Z, int i)
{
    if (i >= 0 && i <= 15)
        return X ^ Y ^ Z;
    else if (i >= 16 && i <= 63)
        return (X & Y) | (~X & Z);
    else
        return 0;
}

/*
* P0
*/
unsigned int P0(unsigned int X)
{
    return X ^ LeftRotate(X, 9) ^ LeftRotate(X, 17);
}

/*
* P1
*/
unsigned int P1(unsigned int X)
{
    return X ^ LeftRotate(X, 15) ^ LeftRotate(X, 23);
}

/*
* 初始化函數
*/
void SM3Init(SM3Context *context)
{
    context->intermediateHash[0] = 0x7380166F;
    context->intermediateHash[1] = 0x4914B2B9;
    context->intermediateHash[2] = 0x172442D7;
    context->intermediateHash[3] = 0xDA8A0600;
    context->intermediateHash[4] = 0xA96F30BC;
    context->intermediateHash[5] = 0x163138AA;
    context->intermediateHash[6] = 0xE38DEE4D;
    context->intermediateHash[7] = 0xB0FB0E4E;
}

/*
* 處理消息塊
*/
void SM3ProcessMessageBlock(SM3Context *context)
{
    int i;
    unsigned int W[68];
    unsigned int W_[64];
    unsigned int A, B, C, D, E, F, G, H, SS1, SS2, TT1, TT2;

    /* 消息擴充 */
    for (i = 0; i < 16; i++)
    {
        W[i] = *(unsigned int *)(context->messageBlock + i * 4);
        if (IsLittleEndian())
            ReverseWord(W + i);
//        printf("%d: %x\n", i, W[i]);
    }
    for (i = 16; i < 68; i++)
    {
        W[i] = P1(W[i - 16] ^ W[i - 9] ^ LeftRotate(W[i - 3], 15))
               ^ LeftRotate(W[i - 13], 7)
               ^ W[i - 6];
//        printf("%d: %x\n", i, W[i]);
    }
    for (i = 0; i < 64; i++)
    {
        W_[i] = W[i] ^ W[i + 4];
//        printf("%d: %x\n", i, W_[i]);
    }

    /* 消息壓縮 */
    A = context->intermediateHash[0];
    B = context->intermediateHash[1];
    C = context->intermediateHash[2];
    D = context->intermediateHash[3];
    E = context->intermediateHash[4];
    F = context->intermediateHash[5];
    G = context->intermediateHash[6];
    H = context->intermediateHash[7];
    for (i = 0; i < 64; i++)
    {
//        printf("%d: %x\n", i, A);
//        printf("%d: %x\n", i, B);
//        printf("%d: %x\n", i, C);
//        printf("%d: %x\n", i, D);
//        printf("%d: %x\n", i, E);
//        printf("%d: %x\n", i, F);
//        printf("%d: %x\n", i, G);
//        printf("%d: %x\n", i, H);
        unsigned int SS3;
//        SS3 = LeftRotate(A, 12);
//        printf("SS3: %d: %x\n", i, SS1);

        SS1 = LeftRotate((LeftRotate(A, 12) + E + LeftRotate(T(i), i)), 7);
        SS2 = SS1 ^ LeftRotate(A, 12);
        TT1 = FF(A, B, C, i) + D + SS2 + W_[i];
        TT2 = GG(E, F, G, i) + H + SS1 + W[i];


//        printf("SS1: %d: %x\n", i, SS1);
//        printf("SS2: %d: %x\n", i, SS2);
//        printf("TT1: %d: %x\n", i, TT1);
//        printf("TT2: %d: %x\n", i, TT2);

        D = C;
        C = LeftRotate(B, 9);
        B = A;
        A = TT1;
        H = G;
        G = LeftRotate(F, 19);
        F = E;
        E = P0(TT2);
    }
    context->intermediateHash[0] ^= A;
    context->intermediateHash[1] ^= B;
    context->intermediateHash[2] ^= C;
    context->intermediateHash[3] ^= D;
    context->intermediateHash[4] ^= E;
    context->intermediateHash[5] ^= F;
    context->intermediateHash[6] ^= G;
    context->intermediateHash[7] ^= H;
}

/*
* SM3算法主函數
*/
unsigned char *SM3Calc(const unsigned char *message,
                       unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE])
{
    SM3Context context;
    unsigned int i, remainder, bitLen;

    /* 初始化上下文 */
    SM3Init(&context);

    /* 對前面的消息分組進行處理 */
    for (i = 0; i < messageLen / 64; i++)
    {
        memcpy(context.messageBlock, message + i * 64, 64);
        SM3ProcessMessageBlock(&context);
    }

    /* 填充消息分組,并處理 */
    bitLen = messageLen * 8;
    if (IsLittleEndian())
        ReverseWord(&bitLen);
    remainder = messageLen % 64;
    memcpy(context.messageBlock, message + i * 64, remainder);
    context.messageBlock[remainder] = 0x80;
    if (remainder <= 55)
    {
        /* 長度按照大端法占8個位元組,該程式隻考慮長度在 2**32 - 1(機關:比特)以内的情況,
        * 故将高 4 個位元組賦為 0 。*/
        memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1 - 8 + 4);
        memcpy(context.messageBlock + 64 - 4, &bitLen, 4);
        SM3ProcessMessageBlock(&context);
    }
    else
    {
        memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1);
        SM3ProcessMessageBlock(&context);
        /* 長度按照大端法占8個位元組,該程式隻考慮長度在 2**32 - 1(機關:比特)以内的情況,
        * 故将高 4 個位元組賦為 0 。*/
        memset(context.messageBlock, 0, 64 - 4);
        memcpy(context.messageBlock + 64 - 4, &bitLen, 4);
        SM3ProcessMessageBlock(&context);
    }

    /* 傳回結果 */
    if (IsLittleEndian())
        for (i = 0; i < 8; i++)
            ReverseWord(context.intermediateHash + i);
    memcpy(digest, context.intermediateHash, SM3_HASH_SIZE);

    return digest;
}
           

sm3test.cpp

#include <string.h>
#include <stdio.h>
#include "sm3.h"
#include <iostream>

//#pragma comment(lib,"sm3dll2")
//extern "C" void SM3Call(const unsigned char *message,unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE]);

int main( int argc, char *argv[] )
{
    unsigned char input[256] = "abc";
    int ilen = 3;
    unsigned char output[32];
    int i;
    // ctx;

    printf("Message:\n");
    printf("%s\n",input);

    SM3Calc(input, ilen, output);
    printf("Hash:\n   ");
    for(i=0; i<32; i++)
    {
        printf("%02x",output[i]);
        if (((i+1) % 4 ) == 0) printf(" ");
    }

    printf("\n");


    unsigned char input2[256] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
    int ilen2 = 64;
    unsigned char output2[32];
    int i2;
    // ctx;

    printf("Message:\n");
    printf("%s\n", input2);

    SM3Calc(input2, ilen2, output2);
    printf("Hash:\n   ");
    for (i2 = 0; i2<32; i2++)
    {
        printf("%02x", output2[i2]);
        if (((i2 + 1) % 4) == 0) printf(" ");
    }
    printf("\n");
    system("pause");
}
           

參考資料

論文:http://www.doc88.com/p-9025639971932.html 需要注意這裡面的壓縮函數部分僞代碼是錯誤的

過程測試資料:https://wenku.baidu.com/view/8d67d80178563c1ec5da50e2524de518964bd3b6.html?qq-pf-to=pcqq.c2c

Python

https://blog.csdn.net/qq_37726361/article/details/84196058

C

https://blog.csdn.net/a344288106/article/details/80094878

Go

https://github.com/ZZMarquis/gm/blob/e92bc99ad9a0305b01cf00d53fd64f356ce37026/sm3/sm3.go#L137