Much wider support for Catacomb in all its glory.
[catacomb-perl] / Catacomb / Field.pm
diff --git a/Catacomb/Field.pm b/Catacomb/Field.pm
new file mode 100644 (file)
index 0000000..3ca9d37
--- /dev/null
@@ -0,0 +1,222 @@
+# -*-perl-*-
+#
+# $Id$
+#
+# Field abstraction
+#
+# (c) 2004 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Perl interface to Catacomb.
+#
+# Catacomb/Perl is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# Catacomb/Perl is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with Catacomb/Perl; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Abstract fields ------------------------------------------------------
+
+package Catacomb::Field;
+use Carp;
+use Catacomb::Base;
+use Catacomb::Cache;
+
+$cache = Catacomb::Cache->new();
+
+sub intern {
+  croak("USage: Catacomb::Field::intern(f)") unless @_ == 1;
+  my ($f) = @_;
+  return $cache->intern($f);
+}
+
+sub elt {
+  croak("Usage: Catacomb::Field::elt(f, x)") unless @_ == 2;
+  my ($f, $x) = @_;
+  return Catacomb::Field::Elt->new($f, $x);
+}
+
+sub zero {
+  croak("Usage: Catacomb::Field::zero(f)") unless @_ == 1;
+  my ($f) = @_;
+  return Catacomb::Field::Elt->new($f, $f->_zero());
+}
+  
+sub one {
+  croak("Usage: Catacomb::Field::one(f)") unless @_ == 1;
+  my ($f) = @_;
+  return Catacomb::Field::Elt->new($f, $f->_one());
+}
+
+sub rand {
+  croak("Usage: Catacomb::Field::rand(f, [rng])")
+    unless @_ >= 1 && @_ <= 2;
+  my ($f, $rng) = @_;
+  $rng ||= $Catacomb::random;
+  return Catacomb::Field::Elt->new($f, $f->_one($rng));
+}
+
+sub div {
+  croak("Usage: Catacomb::Field::div(f, x, y)") unless @_ == 3;
+  my ($f, $x, $y) = @_;
+  return $f->mul($x, $f->inv($y));
+}
+
+sub primecurve {
+  croak("Usage: Catacomb::Field::primecurve(f, a, b)") unless @_ == 3;
+  my ($f, $a, $b) = @_;
+  croak("not a prime field") unless $f->type == Catacomb::FTY_PRIME;
+  return Catacomb::EC::Curve->prime($f, $a, $b);
+}
+
+sub primeprojcurve {
+  croak("Usage: Catacomb::Field::primeprojcurve(f, a, b)") unless @_ == 3;
+  my ($f, $a, $b) = @_;
+  croak("not a prime field") unless $f->type == Catacomb::FTY_PRIME;
+  return Catacomb::EC::Curve->primeproj($f, $a, $b);
+}
+
+sub bincurve {
+  croak("Usage: Catacomb::Field::bincurve(f, a, b)") unless @_ == 3;
+  my ($f, $a, $b) = @_;
+  croak("not a prime field") unless $f->type == Catacomb::FTY_BINARY;
+  return Catacomb::EC::Curve->bincurve($f, $a, $b);
+}
+
+sub binprojcurve {
+  croak("Usage: Catacomb::Field::binprojcurve(f, a, b)") unless @_ == 3;
+  my ($f, $a, $b) = @_;
+  croak("not a prime field") unless $f->type == Catacomb::FTY_BINARY;
+  return Catacomb::EC::Curve->binproj($f, $a, $b);
+}
+
+#----- Field elements -------------------------------------------------------
+
+package Catacomb::Field::Elt;
+use Carp;
+use Catacomb::Base;
+
+sub _elt { bless [@_], Catacomb::Field::Elt; }
+
+sub new {
+  croak("Usage: Catacomb::Field::Elt::new(me, f, x)"), unless @_ == 3;
+  my ($me, $f, $x) = @_;
+  my $r;
+  ($f, $r) = $f->intern();
+  return _elt($f->in($x), $f, $r);
+}
+
+sub field {
+  croak("Usage: Catacomb::Field::Elt::field(e)") unless @_ == 1;
+  return $_[0][1];
+}
+
+sub value {
+  croak("Usage: Catacomb::Field::Elt::value(e)") unless @_ == 1;
+  return $_[0][1]->out($_[0][0]);
+}
+
+sub elt {
+  croak("Usage: Catacomb::Field::Elt::elt(e, x)") unless @_ == 2;
+  my ($e, $x) = @_;
+  my $f = $e->[1];
+  return _elt($f->in($x), $f, $e->[2]);
+}
+
+sub tostring {
+  croak("Usage: Catacomb::Field::Elt::tostring(e, [radix])")
+    unless @_ >= 1 && @_ <= 2;
+  my ($e, $radix) = @_;
+  $radix = 16 unless defined($radix);
+  return $e->value()->tostring($radix);
+}
+
+sub _convert {
+  my ($x, $f, $r) = @_;
+  if (UNIVERSAL::isa($x, Catacomb::Field::Elt)) {
+    croak("field mismatch") unless $f == $x->[1];
+    return $x;
+  }
+  if ($x == 0) {
+    return _elt($f->_zero(), $f, $r);
+  }
+  if ($x == 1) {
+    return _elt($f, $f->_one(), $f, $r);
+  }
+  croak("can't convert to field element");
+}
+
+sub _binop {
+  my ($op, $x, $y, $swap) = @_;
+  my $f = $x->[1];
+  my $r = $x->[2];
+  $y = _convert($y, $f, $r);
+  my $z = $swap ?
+    &$op($f, $x->[0], $y->[0]) :
+    &$op($f, $y->[0], $x->[0]);
+  return _elt($z, $f, $r);
+}
+  
+sub _unop {
+  my ($op, $x) = @_;
+  my $f = $x->[1];
+  my $r = $x->[2];
+  my $z = &$op($f, $x->[0]);
+  return _elt($z, $f, $r);
+}
+
+sub exp {
+  croak("Usage: Catacomb::Field::Elt::exp(x, n)") unless @_ == 2;
+  my ($x, $n) = @_;
+  my ($xx, $f, $fr) = @$x;
+  return _elt($f->exp($xx, $n), $f, $fr);
+}
+
+sub sqrt {
+  croak("Usage: Catacomb::Field::Elt::sqrt(x)") unless @_ == 1;
+  my ($x) = @_;
+  my ($xx, $f, $fr) = @$x;
+  return _elt($f->sqrt($xx), $f, $fr);
+}
+
+sub zerop {
+  croak("Usage: Catacomb::Field::Elt::zerop(x)") unless @_ == 1;
+  my ($x) = @_;
+  my ($xx, $f, $fr) = @$x;
+  return $f->zero($xx);
+}
+
+sub _eq {
+  my ($x, $y) = @_;
+  $y = _convert($y, $x->[1], $x->[2]);
+  return Catacomb::MP::eq($x->[0], $y->[0]);
+}
+
+use overload
+  '+' => sub { _binop(\&Catacomb::Field::add, @_); },
+  '-' => sub { _binop(\&Catacomb::Field::sub, @_); },
+  '*' => sub { _binop(\&Catacomb::Field::mul, @_); },
+  '/' => sub { _binop(\&Catacomb::Field::div, @_); },
+  '**' => sub { &exp($_[0], $_[1]); },
+  '==' => sub { _eq(@_); },
+  '!=' => sub { !_eq(@_); },
+  'eq' => sub { _eq(@_); },
+  'ne' => sub { !_eq(@_); },
+  '""' => sub { "0x" . $_[0]->tostring(16); },
+  '0+' => sub { $_[0][1]->toint(); },
+  'sqrt' => sub { _unop(\&Catacomb::Field::sqrt, @_); },
+  'neg' => sub { _unop(\&Catacomb::Field::neg, @_); };
+
+sub inv { _unop(\&Catacomb::Field::inv, @_); }
+
+#----- That's all, folks ----------------------------------------------------