当前位置: 首页 > article >正文

golang 实现比特币内核:椭圆曲线有限域的代码实现

让我们开始有限域的代码之旅,进入一个空目录,创建一个名为bitcoin的新文件夹,在bitcoin目录中,再创建一个名为elliptic-curve的新文件夹。在该文件夹中初始化一个新的包,运行以下命令:


go init mod elliptic_curve

然后我们创建一个新文件finite-element,我们将在这里编写有限域元素的代码,将以下代码放入文件中:


package elliptic_curve

import (
	"fmt"
)

type FieldElement struct {
	order uint64 // field的阶
	num   uint64 // 该元素在域中的值
}

func NewFieldElement(order uint64, num uint64) FieldElement {
	/*
		FieldElement的构造函数,相当于Python中的__init__
	*/

	if num >= order || num < 0 {
		err := fmt.Sprintf("Num not in the range from 0 to %d", order)
		panic(err)
	}

	return FieldElement{
		order: order,
		num:   num,
	}
}

func (f FieldElement) String() string {
	// 将对象格式化为可打印的字符串,相当于Python中的__repr__
	return fmt.Sprintf("FieldElement{order: %d, num: %d}", f.order, f.num)
}

func (f FieldElement) EqualTo(other FieldElement) bool {
	/*
		两个域元素在阶和数值相等时才相等
	*/
	return f.order == other.order && f.num == other.num
}

现在我们已经有了有限域元素的基本结构,让我们添加更多的方法。对于域元素有两种操作,一种是“+”即模加法,另一种是“.”即模乘法。让我们看看如何进行加法操作:


func (f *FieldElement) Add(other *FieldElement) *FieldElement {
	if other.order != f.order {
		panic("add need to do on field element with the same order")
	}

	// 记得做模运算
	return NewFieldElement(f.order, (f.num+other.num)%f.order)
}

func (f *FieldElement) Negate() *FieldElement {
	/*
		对于一个域元素a,其负值是域中另一个元素b,使得(a + b) % order= 0
		(注意模数是order),由于域中元素的值小于其阶,我们可以通过order - a得到a的负值。
	*/

	return NewFieldElement(f.order, f.order-f.num)
}

func (f *FieldElement) Substract(other *FieldElement) *FieldElement {
	// 如何实现?
	return nil
}

现在在main.go文件中调用以上代码来检查结果,如下所示:


package main

import (
	ecc "elliptic_curve"
	"fmt"
)

func main() {
	/*
		构建阶为57的域,并进行加减法操作
	*/
	f44 := ecc.NewFieldElement(57, 44)
	f33 := ecc.NewFieldElement(57, 33)
	// 44 + 33 等于 (44+33) % 57 等于 20
	res := f44.Add(f33)
	fmt.Printf("域元素44加上域元素33结果是:%v\n", res)
	// -44是域元素44的负值,即57 - 44 = 13
	fmt.Printf("域元素44的负值是:%v\n", f44.Negate())
}

然后运行以下命令:


go run main.go

如果一切正常,您将看到以下结果:


