1 条题解

  • 0
    @ 2025-5-14 23:56:51

    问题理解

    我们需要从给定的密文 CC 和密钥 (x,S,P)(x, S, P) 中恢复明文 MM。加密过程如下:

    1. 计算 dd: [ d = \left\lfloor n^{1.5} + x \right\rfloor \mod n ] 其中 nn 是明文或密文的长度。

    2. 加密 C[d]C[d]

      • C[d]C[d]SS 中位置与 M[d]M[d]PP 中的位置相同的符号。
      • 即,找到 M[d]M[d]PP 中的位置 pospos,然后 C[d]=S[pos]C[d] = S[pos]
    3. 加密其他 C[j]C[j]

      • 对于 jdj \neq dC[j]C[j]SS 中位置等于 M[j]M[j]PP 中的位置与 M[(j+1)modn]M[(j+1) \mod n]SS 中的位置的异或。
      • 即,$pos_C[j] = pos_P[M[j]] \oplus pos_S[M[(j+1) \mod n]]$,然后 C[j]=S[posC[j]]C[j] = S[pos_C[j]]

    解密思路分析

    解密的目标是逆向上述过程:

    1. 计算 dd

      • 同样使用 d=n1.5+xmodnd = \left\lfloor n^{1.5} + x \right\rfloor \mod n
    2. 解密 M[d]M[d]

      • C[d]=S[posP[M[d]]]C[d] = S[pos_P[M[d]]],因此 posP[M[d]]=posS[C[d]]pos_P[M[d]] = pos_S[C[d]]
      • 因为 PPSS 的排列,可以找到 M[d]=P[posS[C[d]]]M[d] = P[pos_S[C[d]]]
    3. 解密其他 M[j]M[j]

      • 对于 jdj \neq d,$pos_C[j] = pos_P[M[j]] \oplus pos_S[M[(j+1) \mod n]]$。
      • 这是一个方程,我们需要解出 posP[M[j]]pos_P[M[j]]posS[M[(j+1)modn]]pos_S[M[(j+1) \mod n]]
      • 由于 posS[M[(j+1)modn]]pos_S[M[(j+1) \mod n]]M[(j+1)modn]M[(j+1) \mod n]SS 中的位置,我们可以利用后续的 MM 值来推断 posS[M[(j+1)modn]]pos_S[M[(j+1) \mod n]]

    解密算法实现

    dd 开始,逆向填充 MM

    1. 初始化

      • 读取 xx, SS, PP, CC
      • 计算 nndd
    2. 解密 M[d]M[d]

      • 找到 C[d]C[d]SS 中的位置 pospos,然后 M[d]=P[pos]M[d] = P[pos]
    3. 解密其他 M[j]M[j]

      • d1d-1 开始,逆向遍历到 dd
      • 对于每个 ii,计算 C[i]C[i]SS 中的位置 temp1temp1
      • 计算 M[(i+1)modn]M[(i+1) \mod n]SS 中的位置 temp2temp2
      • 然后 M[i]=P[temp1temp2]M[i] = P[temp1 \oplus temp2]

    代码实现

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<stdlib.h>
    int main()
    {
        int x,i,j;
        while(~scanf("%d",&x))
        {
            char s[35],p[35],c[70],m[70];
            int splen,n,d;
            if(x==0) break;
            scanf("%s\n%s\n%s",s,p,c);
            splen=strlen(s);
            n=strlen(c);
            d=((int)(pow(n,1.5))+x)%n;
            for(i=0;i<splen;i++)
                if(c[d]==s[i])
                    m[d]=p[i];
            int temp1,temp2;//分别记录c[i]在s中的位置,与m[(i+1)%n]在s中的位置
            for(i=d-1;(i+n)%n!=d;i--)
            {
                if(i<0)
                    i=(i+n)%n;
                for(j=0;j<splen;j++)
                    if(c[i]==s[j])
                    {
                        temp1=j;
                        break;
                    }
                for(j=0;j<splen;j++)
                    if(m[(i+1)%n]==s[j])
                    {
                        temp2=j;
                        break;
                    }
                m[i]=p[temp1^temp2];//运用题解中提到的公式
            }
            for(j=0;j<n;j++)
                printf("%c",m[j]);
            printf("\n");
        }
        return 0;
    }
    

    代码解释

    1. 输入读取

      • 读取 xx, SS, PP, CC
    2. 计算 dd

      • 使用 d=n1.5+xmodnd = \left\lfloor n^{1.5} + x \right\rfloor \mod n
    3. 解密 M[d]M[d]

      • 找到 C[d]C[d]SS 中的位置,然后 M[d]=P[pos]M[d] = P[pos]
    4. 解密其他位置

      • 对于每个 idi \neq d
        • 找到 C[i]C[i]SS 中的位置 posCpos_C
        • 找到 M[(i+1)modn]M[(i+1) \mod n]SS 中的位置 pos_M_next
        • 计算 pos_P_M_i = pos_C \oplus pos_M_next
        • M[i] = P[pos_P_M_i]
    5. 输出结果

      • 打印解密后的 MM
    • 1

    信息

    ID
    1016
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者