cascade算法的java实现

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;
	}
	
	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章