Cascade信息协商算法 matlab实现

Cascade信息协商算法的具体实现步骤
  1. Alice 和 Bob 生成随机序列并完成交织,即改变初始密钥 K A K_A KA K B K_B KB的顺序,使错误比特尽可能地均匀分布。
  2. 完成交织后,Alice 和 Bob 对随机序列进行分组,记每次分组的长度为 L i L_i Li i i i为协商次数),使每组中错误个数不大于1。同时记录每个比特所在的分组号。初始分组的长度可设定为 L 1 = α p k d r L_1=\frac{\alpha}{p_{kdr}} L1=pkdrα α \alpha α为块长参数, p k d r p_{kdr} pkdr为协商前的密钥不匹配率),之后协商轮次的分组长度可设为 L i = β L i − 1 L_i={\beta}L_{i-1} Li=βLi1 β \beta β为增长参数, β ≥ 1 \beta\geq1 β1)。
  3. 发送方和接收方在公开信道交互奇偶校验的结果,并将接收到的校验比
    特与自身对应分组的校验比特进行对比。若双方校验比特不同,则利用二分法查错,然后将错误位统一纠正为比特 1 或 0。本轮纠错结束后,每组中的错误个数均为偶数。
  4. 重新进行交织分组,开始新一轮纠错。通信双方同样进行校验位对比,
    若不同,则再次进行二分法差错。如果在新一轮的查找中发现了新的错误,则说明,该分组中还有包括该错误在内的偶数个错误在上一轮纠错中没有被发现。因为之前已经保存了每个比特所在的分组号,此时只需要找出该错误位在上一轮中所在的分组重新进行纠错即可。两轮纠错并不能保证所有错误均被找出,因此还需更多轮次的纠错。
  5. 重复上个步骤直到新的轮次中未出现新的错误。需要注意的是,若纠错
    轮次大于 2 轮,进行回溯操作时需要注意回溯到之前所有轮,这样可以使纠正的错误达到最多。
  6. 分组一致性确认,使得双方密钥完全相同。
clc,
clear all;

% Cascade信息协商算法

n = 10000; % 密钥总长度
p = 0.01; % 误码率
alpha = 0.58; % 块长参数
beta = 2.5; % 块长增长参数
blockLength1 = round(alpha/p); % 第一轮分块长度
blockLength2 = round(blockLength1*beta); % 第二轮分块长度

% 设置循环次数
num = 100;
% 协议成功次数
suc = 0;
efft = 0.0;
for i = 1:num
    leakedMsg = 0; % 泄露的信息
    correctedErr = 0; % 已纠正的错误数
    % 错误分块的集合(都是第一轮分块),即第几个分块还存在奇数个错误
    errBlocks = [];
    [eff, correctedErr] = cascade(n, p, blockLength1, blockLength2, leakedMsg, correctedErr, errBlocks);
    efft = efft+eff;
    % 纠正的个数等于误码个数
    if correctedErr == p*n
        % disp('协商成功');
        suc = suc+1;
    end
end
efft = efft/num;
disp(strcat('平均协商效率:',num2str(efft)));
disp(strcat('成功概率:',num2str(suc/num)));

%% 方法部分

