原理
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)))