标签:
出于无聊, 打算从头实现一遍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个数, 就能碰到一个素数
原理大概就是这样
中间有一些优化, 是为了减少对大整数的直接计算
附上代码如下
1 /** 2 * 计算 base^exp % n 3 * 4 * @param base 5 * @param exp 6 * @param n 7 * @return 8 */ 9 public static BigInteger expmod(int base, BigInteger exp, BigInteger n) { 10 if (exp.equals(BigInteger.ZERO)) { 11 return BigInteger.ONE; 12 } 13 14 if (!exp.testBit(0)) {//如果为偶数 15 return expmod(base, exp.divide(BigInteger.valueOf(2)), n).pow(2).remainder(n); 16 } else { 17 return (expmod(base, exp.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)), n).pow(2).multiply(BigInteger.valueOf(base))).remainder(n); 18 } 19 } 20 21 /** 22 * 费马测试, 如果返回false, 则n肯定为合数, 如果为true, 则n有一半以上的概率为素数 23 * 24 * @param n 25 * @return 26 */ 27 public static boolean fermatTest(BigInteger n) { 28 int base = 0; 29 if (n.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) < 0) { 30 base = ran.nextInt(n.intValue() - 1) + 1; 31 } else { 32 base = ran.nextInt(Integer.MAX_VALUE - 1) + 1; 33 } 34 if (expmod(base, n, n).equals(BigInteger.valueOf(base))) { 35 return true; 36 } else { 37 return false; 38 } 39 } 40 41 42 public static boolean isPrime(BigInteger n) { 43 return isPrime(n, 100); 44 } 45 46 /** 47 * 多次调用费马测试, 判定输入的n是否为质数 48 * 49 * @param n 50 * @param tryTime 51 * @return 52 */ 53 public static boolean isPrime(BigInteger n, int tryTime) { 54 for (int i = 0; i < tryTime; i++) { 55 if (!fermatTest(n)) { 56 return false; 57 } 58 } 59 return true; 60 } 61 62 /** 63 * 产生一个n bit的素数 64 * 65 * @param bitCount 66 * @return 67 */ 68 public static BigInteger getPrime(int bitCount) { 69 //随机生成一个n bit的大整数 70 BigInteger init = new BigInteger(bitCount, ran); 71 //如果n为偶数, 则加一变为奇数 72 if (!init.testBit(0)) { 73 init = init.setBit(0); 74 } 75 int i = 0; 76 //基于素数定理, 平均只需要不到n次搜索, 就能找到一个素数 77 while (!isPrime(init)) { 78 i++; 79 init = init.add(BigInteger.valueOf(2)); 80 } 81 //System.out.println(String.format("try %d\ttimes", i)); 82 return init; 83 }
标签:
原文地址:http://www.cnblogs.com/stevenczp/p/4299072.html