Much wider support for Catacomb in all its glory.
[catacomb-perl] / Catacomb / Field.pm
CommitLineData
fcd15e0b 1# -*-perl-*-
2#
3# $Id$
4#
5# Field abstraction
6#
7# (c) 2004 Straylight/Edgeware
8#
9
10#----- Licensing notice -----------------------------------------------------
11#
12# This file is part of the Perl interface to Catacomb.
13#
14# Catacomb/Perl is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# Catacomb/Perl is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with Catacomb/Perl; if not, write to the Free Software Foundation,
26# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
28#----- Abstract fields ------------------------------------------------------
29
30package Catacomb::Field;
31use Carp;
32use Catacomb::Base;
33use Catacomb::Cache;
34
35$cache = Catacomb::Cache->new();
36
37sub intern {
38 croak("USage: Catacomb::Field::intern(f)") unless @_ == 1;
39 my ($f) = @_;
40 return $cache->intern($f);
41}
42
43sub elt {
44 croak("Usage: Catacomb::Field::elt(f, x)") unless @_ == 2;
45 my ($f, $x) = @_;
46 return Catacomb::Field::Elt->new($f, $x);
47}
48
49sub zero {
50 croak("Usage: Catacomb::Field::zero(f)") unless @_ == 1;
51 my ($f) = @_;
52 return Catacomb::Field::Elt->new($f, $f->_zero());
53}
54
55sub one {
56 croak("Usage: Catacomb::Field::one(f)") unless @_ == 1;
57 my ($f) = @_;
58 return Catacomb::Field::Elt->new($f, $f->_one());
59}
60
61sub rand {
62 croak("Usage: Catacomb::Field::rand(f, [rng])")
63 unless @_ >= 1 && @_ <= 2;
64 my ($f, $rng) = @_;
65 $rng ||= $Catacomb::random;
66 return Catacomb::Field::Elt->new($f, $f->_one($rng));
67}
68
69sub div {
70 croak("Usage: Catacomb::Field::div(f, x, y)") unless @_ == 3;
71 my ($f, $x, $y) = @_;
72 return $f->mul($x, $f->inv($y));
73}
74
75sub primecurve {
76 croak("Usage: Catacomb::Field::primecurve(f, a, b)") unless @_ == 3;
77 my ($f, $a, $b) = @_;
78 croak("not a prime field") unless $f->type == Catacomb::FTY_PRIME;
79 return Catacomb::EC::Curve->prime($f, $a, $b);
80}
81
82sub primeprojcurve {
83 croak("Usage: Catacomb::Field::primeprojcurve(f, a, b)") unless @_ == 3;
84 my ($f, $a, $b) = @_;
85 croak("not a prime field") unless $f->type == Catacomb::FTY_PRIME;
86 return Catacomb::EC::Curve->primeproj($f, $a, $b);
87}
88
89sub bincurve {
90 croak("Usage: Catacomb::Field::bincurve(f, a, b)") unless @_ == 3;
91 my ($f, $a, $b) = @_;
92 croak("not a prime field") unless $f->type == Catacomb::FTY_BINARY;
93 return Catacomb::EC::Curve->bincurve($f, $a, $b);
94}
95
96sub binprojcurve {
97 croak("Usage: Catacomb::Field::binprojcurve(f, a, b)") unless @_ == 3;
98 my ($f, $a, $b) = @_;
99 croak("not a prime field") unless $f->type == Catacomb::FTY_BINARY;
100 return Catacomb::EC::Curve->binproj($f, $a, $b);
101}
102
103#----- Field elements -------------------------------------------------------
104
105package Catacomb::Field::Elt;
106use Carp;
107use Catacomb::Base;
108
109sub _elt { bless [@_], Catacomb::Field::Elt; }
110
111sub new {
112 croak("Usage: Catacomb::Field::Elt::new(me, f, x)"), unless @_ == 3;
113 my ($me, $f, $x) = @_;
114 my $r;
115 ($f, $r) = $f->intern();
116 return _elt($f->in($x), $f, $r);
117}
118
119sub field {
120 croak("Usage: Catacomb::Field::Elt::field(e)") unless @_ == 1;
121 return $_[0][1];
122}
123
124sub value {
125 croak("Usage: Catacomb::Field::Elt::value(e)") unless @_ == 1;
126 return $_[0][1]->out($_[0][0]);
127}
128
129sub elt {
130 croak("Usage: Catacomb::Field::Elt::elt(e, x)") unless @_ == 2;
131 my ($e, $x) = @_;
132 my $f = $e->[1];
133 return _elt($f->in($x), $f, $e->[2]);
134}
135
136sub tostring {
137 croak("Usage: Catacomb::Field::Elt::tostring(e, [radix])")
138 unless @_ >= 1 && @_ <= 2;
139 my ($e, $radix) = @_;
140 $radix = 16 unless defined($radix);
141 return $e->value()->tostring($radix);
142}
143
144sub _convert {
145 my ($x, $f, $r) = @_;
146 if (UNIVERSAL::isa($x, Catacomb::Field::Elt)) {
147 croak("field mismatch") unless $f == $x->[1];
148 return $x;
149 }
150 if ($x == 0) {
151 return _elt($f->_zero(), $f, $r);
152 }
153 if ($x == 1) {
154 return _elt($f, $f->_one(), $f, $r);
155 }
156 croak("can't convert to field element");
157}
158
159sub _binop {
160 my ($op, $x, $y, $swap) = @_;
161 my $f = $x->[1];
162 my $r = $x->[2];
163 $y = _convert($y, $f, $r);
164 my $z = $swap ?
165 &$op($f, $x->[0], $y->[0]) :
166 &$op($f, $y->[0], $x->[0]);
167 return _elt($z, $f, $r);
168}
169
170sub _unop {
171 my ($op, $x) = @_;
172 my $f = $x->[1];
173 my $r = $x->[2];
174 my $z = &$op($f, $x->[0]);
175 return _elt($z, $f, $r);
176}
177
178sub exp {
179 croak("Usage: Catacomb::Field::Elt::exp(x, n)") unless @_ == 2;
180 my ($x, $n) = @_;
181 my ($xx, $f, $fr) = @$x;
182 return _elt($f->exp($xx, $n), $f, $fr);
183}
184
185sub sqrt {
186 croak("Usage: Catacomb::Field::Elt::sqrt(x)") unless @_ == 1;
187 my ($x) = @_;
188 my ($xx, $f, $fr) = @$x;
189 return _elt($f->sqrt($xx), $f, $fr);
190}
191
192sub zerop {
193 croak("Usage: Catacomb::Field::Elt::zerop(x)") unless @_ == 1;
194 my ($x) = @_;
195 my ($xx, $f, $fr) = @$x;
196 return $f->zero($xx);
197}
198
199sub _eq {
200 my ($x, $y) = @_;
201 $y = _convert($y, $x->[1], $x->[2]);
202 return Catacomb::MP::eq($x->[0], $y->[0]);
203}
204
205use overload
206 '+' => sub { _binop(\&Catacomb::Field::add, @_); },
207 '-' => sub { _binop(\&Catacomb::Field::sub, @_); },
208 '*' => sub { _binop(\&Catacomb::Field::mul, @_); },
209 '/' => sub { _binop(\&Catacomb::Field::div, @_); },
210 '**' => sub { &exp($_[0], $_[1]); },
211 '==' => sub { _eq(@_); },
212 '!=' => sub { !_eq(@_); },
213 'eq' => sub { _eq(@_); },
214 'ne' => sub { !_eq(@_); },
215 '""' => sub { "0x" . $_[0]->tostring(16); },
216 '0+' => sub { $_[0][1]->toint(); },
217 'sqrt' => sub { _unop(\&Catacomb::Field::sqrt, @_); },
218 'neg' => sub { _unop(\&Catacomb::Field::neg, @_); };
219
220sub inv { _unop(\&Catacomb::Field::inv, @_); }
221
222#----- That's all, folks ----------------------------------------------------