提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
学习密码学遇到二次剩余问题,发现cipolla算法可以快速解决,找了相关c++和python代码学习,但密码学涉及数据都是bigint大数类型,所以改了改代码
提示:以下是本篇文章正文内容,下面案例可供参考
一、二次剩余问题
已知同余方程 ,给定 n,p判断该方程是否有解,如果有解则输出所有非负整数解。
注意到的情况是平凡的,只有 一解。如果该方程有解且,则称n为模 p意义下的二次剩余。
p为奇素数的时Cipolla 算法非常有效!!
二、算法流程
1.引入库
代码如下(示例):
import (
"crypto/rand"
"fmt"
"github.com/ZZMarquis/gm/util"
"math/big"
"strconv"
)
2.素数判断
代码如下(示例):
if n.ProbablyPrime(20) { fmt.Println(n, "is probably prime") } else { fmt.Println(n, "is not prime") }
3.算法实现
package main import ( "crypto/rand" "fmt" "github.com/ZZMarquis/gm/util" "math/big" "strconv" type CN struct { R *big.Int //real part I *big.Int //imaginary part } var w *big.Int func CNmul(i1 *CN, i2 *CN, p, w *big.Int) *CN { var z *CN z = new(CN) newR1 := new(big.Int).Mul(i1.R, i2.R) newR2 := new(big.Int).Mul(i1.I, i2.I) newR2 = new(big.Int).Mul(newR2, w) z.R = util.Mod(new(big.Int).Add(newR1, newR2), p) newI1 := new(big.Int).Mul(i1.R, i2.I) newI2 := new(big.Int).Mul(i1.I, i2.R) z.I = util.Mod(new(big.Int).Add(newI1, newI2), p) return z } func qsm(x, y, n *big.Int) (*big.Int, error) { z := new(big.Int).SetInt64(1) zero := new(big.Int).SetInt64(0) if y != zero { for { i := fmt.Sprintf("%b", y) //转成2进制 int, err := strconv.Atoi(i) if err != nil { return nil, err } if int&1 == 1 { z = new(big.Int).Mul(z, x) z = util.Mod(z, n) fmt.Println("z=", z) } x = new(big.Int).Mul(x, x) x = util.Mod(x, n) y = new(big.Int).Div(y, new(big.Int).SetInt64(2)) if y.Cmp(zero) == 0 { z = z break } } } return z, nil } func Cqsm(x *CN, y, p, w *big.Int) (*CN, error) { var z *CN z = new(CN) z.R = new(big.Int).SetInt64(1) z.I = new(big.Int).SetInt64(0) zero := new(big.Int).SetInt64(0) if y != zero { for { i := fmt.Sprintf("%b", y) int, err := strconv.Atoi(i) if err != nil { return nil, err } if int&1 == 1 { z = CNmul(z, x, p, w) } x = CNmul(x, x, p, w) y = new(big.Int).Div(y, new(big.Int).SetInt64(2)) if y.Cmp(zero) == 0 { z = z break } } } return z, nil } var u, v *CN func Findsqrt(n, p *big.Int) (*big.Int, *big.Int) { n = util.Mod(n, p) if p == new(big.Int).SetInt64(2) { z := new(big.Int).SetInt64(1) return z, nil } pp := util.Sub(p, new(big.Int).SetInt64(1)) p_2 := new(big.Int).Div(pp, new(big.Int).SetInt64(2)) req, _ := qsm(n, p_2, p) if req.Cmp(pp) == 0 { fmt.Println("No root") z := new(big.Int).SetInt64(0) return z, nil } var a1 *big.Int Loop: for { a, err := rand.Int(rand.Reader, p) if err != nil { z := new(big.Int).SetInt64(0) return z, nil } a = util.Mod(a, p) w = new(big.Int).Mul(a, a) w = w.Sub(w, n) w = w.Add(w, p) w = util.Mod(w, p) res, err := qsm(w, p_2, p) if err != nil { z := new(big.Int).SetInt64(0) return z, nil } if res.Cmp(pp) == 0 { a1 = a break Loop } } u = new(CN) u.R = a1 u.I = new(big.Int).SetInt64(1) ps := util.Add(p, new(big.Int).SetInt64(1)) p_s := new(big.Int).Div(ps, new(big.Int).SetInt64(2)) u, _ = Cqsm(u, p_s, p, w) yi := u.R er := new(big.Int).Sub(p, u.R) return yi, er } var a, b *big.Int func main() { n := new(big.Int).SetInt64(17) m := new(big.Int).SetInt64(4) a, b = Findsqrt(m, n) fmt.Printf("a=%v\n,b=%v\n", a, b) }
总结
实现了实现了,感恩的心
主函数里实现的是该题的一个例子。
Timus Online Judge 1132 Square Root