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

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