基于Go实现Cipolla算法

原理

Cipolla算法学习小记里面很详细了,这里不在赘述。

源码

https://github.com/lwqt99/myInterest,在tools文件夹的bigNumber.go中提供了Cipolla函数,在example.go中提供了一个示例。

Cipolla算法

/*
	Legendre symbol
	计算勒让德符号
	n 整数, p素数
*/
func LegendreSymbol(n, p *big.Int) (*big.Int, error) {
    
    
	//判断p是否为素数
	if !MillerRabbin(p) {
    
    
		return nil, errors.New("p should be prime number")
	}
	//重置n
	n.Mod(n, p)
	//计算 n^((p-1)/2) mod p
	t := new(big.Int).Sub(p, Positive1)
	t.Div(t, Positive2) //t = (p - 1) / 2

	LS := new(big.Int).Exp(n, t, p)
	//fmt.Println("LS=", LS.String())
	return LS, nil
}

/*
	Cipolla算法
	解决二次剩余计算问题:求解 x*x = n mod p
*/
func Cipolla(n, p *big.Int) (*big.Int, error) {
    
    
	//判断是否存在解
	LS, err := LegendreSymbol(n, p)
	if err != nil || LS.String() != "1" {
    
    
		return nil, errors.New("There doesn't exit an solution. ")
	}
	//求解
	//随机生成r
	r := GenerateBigIntByRange(p)
	squareR := new(big.Int).Exp(r, Positive2, p)
	//重新计算LS
	for LS.String() != new(big.Int).Sub(p, Positive1).String() {
    
    
		r = GenerateBigIntByRange(p)
		squareR = new(big.Int).Exp(r, Positive2, p)
		//计算r^2 - n的勒让德符号
		t := new(big.Int).Sub(squareR, n)
		t.Mod(t, p) //t = r^2 - n
		LS, _ = LegendreSymbol(t, p)
	}
	//计算二次剩余
	//x := new(big.Int)
	//定义 w^2 = r^2 - n
	squareW := new(big.Int).Sub(squareR, n)
	squareW.Mod(squareW, p)
	//x = (a + w) ^ ((p+1)/2)
	//复数的快速幂
	t := new(big.Int).Add(p, Positive1)
	t.Div(t, Positive2) //t = ((p+1)/2)
	//定义虚数
	im := struct {
    
    
		x *big.Int
		y *big.Int
	}{
    
    }
	im.x = new(big.Int).SetInt64(1)
	im.y = new(big.Int).SetInt64(0)
	//定义Ax Ay
	Ax, Ay := new(big.Int).Set(r), new(big.Int).SetInt64(1)

	seq := BigNumBaseConversion(t, 2)
	//fmt.Println(seq)
	for i := 0; i < len(seq); i++ {
    
    
		if string(seq[len(seq)-i-1]) == "1" {
    
    
			//做乘法
			//new(big.Int).Mul(im.y, Ay)要乘上w*w
			im.x, im.y = new(big.Int).Add(new(big.Int).Mul(im.x, Ax), new(big.Int).Mul(new(big.Int).Mul(im.y, Ay), squareW)),
				new(big.Int).Add(new(big.Int).Mul(im.x, Ay), new(big.Int).Mul(im.y, Ax))

			im.x = im.x.Mod(im.x, p)
			im.y = im.y.Mod(im.y, p)
		}
		//Ax Ay 自乘
		Ax, Ay = new(big.Int).Add(new(big.Int).Mul(Ax, Ax), new(big.Int).Mul(new(big.Int).Mul(Ay, Ay), squareW)),
			new(big.Int).Mul(new(big.Int).Mul(Ax, Ay), Positive2)

		Ax = Ax.Mod(Ax, p)
		Ay = Ay.Mod(Ay, p)
	}
	//fmt.Println("x=", im.x, "y=", im.y)
	//fmt.Println("x=", new(big.Int).Sub(p, im.x), "y=", im.y)
	//验证
	//v := new(big.Int).Exp(im.x, Positive2, p)
	//fmt.Println("x^2=", v.String())
	return im.x, nil
}

例子

fmt.Println(Cipolla(new(big.Int).SetInt64(5), new(big.Int).SetInt64(84906529)))

猜你喜欢

转载自blog.csdn.net/u012421101/article/details/128437210