出于无聊, 打算从头实现一遍RSA算法

第一步, 大素数生成

Java的BigInteger里, 有个现成的方法

  public static BigInteger probablePrime(int bitLength, Random rnd) {

  bitLength是期望生成的素数的二进制位数, rnd是随机数发生器

  函数注释表明, 这个方法的返回值为合数的概率为2^-100

生成100个1024位的素数, 耗时13471ms

但是显然我不打算直接使用这个函数, 要做就从最底层做起!

目前的做法是基于费马素性检测

假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

也就是说, 如果p为素数, 那么对于任何a<p, 有

a ^ p % p == a   成立

而它的逆命题则至少有1/2的概率成立

那么我们就可以通过多次素性检测, 来减少假素数出现的概率

而素数定理, 又指出了素数的密度与ln(x)成反比, 也就是说, 我们可以先随机生成一个n bit的整数, 如果不是素数, 则继续向后取, 那么, 大概取n个数, 就能碰到一个素数

原理大概就是这样

中间有一些优化, 是为了减少对大整数的直接计算

2015.2.25更新

Miller-Rabin检测  http://www.matrix67.com/blog/archives/234

Carmichael数: 本身为合数, 但是无论做多少次费马检查, 都会被判定为素数

为了避免Carmichael数, 就有了新的检查方式

1. 如果p是素数,x是小于p的正整数,且x^2 mod p = 1,那么要么x=1,要么x=p-1

2. 尽可能提取因子2,把n-1表示成d*2^r,如果n是一个素数,那么或者a^d mod n=1,或者存在某个i使得a^(d*2^i) mod n=n-1 ( 0<=i<r )

生成100个1024位素数, 耗时182141ms

性能不到标准库的十分之一

附上代码如下

package com.steven.rsa;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random; /**
*
* @author steven
*/
public class Utils { private static Random ran = null; static {
ran = new SecureRandom();
} /**
* 计算 base^exp % n
*
* @param base
* @param exp
* @param n
* @return
*/
public static BigInteger expmod(int base, BigInteger exp, BigInteger n) {
if (exp.equals(BigInteger.ZERO)) {
return BigInteger.ONE;
} if (!exp.testBit(0)) {//如果为偶数
return expmod(base, exp.divide(BigInteger.valueOf(2)), n).pow(2).remainder(n);
} else {
return (expmod(base, exp.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)), n).pow(2).multiply(BigInteger.valueOf(base))).remainder(n);
}
} /**
* 费马测试, 如果返回false, 则n肯定为合数, 如果为true, 则n有一半以上的概率为素数
*
* @param n
* @return
*/
public static boolean fermatTest(BigInteger n) {
int base = 0;
if (n.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) < 0) {
base = ran.nextInt(n.intValue() - 1) + 1;
} else {
base = ran.nextInt(Integer.MAX_VALUE - 1) + 1;
}
if (expmod(base, n, n).equals(BigInteger.valueOf(base))) {
return true;
} else {
return false;
}
} /**
* Miller-Rabin测试
*
* @param n
* @return
*/
public static boolean passesMillerRabin(BigInteger n) {
int base = 0;
if (n.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) < 0) {
base = ran.nextInt(n.intValue() - 1) + 1;
} else {
base = ran.nextInt(Integer.MAX_VALUE - 1) + 1;
} BigInteger thisMinusOne = n.subtract(BigInteger.ONE);
BigInteger m = thisMinusOne;
while (!m.testBit(0)) {
m = m.shiftRight(1);
BigInteger z = expmod(base, m, n);
if (z.equals(thisMinusOne)) {
break;
} else if (z.equals(BigInteger.ONE)) { } else {
return false;
}
}
return true;
} public static boolean isPrime(BigInteger n) {
//copy自jdk源码, n的bit数越多, 需要的检测次数就越少
//注释说是根据标准 ANSI X9.80, "PRIME NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES".
//我不知道为什么
int sizeInBits = n.bitLength();
int tryTime = 0;
if (sizeInBits < 100) {
tryTime = 50;
} if (sizeInBits < 256) {
tryTime = 27;
} else if (sizeInBits < 512) {
tryTime = 15;
} else if (sizeInBits < 768) {
tryTime = 8;
} else if (sizeInBits < 1024) {
tryTime = 4;
} else {
tryTime = 2;
}
return isPrime(n, tryTime);
} /**
* 多次调用素数测试, 判定输入的n是否为质数
*
* @param n
* @param tryTime
* @return
*/
public static boolean isPrime(BigInteger n, int tryTime) {
for (int i = 0; i < tryTime; i++) {
if (!passesMillerRabin(n)) {
return false;
}
}
return true;
} /**
* 产生一个n bit的素数
*
* @param bitCount
* @return
*/
public static BigInteger getPrime(int bitCount) {
//随机生成一个n bit的大整数
BigInteger init = new BigInteger(bitCount, ran);
//如果n为偶数, 则加一变为奇数
if (!init.testBit(0)) {
init = init.setBit(0);
}
int i = 0;
//基于素数定理, 平均只需要不到n次搜索, 就能找到一个素数
while (!isPrime(init)) {
i++;
init = init.add(BigInteger.valueOf(2));
}
//System.out.println(String.format("try %d\ttimes", i));
return init;
}
}

  

