【学习笔记】二次剩余& Cipolla 算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

学习密码学遇到二次剩余问题,发现cipolla算法可以快速解决,找了相关c++和python代码学习,但密码学涉及数据都是bigint大数类型,所以改了改代码


提示:以下是本篇文章正文内容,下面案例可供参考

一、二次剩余问题

已知同余方程 x^{^{2}}\equiv n(modp),给定 n,p判断该方程是否有解,如果有解则输出所有非负整数解。

注意到n=0的情况是平凡的,只有x=0 一解。如果该方程有解且n\neq 0,则称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

参考(4条消息) Cipolla算法学习小记_Facico的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值