Problem:
Problem C:
Leaky Cryptography
The ACM ICPC judges are very careful about not leaking their problems, and all communications are encrypted. However, one does sometimes make mistakes, like using too weak an
encryption scheme. Here is an example of that.
The encryption chosen was very simple: encrypt each chunk of the input by flipping some bits
according to a shared key. To provide reasonable security, the size of both chunk and key is 32
bits.
That is, suppose the input was a sequence of
m
32-bit integers.
N
1
N
2
N
3
...
N
m
After encoding with the key
K
it becomes the following sequence of
m
32-bit integers.
(
N
1
∧
K
) (
N
2
∧
K
) (
N
3
∧
K
) ... (
N
m
∧
K
)
where (
a
∧
b
) is the bitwise
exclusive or
of
a
and
b
.
Exclusive or is the logical operator which is 1 when only one of its operands is 1, and 0 otherwise.
Here is its definition for 1-bit integers.
0 ⊕ 0 = 0      0 ⊕ 1 = 1
     1 ⊕ 0 = 1      1 ⊕ 1 =0
As you can see, it is identical to addition modulo 2. For two 32-bit integers
a
and
b
, their bitwise
exclusive or
a
∧
b
is defined as follows, using their binary representations, composed of 0's and 1's.
a
∧
b
=
a
31
...
a
1
a
0
∧
b
31
...
b
1
b
0
=
c
31
...
c
1
c
0
where
c
i
=
a
i
⊕
b
i
(
i
= 0, 1, ... , 31).
For instance, using binary notation, 11010110 ∧ 01010101 = 10100011, or using hexadecimal,
d6 ∧ 55 = a3.
Since this kind of encryption is notoriously weak to statistical attacks, the message has to be
compressed in advance, so that it has no statistical regularity. We suppose that
N
1
N
2
...
N
m
is already in compressed form.
However, the trouble is that the compression algorithm itself introduces some form of regularity:
after every 8 integers of compressed data, it inserts a checksum, the sum of these integers. That
is, in the above input,
N
9
= ∑
8
i
=1
N
i
=
N
1
+ ... +
N
8
, where additions are modulo 2
32
.
Luckily, you could intercept a communication between the judges. Maybe it contains a problem for the finals!
As you are very clever, you have certainly seen that you can easily find the lowest bit of the key,
denoted by
K
0
. On the one hand, if
K
0
= 1, then after encoding, the lowest bit of ∑
8
i
=1
N
i
∧
K
is unchanged, as
K
0
is added an even number of times, but the lowest bit of
N
9
∧
K
is changed,
so they shall differ. On the other hand, if
K
0
= 0, then after encoding, the lowest bit of ∑
8
i
=1
N
i
∧
K
shall still be identical to the lowest bit of
N
9
∧
K
, as they do not change. For instance, if the lowest bits after encoding are 1 1 1 1 1 1 1 1 1 then
K
0
must be 1, but if
they are 1 1 1 1 1 1 1 0 1 then
K
0
must be 0.
So far, so good. Can you do better?
You should find the key used for encoding.
Input
The input starts with a line containing only a positive integer
S
, indicating the number of
datasets in the input.
S
is no more than 1000.
It is followed by
S
datasets. Each dataset is composed of nine 32-bit integers corresponding
to the first nine chunks of a communication. They are written in hexadecimal notati
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long int;
using ull = unsigned long long int;
using P = pair<ll, ll>;

ll decode(string s){
    ll res = 0;
    for(auto c : s){
        res <<= 4;
        if(isdigit(c)){
            res |= (c-'0');
        }else{
            res |= (c-'a'+10);
        }
    }
    return res;
}

string encode(ll x){
    if(x == 0) return "0";
    string res = "";
    const ll base = (1<<4)-1;
    while(x > 0){
        ll b = x&base;
        if(b<10){
            res.push_back('0'+b);
        }else{
            res.push_back('a'+b-10);
        }
        x >>= 4;
    }
    reverse(res.begin(), res.end());
    return res;
}

ll A[9], c[32]{};

vector<P> build(int a, int b){
    vector<P> res;
    int n = b-a;
    for(ll S=0;S<1<<n;S++){
        ll sum = 0;
        for(int i=0;i<n;i++){
            if((S>>i)&1){
                sum += c[a+i];
            }
        }
        sum -= ((A[8]^(S<<a))-A[8]);
        res.push_back(P(sum, S<<a));
    }
    sort(res.begin(),res.end());
    return res;
}

int solve(){
    ll S = 0;
    string str;
    for(int i=0;i<9;i++){
        cin >> str;
        A[i] = decode(str);
        if(i<8) S+=A[i];
    }
    fill(c,c+32,0);
    for(int i=0;i<8;i++){
        for(int j=0;j<32;j++){
            if((A[i]>>j)&1){
                c[j] -= 1LL<<j;
            }else{
                c[j] += 1LL<<j;
            }
        }
    }
    auto v1 = build(0,16);
    auto v2 = build(16,32);
    ll ans = -1;
    for(auto p : v1){
        ll dS = p.first;
        for(ll i=0;i<8;i++){
            auto itr = lower_bound(v2.begin(), v2.end(), P(A[8]+(i<<32)-(S+dS),0));
            if(itr != v2.end() && S+dS+(*itr).first == A[8]+(i<<32)){
                ans = (*itr).second + p.second;
                break;
            }
        }
        if(ans>=0) break;
    }
    assert(ans>=0);
    cout << encode(ans) << endl;
    return 0;
}