function [eff, correctedErr] = cascade(n, p, blockLength1, blockLength2, leakedMsg, correctedErr, errBlocks)
    % 产生Alice和Bob的密钥
    keyA = AliceKeyGenerator(n); 
    keyB = BobKeyGenerator(n, keyA, p);

    % 产生Alice和Bob的分块密钥
    BlocksA1 = divIntoBlocks(keyA, blockLength1);
    BlocksB1 = divIntoBlocks(keyB, blockLength1);

    % 第一轮纠错
    for i = 1:length(BlocksA1)
        % 对每一块进行奇偶校验,返回布尔值
        [parity, leakedMsg] = parityCheck(BlocksA1{i}, BlocksB1{i}, leakedMsg);
        if parity == 0
            % binary函数自带纠错,同时返回当前块的index,这一步纠正了BlocksB1分块密钥的错误
            [index, correctedErr, BlocksB1{i}] = binary(BlocksA1{i}, BlocksB1{i}, leakedMsg, correctedErr);
            % 然后纠正原始密钥的错误
            keyB(blockLength1*(i-1)+index) = mod(keyB(blockLength1*(i-1)+index)+1, 2);
        end
    end

    % 开始第二轮,先获取随机置乱规则
    % 置乱规则就是一个乱序的随机数组
    mapRule = getMapRule(n);

    % 获取置乱后的密钥
    keyAShuffled = getShuffledKeys(keyA, n, mapRule);
    keyBShuffled = getShuffledKeys(keyB, n, mapRule);

    % 将置乱后的密钥分块,这时的块长和第一次纠错的块长不一样,要更长
    BlocksA2 = divIntoBlocks(keyAShuffled, blockLength2);
    BlocksB2 = divIntoBlocks(keyBShuffled, blockLength2);

    % 第二轮第一阶段,与第一轮一样
    for i = 1:length(BlocksA2)
        [parity, leakedMsg] = parityCheck(BlocksA2{i}, BlocksB2{i}, leakedMsg);
        if parity == 0
            % 进行纠错
            [index, correctedErr, BlocksB2{i}] = binary(BlocksA2{i}, BlocksB2{i}, leakedMsg, correctedErr);
            % 同时计算出在置换后密钥的错误位置
            errIndex = blockLength2*(i-1)+index;
            % 这里的纠错只是把其他需要纠正的密钥中的错误一起纠正了,真正的纠正由binary方法完成
            [blockId1, keyBShuffled, keyB, BlocksB1] = correctErr2(errIndex, keyB, keyBShuffled, BlocksB1, mapRule, blockLength1);
            % 被纠正的错误在第一轮中处于第blockId个分块,将它添加到错误分块中
            errBlocks = addToErrBlocks(errBlocks, blockId1);
        end
    end

    % 只要errBlocks不为空,就不断往返进行回溯
    while ~isempty(errBlocks)
        blockId1 = errBlocks(1);
        [index1, correctedErr, BlocksB1{blockId1}] = binary(BlocksA1{blockId1}, BlocksB1{blockId1}, leakedMsg, correctedErr);
        % 纠正以后立马移除
        errBlocks(errBlocks == blockId1) = [];
        % 得到第一轮分块中的错误位置
        errIndex1 = (blockId1-1)*blockLength1+index1;
        [blockId2, keyBShuffled, keyB, BlocksB2] = correctErr1(errIndex1, keyB, keyBShuffled, BlocksB2, mapRule, blockLength2, n);
        % 由第一轮的错误连锁纠正第二轮中的错误
        [index2, correctedErr, BlocksB2{blockId2}] = binary(BlocksA2{blockId2}, BlocksB2{blockId2}, leakedMsg, correctedErr);
        errIndex2 = (blockId2-1)*blockLength2+index2;
        [blockId1, keyBShuffled, keyB, BlocksB1] = correctErr2(errIndex2, keyB, keyBShuffled, BlocksB1, mapRule, blockLength1);
        % 由第二轮的错误又能得到第一轮的错误
        errBlocks = addToErrBlocks(errBlocks, blockId1);  
    end

    % 第三轮,为了保证成功率循环纠错5次
    for i = 1:5
        mapRule = getMapRule(n);
        % Alice和Bob的第三轮密钥
        keyA3 = getShuffledKeys(keyA, n, mapRule);
        keyB3 = getShuffledKeys(keyB, n, mapRule);
    
        % 前两轮误码率较低,块长直接固定为n/2
        keyALeft = keyA3(1:n/2);
        keyARight = keyA3(n/2+1:n);
        keyBLeft = keyB3(1:n/2);
        keyBRight = keyB3(n/2+1:n);
    
        [parity, leakedMsg] = parityCheck(keyALeft, keyBLeft, leakedMsg);
        if parity == 0
            [errIndex1, correctedErr] = binary(keyALeft, keyBLeft, leakedMsg, correctedErr);
            keyB(mapRule(errIndex1)) = mod(keyB(mapRule(errIndex1))+1, 2);
            blockId = ceil(mapRule(errIndex1)/blockLength1);
            errBlocks = addToErrBlocks(errBlocks, blockId);
            % 如果左段出现错误,右段也必然有错误,可以直接纠错
            [errIndex2, correctedErr] = binary(keyARight, keyBRight, leakedMsg, correctedErr);
            errIndex2 = errIndex2+n/2;
            keyB(mapRule(errIndex2)) = mod(keyB(mapRule(errIndex2))+1, 2);
            blockId = ceil(mapRule(errIndex2)/blockLength2);
            errBlocks = addToErrBlocks(errBlocks, blockId);
        end
        while ~isempty(errBlocks)
            blockId1 = errBlocks(1);
            [index, correctedErr, BlocksB1{blockId1}] = binary(BlocksA1{blockId1}, BlocksB1{blockId1}, leakedMsg, correctedErr);
            % 纠正以后立马移除
            errBlocks(errBlocks == blockId1) = [];
            % 得到第一轮分块中的错误位置
            errIndex = (blockId1-1)*blockLength1+index;
            keyB(errIndex) = mod(keyB(errIndex)+1, 2);
        end
    end

    eff = 1-leakedMsg/n;

