BNUOJ---29141 背包密码

本文介绍了一种基于背包密码系统的解密方法。通过选取超递增序列与特定的数学运算,实现对二进制串的加密与解密。文章详细解释了如何利用已知的加密参数逆向求解原始消息。

背包密码系统是一种非常经典的公钥密码系统,这种密码系统加密过程如下:

  1. 选取一个长度为n的正整数超递增序列a[i],满足a[1]<a[2],a[1]+a[2]<a[3],……,a[1]+a[2]+…+a[n-1]<a[n]。
  2. 选取正整数m>2*a[n],w和m互质,v是w模m的逆,即(v*w)%m=1。b[i]=(w*a[i])%m。
  3. 加密时,对一段长为n的二进制串x[i]。有S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n])%m。
现在告诉你b[i]、v和m以及S,请你帮忙进行解密。
v是w的逆,所以可以求解出a[i] = (b[i] * v) % m.
因为sum = ∑a[i](i = 1~n-1) < a[n],所以当a[i] <= sum时,a[i] += ((sum - a[i]) + 1) * m, 使其大于sum。
S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n])%m
 =w * (a[1]*x[1]+a[2]*x[2]+…+a[n]*x[n]) % m
∑a[i] * x[i] = (S * v) % m,令ans = (S * v) % m
由于a[i]是超递增序列,当ans > a[i]时,x[i]一定为1。因为a[1] +.... + a[i - 1] < a[i] 。由此便可解出x[i].
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 35;
ll t, n, b[maxn], v, m, s, a[maxn], x[maxn];
int main(){
    scanf("%lld", &t);
    while(t--){
        memset(x, 0, sizeof(x));
        scanf("%lld", &n);
        for(int i=0; i<n; i++) scanf("%lld", &b[i]);
        scanf("%lld%lld%lld", &v, &m, &s);
        ll sum = 0;
        for(int i=0; i<n; i++){
            a[i] = (b[i] * v) % m;
            if(a[i] <= sum)
                a[i] += m * ((sum - a[i]) / m + 1);
        }
        ll ans = (v * s) % m;
        for(int i=n-1; i>=0; i--){
            if(a[i] <= ans){
                x[i] = 1;
                ans -= a[i];
            }
        }
        for(int i=0; i<n; i++) printf("%lld", x[i]);
        puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值