#!/usr/bin/perl

package CKE;

use XML::Dumper;
use Matrix;

sub BEGIN
{
   srand;
}

#---------------------------------------------------------------------
# method: new
# construct and return a new CKE identity object
# 
# p - prime modulus, matrix elements are taken from field Zp
# n - dimension of the n x n matrices
# k - number of matrices in the identity object

sub new
{
   my ($class, $p, $n, $k) = @_;
   my $a = [];
   
   for (my $i = 0; $i < $k; $i++)
   {
      push @$a, Matrix->random ($n, $p);
   }
   
   $identity = { n => $n, p => $p, k => $k, a => $a };
   bless $identity, $class;
   
   return $identity;
}


#---------------------------------------------------------------------
# method: serialize_xml
#

sub serialize_xml
{
   my ($id) = @_;
   
   return pl2xml ($id);   
}


#---------------------------------------------------------------------
# method: deserialize_xml
sub deserialize_xml
{
   my ($class, $xml) = @_;
   return xml2pl ($xml);
}


#---------------------------------------------------------------------
# method: put_xml
#

sub put_xml
{
   my ($id, $socket) = @_;
   
   print $socket $id->serialize_xml();
   print $socket "END\n";
}
   
   
#---------------------------------------------------------------------
# method: get_xml
#
sub get_xml
{
   my ($class, $socket) = @_;
   
   my ($xmltext, $line);
   
   while ($line = <$socket>)
   {
      last if $line eq "END\n";
      $xmltext .= $line;
   }
   
   return CKE->deserialize_xml($xmltext);
}   
   

#---------------------------------------------------------------------
# method: store_xml
# serialize and store an CKE identity object to a file as XML

sub store_xml
{
   my ($id, $filename) = @_;
   
   open $out, ">", $filename or return 0;
   print $out "<!-- CKE Identity-->\n";
   print $out serialize_xml ($id);   
   close $out;
}


#---------------------------------------------------------------------
# method: load_xml
# load and deserialize an CKE identity object from a file

sub load_xml
{
   my ($class, $filename) = @_;
   
   open $in, "<", $filename or return 0;
   local $/ = q//;
   my $xml = <$in>;   
   close $in;

   my $id = xml2pl ($xml);
   return $id;
}


#---------------------------------------------------------------------
# method: random_vector
# return vector of $n random numbers to index into the a element array

sub random_vector
{
   my ($id, $n) = @_;
   
   my ($k) = @$id{'k'};

   @row = map int(rand($k)), ( 1.. $n);

   return @row;
}


#---------------------------------------------------------------------
# method: group_word
#

sub group_word
{
   my ($id, @indices) = @_;
   
   my ($a, $p) = @$id{'a', 'p'};
   
   my $i = shift @indices;
   $word = $a->[$i];

   foreach $i (@indices)
   {
       $next = $a->[$i];
       $word = $word->multiply($next, $p);
   }
   
   return $word;
}


#---------------------------------------------------------------------
# method: conjugate
# 

sub conjugate
{
   my ($id, $x, $x_inv) = @_;
   my ($a, $p) = @$id{'a', 'p'};

   
   foreach $element (@$a)
   {
      $temp = $x_inv->multiply($element, $p);
      $element = $temp->multiply($x, $p);      
   }
   
   return $id;
}


#---------------------------------------------------------------------
# method: show_mathematica
# 

sub show_mathematica
{
   my ($id, $label) = @_;
   
   print "\n(* ----------- CKE object: $label ----------- *)\n\n";
   
   printf "p = %d;  n = %d;  k = %d;\n\n", $id->{'p'},$id->{'n'},$id->{'k'};

   for (my $i = 0; $i < $id->{'k'}; $i++)
   {
      $id->{'a'}[$i]->show_mathematica("$label$i");
   }
   
   print "\n(* ", "-" x (length ($label) + 36), " *)\n\n\n";
}

   
1;


      
