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實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.