/* **************************************
   "braidpkc.cpp"
   公開鍵暗号系の設計に必要な関数−実現部
   ************************************** */

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

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

// ランダムにブレイドを生成
void create_random(List& L,int l) {

  // 時間をシードに乱数を発生させる
  time_t t;
  time(&t);
  srand((unsigned int)t);

  int x;
  Cell* p=L.Init();
  do{
    x=rand()%(L.Num()*2); // x:1から2n-1までの整数
    if(x!=0){
      x-=L.Num(); // x:-n+1からn-1までの整数
      if(x!=0){
	L.Insert(p,x);
	p=L.Next(p);
	l--;
      }
    }
  }while(l>0);
}

// 生成元をn本ずらす
void shift_braid(List& L,int n){
  Cell* p=L.Next(L.Init());
  int e;
  do{
    e=L.Element(p);
    if(e>0) e+=n; else e-=n;
    L.Set_element(p,e);
    p=L.Next(p);
  }while(p!=L.Last());
}

// y=axa^-1を計算
void product_conj(Canonical& a,Canonical& x,Canonical& y){

  Canonical a_inverse; inverse(a,a_inverse);
  Canonical ax; product(a,x,ax);
  product(ax,a_inverse,y);
}

// 紐の交差の状態を調べる
int cross_strings(Canonical& C,int CS[]){

  List L; C.GList(L);

  int i,j;
  int CRS[L.Num()+1][L.Num()+1]; // 交差を記録
  for(i=1;i<=L.Num();i++)
    for(j=1;j<=L.Num();j++) CRS[i][j]=0;
  int S[L.Num()+1]; // 紐の動きを記録
  for(i=1;i<=L.Num();i++) S[i]=i;

  int x,tmp,k=0;
  Cell* p=L.Next(L.Init());
  do{
    x=L.Element(p);
    tmp=S[x]; S[x]=S[x+1]; S[x+1]=tmp;
    i=S[x]; j=S[x+1];
    if(CRS[i][j]==1){ // ここまでが順列ブレイド
      // CRSをCSに記録
      for(i=1;i<L.Num();i++){
	for(j=i+1;j<=L.Num();j++){
	  CS[k]=CRS[i][j]; k++;
	}
      }
      // CRSをリセット
      for(i=1;i<=L.Num();i++)
	for(j=1;j<=L.Num();j++) CRS[i][j]=0;
      // Sをリセット
      for(i=1;i<=L.Num();i++) S[i]=i;
    }else{
      CRS[i][j]=CRS[j][i]=1;
      p=L.Next(p);
    }
  }while(p!=L.Last());

  // CRSをCSに記録
  for(i=1;i<L.Num();i++){
    for(j=i+1;j<=L.Num();j++){
      CS[k]=CRS[i][j]; k++;
    }
  }

  return k;
}

// ハッシュ関数
void hash_md5(int D[],int size,int H[]){
  int i;

  FILE* fp=fopen("data.txt","w");
  for(i=0;i<size;i++) fprintf(fp,"%d",D[i]);
  fclose(fp); 
  MD5_CTX mdContext=MDFile("data.txt");
  for(i=0;i<16;i++) H[i]=mdContext.digest[i];
}

// 排他的論理和
int exclusive_or(int H[],char M[],int D[]){
  int i,j,len=16;

  if(strlen(M)>16) len=strlen(M);
  for(i=0,j=0;i<len;i++,j++){
    if(j==16) j=0;
    D[i]=H[j]^M[i];
  }

  return len;
}

// 排他的論理和
void exclusive_or(int D[],int H[],int len,char M[]){
  int i,j;

  for(i=0,j=0;i<len;i++,j++){
    if(j==16) j=0;
    M[i]=D[i]^H[j];
  }
}