“知乎杯”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; }