int main(){
    int t; cin >> t; for(;t>0;t--) solve();
    return 0;
}
accuracy: 1
time_ms: 1650
memory_kb: 5924
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, n) for(int i = 0; i < (n); i++)
#define repp(i, l, r) for(int i = (l); i < (r); i++)
#define per(i, n) for(int i = ((n)-1); i >= 0; i--)
#define perr(i, l, r) for(int i = ((r)-1); i >= (l); i--)
#define all(x) (x).begin(),(x).end()
#define MOD 1000000007
#define IINF 1000000000
#define LINF 1000000000000000000
#define SP <<" "<<
#define CYES cout<<"Yes"<<endl
#define CNO cout<<"No"<<endl
#define CFS cin.tie(0);ios::sync_with_stdio(false)

typedef long long LL;
typedef long double LD;

LL htoi(string &s){
  LL ans=0;
  rep(i,s.length()){
    ans*=16;
    if('0'<=s[i]&&s[i]<='9') ans+=s[i]-'0';
    else ans+=s[i]-'a'+10;
  }
  return ans;
}

string itoh(LL x){
  string ans="";
  while(x){
    if(x%16<=9) ans.push_back('0'+x%16);
    else ans.push_back('a'+x%16-10);
    x/=16;
  }
  if(ans.size()==0) ans="0";
  reverse(all(ans));
  return ans;
}

int main(){
  int q;
  cin >> q;
  rep(t,q){
    string s;
    vector<LL> p(9),q(9);
    rep(i,9){
      cin >> s;
      p[i]=htoi(s);
      q[i]=p[i]%65536;
      p[i]/=65536;
    }
    map<LL,vector<LL>> mp;
    rep(i,65536){
      LL sum=0;
      rep(j,8) sum+=(p[j]^i);
      sum%=65536;
      mp[(p[8]^i)-sum].push_back(i);
    }
    rep(i,65536){
      LL sum=0;
      rep(j,8) sum+=(q[j]^i);
      if(sum%65536==(q[8]^i)){
        auto itr=mp.find(sum/65536);
        if(itr!=mp.end()){
          vector<LL> &v = itr->second;
          for(LL x:v){
            sum=0;
            rep(j,8) sum+=((p[j]*65536+q[j])^(x*65536+i));
            sum%=65536LL*65536;
            if(sum==(p[8]*65536+q[8])^(x*65536+i)){
              cout << itoh(x*65536+i) << endl;
              goto next;
            }
          }
        }
      }
    }
    next:;
  }
  return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 10264
final_rank: 4

code_snippet: #include<iostream>
#include<string>
#include<vector>
using namespace std;
long long L[9], K[9], c[32], power[33];
char T[17] = "0123456789abcdef";
vector<int>vec;
int main() {
	power[0] = 1; for (long long i = 1; i <= 32; i++)power[i] = power[i - 1] * 2;
	int n; cin >> n;
	for (int t = 0; t < n; t++) {
		vec.clear(); for (long long i = 0; i < 9; i++) { L[i] = 0; K[i] = 0; }
		for (long long i = 0; i < 32; i++)c[i] = 0;
		for (long long i = 0; i < 9; i++) {
			string S; cin >> S; long long b[8];
			while (S.size() < 8)S = '0' + S;
			for (long long j = 0; j < 8; j++) {
				for (long long k = 0; k < 16; k++) {
					if (T[k] == S[j])b[7 - j] = k;
				}
			}
			for (long long j = 0; j < 4; j++)L[i] += power[j * 4] * b[j];
			for (long long j = 0; j < 8; j++)K[i] += power[j * 4] * b[j];
		}
		for (long long j = 0; j < 65536; j++) {
			long long S = 0;
			for (long long k = 0; k < 8; k++) {
				S += j^L[k];
			}
			if (S % 65536 == (L[8] ^ j))vec.push_back(j);
		}
		for (long long i = 0; i < vec.size(); i++) {
			for (long long j = 0; j < 65536; j++) {
				long long W = j * 65536 + vec[i], S = 0;
				for (long long k = 0; k < 8; k++) {
					S += W^K[k];
				}
				if (S%power[32] == (K[8] ^ W)) {
					long long OK = 0;
					for (long long k = 7; k >= 0; k--) {
						char V = T[(W / power[k * 4]) % 16];
						if (V >= '1')OK = 1;
						if (OK == 1 || k == 0)cout << V;
					}
					cout << endl;
					goto E;
				}
			}
		}
	E:;
	}
	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 1204
final_rank: 2

code_snippet: //19
#include<cstdio>

int main(){
  int n;
  scanf("%d",&n);
  while(n--){
    unsigned b[2][9];
    for(int i=0;i<9;i++){
      unsigned bb;
      scanf("%x",&bb);
      b[1][i]=bb>>16;
      b[0][i]=bb&(1<<16)-1;
    }
    unsigned c=0;
    unsigned r=0;
    for(int i=0;i<2;i++){
      for(unsigned j=0;j<1<<16;j++){
	unsigned s=c;
	for(int k=0;k<8;k++){
	  s+=b[i][k]^j;
	}
	if((s&(1<<16)-1)==(b[i][8]^j)){
	  r+=j<<(16*i);
	  c=s>>16;
	  break;
	}
      }
    }
    printf("%x\n",r);
  }
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 1032
final_rank: 1