“知乎杯”2018 CCF 大学生计算机系统与程序设计竞赛 分组加密器(encryption)

 

分组加密器(encryption)

  题解点这里

#include<map>
#include<stack>
#include<vector>
#include<cstdio>
#include<iostream>
#define debug(x) cerr<<#x<<" "<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int PLEN=64;
const int SLEN=8;
struct ptable_type{
    int input_size,output_size;
    int element[PLEN];
    inline void Read(){
        scanf("%d%d",&input_size,&output_size);
        for(int i=0;i<output_size;i++) scanf("%d",element+i);
    }
};
struct sbox_type{
    int input_size,output_size;
    int element[1<<SLEN];
    inline void Read(){
        scanf("%d%d",&input_size,&output_size);
        for(int i=0;i<(1<<input_size);i++) scanf("%d",element+i);
    }
};
struct lex_type{
    string name;int type;ull value;
    lex_type(string name="",int type=0,ull value=0):name(name),type(type),value(value){}
};
struct bs_var_type{
    string name;int len;ull value;
    bs_var_type(string name="",int len=0,ull value=0):name(name),len(len),value(value){}
    vector<bs_var_type*> ch;
};
struct expr_type{
    int id,type;ull value;
    vector<int> bs_varp;
    expr_type *expr1,*expr2;
};
struct gra_type{
    int type,var,value,jmp;
    vector<int> bs_varp;
    expr_type* expr;
    int st,ed;//lex[st] .. lex[ed]
};
int n,m;
ptable_type ptable[10];
sbox_type sbox[10];