field element 44 add to field element 33 is : FieldElement{order: 57, num: 20}
negate of field element 44 is : FieldElement{order: 57, num: 37}```

现在我们解决减法的问题,对于域元素a, b,我们希望找到域元素c,使得c = a - b。注意a - b等于a + (-b),而(-b)是b的负值,这意味着c等于a加上b的负值。让我们将其写入代码:


func (f *FieldElement) Subtract(other *FieldElement) *FieldElement {
	// 首先找到other的负值
	// 将其加上other的负值
	return f.Add(other.Negate())
}

现在在main中添加一些代码来运行Subtract函数:


func main() {
    ....
fmt.Printf("域元素44 - 33结果是:%v\n", f44.Substract(f33))
	fmt.Printf("域元素33 - 44结果是:%v\n", f33.Subtract(f44))

	// 检查 (11+33)%57 == 44
	// 检查 (46 + 44) % 57 == 33
	fmt.Printf("检查46 + 44在57模下结果是%d\n", (46+44)%57)
	// 使用域元素检查
	f46 := ecc.NewFieldElement(57, 46)
	fmt.Printf("域元素46 + 44结果是%v\n", f46.Add(f44))
}

运行代码,我们可以得到以下结果:


field element 44 add to field element 33 is : FieldElement{order: 57, num: 20}
negate of field element 44 is : FieldElement{order: 57, num: 37}
field element 44 - 33 is : FieldElement{order: 57, num: 11}
field element 33 - 44 is : FieldElement{order: 57, num: 46}
check 46 + 44 over modulur 57 is 33
field element 46 + 44 is FieldElement{order: 57, num: 33}

我们可以进行一些简单的算术计算,(46+44) % 57的结果确实是33,这意味着我们的代码逻辑是正确的。接下来我们看看如何添加乘法和幂运算操作,即在模数order下的乘法和幂操作,代码如下:


func (f *FieldElement) checkOrder(other *FieldElement) {
	if other.order != f.order {
		panic("add need to do on field element with the same order")
	}
}

func (f *FieldElement) Multiplie(other *FieldElement) *FieldElement {
	f.checkOrder(other)
	// 在模数order下乘法
	return NewFieldElement(f.order, (f.num*other.num)%f.order)
}

func (f *FieldElement) Power(power int64) *FieldElement {
	return NewFieldElement(f.order, uint64(math.Pow(float64(f.num), float64(power)))%f.order)
}

我们运行新增的代码进行测试,在main.go中添加如下代码:


func main() {
...
    fmt.Printf("元素46自身相乘的结果是:%v\n", f46.Multiplie(f46))
    fmt.Printf("元素46的2次幂是%v\n", f46.Power(2))
}

运行结果是:

multiplie element 46 with itself is :FieldElement{order: 57, num: 7}
element 46 with power to 2 is FieldElement{order: 57, num: 7}

可以看到,元素46的自乘等于其2次幂的计算结果。现在是问题时间了,对于阶为19的有限域,随机选择一个元素k,计算{k . 0, k . 1, … k . 18},结果会是什么呢?

让我们用代码来解决这个问题,首先我们需要为域元素添加一个方法,使其可以乘以标量数:


func (f *FieldElement) ScalarMul(val uint64) *FieldElement {
	return NewFieldElement(f.order, (f.num*val)%f.order)
}

现在到main.go中,并用以下代码解决问题:


package main

import (
	ecc "elliptic_curve"
	"fmt"
	"math/rand"
)

func SolveField19MultiplieSet() {
	// 随机选择一个1到18的数
	min := 1
	max := 18
	k := rand.Intn(max-min) + min
	fmt.Printf("随机选择的k是:%d\n", k)
	element := ecc.NewFieldElement(19, uint64(k))
	for i := 0; i < 19; i++ {
		fmt.Printf("元素%d乘以%d的结果是%v\n", k, i, element.ScalarMul(uint64(i)))
	}
}

func main() {
	SolveField19MultiplieSet()
}

如果运行以上代码,您可能会得到以下结果:

element 2 multiplie with 0 is FieldElement{order: 19, num: 0}
element 2 multiplie with 1 is FieldElement{order: 19, num: 2}
element 2 multiplie with 2 is FieldElement{order: 19, num: 4}
element 2 multiplie with 3 is FieldElement{order: 19, num: 6}
element 2 multiplie with 4 is FieldElement{order: 19, num: 8}
element 2 multiplie with 5 is FieldElement{order: 19, num: 10}
element 2 multiplie with 6 is FieldElement{order: 19, num: 12}
element 2 multiplie with 7 is FieldElement{order: 19, num: 14}
element 2 multiplie with 8 is FieldElement{order: 19, num: 16}
element 2 multiplie with 9 is FieldElement{order: 19, num: 18}
element 2 multiplie with 10 is FieldElement{order: 19, num: 1}
element 2 multiplie with 11 is FieldElement{order: 19, num: 3}
element 2 multiplie with 12 is FieldElement{order: 19, num: 5}
element 2 multiplie with 13 is FieldElement{order: 19, num: 7}
element 2 multiplie with 14 is FieldElement{order: 19, num: 9}
element 2 multiplie with 15 is FieldElement{order: 19, num: 11}
element 2 multiplie with 16 is FieldElement{order: 19, num: 13}
element 2 multiplie with 17 is FieldElement{order: 19, num: 15}
element 2 multiplie with 18 is FieldElement{order: 19, num: 17}

http://www.kler.cn/a/380967.html

相关文章:

  • 3.4 stm32系列:定时器(PWM、定时中断)
  • 小白考研历程:跌跌撞撞,起起伏伏,五个月备战历程!!!
  • 相机雷达外参标定综述“Automatic targetless LiDAR–camera calibration: a survey“
  • 使用FakeSMTP创建本地SMTP服务器接收邮件具体实现。
  • RHEL 7.5 源码安装 mysql-5.7.17 数据库
  • linux springboot项目启动端口被占用 Port 8901 was already in use.
  • #渗透测试#SRC漏洞挖掘# 操作系统-windows系统bat病毒
  • 有线电视 1.27.5 | 完全免费的电视直播应用,频道丰富,画质清晰
  • 成功解决WSL2上的Ubuntu22.04执行sudo apt-get update指令报错问题
  • 基于A*算法的无人车路径规划
  • 高斯飞溅OccGaussian 人体重建
  • IP-guard与Ping32文档加密解决方案对比,选择适合自己的解决方案
  • glsl基于LTC的面光源渲染 - 矩形光通过three.js
  • Java基础-Java中的常用类(上)
  • 服务器作业3
  • H7-TOOL的LUA小程序教程第17期:扩展驱动AD7606, ADS1256,MCP3421, 8路继电器和5路DS18B20(2024-11-01)
  • RPC核心实现原理
  • 华为eNSP:配置DHCP Snooping
  • 梁山派入门指南3——串口使用详解,包括串口发送数据、重定向、中断接收不定长数据、DMA+串口接收不定长数据,以及对应的bsp文件和使用示例
  • 冒泡排序、选择排序、计数排序、插入排序、快速排序、堆排序、归并排序JAVA实现
  • 小新学习k8s第四天之发布管理
  • Pr 视频效果:透视
  • 【Nginx】前端项目开启 Gzip 压缩大幅提高页面加载速度
  • Ant Design Vue 的 a-table 行选择分页时bug处理
  • 官方redis安装
  • React Hooks 为什么不能在 if 语句中使用???