end

% Alice的密钥发生器
function keyA = AliceKeyGenerator(n)
    keyA = randi([0 1],1,n);
end

% Bob的密钥发生器
function keyB = BobKeyGenerator(n, keyA, p)
    keyB = keyA;
    % 误码数由误码率决定
    errornum = round(n*p);
    % 误码索引
    errorIndex = [];
    cnt = length(errorIndex)+1;
    while cnt <= errornum
        errorIndex(cnt) = randi([1 n],1,1);
        cnt = cnt+1;
    end
    % Bob密钥是在Alice密钥基础上增加误码
    for i = 1:length(errorIndex)
        idB = errorIndex(i);
        keyB(idB) = mod(keyB(idB)+1, 2); 
    end
end

% 将密钥按照指定大小分块,每个元素是一个分块
function blocks = divIntoBlocks(keys, blocklength)
    blocknum = ceil(length(keys)/blocklength);
%     blocks = zeros(blocknum, blocklength);
    blocks = {};
    for i = 1:blocknum
        if i ~= blocknum
            blocks{i} = keys((i-1)*blocklength+1:i*blocklength);
        else
            blocks{i} = keys((i-1)*blocklength+1:length(keys));
        end
    end
end

% 奇偶校验,将一个块中所有数组相加最后对2求余
function [parity,leakedMsg] = parityCheck(a, b, leakedMsg)
    parity1 = 0;
    parity2 = 0;
    for i = 1:length(a)
        parity1 = parity1+a(i);
        parity2 = parity2+b(i);
    end
    parity1 = mod(parity1,2);
    parity2 = mod(parity2,2);
    leakedMsg = leakedMsg+1;
    if parity1 == parity2
        parity = 1;
    else
        parity = 0;
    end
end

% Binary纠错,先找出一个错误位置,再实现纠错
function [index, correctedErr, b] = binary(a, b, leakedMsg, correctedErr)
    index = binaryRecursion(a, b, 1, leakedMsg);
    b(index) = mod(b(index)+1, 2);
    correctedErr = correctedErr+1;
end

% Binary纠错,返回的是出现错误的下标,并没有真正纠正错误
% 不断进行二分奇偶校验,直到得到index
function id = binaryRecursion(a, b, n, leakedMsg)
    % 在div处将数组一分为二,并进行递归
    if length(a) == 1
        id = n;
        return;
    end
    div = floor(length(a)/2);
    [parity,leakedMsg] = parityCheck(a(1:div), b(1:div), leakedMsg);
    if parity == 1
        id = binaryRecursion(a(div+1:length(a)), b(div+1:length(b)), n+div, leakedMsg);
    else
        id = binaryRecursion(a(1:div), b(1:div), n, leakedMsg);
    end
end

% 获取置乱规则
function res = getMapRule(n)
    aa = zeros(1,n);
    for i = 1:n
        aa(i) = i;
    end
    res = shuffleKeys(aa);
end

% 随机置乱
function res = shuffleKeys(a)
    res = randperm(length(a)); % 生成随机顺序的索引
end

