Go语言基础&区块链中的典型密码算法
Go语言基础&区块链中的典型密码算法
实验概述
Go(又称golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。由于实验环境是在go环境下开发,因此需要预先对go的语法规则有一个基本的了解。
实验1-1:入门练习
请使用Go语言编写一段程序,实现以下功能:给定三个不同的正整数,求它们的最小公倍数。
实验流程
- 假设参与计算的三个数为
; - 首先计算
两数的最小公倍数:- 遍历从1到
的所有整数,假设 能被 整除; 即为 和 的最小公倍数,记作 ;
- 遍历从1到
- 再使用同样的方法即可计算
和 的最小公倍数 。
源代码
package main
import (
"fmt"
"os"
"strconv"
)
func lcm(num1, num2 int) int {
for i := 1; i <= num1; i++ {
if num1%i == 0 {
if i*num2%num1 == 0 {
return i * num2
}
}
}
return num1 * num2
}
func leastCommonMultiple(num1 int, num2 int, num3 int) int {
var lcmResult int
//在这里写求最小公倍数的代码
lcmResult = lcm(lcm(num1, num2), num3)
return lcmResult
}
// 测试时,在终端进入ex1-1文件夹,输入以下指令
// go run main.go 整数1 整数2 整数3
// 例如:
// go run main.go 6 8 10
func main() {
args := os.Args
num1, _ := strconv.Atoi(args[1])
num2, _ := strconv.Atoi(args[2])
num3, _ := strconv.Atoi(args[3])
lcmResult := leastCommonMultiple(num1, num2, num3)
fmt.Print(lcmResult)
}
实验结果截图

实验1-2:比特币测试网地址的生成
参考以下比特币地址生成流程,用Go语言实现如下操作:
使用RIPEMD-160、SHA-256哈希算法以及Base58编码对给定公钥生成地址给定公钥:
- public key 1:
02b1ebcdbac723f7444fdfb8e83b13bd14fe679c59673a519df6a1038c07b719c6
- public key 2:
036e69a3e7c303935403d5b96c47b7c4fa8a80ca569735284a91d930f0f49afa86
提示:
比特币中有两种复合式的哈希函数,分别为:
HASH160,即先对输入做一次SHA256,再做一次RIPEMD160;
HASH256,即先对输入做一次SHA256,再做一次SHA256。
本练习要求的version byte为0x6f(测试网)。
实验流程
- 输入公钥
并对其进行 运算得到 ; - 将
与 进行连接,然后进行 运算,并取前4个字节作为 ; - 将
连接在 与 之后,整体进行 编码,即可得到比特币测试网地址 。
源代码
package main
import (
"base58"
"crypto/sha256"
"encoding/hex"
"fmt"
"golang.org/x/crypto/ripemd160"
)
const version byte = 0x6f
const addressChecksumLen = 4 //定义checksum长度为四个字节
var myAlphabet = base58.BitcoinAlphabet
var PublicKey1 = "02b1ebcdbac723f7444fdfb8e83b13bd14fe679c59673a519df6a1038c07b719c6"
var PublicKey2 = "036e69a3e7c303935403d5b96c47b7c4fa8a80ca569735284a91d930f0f49afa86"
func hash160(inputByte []byte) (hash160Result []byte) {
//在这里实现计算hash160的代码
sha := sha256.New()
sha.Write(inputByte)
sha256Result := sha.Sum(nil)
ripemd := ripemd160.New()
ripemd.Write(sha256Result)
hash160Result = ripemd.Sum(nil)
return hash160Result
}
func hash256(inputByte []byte) (hash256Result []byte) {
//在这里实现计算hash256的代码
sha_1 := sha256.New()
sha_1.Write(inputByte)
sha256Result := sha_1.Sum(nil)
sha_2 := sha256.New()
sha_2.Write(sha256Result)
hash256Result = sha_2.Sum(nil)
return hash256Result
}
func GetAddress(PublicKey string) (encodestring string) {
//在这里实现计算比特币地址的代码
PublicKey_bytes, _ := hex.DecodeString(PublicKey)
fingerprint := hash160(PublicKey_bytes)
ver_fingerprint := append([]byte{version}, fingerprint...)
var checksum []byte = hash256(ver_fingerprint)[:addressChecksumLen]
address := append(ver_fingerprint, checksum...)
output := base58.Encode(address, myAlphabet)
return output
}
func main() {
address1 := GetAddress(PublicKey1)
address2 := GetAddress(PublicKey2)
fmt.Printf("address1: %s\n", address1)
fmt.Printf("address2: %s\n", address2)
}
实验结果截图
实验3
Merkle Tree是比特币中用来存储交易单的一种数据结构,它是一种二叉树,所有叶子节点均为交易数据块,而非叶子节点则存储了该节点两个子节点的Hash值,经过层层传递,最终得到根Hash值,这样,当任何叶子节点的交易数据发生改变时,都会导致根Hash值的改变,这对于验证和定位被修改的交易十分高效:
实验流程
Merkle Tree搭建流程:
- 首先将16组数据(
)封装在二维数组datas
中,将每组数据分别作为每个叶节点的值; - 叶节点上一层的节点中存储对应叶节点的哈希值;
- 叶节点两层及以上的节点则存储其对应的两个子节点的哈希值相连接的哈希值;
- 如此层层往上,直到计算出该Merkle Tree根节点的哈希值。
compareMerkleTree函数设计流程:
- 假设Tree1和Tree2是修改前后的两棵Merkle Tree,定义初始索引值
,高度 ; - 从根节点开始从上往下依次遍历(两树根节点中对应的数据必然不同),当该节点的左右节点均不为空时,如果两节点的左子节点中对应的数据不同,则将检索节点转移到其左子节点,索引值
乘以2再加1;如果两节点的右子节点中对应的数据不同,则将检索节点转移到其右子节点,索引值 乘以2再加2;检索节点每向下转移一层,高度 增加1; - 当检索节点的左子节点非空而右子节点为空时,函数返回值
,对应被修改过的数据 的下标 。
源代码
package main
import (
"bytes"
"crypto/sha256"
"fmt"
"math"
)
// 定义一个MerkleNode节点
type MerkleNode struct {
Left *MerkleNode
Right *MerkleNode
Data []byte
}
// 定义一个MerkleTree
type MerkleTree struct {
RootNode *MerkleNode
}
// 你可以自己定义一系列函数
func sha_256(value []byte) []byte {
sha := sha256.New()
sha.Write(value)
return sha.Sum(nil)
}
func createMerkleNode(left *MerkleNode, right *MerkleNode, data []byte) *MerkleNode {
node := MerkleNode{}
if left == nil && right == nil {
node.Data = data
} else if left != nil && right == nil {
node.Data = sha_256(left.Data)
} else {
node.Data = sha_256(append(left.Data, right.Data...))
}
node.Left = left
node.Right = right
return &node
}
func buildMerkleTree(datas [][]byte) *MerkleTree {
var nodes []MerkleNode
for _, datum := range datas {
dataNode := createMerkleNode(nil, nil, datum)
node := createMerkleNode(dataNode, nil, nil)
nodes = append(nodes, *node)
}
for {
var newLevel []MerkleNode
if len(nodes)%2 == 1 {
for j := 0; j < len(nodes)-1; j += 2 {
node := createMerkleNode(&nodes[j], &nodes[j+1], nil)
newLevel = append(newLevel, *node)
}
node := createMerkleNode(&nodes[len(nodes)-1], nil, nil)
newLevel = append(newLevel, *node)
} else {
for j := 0; j < len(nodes); j += 2 {
node := createMerkleNode(&nodes[j], &nodes[j+1], nil)
newLevel = append(newLevel, *node)
}
}
nodes = newLevel
if len(nodes) == 1 {
break
}
}
mTree := MerkleTree{&nodes[0]}
return &mTree
}
func compareMerkleTree(tree1 *MerkleTree, tree2 *MerkleTree) int {
p, q := *tree1.RootNode, *tree2.RootNode
index := 0
height := 0
for {
if p.Left != nil && p.Right != nil {
if bytes.Compare(p.Left.Data, q.Left.Data) != 0 {
p = *p.Left
q = *q.Left
index = 2*index + 1
} else {
p = *p.Right
q = *q.Right
index = 2*index + 2
}
height++
} else if p.Left != nil && p.Right == nil {
return index - int(math.Pow(2, float64(height))) + 2
}
}
}
func main() {
datas := [][]byte{
[]byte("node1"),
[]byte("node2"),
[]byte("node3"),
[]byte("node4"),
[]byte("node5"),
[]byte("node6"),
[]byte("node7"),
[]byte("node8"),
[]byte("node9"),
[]byte("node10"),
[]byte("node11"),
[]byte("node12"),
[]byte("node13"),
[]byte("node14"),
[]byte("node15"),
[]byte("node16"),
}
tree := buildMerkleTree(datas)
root := tree.RootNode
fmt.Println(root.Data)
var index int
var data string
fmt.Println("请输入要修改的数据块的索引号和修改后的值:")
_, _ = fmt.Scanln(&index, &data)
datas[index-1] = []byte(data)
tree2 := buildMerkleTree(datas)
root2 := tree2.RootNode
fmt.Println(root2.Data)
fmt.Println(compareMerkleTree(tree, tree2))
}
实验结果截图
分别修改
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具