golang 实现比特币内核:实现基于有限域上的椭圆曲线

我们已经看到了椭圆曲线上整数的操作,令人惊讶的是,我们可以将这些整数转换为有限域中的成员而不出现问题。请记住,字段成员的运算“+”和“.”是正常的算术运算,但结果会进行模运算。结果表明,即使基于模数操作,椭圆曲线点加法仍然成立。

例如,我们可以验证有限域的阶为103,从该字段中取出两个成员17和64,将它们组合为一个点坐标(17, 64),该点在模103的曲线 y^2 = x^3 + 7 上:

y^2 = 64^2 % 103 = 79,x^3 + 7 = (17^3 + 7) % 103 = 79

现在让我们将Point结构重写,将其组件从big.Int改为FieldElement,修改后的代码如下所示:

package elliptic_curve

import (
	"fmt"
	"math/big"
)

type OP_TYPE int

const (
	ADD OP_TYPE = iota
	SUB
	MUL
	DIV
	EXP
)

type Point struct {
	a *FieldElement
	b *FieldElement
	x *FieldElement
	y *FieldElement
}

func OpOnBig(x *FieldElement, y *FieldElement, scalar *big.Int, opType OP_TYPE) *FieldElement {
	switch opType {
	case ADD:
		return x.Add(y)
	case SUB:
		return x.Subtract(y)
	case MUL:
		/*
			Multiply in two cases, one is two field member multiply,
			the other is field member multiply with scalar
		*/
		if y != nil {
			return x.Multiply(y)
		}
		if scalar != nil {
			return x.ScalarMul(scalar)
		}
		panic("error in multiply")
	case DIV:
		return x.Divide(y)
	case EXP:
		if scalar == nil {
			panic("scalar should not be nil for EXP op")
		}
		return x.Power(scalar)
	}

	panic("should not come to here")
}

func NewEllipticCurvePoint(x *FieldElement, y *FieldElement, a *FieldElement, b *FieldElement) *Point {
	if x == nil && y == nil {
		return &Point{
			x: x,
			y: y,
			a: a,
			b: b,
		}
	}

	left := OpOnBig(y, nil, big.NewInt(int64(2)), EXP)
	x3 := OpOnBig(x, nil, big.NewInt(int64(3)), EXP)
	ax := OpOnBig(a, x, nil, MUL)
	right := OpOnBig(OpOnBig(x3, ax, nil, ADD), b, nil, ADD)
	if left.EqualTo(right) != true {
		err := fmt.Sprintf("Point(%v, %v) is not on the curve with a:%v, b:%v\n", x, y, a, b)
		panic(err)
	}

	return &Point{
		x: x,
		y: y,
		a: a,
		b: b,
	}

}

func (p *Point) Add(other *Point) *Point {
	//check two points are on the same curve
	if p.a.EqualTo(other.a) != true || p.b.EqualTo(other.b) != true {
		panic("given two points are not on the same curve")
	}

	if p.x == nil {
		return other
	}

	if other.x == nil {
		return p
	}

	//points are on the vertical A(x,y) B(x,-y),
	zero := NewFieldElement(p.x.order, big.NewInt(int64(0)))
	if p.x.EqualTo(other.x) == true &&
		OpOnBig(p.y, other.y, nil, ADD).EqualTo(zero) == true {
		return &Point{
			x: nil,
			y: nil,
			a: p.a,
			b: p.b,
		}
	}

	//find slope of line AB
	//x1 -> p.x, y1->p.y, x2 ->other.x, y2->other.y
	var numerator *FieldElement
	var denominator *FieldElement
	if p.x.EqualTo(other.x) == true && p.y.EqualTo(other.y) == true {
		//slope = (3*x^2+a)/2y
		xSqrt := OpOnBig(p.x, nil, big.NewInt(int64(2)), EXP)
		threeXSqrt := OpOnBig(xSqrt, nil, big.NewInt(int64(3)), MUL)
		numerator = OpOnBig(threeXSqrt, p.a, nil, ADD)
		//denominator: 2y
		denominator = OpOnBig(p.y, nil, big.NewInt(int64(2)), MUL)
	} else {
		numerator = OpOnBig(other.y, p.y, nil, SUB)   //(y2-y1)
		denominator = OpOnBig(other.x, p.x, nil, SUB) //(x2-x1)
	}

	//s=(y2-y1) / (x2-x1)
	slope := OpOnBig(numerator, denominator, nil, DIV)
	//s^2
	slopeSqrt := OpOnBig(slope, nil, big.NewInt(int64(2)), EXP)
	//x3 = s^2 - x1 - x2
	x3 := OpOnBig(OpOnBig(slopeSqrt, p.x, nil, SUB), other.x, nil, SUB)
	// x3-x1
	x3Minusx1 := OpOnBig(x3, p.x, nil, SUB)
	//y3 = s(x3-x1)+y1
	y3 := OpOnBig(OpOnBig(slope, x3Minusx1, nil, MUL), p.y, nil, ADD)
	//-y3
	minusY3 := OpOnBig(y3, nil, big.NewInt(int64(-1)), MUL)

	return &Point{
		x: x3,
		y: minusY3,
		a: p.a,
		b: p.b,
	}
}

func (p *Point) String() string {
	xString := "nil"
	yString := "nil"
	if p.x != nil {
		xString = p.x.String()
	}
	if p.y != nil {
		yString = p.y.String()
	}
	return fmt.Sprintf("(x:%s\n, y:%s\n, a:%s\n, b:%s\n)", xString, yString,
		p.a.String(), p.b.String())
}

func (p *Point) Equal(other *Point) bool {
	if p.a.EqualTo(other.a) == true && p.b.EqualTo(other.b) == true &&
		p.x.EqualTo(other.x) == true &&
		p.y.EqualTo(other.y) == true {
		return true
	}

	return false
}

func (p *Point) NotEqual(other *Point) bool {
	if p.a.EqualTo(other.a) != true || p.b.EqualTo(other.b) != true ||
		p.x.EqualTo(other.x) != true ||
		p.y.EqualTo(other.y) != true {
		return true
	}

	return false
}

我们相应地修改了代码,没有新的内容,现在我们可以测试更改后的代码如下:

elliptic curve point over finite field is (x:FieldElement{order: 223, num: 192}

, y:FieldElement{order: 223, num: 105}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
addition of points on vertical line over finit field is (x:nil
, y:nil
, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
p1 + p2 over field order 223 is (x:FieldElement{order: 223, num: 170}

, y:FieldElement{order: 223, num: 142}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
p1 + p1 over field order 223 is (x:FieldElement{order: 223, num: 49}

, y:FieldElement{order: 223, num: 71}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)

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

elliptic curve point over finite field is (x:FieldElement{order: 223, num: 192}

, y:FieldElement{order: 223, num: 105}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
addition of points on vertical line over finit field is (x:nil
, y:nil
, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
p1 + p2 over field order 223 is (x:FieldElement{order: 223, num: 170}

, y:FieldElement{order: 223, num: 142}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)
p1 + p1 over field order 223 is (x:FieldElement{order: 223, num: 49}

, y:FieldElement{order: 223, num: 71}

, a:FieldElement{order: 223, num: 0}

, b:FieldElement{order: 223, num: 7}

)

请放心,我已经用纸和笔验证了这些结果,您可以相信我!

完整代码下载:
https://github.com/wycl16514/golang-bitcoin-elliptic-curve-cryptography

更多内容请参看:
http://m.study.163.com/provider/7600199/index.htm?share=2&shareId=7600199
B 站搜索:coding 迪斯尼
公号:coding 迪斯尼

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值