% 获取置乱后的密钥
function shuffledKeys = getShuffledKeys(keys, n, mapRule)
    shuffledKeys = zeros(1,n);
    for i = 1:n
        shuffledKeys(i) = keys(mapRule(i));
    end
end

% 纠正错误
% 根据第一轮错误的下标纠错,纠正三处错误(其实是一个错误)
% 1 第一轮Bob的密钥
% 2 第二轮Bob的密钥
% 3 第二轮Bob的分块密钥
function [id, keyBShuffled, keyB, BlocksB2] = correctErr1(errIndex, keyB, keyBShuffled, BlocksB2, mapRule, blockLength2, n)
    keyB(errIndex) = mod(keyB(errIndex)+1, 2);
    % 该错误在第二轮Bob分块密钥中的位置
    [pos, ~] = getPosByErrIndex1to2(n, errIndex, mapRule, blockLength2);
    keyBShuffled((pos(1)-1)*blockLength2+pos(2)) = mod(keyBShuffled((pos(1)-1)*blockLength2+pos(2))+1, 2);
    BlocksB2{pos(1)}(pos(2)) = mod(BlocksB2{pos(1)}(pos(2))+1, 2);
    % 该方法顺带返回该错误在第二轮Bob分块中处于第几个分块
    id = pos(1);
end

% 根据第二轮错误的下标纠错,纠正三处错误(其实是一个错误)
% 1 第二轮Bob的密钥
% 2 第一轮Bob的密钥
% 3 第一轮Bob的分块密钥
% 第二轮Bob分块的错误已经在Binary中纠正了
function [id, keyBShuffled, keyB, BlocksB1] = correctErr2(errIndex, keyB, keyBShuffled, BlocksB1, mapRule, blockLength1)
    % 对置换后的密钥进行纠错
    keyBShuffled(errIndex) = mod(keyBShuffled(errIndex)+1, 2);
    % 该错误在第一轮Bob分块密钥的位置,返回一个二元数组,分别是块数和块内的index
    pos = getPosByErrIndex2to1(errIndex, mapRule, blockLength1);
    % 对原始密钥进行纠错
    keyB(mapRule(errIndex)) = mod(keyB(mapRule(errIndex))+1, 2);
    % 对BlocksB1进行纠错
    BlocksB1{pos(1)}(pos(2)) = mod(BlocksB1{pos(1)}(pos(2))+1, 2);
    % 该方法顺带返回该错误在第一轮Bob分块中处于第几个分块
    id = pos(1);
end

% 根据第一轮错误的下标,它会告诉你这个错误在第二轮属于第几个分块的第几个位置
function [res, index2] = getPosByErrIndex1to2(n, index, mapRule, blockLength2)
    % index2是该错误在第二轮的下标
    index2 = 0;
    res = zeros(1,2);
    for i = 1:n
        if mapRule(i) == index
            index2 = i;
            break;
        end
    end
    blockId = ceil(index2/blockLength2);
    blockPos = mod(index2-1, blockLength2)+1;
    res(1,1) = blockId;
    res(1,2) = blockPos;
end

% 根据第二轮错误的下标,它会告诉你这个错误在第一轮属于第几个分块的第几个位置
function res = getPosByErrIndex2to1(index, mapRule, blockLength1)
    res = zeros(1,2);
    blockId = ceil(mapRule(index)/blockLength1);
    blockPos = mod(mapRule(index)-1, blockLength1)+1;
    res(1,1) = blockId;
    res(1,2) = blockPos;
end

% 将该block添加到错误集合中
function errBlocks = addToErrBlocks(errBlocks, blockId1)
    len = length(errBlocks);
    % 如果集合中已经有了这个block,说明之前该block就有奇数个错误,纠正了一个错误
    if ~isempty(find(errBlocks == blockId1, 1)) 
        % 因为奇偶校验只能解决有奇数个错误的块,有偶数个错误的解决不了,所以移除
        errBlocks(errBlocks == blockId1) = [];
    else
        errBlocks(len+1) = blockId1;
    end
end

参考:

  1. CASCADE算法解读
  2. 基于信道特性的密钥生成关键技术研究及实现
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值