X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-perl/blobdiff_plain/f9952aec1cf6c64a5681308eea817b6113a37433..fcd15e0b7a3d0f0ca2f30953573f8d1f6b8e8bd2:/Catacomb/Field.pm diff --git a/Catacomb/Field.pm b/Catacomb/Field.pm new file mode 100644 index 0000000..3ca9d37 --- /dev/null +++ b/Catacomb/Field.pm @@ -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 ----------------------------------------------------