【问题标题】:Generate permutation with keyword使用关键字生成排列
【发布时间】:2016-03-07 18:55:36
【问题描述】:

我必须实现以下算法,该算法将通过爬山算法在特定密码的密码分析中运行数十亿次。 该算法生成标准字母表 {A,B,C,...,Y,Z} 的排列,其密钥 K 由相同字母表的 7 个字母组成,如下所示:

  • 假设 K = INGXNDM = {9, 14, 7, 24, 14, 4, 13}
  • 从右到左,在字母表上数 K1=9 个位置。到达了 R,所以排列的第一个元素是 R:P = {R,...}
  • 将 R 标记为已使用,稍后我们将不得不“跳过”它。
  • 从 R 向左计数 K2=14 个位置,我们到达 D 并将其标记为已使用。 P={R,D,...}
  • 下一个计数是 7,当到达 A 时,我们循环并认为 Z 跟随 A,所以我们到达 W:将其标记为已使用,P={R,D,W,...}
  • 下一个计数是 24,所以我们到达 V,因为我们跳过了 R、D 和 W。
  • 以此类推...当 K7=13 已经使用时,我们以 K1=9 重新启动
  • 得到的转置字母为:RDWVGBL ZHUKNFI PJSAMXT CQOYE

事实上,我需要解密代码中的逆排列。 我的代码实现了一个链表来跳过使用过的字母。 它以 0 为底,所以 A = 0, ... Z = 25 并返回逆排列 Pinv(i)=j 表示字母 i 在位置 j。

#define ALPHALEN 26
void KeyToPermut(int *K, int * Pinv);
int previnit[ALPHALEN], prev[ALPHALEN], nextinit[ALPHALEN], next[ALPHALEN];

int main() {
    int l, Pinv[ALPHALEN], K[7] = { 8, 13, 6, 23, 13, 3, 12 }, P[ALPHALEN];
    // precalculate links between letters, ordered right to left , from Z to A
    for (l = 0; l < ALPHALEN; l++) {
        previnit[l] = l + 1;  // prev[A] = B
        if (previnit[l] >= ALPHALEN) previnit[l] -= ALPHALEN;  // prev[Z] = A
        nextinit[l] = l - 1; // next[B] = A
        if (nextinit[l] < 0) nextinit[l] += ALPHALEN; // next[A] = Z
    }

    KeyToPermut(K, Pinv); // this is the code to be optimized

    for (l = 0; l < ALPHALEN; l++) P[Pinv[l]] = l;  // calculate direct permutation
    for (l = 0; l < ALPHALEN; l++)  printf("%c", P[l] + 65);
    printf("\n");
}

void KeyToPermut(int *K, int * Permut) {
    int l, keyptr=0, cnt=0, p=0;
    // copy prev[] and next[] from precalculated arrays previnit[] and nextinit[]
    for (l = 0; l < ALPHALEN; l++) {
        prev[l] = previnit[l];
        next[l] = nextinit[l];
    }

    while (1) {
        for (l = 0; l <= K[keyptr] % (ALPHALEN-cnt); l++) p = next[p];

        Permut[p] = cnt++;
        if (cnt < ALPHALEN)
        {
            prev[next[p]] = prev[p];      // link previous and next positions
            next[prev[p]] = next[p];
            keyptr++;
            if (keyptr >= 7) keyptr = 0;  // re-use K1 after K7
        }
        else
            break;
    }
}

我有两个问题:

  1. 如何优化 KeyToPermut 中的代码?分析器显然表明跨链的 for 循环是瓶颈。可能有避免链表的方法...?
  2. 显然密钥空间不是26!但要小得多:26^7,所以只是 26 的一个子集!可以生成。你知道生成的排列有多具体吗?它们是否属于已知的排列类别?例如,(到目前为止)我无法识别这些排列循环中的任何模式。

我使用VS2013和C,项目的其他部分是CUDA代码。 (x64 平台)

感谢您的关注。

背景信息:密码使用的加密方案使用 4 个长度为 7 的密钥 K。因此,用于寻找纯文本的理论密钥空间是 26^28,即 131 位。该方法可以使用其他密钥长度:1 到 25 之间的任何值都可以。

【问题讨论】:

    标签: c algorithm permutation cryptanalysis


    【解决方案1】:

    如何优化 KeyToPermut 中的代码?剖析器显然 表示跨链的 for 循环是瓶颈。 可能有避免链表的方法...?

    我没有找到更好的方法来避免链表,但我们可以使用单链表而不是双链表,因为可以从 for 循环的最后一次迭代中获得所需的先前位置。

    void KeyToPermut(int *K, int *Permut)
    {
        int l, keyptr=0, cnt=0, p=0, prev;
        // copy next[] from precalculated array nextinit[]
        for (l = 0; l < ALPHALEN; l++) next[l] = nextinit[l];
        while (1)
        {
            for (l = 0; l <= K[keyptr] % (ALPHALEN-cnt); l++) prev = p, p = next[p];
            Permut[p] = cnt++;
            if (cnt < ALPHALEN)
            {
                next[prev] = next[p];         // link previous to next position
                p = prev;
                keyptr++;
                if (keyptr >= 7) keyptr = 0;  // re-use K1 after K7
            }
            else
                break;
        }
    }
    

    这节省了大约 10% 的函数运行时间。

    【讨论】:

    • 这个聪明的 10% 增益值得实施。感谢您的宝贵时间
    猜你喜欢
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 2015-03-02
    • 2011-05-18
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多