import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.junit.Test;
public class Cascade {
//密钥总长度
int n = 10000;
//误码率
double p = 0.01;
//块长参数
double alpha = 0.58;
//块长增长参数
double beta = 2.5;
//Alice的密钥
int[] aliceKeys;
//Bob的密钥
int[] bobKeys;
//第二轮置乱后的Alice密钥
int[] alieceKeysShuffled;
//第二轮置乱后Bob的密钥
int[] bobKeysShuffled;
//第一轮Alice的分块,如aliceBlock[0]表示第一个分块,也是个数组
int[][] aliceBlocks1;
//第一轮Bob的分块
int[][] bobBlocks1;
//第二轮Alice的分块
int[][] aliceBlocks2;
//第二轮Bob的分块
int[][] bobBlocks2;
//第一轮分块长度
int blockLength1 = (int) Math.rint(alpha/p);
//第二轮分块长度
int blockLength2 = (int) Math.rint(blockLength1 * beta);
//第三轮Alice的密钥
int[] aliceKeysR3;
//第三轮Bob的密钥
int[] bobKeysR3;
//置乱的规则
int[] mapRule;
//泄露的信息
int leakedMsg = 0;
//已纠正的错误数
int correctedErr = 0;
//错误分块的集合(都是第一轮的分块),即第几个分块还存在奇数个错误
List<Integer> errBlocks = new LinkedList<Integer>();
//用于产生随机数
Random r = new Random();
public static void main(String[] args) {
//设置循环次数
int num = 1000;
//协议成功次数
int suc = 0;
double eff = 0;
for (int i=0; i<num; i++){
Cascade c = new Cascade();
eff += c.cascade();
if (c.correctedErr == c.n * c.p) suc += 1;
}
eff = eff/num;
System.out.println("效率: "+eff);
System.out.println("成功概率:"+(double)suc/num);
}
//执行cascade流程,返回协商效率
public double cascade(){
//产生Alice和Bob的密钥
aliceKeys = aliceKeysGenerator();
//System.out.println(Arrays.toString(aliceKeys));
bobKeys = bobKeysGenerator();
//System.out.println(Arrays.toString(bobKeys));
//产生Alice和Bob的分块密钥
aliceBlocks1 = divIntoBlocks(aliceKeys, blockLength1);
bobBlocks1 = divIntoBlocks(bobKeys, blockLength1);
//printBlocks(aliceBlocks1,bobBlocks1);
//第一轮纠错
for (int i=0; i<aliceBlocks1.length; i++){
boolean parity = parityCheck(aliceBlocks1[i], bobBlocks1[i]);
//System.out.print(parity+" ");
if (parity == false){
int index = binary(aliceBlocks1[i], bobBlocks1[i]);
bobKeys[blockLength1*i + index] = (bobKeys[blockLength1*i + index]+1) % 2;
}
}
//System.out.println(correctedErr);
//printBlocks(aliceBlocks1,bobBlocks1);
//System.out.println(leakedMsg);
//这里开始第二轮,先获取随机置乱规则
//System.out.println("-------------");
mapRule = getMapRule();
//获取Alice和Bob置乱后的密钥
alieceKeysShuffled = getShuffledKeys(aliceKeys);
bobKeysShuffled = getShuffledKeys(bobKeys);
//将置乱后的密钥分块
aliceBlocks2 = divIntoBlocks(alieceKeysShuffled, blockLength2);
bobBlocks2 = divIntoBlocks(bobKeysShuffled, blockLength2);
//printBlocks(aliceBlocks2, bobBlocks2);
//第二轮第一阶段,和第一轮一样
for (int i=0; i<aliceBlocks2.length; i++){
boolean parity = parityCheck(aliceBlocks2[i], bobBlocks2[i]);
//System.out.print(parity+" ");
if (parity == false){
int index = binary(aliceBlocks2[i], bobBlocks2[i]);
int errIndex = blockLength2*i + index;
//这里的纠错只是把其他需要纠正的密钥中的错误一起纠正了,真正的纠正由binary方法完成
int blockId1 = correctErr2(errIndex);
//被纠正的错误在第一轮中处于第 blockId 个分块,将它添加到错误分块中
addToErrBlocks(blockId1);
}
}
//System.out.println("第二轮一阶段结束后分块情况:");
//printBlocks(aliceBlocks1, bobBlocks1);
//printBlocks(aliceBlocks2, bobBlocks2);
//System.out.println(leakedMsg);
//System.out.println(errBlocks);
//回溯阶段
//System.out.println("----------回溯-------------");
//只要errBlocks不为空,就不断往返进行回溯
while (!errBlocks.isEmpty()){
int blockId1 = errBlocks.get(0);
int index = binary(aliceBlocks1[blockId1], bobBlocks1[blockId1]);
//纠正以后立马移除
errBlocks.remove(new Integer(blockId1));
//得到第一轮分块中的错误位置
int errIndex = blockId1 * blockLength1 + index;
int blockId2 = correctErr1(errIndex);
//由第一轮的错误连锁纠正第二轮中的错误
index = binary(aliceBlocks2[blockId2], bobBlocks2[blockId2]);
errIndex = blockId2 * blockLength2 + index;
blockId1 = correctErr2(errIndex);
//由第二轮的错误又可以得到第一轮的错误,再次添加到错误集合中
addToErrBlocks(blockId1);
}
//第三轮,把第二轮之后的轮次统称为第三轮
//这里为了保证成功率循环纠错5次,某篇改进文章中循环了10次
for (int i=0; i<5; i++){
mapRule = getMapRule();
//Alice和Bob第三轮的密钥
aliceKeysR3 = getShuffledKeys(aliceKeys);
bobKeysR3 = getShuffledKeys(bobKeys);
//考虑到两轮过后误码率极低,因此块长直接固定为n/2
int[] aliceKeysR3Left = Arrays.copyOfRange(aliceKeysR3, 0, n/2);
int[] aliceKeysR3Right = Arrays.copyOfRange(aliceKeysR3, n/2, n);
int[] bobKeysR3Left = Arrays.copyOfRange(bobKeysR3, 0, n/2);
int[] bobKeysR3Right = Arrays.copyOfRange(bobKeysR3, n/2, n);
if (parityCheck(aliceKeysR3Left, bobKeysR3Left) == false){
int errIndex1 = binary(aliceKeysR3Left, bobKeysR3Left);
bobKeys[mapRule[errIndex1]] = (bobKeys[mapRule[errIndex1]]+1) % 2;
int blockId = (int)Math.floor((double)mapRule[errIndex1]/blockLength1);
addToErrBlocks(blockId);
//如果左段出现错误,那么右段也必然有错误,可以直接纠错
int errIndex2 = binary(aliceKeysR3Right, bobKeysR3Right) + n/2;
bobKeys[mapRule[errIndex2]] = (bobKeys[mapRule[errIndex2]]+1) % 2;
blockId = (int)Math.floor((double)mapRule[errIndex2]/blockLength1);
addToErrBlocks(blockId);
}
while (!errBlocks.isEmpty()){
int blockId1 = errBlocks.get(0);
int index = binary(aliceBlocks1[blockId1], bobBlocks1[blockId1]);
//纠正以后立马移除
errBlocks.remove(new Integer(blockId1));
//得到第一轮分块中的错误位置
int errIndex = blockId1 * blockLength1 + index;
bobKeys[errIndex] = (bobKeys[errIndex]+1) % 2;
}
}
//printBlocks(aliceBlocks1, bobBlocks1);
//printBlocks(aliceBlocks2, bobBlocks2);
//System.out.println(leakedMsg);
//System.out.println("已纠正:" + correctedErr);
//该协议最终返回协商效率
double eff = 1 - (double)leakedMsg/n;
return eff;
}
//---------------------------------------------------------------------------
//将该block添加到错误集合中
//如果集合中已经有了这个block,说明之前该block就有奇数个错误,纠正了一个错误
//之后反倒包含偶数个错误,将该block移除
private void addToErrBlocks(int blockId1) {
if (errBlocks.contains(blockId1)){
errBlocks.remove(new Integer(blockId1));
}else{
errBlocks.add(blockId1);
}
}
//根据第一轮错误的下标纠错,纠正三处错误(其实是一个错误)
// 1 第一轮Bob的密钥
// 2 第二轮Bob的密钥
// 3 第二轮Bob的分块密钥
private int correctErr1(int errIndex){
bobKeys[errIndex] = (bobKeys[errIndex]+1) % 2;
//该错误在第二轮Bob分块密钥中的位置
int[] pos = getPosByErrIndex1to2(errIndex);
bobKeysShuffled[pos[0]*blockLength2+pos[1]]
= (bobKeysShuffled[pos[0]*blockLength2+pos[1]]+1) % 2;
bobBlocks2[pos[0]][pos[1]] = (bobBlocks2[pos[0]][pos[1]]+1) % 2;
//该方法顺带返回该错误在第二轮Bob分块中处于第几个分块
return pos[0];
}
//根据第二轮错误下标纠错,纠正三处错误(其实是一个错误):
// 1 第二轮Bob密钥
// 2 第一轮Bob密钥
// 3 第一轮Bob分块密钥
//第二轮Bob分块的错误已经在BINARY中纠正了
private int correctErr2(int errIndex){
bobKeysShuffled[errIndex] = (bobKeysShuffled[errIndex]+1) % 2;
//该错误在第一轮Bob分块密钥中的位置
int[] pos = getPosByErrIndex2to1(errIndex);
bobKeys[mapRule[errIndex]] = (bobKeys[mapRule[errIndex]]+1) % 2;
bobBlocks1[pos[0]][pos[1]] = (bobBlocks1[pos[0]][pos[1]]+1) % 2;
//该方法顺带返回该错误在第一轮Bob分块中处于第几个分块
return pos[0];
}
//根据第一轮错误的下标,它会告诉你这个错误在第二轮属于第几个分块的第几个位置
private int[] getPosByErrIndex1to2(int index){
//index2是该错误在第二轮中的下标
int index2 = 0;
for (int i=0; i<n; i++){
if (mapRule[i] == index) {
index2 = i;
break;
}
}
int blockId = (int)Math.floor((double)index2/blockLength2);
int blockPos = index2 % blockLength2;
return new int[]{blockId, blockPos};
}
//根据第二轮错误的下标,它会告诉你这个错误在第一轮属于第几个分块的第几个位置
private int[] getPosByErrIndex2to1(int index){
int blockId = (int)Math.floor((double)mapRule[index]/blockLength1);
int blockPos = mapRule[index] % blockLength1;
return new int[]{blockId, blockPos};
}
//获取置乱后的密钥,对任何密钥都适用,给它一串密钥它就能按照定义好的规则置乱
private int[] getShuffledKeys(int[] origKeys){
int[] shuffledKeys = new int[n];
for (int i=0; i<n; i++){
shuffledKeys[i] = origKeys[mapRule[i]];
}
return shuffledKeys;
}
//获取置乱规则
private int[] getMapRule(){
int[] a = new int[n];
for (int i=0; i<n; i++){
a[i] = i;
}
int[] res = shuffleKeys(a);
return res;
}
//随机置乱,由于Arrays.aslist不能用于基本类型数组,所以这个方法还有点麻烦
//要么先把int数组转为Integer数组,再用Arrays.aslist,要么就逐个添加
//同理把List转为int数组也得过渡一下
//Python可以直接置乱List,方便很多
private int[] shuffleKeys(int[] a){
List<Integer> list = new ArrayList<Integer>();
for (int i : a) {
list.add(i);
}
Collections.shuffle(list);
Integer[] temp = list.toArray(new Integer[1]);
int[] res = new int[a.length];
for (int i=0; i<a.length; i++) {
res[i] = temp[i].intValue();
}
return res;
}
//测试用的,用来显示Alice和Bob的分块信息
private void printBlocks(int[][] a, int[][] b){
for (int[] i : a) {
System.out.print(Arrays.toString(i));
}
System.out.println();
for (int[] i : b) {
System.out.print(Arrays.toString(i));
}
System.out.println();
}
//BINARY纠错,先找出一个错误位置,再实现纠错
private int binary(int[] a, int[] b) {
int index = binaryRecursion(a, b, 0);
b[index] = (b[index]+1) % 2;
correctedErr += 1;
return index;
}
//BINARY纠错,返回的是出现错误的下标,并没有真正纠正错误
private int binaryRecursion(int[] a, int[] b, int n) {
if (a.length == 1){
return n;
}
//再div处将数组一分为二,并进行递归
int div = (int) Math.floor(a.length/2.0);
if (parityCheck(Arrays.copyOfRange(a, 0, div), Arrays.copyOfRange(b, 0, div))){
return binaryRecursion(Arrays.copyOfRange(a, div, a.length), Arrays.copyOfRange(b, div, b.length), n+div);
}else{
return binaryRecursion(Arrays.copyOfRange(a, 0, div), Arrays.copyOfRange(b, 0, div), n);
}
}
// @Test
// public void test(){
// int[] a = {1,2,3,4,5,6};
// int[] b = shuffleKeys(a);
// System.out.println(Arrays.toString(a));
// System.out.println(Arrays.toString(b));
// }
//奇偶检验
private boolean parityCheck(int[] a, int[] b){
// if (a.length != b.length){
// throw new RuntimeException("奇偶校验时数组长度不一致!");
// }
int parity1 = 0;
int parity2 = 0;
for (int i=0; i<a.length; i++){
parity1 += a[i];
parity2 += b[i];
}
parity1 = parity1%2;
parity2 = parity2%2;
//泄露的信息加一
leakedMsg += 1;
return parity1 == parity2;
}
//将密钥按指定的分块大小分块,得到的是一个二维数组,每个元素是一个分块(也是一个01数组)
private int[][] divIntoBlocks(int[] keys, int blockLength){
int blockNum = (int) Math.ceil((double)keys.length/blockLength);
int[][] blocks = new int[blockNum][];
for (int i=0; i<blockNum; i++){
if (i != blockNum-1){
blocks[i] = Arrays.copyOfRange(keys, i*blockLength, (i+1)*blockLength);
}else{
blocks[i] = Arrays.copyOfRange(keys, i*blockLength, keys.length);
}
}
return blocks;
}
//Bob的密钥发生器
private int[] bobKeysGenerator() {
int[] keys = Arrays.copyOf(aliceKeys, n);
//误码个数
int errorNum = (int) (n * p);
//误码所在的下标,不能重复所以用Set
Set<Integer> errorIndex = new HashSet<Integer>();
while (errorIndex.size() < errorNum){
errorIndex.add(r.nextInt(n));
}
//Bob的密钥是在Alice密钥基础上增加误码
for (int index : errorIndex) {
keys[index] = (keys[index]+1) % 2;
}
return keys;
}
//Alice的密钥发生器
private int[] aliceKeysGenerator() {
int[] keys = new int[n];
for (int i=0; i<keys.length; i++) {
keys[i] = r.nextInt(2);
}
return keys;
}
}
cascade算法的java实现
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.