重复造轮子之RSA算法(一) 大素数生成的更多相关文章

  1. 重复造轮子系列--dijkstra算法

    前年一时脑热(理想很丰满,现实很骨感),写了这个最短路径优先的低效版本,且留着回忆吧. spf.h #ifndef SPF_H_ #define SPF_H_ typedef struct { int ...

  2. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  3. 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

    一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...

  4. 重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关

    重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关 引言 重复造轮子系列是自己平时的一些总结.有的轮子依赖社区提供的轮子为基础,这里把使用过程的一些觉得有意思的做个分享.有些思路或者方法在 ...

  5. 重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

    重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印 一.引言 桌面端系统经常需要对接各种硬件设备,比如扫描器.读卡器.打印机等. 这里介绍下桌面端 ...

  6. Meteva——让预报检验不再重复造轮子

    更多精彩,请点击上方蓝字关注我们! 检验是什么?****预报准确率的客观表达 说到天气预报,你最先会想到什么? 早上听了预报,带了一天伞却没下一滴雨的调侃? 还是 "蓝天白云晴空万里突然暴风 ...

  7. 54 个官方 Spring Boot Starters 出炉!别再重复造轮子了…….

    在之前的文章,栈长介绍了 Spring Boot Starters,不清楚的可以点击链接进去看下. 前段时间 Spring Boot 2.4.0 也发布了,本文栈长再详细总结下最新的 Spring B ...

  8. GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

    1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...

  9. 第27篇 重复造轮子---模拟IIS服务器

    在写程序的时候,重复造轮子是程序员的一个大忌,很多人对重复造轮子持有反对的态度,但是我觉得这个造轮子的过程,是对于现有的知识的一个深入的探索的过程,虽然我们不可能把轮子造的那么的完善,对于现在有的东西 ...

随机推荐

  1. Manjaro 添加国内源和安装搜狗输入法

    Manjaro 系统虽然比 Ubuntu 用着稳定,但有些小地方没有 Ubuntu 人性化,比如默认安装完的系统貌似没有中国的,Ubuntu 估计是用的人多,所以安装完后会根据所在地给你配置更新的源. ...

  2. POJ:1185-炮兵阵地(状压dp入门)

    炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组 ...

  3. Linux学习-额外(单一)核心模块编译

    编译前注意事项 由于我们的核心原本就有提供很多的核心工具给硬件开发商来使用, 而硬件开发商也需要针对核心 所提供的功能来设计他们的驱动程序模块,因此, 我们如果想要自行使用硬件开发商所提供的模块 来进 ...

  4. Linux学习-检验软件正确性

    md5sum / sha1sum / sha256sum 目前有多种机制可以计算文件的指纹码,我们选择使用较为广泛的 MD5, SHA1 或 SHA256 加密机 制来处理,我们拿NTP 软件来检查看 ...

  5. Linux学习-进程管理

    为什么进程管理这么重要呢? 这是因为: 首先,我们在操作系统时的各项工作其实都是经过某个 PID 来达成的 (包括你的 bash 环境), 因此,能不能进行某项工作,就与该进程的权限有关了. 再来,如 ...

  6. selenium2 页面对象模型Page Object

    开发Selenium WebDriver测试时,可以使用页面对象模型,这样可使得测试脚本有更高的可维护性,减少了重复的代码,把页面抽象出来.同时页面对象模型也提供了一个注释,帮助缓存远程,避免出现元素 ...

  7. 实现hadoop自动安装包

    最近研究hadoop,需要安装多个dadanode,想从重复劳动解脱出来,只能自己实现自动安装包,开始考虑使用shell.python等实现,感觉比较费时间,用installshield又有点牛刀小试 ...

  8. JAVA-基础(六) Java.io

    由于IDEA相对于我这种新手来说,对学习JAVA还是比较方便,后记都移步到IDEA中进行基础学习 1.File(文件类) 尽管java.io定义的大多数类是实行流式操作的,File类不是.它直接处理文 ...

  9. hdu1787 GCD Again poj 2478 Farey Sequence 欧拉函数

    hdu1787,直接求欧拉函数 #include <iostream> #include <cstdio> using namespace std; int n; int ph ...

  10. rocketmq源码分析2-broker的消息接收

    broker消息接收,假设接收的是一个普通消息(即没有事务),此处分析也只分析master上动作逻辑,不涉及ha. 1. 如何找到消息接收处理入口 可以通过broker的监听端口10911顺藤摸瓜式的 ...