/* **************************************
   公開鍵暗号系を実現するメインプログラム
   ************************************** */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "list.h"
#include "braid.h"
#include "canonical.h"
#include "make_canonical.h"
#include "braidpkc.h"

#define MAX 10000

int main(int argc,char *argv[]){

  int STRING_NUM=atoi(argv[1]);
  int BRAID_LEN=atoi(argv[2]);

  int i,j;
  int lb_num=STRING_NUM-STRING_NUM/2; // 部分群LBの紐の本数
  int rb_num=STRING_NUM/2; // 部分群RBの紐の本数

  /* ***** 鍵の生成 ***** */

  // 公開鍵xの生成
  List x_list(STRING_NUM); create_random(x_list,BRAID_LEN);
  Canonical x; make_canonical(x_list,x);

  printf("Public  key x:"); display_canonical(x);

  // 秘密鍵aの生成
  List a_list(lb_num); create_random(a_list,BRAID_LEN);
  a_list.Set_num(STRING_NUM); // 紐の本数をxに合わせる
  Canonical a; make_canonical(a_list,a);

  printf("Private key a:"); display_canonical(a);

  // 公開鍵y=axa^-1を計算
  Canonical y; product_conj(a,x,y);

  printf("Public  key y:"); display_canonical(y);

  /* ***** 暗号化 ***** */

  // メッセージ
  char M[MAX]={"Public-key Cryptosystem Using Braid Groups"};

  printf("message:");
  for(i=0;i<strlen(M);i++) printf("%c",M[i]); putchar('\n');
 
  // bの生成
  List b_list(rb_num); create_random(b_list,BRAID_LEN);
  shift_braid(b_list,lb_num); // b∈RBなので生成元をlb_num本ずらす
  b_list.Set_num(STRING_NUM); // 紐の本数をxに合わせる
  Canonical b; make_canonical(b_list,b);

  // c=bxb^-1を計算
  Canonical c; product_conj(b,x,c);

  printf("Ciphertext c:"); display_canonical(c);

  // byb^-1を計算,紐の交差の状態を調べる
  Canonical byb; product_conj(b,y,byb);
  int CS[MAX];
  int CS_size=cross_strings(byb,CS);

  // ハッシュ関数H(byb^-1)を計算
  int byb_md5[16];
  hash_md5(CS,CS_size,byb_md5);

  // d=H(byb^-1)とメッセージの排他的論理和をとる
  int d[MAX];
  int len=exclusive_or(byb_md5,M,d);

  printf("Ciphertext d:");
  for(i=0;i<len;i++) printf("%x",d[i]); putchar('\n');

  /* ***** 復号化 ***** */

  // aca^-1を計算,紐の交差の状態を調べる
  Canonical aca; product_conj(a,c,aca);
  CS_size=cross_strings(aca,CS);

  // ハッシュ関数H(aca^-1)を計算
  int aca_md5[16];
  hash_md5(CS,CS_size,aca_md5);

  // dとH(aca^-1)メッセージの排他的論理和をとる
  char message[MAX];
  exclusive_or(d,aca_md5,len,message);

  printf("message:");
  for(i=0;i<len;i++) printf("%c",message[i]); putchar('\n');

  return 0;
}