string code;//store all characters of the code
int loop_var[26];
vector<bs_var_type> bs_var;
vector<lex_type> lex;
vector<gra_type> gra;
stack<int> loop_pos;
vector<expr_type*> expr_ptr;
void ReadPtable(){
    for(int i=0;i<n;i++) ptable[i].Read();
}
void ReadSbox(){
    for(int i=0;i<m;i++) sbox[i].Read();
}
void ReadCode(){
    char ch=getchar();
    while(ch!='\n') ch=getchar();
    for(bool meet_end=false;;){
        code+=ch=getchar();
        if(ch=='D') meet_end=true;
        if(ch=='L') meet_end=false;
        if(ch=='\n'&&meet_end) break;
    }
}
int find_bs(string &name){
    for(int i=0,sz=bs_var.size();i<sz;i++) if(bs_var[i].name==name) return i;
    return -1;
}
char type5[7]={'=','+','(',')','[',']','\n'};
string type0[8]={"BEGIN","END","P","S","LOOP","ENDLOOP","SPLIT","MERGE"};
void lex_ana(){
    string str;lex_type tmp;
    for(int i=0,j,codelen=code.length();i<codelen;str.clear()){
        while(code[i]==','||code[i]==' '||code[i]=='\t') i++;
        str+=code[i++];
        if(str[0]>='A'&&str[0]<='Z'){//type 0
            while(i<codelen&&code[i]>='A'&&code[i]<='Z') str+=code[i++];
            for(j=0;j<8;j++) if(str==type0[j]) break;
            tmp.name=str;tmp.type=0;tmp.value=j;
            lex.push_back(tmp);
        }
        else if(str[0]>='a'&&str[0]<='z'){//type 1 or 2
            while(i<codelen&&code[i]>='a'&&code[i]<='z')  str+=code[i++];
            if(str.length()==1){//type 1
                lex.push_back(lex_type(str,1,str[0]-'a'));
            }
            else{//type 2
                j=find_bs(str);
                if(j==-1){
                    j=bs_var.size();
                    bs_var.push_back(bs_var_type(str,0,0));
                }
                lex.push_back(lex_type(str,2,j));
            }
        }
        else if(str[0]>='0'&&str[0]<='9'){ //type 3
            while(i<codelen&&code[i]>='0'&&code[i]<='9') str+=code[i++];
            int strl=str.length(); ull x(0);
            for(j=0;j<strl;j++) x=x*10+str[j]-'0';
            lex.push_back(lex_type(str,3,x));
        }
        else if(str[0]=='\"'){   //type 4
            while(i<codelen&&code[i]>='0'&&code[i]<='1') str+=code[i++];
//            str+=code[i++]);
            i++;
            int strl=str.length();ull x=0;
            for(j=1;j<strl;j++) x=(x<<1)|str[j]-'0';
            lex.push_back(lex_type(str,4,x));
        }
        else{    //type 5
            for(j=0;j<7;j++) if(str[0]==type5[j]) break;
            lex.push_back(lex_type(str,5,j));
        }
    }
}
void init_bs_var(){
    for(int i=0,tmp;lex[i].name!="BEGIN";i+=5){
        tmp=lex[i].value;
        bs_var[tmp].len=lex[i+2].value;
        bs_var[tmp].value=0;
    }
}
void get_bs_var(int l,int r,ull& value,vector<int>& bs_varp){
    value=lex[l].value;
    for(int i=l + 1;i<r;i+=3){
        if(lex[i+1].type==1) bs_varp.push_back((int)(lex[i+1].value)-26);  // 0..25 -> -26..-1
        else bs_varp.push_back(lex[i+1].value); // 0..63
    }
}
expr_type* generate_expr(int l,int r){
    expr_type* ptr=new expr_type;
    ptr->id=expr_ptr.size();
    expr_ptr.push_back(ptr);
    ptr->expr1=NULL;ptr->expr2=NULL;ptr->value=0;
    int i=l;
    for(int num=0;i<=r;i++){
        if(lex[i].name=="(") num++;
        if(lex[i].name==")") num--;
        if(lex[i].name=="+"&&num==0) break;
    }
    if(i<=r){
        ptr->type=2;
        ptr->expr1=generate_expr(l,i-1);
        ptr->expr2=generate_expr(i+1,r);
        return ptr;
    }
    if(lex[l].name=="P"||lex[l].name=="S"){
        if(lex[l].name=="P") ptr->type=3;else ptr->type=4;
        if(lex[l+2].type==1) ptr->value=lex[l+2].value-26;
        else if(lex[l+2].type==3) ptr->value=lex[l+2].value;
        ptr->expr1=generate_expr(l+5,r-1);
        return ptr;
    }
    if(lex[l].type==4){
        ptr->type=1;
        ptr->value=lex[l].value;
        return ptr;
    }
    if(lex[l].type==2){
        ptr->type=0;
        get_bs_var(l,r,ptr->value,ptr->bs_varp);
        return ptr;
    }
}
void generate_gra(int l,int r){
    gra_type tmp;
    tmp.st=l;tmp.ed=r;
    tmp.var=tmp.value=tmp.jmp=0;
    tmp.expr=NULL;
    if(lex[l].name=="BEGIN"){
        tmp.type=tmp.value=0;
    }
    else if(lex[l].name=="END"){
        tmp.type=0;
        tmp.value=1;
    }
    else if(lex[l].name=="LOOP"){
        tmp.type=2;
        tmp.var=lex[l+1].value;
        tmp.value=lex[l+2].value;
        tmp.jmp=lex[l+3].value;
        loop_pos.push(gra.size());
    }
    else if(lex[l].name=="ENDLOOP"){
        int pos=loop_pos.top();loop_pos.pop();
        tmp.type=3;
        tmp.var=gra[pos].var;
        tmp.value=gra[pos].jmp;
        gra[pos].jmp=0;
        tmp.jmp=pos+1;
    }
    else if(lex[l].name=="SPLIT"){
        tmp.type=4;
        tmp.value=lex[r-2].value;
        ull beta;
        get_bs_var(l+2,r-3,beta,tmp.bs_varp);
        tmp.var=beta;
    }
    else if(lex[l].name=="MERGE"){
        tmp.type=5;
        ull beta;
        get_bs_var(l+2,r-2,beta,tmp.bs_varp);
        tmp.var=beta;
    }
    else if(lex[l].type==2){   //assignment statement
        int i=l;
        while(i<=r&&lex[i].name!="=") i++;
        tmp.type=1;
        ull beta;
        get_bs_var(l,i-1,beta,tmp.bs_varp);
        tmp.var=beta;
        tmp.expr=generate_expr(i+1,r-1);
    }
    gra.push_back(tmp);
}
void gra_ana(){
    int i=0,j,sz=lex.size();
    for(i=0;lex[i].name!="BEGIN";i++);
    for(;i<sz;i=j+1){
        for(j=i;lex[j].name!="\n";j++);
        generate_gra(i,j);
    }
}
void bs_to_num(const string& str,ull& num){
    num=0;
    for(int i=0,sz=str.length();i<sz;i++) num=(num<<1)|str[i]-'0';
}
void num_to_bs(const ull& num,string& str,int size=PLEN){
    str.clear();
    for(ull tmp=1ull<<size-1;tmp;tmp>>=1) if(num&tmp) str+='1';else str+='0';
}
string int_to_str(int i){
    string str;
    stack<char>s;
    if(i==0){str="0";return str;}
    if(i<0) str+='-',i=-i;
    for(;i>0;i/=10) s.push((i%10)+'0');
    while(!s.empty()) str+=s.top(),s.pop();
    return str;
}
bs_var_type* find_bs_varp(ll pos,const vector<int>& bs_varp){
    bs_var_type* ptr=&bs_var[pos];//?????
    for(int i=0,sz=bs_varp.size();i<sz;i++){
        int j=bs_varp[i];
        if(j<0) j=loop_var[j+26];
        ptr=ptr->ch[j];
    }
    return ptr;
}
ull cal_expr(expr_type* ptr){
    if(ptr->type==0) return find_bs_varp(ptr->value,ptr->bs_varp)->value;
    else if(ptr->type==1) return ptr->value;
    else if(ptr->type==2) return cal_expr(ptr->expr1)^cal_expr(ptr->expr2);
    else if(ptr->type==3){
        ull tmp=cal_expr(ptr->expr1);
        ll j=ptr->value;
        if(j<0) j=loop_var[j+26];
        string sin,sout;
        num_to_bs(tmp,sin,ptable[j].input_size);
        for(int i=0;i<ptable[j].output_size;i++)
            sout.push_back(sin[ptable[j].element[i]]);
        bs_to_num(sout,tmp);
        return tmp;
    }
    else if(ptr->type==4){
        ull tmp=cal_expr(ptr->expr1);
        ll j=ptr->value;
        if(j<0) j=loop_var[j+26];
        return sbox[j].element[tmp];
    }
}
ull encrypt(ull state,ull key){
    for(int now=0;;){
        if(gra[now].type==0){
            if(gra[now].value==0){   //BEGIN
                bs_var[0].value=state;
                bs_var[1].value=key;
                for(int i=2;i<bs_var.size();i++) bs_var[i].value=0;
                now++;
            }
            else return bs_var[0].value;  //END
        }
        else if(gra[now].type==1){
            bs_var_type* ptr=find_bs_varp(gra[now].var,gra[now].bs_varp);
            ptr->value=cal_expr(gra[now].expr);
            now++;
        }
        else if(gra[now].type==2){
            loop_var[gra[now].var]=gra[now].value;
            now++;
        }
        else if(gra[now].type==3){
            loop_var[gra[now].var]++;
            if(loop_var[gra[now].var]>gra[now].value) now++;
            else now=gra[now].jmp;
        }
        else if(gra[now].type==4){
            bs_var_type* ptr=find_bs_varp(gra[now].var,gra[now].bs_varp);
            int tmp=gra[now].value;
            int chlen=ptr->len / tmp;
            for(int i=0;i<tmp;i++){
                bs_var_type* chptr=new bs_var_type;
                chptr->len=chlen;
                chptr->name=ptr->name+"["+int_to_str(i)+"]";
                chptr->value=0;
                ptr->ch.push_back(chptr);
            }
            ull beta=(1ull<<chlen)-1;
            for(int i=tmp-1;~i;i--){
                ptr->ch[i]->value=ptr->value & beta;
                ptr->value=ptr->value>>chlen;
            }
            now++;
        }
        else if(gra[now].type==5){
            bs_var_type* ptr=find_bs_varp(gra[now].var,gra[now].bs_varp);
            int tmp=ptr->ch.size();
            int chlen=ptr->len / tmp;
            ptr->value=0;
            for(int i=0;i<tmp;i++){
                bs_var_type* chptr=ptr->ch[i];
                ptr->value=(ptr->value<<chlen)|chptr->value;
                delete chptr;
            }
            ptr->ch.clear();
            now++;
        }
    }
}
void InitTaskA(){
    scanf("%d%d",&n,&m);
    ReadPtable();
    ReadSbox();
    ReadCode();
}
void SolveTaskA(){
    lex_ana();
    init_bs_var();
    gra_ana();
    int k; ull state,key; string str1,str2;
    scanf("%d",&k);
    for(int i=0;i<k;i++){
        cin>>str1>>str2;
        bs_to_num(str1,state);
        bs_to_num(str2,key);
        num_to_bs(encrypt(state,key),str1,bs_var[0].len);
        puts(str1.c_str());
    }
}
void taskB_init(){
    code="state(32)\n";
    code += "key(12)\n";
    code += "dkey(16)\n";
    code += "tmp(32)\n";
    code += "BEGIN\n";
    code += "SPLIT(dkey,4)\n";
    code += "SPLIT(key,3)\n";
    code += "dkey[0]=key[0]\n";
    code += "dkey[1]=key[1]\n";
    code += "dkey[2]=key[2]\n";
    code += "dkey[3]=key[0] + key[1] + key[2]\n";
    code += "MERGE(key)\n";
    code += "MERGE(dkey)\n";
    code += "LOOP i 1 16\n";
    code += "dkey=P[2](dkey)\n";
    code += "tmp=state\n";
    code += "SPLIT(state,2)\n";
    code += "SPLIT(tmp,2)\n";
    code += "state[0]=tmp[1]\n";
    code += "tmp[1]=tmp[1] + dkey\n";
    code += "SPLIT(tmp[1],4)\n";
    code += "LOOP j 0 3\n";
    code += "tmp[1][j]=S[0](tmp[1][j])\n";
    code += "ENDLOOP\n";
    code += "MERGE(tmp[1])\n";
    code += "state[1]=tmp[0] + P[0](tmp[1])\n";
    code += "MERGE(state)\n";
    code += "MERGE(tmp)\n";
    code += "dkey=P[1](dkey)\n";
    code += "ENDLOOP\n";
    code += "tmp=state\n";
    code += "SPLIT(state,2)\n";
    code += "SPLIT(tmp,2)\n";
    code += "state[0]=tmp[1]\n";
    code += "state[1]=tmp[0]\n";
    code += "MERGE(state)\n";
    code += "MERGE(tmp)\n";
    code += "END\n";
    n=3;
    m=1;
    ptable[0].input_size=16;
    ptable[0].output_size=16;
    ptable[1].input_size=16;
    ptable[1].output_size=16;
    ptable[2].input_size=16;
    ptable[2].output_size=16;
    sbox[0].input_size=4;
    sbox[0].output_size=4;
    int p0[16]={12, 1, 9, 2, 0, 11, 7, 3, 4, 15, 8, 5, 14, 13, 10, 6};
    int p1[16]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
    int p2[16]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    int s0[16]={12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2};
    for(int i=0;i<16;i++){
        ptable[0].element[i]=p0[i];
        ptable[1].element[i]=p1[i];
        ptable[2].element[i]=p2[i];
        sbox[0].element[i]=s0[i];
    }
}
void solve_taskB(){
    lex_ana();
    init_bs_var();
    gra_ana();
    ull state, ans, tmp;
    string str1, str2;
    int key1,key2;
    map<ull,int> h;
    cin >> str1 >> str2;
    bs_to_num(str1,state);
    bs_to_num(str2,ans);
    for(int i=0;i<4096;i++){
        tmp=encrypt(state,i);
        h[tmp]=i;
    }
    int p1[16]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    int p2[16]={15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
    for(int i=0;i<16;i++){
        ptable[1].element[i]=p1[i];
        ptable[2].element[i]=p2[i];
    }
    for(int i=0;i<4096;i++){
        tmp=encrypt(ans,i);
        if(h.find(tmp)==h.end()) continue;
        key1=h[tmp];
        key2=i;
        num_to_bs(key1,str1,12);
        num_to_bs(key2,str2,12);
        cout << "YES" << endl;
        cout << str1 << endl;
        cout << str2 << endl;
        return;
    }
    cout << "NO" << endl;
}
char task_id[10];
int main(){
    freopen("encryption.in","r",stdin);
    freopen("encryption.out","w",stdout);
    scanf("%s",task_id);
    if(task_id[4]=='A'){
        InitTaskA();
        SolveTaskA();
    } 
    else{
//        puts("NO");//pass 3 points
        taskB_init();
        solve_taskB();
    }
    fclose(stdin);fclose(stdout);
    return 0;
}

 

posted @ 2019-10-01 10:08  神犇(shenben)  阅读(318)  评论(0编辑  收藏  举报