#----- Basic stuff ----------------------------------------------------------
package Catacomb;
-use DynaLoader;
-use Exporter;
-@ISA = qw(DynaLoader Exporter);
+use Catacomb::Base;
$VERSION = "1.0.0";
-bootstrap Catacomb;
-
-@EXPORT_OK = qw($random);
-%EXPORT_TAGS = ("const" => [qw(GRAND_CRYPTO PGEN_TRY PGEN_FAIL PGEN_PASS
- PGEN_DONE PGEN_ABORT PGEN_BEGIN)]);
-Exporter::export_ok_tags("const");
-
-sub AUTOLOAD {
- my $val = const($AUTOLOAD);
- *$AUTOLOAD = sub { $val };
- goto &$AUTOLOAD;
-}
-
-#----- Multiprecision arithmetic --------------------------------------------
-
-package Catacomb::MP;
-use Carp;
-
-use overload
- '+' => sub { _binop(\&add, @_); },
- '-' => sub { _binop(\&sub, @_); },
- '*' => sub { _binop(\&mul, @_); },
- '/' => sub { _binop(\&div, @_); },
- '%' => sub { _binop(\&mod, @_); },
- '&' => sub { _binop(\&and2c, @_); },
- '|' => sub { _binop(\&or2c, @_); },
- '^' => sub { _binop(\&xor2c, @_); },
- '**' => sub { _binop(\&pow, @_); },
- '>>' => sub { &lsr2c(@_[0, 1]); },
- '<<' => sub { &lsl2c(@_[0, 1]); },
- '~' => sub { ¬2c($_[0]) },
- '==' => sub { _binop(\&eq, @_); },
- '<=>' => sub { _binop(\&cmp, @_); },
- '""' => sub { &tostring($_[0]); },
- '0+' => sub { &toint($_[0]); },
- 'sqrt' => sub { &sqrt($_[0]); },
- 'neg' => sub { &neg($_[0]); };
-
-sub mod { (&div($_[0], $_[1]))[1]; }
-
-sub pow {
- croak("Usage: Catacomb::MP::pow(a, b)") unless @_ == 2;
- my ($a, $b) = @_;
- my $r = Catacomb::MP->new(1);
- while ($b) {
- $r *= $a if $b & 1;
- $a = sqr($a);
- $b >>= 1;
- }
- return $r;
-}
-
-sub _binop {
- my ($func, $a, $b, $flag) = @_;
- return $flag ? &$func($b, $a) : &$func($a, $b);
-}
-
-sub modexp {
- croak("Usage: Catacomb::MP::modexp(p, g, x)") unless @_ == 3;
- my ($p, $g, $x) = @_;
- $g = $p - $g if $g < 0;
- $g = $g % $p if $g > $p;
- if ($p & 1) {
- my $mm = Catacomb::MP::Mont->new($p);
- return $mm->exp($g, $x);
+BEGIN { @EXPORT_OK = (); }
+
+use Catacomb::MP;
+use Catacomb::GF;
+use Catacomb::Field;
+use Catacomb::EC;
+use Catacomb::Group;
+use Catacomb::Rand;
+use Catacomb::Crypto;
+use Catacomb::Key;
+
+foreach $_ (qw(Catacomb::MP::mp Catacomb::GF::gf
+ Catacomb::MP::newprime
+ Catacomb::MP::mp_loadl Catacomb::MP::mp_loadb
+ Catacomb::MP::mp_loadl2c Catacomb::MP::mp_loadb2c
+ Catacomb::MP::mp_fromstring
+ Catacomb::GF::gf_loadl Catacomb::GF::gf_loadb
+ Catacomb::GF::gf_fromstring
+ Catacomb::MP::Prime::primegen
+ Catacomb::MP::Prime::limleegen
+ Catacomb::MP::Prime::Filter::filterstepper)) {
+ my $new;
+ my $proc;
+ if (m:^(.*)/(.*)$:) {
+ $proc = $1;
+ $new = $2;
+ } elsif (/:(\w+)$/) {
+ $new = $1;
+ $proc = $_;
} else {
- my $mb = Catacomb::MP::Barrett->new($p);
- return $mb->exp($g, $x);
- }
-}
-
-sub modinv {
- croak("Usage: Catacomb::MP::modinv(p, x)") unless @_ == 2;
- my ($g, undef, $i) = gcd($_[0], $_[1]);
- croak("Arguments aren't coprime in Catacomb::MP::modinv") unless $g == 1;
- return $i;
-}
-
-#----- Binary polynomials ---------------------------------------------------
-
-package Catacomb::GF;
-use Carp;
-
-@ISA = qw(Catacomb::MP);
-
-use overload
- '+' => sub { _binop(\&add, @_); },
- '-' => sub { _binop(\&add, @_); },
- '*' => sub { _binop(\&mul, @_); },
- '/' => sub { _binop(\&div, @_); },
- '%' => sub { _binop(\&mod, @_); },
- '&' => sub { _binop(\&Catacomb::MP::and, @_); },
- '|' => sub { _binop(\&Catacomb::MP::or, @_); },
- '^' => sub { _binop(\&Catacomb::MP::xor, @_); },
- '>>' => sub { &Catacomb::MP::lsr(@_[0, 1]); },
- '<<' => sub { &Catacomb::MP::lsl(@_[0, 1]); },
- '~' => sub { &Catacomb::MP::not($_[0]) },
- '==' => sub { _binop(\&Catacomb::MP::eq, @_); },
- '<=>' => sub { _binop(\&Catacomb::MP::cmp, @_); },
- '""' => sub { "0x" . &Catacomb::MP::tostring($_[0], 16); },
- 'neg' => sub { $_[0]; },
- '0+' => sub { &Catacomb::MP::toint($_[0]); };
-
-sub mod { (&div($_[0], $_[1]))[1]; }
-
-sub _binop {
- my ($func, $a, $b, $flag) = @_;
- return $flag ? &$func($b, $a) : &$func($a, $b);
-}
-
-#----- Prime testing --------------------------------------------------------
-
-{
- my $cmpg = "Catacomb::MP::Prime::Gen";
- foreach my $i (qw(FilterStepper JumpStepper RabinTester)) {
- @{"${cmpg}::${i}::ISA"} = ("${cmpg}::MagicProc");
- }
- @{"${cmpg}::MagicProc::ISA"} = ("${cmpg}::Proc");
-}
-
-#----- Crypto algorithms ----------------------------------------------------
-
-package Catacomb;
-
-foreach my $i (qw(Cipher Hash MAC)) {
- my $tag = lc($i);
- my @v = ();
- my $cl = "Catacomb::${i}Class";
- foreach my $c (&{"${cl}::list"}($cl)) {
- my $x = $c->name(); $x =~ tr/a-zA-Z0-9/_/cs;
- ${"Catacomb::${i}::${x}"} = undef; # SUYB
- ${"Catacomb::${i}::${x}"} = $c;
- push(@v, "\$Catacomb::${i}::${x}");
+ next;
}
- $EXPORT_TAGS{$tag} = \@v;
- Exporter::export_ok_tags($tag);
-}
-
-package Catacomb::CipherClass;
-use Carp;
-
-sub encrypt {
- croak("Usage: Catacomb::CipherClass::encrypt(cc, k, [iv], plain)")
- if @_ < 3 || @_ > 4;
- my ($cc, $k, $iv, $p) = @_;
- if (@_ == 3) {
- $p = $iv;
- $iv = undef;
- }
- my $c = $cc->init($k);
- $c->setiv($iv) if defined($iv);
- return $c->encrypt($p);
-}
-
-sub decrypt {
- croak("Usage: Catacomb::CipherClass::decrypt(cc, k, [iv], cipher)")
- if @_ < 3 || @_ > 4;
- my ($cc, $k, $iv, $p) = @_;
- if (@_ == 3) {
- $p = $iv;
- $iv = undef;
- }
- my $c = $cc->init($k);
- $c->setiv($iv) if defined($iv);
- return $c->decrypt($p);
-}
-
-package Catacomb::HashClass;
-use Carp;
-
-sub hash {
- croak("Usage: Catacomb::HashClass::hash(hc, p)") unless @_ == 2;
- my ($hc, $p) = @_;
- my $h = $hc->init();
- $h->hash($p);
- return $h->done();
-}
-
-package Catacomb::MACClass;
-use Carp;
-
-sub mac {
- croak("Usage: Catacomb::MACClass::mac(mc, k, p)") unless @_ == 3;
- my ($mc, $k, $p) = @_;
- my $m = $mc->key($k);
- return $m->hash($p);
-}
-
-package Catacomb::MAC;
-use Carp;
-
-sub hash {
- croak("Usage: Catacomb::MAC::hash(m, p)") unless @_ == 2;
- my ($m, $p) = @_;
- my $h = $m->init();
- $h->hash($p);
- return $h->done();
-}
-
-#----- Random number generators ---------------------------------------------
-
-package Catacomb;
-
-foreach my $i (qw(True Fib LC DSA RC4 SEAL MGF Counter OFB Magic)) {
- @{"Catacomb::Rand::${i}::ISA"} = qw(Catacomb::Rand);
+ *{$new} = \&{$proc};
}
-$Catacomb::random = Catacomb::Rand::True->_global();
-$Catacomb::random->noisesrc();
-$Catacomb::random->seed(160);
+$rabin_tester = Catacomb::MP::Prime::Rabin->tester();
+$pg_events = Catacomb::MP::Prime::Gen::Proc->ev();
+$pg_evspin = Catacomb::MP::Prime::Gen::Proc->evspin();
+$pg_subev = Catacomb::MP::Prime::Gen::Proc->subev();
+
+$EXPORT_TAGS{"const"} = [Catacomb::_constants()];
+$EXPORT_TAGS{"random"} = [qw($random)];
+$EXPORT_TAGS{"mp"} = [qw(mp gf mp_loadb mp_loadl mp_loadb2c mp_loadl2c
+ mp_fromstring gf_loadb gf_loadl gf_fromstring)];
+$EXPORT_TAGS{"pgen"} = [qw(newprime primegen limleegen
+ filterstepper $rabin_tester
+ $pg_events $pg_evspin $pg_subev)];
+Exporter::export_ok_tags(keys %EXPORT_TAGS);
#----- That's all, folks ----------------------------------------------------
--- /dev/null
+=head1 NAME
+
+Catacomb - cryptographic library
+
+=head1 SYNOPSIS
+
+ use Catacomb qw(:const :mp :random :pgen);
+
+ $x = Catacomb::MP->new($str, [$radix]);
+ $x = Catacomb::MP->new($i);
+ $x = Catacomb::MP->loadb($bytes);
+ $x = Catacomb::MP->loadl($bytes);
+ $x = Catacomb::MP->loadb2c($bytes);
+ $x = Catacomb::MP->loadl2c($bytes);
+ ($x, $rest) = Catacomb::MP->fromstring($str, [$radix]);
+ $x = mp($str, [$radix]);
+ $x = mp($i);
+ ($x, $rest) = mp_fromstring($str, [$radix]);
+ $a = $b + $c;
+ $a = $b - $c;
+ $a = $b * $c;
+ $a = $b / $c;
+ $a = $b % $c;
+ $a = $b ** $n;
+ $a = $b << $n;
+ $a = $b >> $n;
+ $a = $b & $c;
+ $a = $b | $c;
+ $a = $b ^ $c;
+ $a = ~$b;
+ $p = $b == $c;
+ $p = $b != $c;
+ $p = $b < $c;
+ $p = $b > $c;
+ $p = $b <= $c;
+ $p = $b >= $c;
+ $a = sqrt($b);
+ $a = -$b;
+ $a = $b->add($c);
+ $a = $b->sub($c);
+ $a = $b->mul($c);
+ ($q, $r) = $a->div($b);
+ $a = $b->exp($c);
+ $a = $b->sqr();
+ $a = $b->sqrt();
+ $a = $b->neg();
+ $a = $b->not();
+ $a = $b->not2c();
+ $a = $b->mod($c);
+ $p = $b->eq($c);
+ $cmp = $b->cmp($c);
+ $a = $b->and($c);
+ $a = $b->and2c($c);
+ $a = $b->or($c);
+ $a = $b->or2c($c);
+ $a = $b->xor($c);
+ $a = $b->xor2c($c);
+ $a = $b->nand($c);
+ $a = $b->nand2c($c);
+ $a = $b->nor($c);
+ $a = $b->nor2c($c);
+ $a = $b->not();
+ $a = $b->not2c();
+ $a = $b->lsl($n);
+ $a = $b->lsl2c($n);
+ $a = $b->lsr($n);
+ $a = $b->lsr2c($n);
+ $a = $b->setbit($n);
+ $a = $b->setbit2c($n);
+ $a = $b->clearbit($n);
+ $a = $b->clearbit2c($n);
+ $p = $b->testbit($n);
+ $p = $b->testbit2c($n);
+ $x = $y->copy(); # largely useless
+ $g = $a->gcd($b);
+ ($g, $u, $v) = $a->gcd($b);
+ ($s, $t) = $m->odd(); # m = 2^s t
+ $a = $p->modexp($x, $e);
+ $a = $p->modinv($b);
+ $r = $p->modsqrt($x);
+ $q = $n->jac($a);
+ $p = $x->primep([$rng]);
+ $nbits = $x->bits();
+ $nbytes = $x->octets();
+ $bytes = $x->storeb([$nbytes]);
+ $bytes = $x->storel([$nbytes]);
+ $bytes = $x->storeb2c([$nbytes]);
+ $bytes = $x->storel2c([$nbytes]);
+ $str = $x->tostring([$radix]);
+ $n = $x->toint();
+
+ $barrett = Catacomb::MP::Barrett->new($p);
+ $barrett = $p->barrett();
+ $p = $barrett->m();
+ $x = $barrett->reduce($y);
+ $a = $barrett->exp($x, $y);
+
+ $mont = Catacomb::MP::Mont->new($p);
+ $mont = $p->mont();
+ $r = $mont->r();
+ $r2 = $mont->r2();
+ $p = $mont->m();
+ $x = $mont->in($y);
+ $a = $mont->mul($x, $y);
+ $a = $mont->expr($x, $y);
+ $a = $mont->mexpr($x0, $e0, $x1, $e1, ...);
+ $x = $mont->reduce($y);
+ $x = $mont->out($y);
+ $a = $mont->exp($x, $y);
+ $a = $mont->mexp($x0, $e0, $x1, $e1, ...);
+
+ $reduce = Catacomb::MP::Reduce->new($p);
+ $reduce = $p->mkreduce();
+ $p = $reduce->m();
+ $x = $reduce->reduce($y);
+ $a = $barrett->exp($x, $y);
+
+ $crt = Catacomb::MP::CRT->new(@n);
+ $n = $crt->product();
+ @n = $crt->moduli();
+ $x = $crt->solve(@r);
+
+ $p = newprime($nbits, [$rng]);
+
+ $filt = Catacomb::MP::Prime::Filter->new($x);
+ $filt = $x->filter();
+ $rc = $filt->status();
+ $x = $filt->m();
+ $rc = $filt->step($n);
+ $rc = $filt->jump($jfilt);
+ $newfilt = $filt->muladd($mul, $add); # integers
+
+ $stepper = Catacomb::MP::Prime::Filter->stepper($step); # integer
+ $stepper = filterstepper($step);
+ $jumper = Catacomb::MP::Prime::Filter->stepper($jump); # MP
+ $jumper = filterjumper($jump);
+
+ $rabin = Catacomb::MP::Prime::Rabin->new($m);
+ $rabin = $p->rabin();
+ $m = $rabin->m();
+ $rc = $rabin->test($wit);
+ $n = $rabin->iters();
+ $n = Catacomb::MP::Prime::Rabin->ntests($bits);
+ $tester = Catacomb::MP::Prime::Rabin->tester();
+ $tester = $rabintester;
+
+ $events = Catacomb::MP::Prime::Gen::Proc->ev();
+ $events = Catacomb::MP::Prime::Gen::Proc->evspin();
+ $events = Catacomb::MP::Prime::Gen::Proc->subev();
+
+ $p = Catacomb::MP::Prime->gen
+ ($name, $x, $nsteps, $stepper, $ntests, $tester, [$events]);
+ $p = primegen
+ ($name, $x, $nsteps, $stepper, $ntests, $tester, [$events]);
+ if (($x, $j) = Catacomb::MP::Prime->strongprime_setup
+ ($name, $nbits, [$rng], [$nsteps], [$subevents])) {
+ $p = Catacomb::MP::Prime->gen
+ ($name, $x, $nsteps, $j, $ntests, $tester, [$events]);
+ }
+ ($p, @f) = Catacomb::MP::Prime->limlee
+ ($name, $qbits, $pbits, [$rng], [$on], [$oev], [$iev]);
+ ($p, @f) = limleegen
+ ($name, $qbits, $pbits, [$rng], [$on], [$oev], [$iev]);
+
+ package MyPrimeGenObject;
+ sub new { ... };
+ sub BEGIN { ... };
+ sub TRY { ... };
+ sub FAIL { ... };
+ sub PASS { ... };
+ sub DONE { ... };
+ sub ABORT { ... };
+ $name = $ev->name();
+ $x = $ev->m([$xx]);
+ $rng = $ev->rand();
+
+ $a = Catacomb::GF->new($x);
+ $a = Catacomb::GF->loadb($bytes);
+ $a = Catacomb::GF->loadl($bytes);
+ ($x, $rest) = Catacomb::GF->fromstring($str, [$radix]);
+ $a = gf($mp);
+ $a = gf($str);
+ $a = gf($i);
+ $a = gf_loadb($bytes);
+ $a = gf_loadl($bytes);
+ ($x, $rest) = gf_fromstring($str, [$radix]);
+ $x = mp($a);
+ $a = $b + $c;
+ $a = $b - $c; # same as +
+ $a = $b * $c;
+ $a = $b / $c;
+ $a = $b % $c;
+ $a = $b << $n;
+ $a = $b >> $n;
+ $a = $b & $c;
+ $a = $b | $c;
+ $a = $b ^ $c;
+ $a = ~$b;
+ $p = $b == $c;
+ $p = $b != $c;
+ $a = -$b; # does nothing
+ $a = $b->copy(); # largely pointless
+ $a = $b->add($c);
+ $a = $b->sub($c);
+ $a = $b->mul($c);
+ $a = $b->sqr();
+ ($q, $r) = $a->div($b);
+ $a = $b->lsl($n);
+ $a = $b->lsr($n);
+ $a = $b->and($c);
+ $a = $b->or($c);
+ $a = $b->xor($c);
+ $a = $b->nand($c);
+ $a = $b->nor($c);
+ $a = $b->setbit($n);
+ $a = $b->clearbit($n);
+ $g = $a->gcd($b);
+ ($g, $u, $v) = $a->gcd($b);
+ $p = $p->irreduciblep();
+ $a = $b->modinv($c);
+ $a = $b->modexp($c, $n);
+ # and all the Catacomb::MP methods
+
+ $F = Catacomb::Field->prime($p);
+ $F = Catacomb::Field->niceprime($p);
+ $F = Catacomb::Field->binpoly($p);
+ $F = Catacomb::Field->binnorm($p, $beta);
+ $F = Catacomb::Field->byname($name);
+ $F = $p->primefield();
+ $F = $p->niceprimefield();
+ $F = $p->binpolyfield();
+ $F = $p>binnormfield($beta);
+ $name = $F->name();
+ $ty = $F->type();
+ $info = $F->get();
+ $p = $F->samep($FF);
+ $q = $F->q();
+ $m = $F->m();
+ $nbits = $F->nbits();
+ $nbytes = $F-noctets();
+ $xi = $F->in($x);
+ $x = $F->out($xi);
+ $p = $F->zerop($xi);
+ $xi = $F->neg($yi);
+ $xi = $F->add($yi, $zi);
+ $xi = $F->sub($yi, $zi);
+ $xi = $F->mul($yi, $zi);
+ $xi = $F->div($yi, $zi);
+ $xi = $F->sqr($yi, $zi);
+ $xi = $F->inv($yi);
+ $xi = $F->reduce($yi);
+ $xi = $F->sqrt($yi);
+ $xi = $F->quadsolve($yi);
+ $xi = $F->dbl($yi);
+ $xi = $F->tpl($yi);
+ $xi = $F->hlv($yi);
+
+ $e = Catacomb::Field::Elt->new($F, $x);
+ $e = $F->elt($x);
+ $e = $F->zero();
+ $e = $F->one();
+ $e = $F->rand([$rng]);
+ $F = $e->field();
+ $x = $e->value();
+ $str = $e->tostring([$radix]);
+ $e = $f->inv();
+ $e = $f + $g;
+ $e = $f - $g;
+ $e = $f * $g;
+ $e = $f / $g;
+ $e = $f ** $n;
+ $p = $f == $g;
+ $p = $f != $g;
+ $e = -$f;
+ $e = sqrt($f);
+ $p = $f->zerop();
+
+ $P = Catacomb::EC::Point->new([$x], [$y], [$z]);
+ ($P, $rest) = Catacomb::EC::Point->get($buf);
+ $p = $P->atinfp();
+ $x = $P->x();
+ $y = $P->y();
+ $z = $P->z();
+ $p = $P->eq($Q);
+ $buf = $P->put();
+ $str = $P->tostring();
+
+ $C = Catacomb::EC::Curve->prime($F, $a, $b);
+ $C = Catacomb::EC::Curve->primeproj($F, $a, $b);
+ $C = Catacomb::EC::Curve->bin($F, $a, $b);
+ $C = Catacomb::EC::Curve->binproj($F, $a, $b);
+ ($C, $G, $r, $h) = Catacomb::EC::Curve->getinfo($name);
+ $C = $F->primecurve($F, $a, $b);
+ $C = $F->primeprojcurve($F, $a, $b);
+ $C = $F->bincurve($F, $a, $b);
+ $C = $F->binprojcurve($F, $a, $b);
+ $name = $C->name();
+ $a = $C->a();
+ $b = $C->b();
+ $F = $C->field();
+ $info = $C->get();
+ $p = $C->samep($CC);
+ $bytes = $C->putraw($P);
+ ($pp, $rest) = $C->getraw($bytes);
+ $buf = $C->putraw($P);
+ ($P, $rest) = $C->getraw($buf);
+ $P = $C->neg($Q);
+ $P = $C->add($Q, $R);
+ $P = $C->dbl($Q);
+ $p = $C->check($P);
+ $P = $C->mul($Q, $n);
+ $P = $C->mmul($P0, $n0, $P1, $n1, ...);
+ $err = $C->checkinfo($G, $r, $h);
+ $Pi = $C->in($P);
+ $Pi = $C->fix($Pi);
+ $Pi = $C->ifind($xi);
+ $Pi = $C->ineg($Qi);
+ $Pi = $C->iadd($Qi, $Ri);
+ $Pi = $C->isub($Qi, $Ri);
+ $Pi = $C->idbl($Qi);
+ $p = $C->icheck($Pi);
+ $Pi = $C->imul($Qi, $n);
+ $Pi = $C->immul($Qi0, $n0, $Qi1, $n1, ...);
+ $P = $C->out($Pi);
+
+ $P = Catacomb::EC::Point->new($C, [$p]);
+ $P = Catacomb::EC::Point->new($C, $x, $y);
+ $P = $C->inf();
+ $P = $C->pt($p);
+ $P = $C->pt($x, $y);
+ $P = $C->find($x);
+ $P = $C->rand([$rng]);
+ $C = $P->curve();
+ $F = $P->field();
+ $P = $Q->point();
+ $p = $P->atinfp();
+ $x = $P->x();
+ $y = $P->y();
+ $p = $P->check();
+ $P = $Q->mul($n);
+ $P = $Q + $R;
+ $P = $Q - $R;
+ $P = $Q * $n;
+ $P = $n * $Q;
+ $p = $Q == $R;
+ $p = $Q != $R;
+ $P = -$Q;
+
+ $G = Catacomb::Group->prime($p, $g, $q);
+ $G = Catacomb::Group->binary($p, $g, $q);
+ $G = Catacomb::Group->ec($C, $G, $r, $h);
+ $G = Catacomb::Group->byname($name);
+ $G = $p->primegroup($g, $q);
+ $G = $p->binpolygroup($g, $q);
+ $G = $C->ecgroup($G, $r, $h);
+ $info = $G->get();
+ $a = $G->mexp($a0, $n0, $a1, $n1, ...);
+ $p = $G->samep($GG);
+ $r = $G->r();
+ $h = $G->h();
+ ($p, $err) = $G->check($rng);
+
+ $a = Catacomb::Group::Elt($G, [$x]);
+ $a = $G->elt([$x]);
+ $a = $G->id();
+ $g = $G->g();
+ $a = $G->fromint($x);
+ $a = $G->fromec($P);
+ ($a, $rest) = $G->frombuf($buf);
+ ($a, $rest) = $G->fromraw($buf);
+ ($a, $rest) = $G->fromstring($str);
+ $x = $a->toint();
+ $P = $a->toec();
+ $buf = $a->tobuf();
+ $buf = $a->toraw();
+ $str = $a->tostring();
+ $G = $a->group();
+ $p = $a->identp();
+ $p = $a->check();
+ $a = $b->exp($n);
+ $a = $b->inv();
+ $a = $b * $c;
+ $a = $b / $c;
+ $a = $b ** $n;
+ $p = $b == $c;
+ $p = $b != $c;
+
+ $pc = Catacomb::PRPClass->find($name);
+ $pc = $Catacomb::rijndael;
+ $ksz = $pc->keysz();
+ $name = $pc->name();
+ $blksz = $pc->blksz();
+ $ct = $pc->eblk($k, $pt);
+ $pt = $pc->eblk($k, $ct);
+ $P = $pc->init($k);
+ $ct = $P->eblk($pt);
+ $pt = $P->dblk($ct);
+ $pc = $P->class();
+
+ $cc = Catacomb::CipherClass->find($name);
+ $cc = $Catacomb::rijndael_cbc;
+ $ksz = $cc->keysz();
+ $name = $cc->name();
+ $blksz = $cc->blksz();
+ $ct = $cc->encrypt($k, $pt, [$iv]);
+ $pt = $cc->decrypt($k, $ct, [$iv]);
+ $c = $cc->init();
+ $ct = $c->encrypt($pt);
+ $pt = $c->decrypt($ct);
+ $c->setiv($iv);
+ $c->bdry();
+ $pc = $c->class();
+
+ $hc = Catacomb::HashClass->find($name);
+ $hc = $Catacomb::sha;
+ $hsz = $hc->hashsz();
+ $name = $hc->name();
+ $res = $hc->hash($msg);
+ $h = $hc->init();
+ $h->hash($buf); # as often as necessary
+ $hh = $h->copy();
+ $hc = $h->class();
+ $res = $h->done();
+
+ $mc = Catacomb::MACClass->find($name);
+ $mc = $Catacomb::sha_hmac;
+ $hsz = $mc->hashsz();
+ $ksz = $mc->keysz();
+ $name = $mc->name();
+ $t = $mc->mac($k, $msg);
+ $m = $mc->key($k);
+ $mc = $m->class();
+ $t = $m->hash($msg);
+ $h = $m->init();
+
+ $rng = Catacomb::Rand::True->new();
+ $rng = Catacomb::random;
+ $rng->gate();
+ $rng->stretch();
+ $rng->key($k);
+ $rng->noisesrc();
+ $rng->seed([$nbits]);
+
+ $rng = Catacomb::Rand::DSA->new($k);
+ $rng->passes($n);
+ $k = $rng->seed();
+
+ $rng = Catacomb::Rand::Fib->new($seed);
+ $rng = Catacomb::Rand::LC->new($seed);
+ $rng = Catacomb::Rand::RC4->new($k);
+ $rng = Catacomb::Rand::SEAL->new($k);
+ $rng = Catacomb::Rand::MGF->new($name, $k);
+ $rng = Catacomb::Rand::Counter->new($name, $k);
+ $rng = Catacomb::Rand::OFB->new($name, $k);
+
+ $rng->seedint($i);
+ $rng->seedblock($buf);
+ $rng->seedmp($x);
+ $rng->seedrand($rng2);
+ $u = $rng->raw();
+ $u = $rng->word();
+ $b = $rng->byte();
+ $c = $rng->char();
+ $u = $rng->range($max);
+ $x = $rng->mp($nbits, [$or]);
+ $x = $rng->mprange($max);
+ $buf = $rng->fill($nbytes);
+ $name = $rng->name();
+ $f = $rng->flags();
+ $u = $rng->max();
+
+ ($p, $g, $q) = Catacomb::PubKey->gen_dh
+ ($ql, $pl, [$steps], [$r], [$events]);
+ ($p, $g, $q, @f) = Catacomb::PubKey->gen_limlee
+ ($ql, $pl, [$flags], [$steps], [$r], [$oevents], [$ievents]);
+ ($p, $g, $q, $seed, $count) = Catacomb::PubKey->gen_dsa
+ ($ql, $pl, [$steps], [$k], [$events]);
+
+ $dsapub = Catacomb::DSA::Public->new([$G, $p, $hunoz, $h, $rng]);
+ $dsapub = Catacomb::DSA::Public->new
+ ({ G => $G, p => $p, h => $h, rng => $rng});
+ $h = $dsapub->beginhash();
+ $dsapub->endhash($h);
+ $p = $dsapub->verify($msg, $r, $s);
+
+ $dsapriv = Catacomb::DSA::Private->new([$G, $p, $u, $h, $rng]);
+ ($r, $s) = $dsapriv->sign($msg, [$k]);
+
+ $kcdsapub = Catacomb::KCDSA::Public->new([$G, $p, $hunoz, $h, $rng]);
+ $h = $kcdsapub->beginhash();
+ $kcdsapub->endhash($h);
+ $p = $kcdsapub->verify($msg, $r, $s);
+
+ $kcdsapriv = Catacomb::KCDSA::Private->new([$G, $p, $u, $h, $rng]);
+ ($r, $s) = $kcdsapriv->sign($msg, [$k]);
+
+ $p1pad = Catacomb::RSA::PKCS1Crypt->new([$ep, $rng]);
+ $p1pad = Catacomb::RSA::PKCS1Sign->new([$ep, $rng]);
+ $oaeppad = Catacomb::RSA::OAEP->new([$c, $h, $ep, $rng]);
+ $psspad = Catacomb::RSA::PSS->new([$c, $h, $ssz, $rng]);
+ $x = $pad->pad($m, $sz, $nbits);
+ $m = $cryptpad->unpad($m, $sz, $nbits);
+ $m = $sigpad->unpad($s, $m, $sz, $nbits);
+
+ $rsapub = Catacomb::RSA::Public->new([$n, $e]);
+ $rsapub = Catacomb::RSA::Public->new({ n => $n, e => $e });
+ $n = $rsapub->n();
+ $h = $rsapub->extract();
+ $x = $rsapub->op($y);
+ $c = $rsapub->encrypt($cryptpad, $m);
+ $rc = $rsapub->verify($signpad, $s, [$m]);
+
+ $rsapriv = Catacomb::RSA::Private->new
+ ([$n, $e, $d, $p, $q, $dp, $dq, $qi]);
+ $rsapriv = Catacomb::RSA::Public->new
+ ({ n => $n, e => $e, d => $d,
+ p => $p, q => $q, dp => $dp, dq => $dq, qi => $qi });
+ $rsapriv = Catacomb::RSA::Private->generate
+ ($nbits, [$rng], [$steps], [$events]);
+ $n = $rsapriv->n();
+ $h = $rsapriv->extract();
+ $x = $rsapriv->op($y, [$rng]);
+ $m = $rsapriv->decrypt($cryptpad, $c, [$rng]);
+ $s = $rsapriv->sign($signpad, $m, [$rng]);
+
+ $s = Catacomb::Share::GF->new($t, $sz);
+ $sz = $s->sz();
+ $t = $s->t();
+ $i = $s->i();
+ $s->mkshares($secret, [$rng]);
+ $share = $s->get($i);
+ $left = $s->add($i, $share);
+ $secret = $s->combine();
+
+ $s = Catacomb::Share::Prime->new($t, [$p]);
+ $p = $s->p();
+ $t = $s->t();
+ $i = $s->i();
+ $s->mkshares($secret, [$rng]);
+ $share = $s->get($i);
+ $left = $s->add($i, $share);
+ $secret = $s->combine();
+
+ $pp = Catacomb::Passphrase->read($tag, [$len]);
+ $pp = Catacomb::Passphrase->verify($tag, [$len]);
+ Catacomb::Passphrase->cancel($tag);
+
+ $ssz = $ksz->keysz($sz);
+ @ksz = $ksz->expand();
+
+ $kf = Catacomb::Key::File->new($name, [$kopen], [$reporter]);
+ $p = $kf->merge($name, $fh, [$reporter]);
+ $p = $kf->extract($key, $fh, [$kfilt]);
+ $kwriteerr = $kf->save();
+ $i = $kf->iterate();
+ $key = $i->next();
+
+ $key = $kf->bytype($kf, $type);
+ $key = $kf->byid($kf, $id);
+ $key = $kf->bytag($kf, $tag);
+ $key = $kf->newkey($kf, $id, $type, $exp);
+ ($key, $kd, $ftag) = $kf->qtag($qtag);
+ $p = $key->chkident($id);
+ $p = $key->chkcomment($id);
+ $exp = $key->exp();
+ $exp = $key->del();
+ $comm = $key->comment();
+ $id = $key->id();
+ $tag = $key->tag();
+ $type = $key->type();
+ $p = $key->setcomment($comm);
+ $p = $key->settag($tag);
+ $p = $key->delete();
+ $ftag = $key->fulltag();
+ $v = $key->getattr($a);
+ $p = $key->putattr($a, $v);
+ $p = $key->expiredp();
+ $p = $key->used();
+ $p = $key->fingerprint($h, [$kfilt]);
+ $Catacomb::Key::error;
+ $str = Catacomb::Key->strerror($errnum);
+ $ah = $key->attrs(); # returns hashref
+ $i = $key->attriter();
+ ($a, $v) = $i->next();
+
+ $kfilt = Catacomb::Key::Filter->new($f, $m);
+ $kfilt = Catacomb::Key::Filter->new($fstr);
+ $fstr = $kfilt->tostring();
+ $f = $kfilt->f();
+ $m = $kfilt->m();
+
+ $kd = Catacomb::Key::Data->new();
+ ($kd, $rest) = Catacomb::Key::Data->read($str);
+ $kd = Catacomb::Key::Data->decode($buf);
+ $kd = $key->data();
+ $kd->setbinary($bin);
+ $kd->setencrypted($crypted);
+ $kd->setmp($x);
+ $kd->setstring($str);
+ $kd->setec($P);
+ $f = $kd->flags();
+ $bin = $kd->getbinary();
+ $crypted = $kd->getcrypted();
+ $x = $kd->getmp();
+ $str = $kd->getstring();
+ $P = $kd->getec();
+ $kd->setstruct();
+ $kkd = $kd->structfind($t);
+ $kkd = $kd->structcreate($t);
+ $kd->structdel($t);
+ $kh = $kd->structopen(); # returns hashref
+ $kkd = $kd->copy();
+ $kkd = $kd->lock($k);
+ $kkd = $kd->unlock($k);
+ $kkd = $kd->plock($tag);
+ $kkd = $kd->punlock($tag);
+ $str = $kd->write();
+ $buf = $kd->encode();
+ $i = $kd->structiter();
+
+=head1 DESCRIPTION
+
+=head1 SEE ALSO
+
+Catacomb(3).
+
+=head1 AUTHOR
+
+Mark Wooding, <mdw@nsict.org>
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Basic support stuff
+#
+# (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.
+
+package Catacomb;
+use DynaLoader;
+use Exporter;
+@ISA = qw(DynaLoader Exporter);
+
+sub AUTOLOAD {
+ my $val = _const($AUTOLOAD);
+ *$AUTOLOAD = sub { $val };
+ goto &$AUTOLOAD;
+}
+
+bootstrap Catacomb;
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Caching for fields, curves, groups, ...
+#
+# (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.
+
+package Catacomb::Cache::Ref;
+
+sub new {
+ my ($me, $c) = @_;
+ $c->[0]++;
+ return bless [$c], $me;
+}
+
+sub DESTROY {
+ my ($me) = @_;
+ my $c = $me->[0];
+ if ($c->[0] > 1) { $c->[0]--; return; }
+ delete $c->[1]{$c->[2]};
+}
+
+package Catacomb::Cache;
+
+$debug = 1;
+
+sub stringify {
+ my ($x) = @_;
+ if (ref($x) eq ARRAY) {
+ return "[" . join("/", map(stringify($_), @$x)) . "]";
+ } else {
+ return $x;
+ }
+}
+
+sub new { my ($me) = @_; return bless { }, $me; }
+
+sub intern {
+ my ($c, $x) = @_;
+ my $k = stringify($x->get());
+ my $e;
+ if (exists($c->{$k})) {
+ $e = $c->{$k};
+ } else {
+ $e = $c->{$k} = [0, $c, $k, $x];
+ }
+ return $e->[3], Catacomb::Cache::Ref->new($e);
+}
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Cryptographic algorithms
+#
+# (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.
+
+#----- Symmetric crypto algorithms -----------------------------------------
+
+package Catacomb;
+use Catacomb::Base;
+use Exporter;
+
+foreach my $i (qw(PRP Cipher Hash MAC)) {
+ my $tag = lc($i);
+ my @v = ();
+ my $cl = "Catacomb::${i}Class";
+ foreach my $c (Catacomb::list($tag)) {
+ (my $x = $c) =~ tr/a-zA-Z0-9/_/cs;
+ $$x = undef; # SUYB
+ $$x = $cl->find($c);
+ push(@v, "\$$x");
+ }
+ $EXPORT_TAGS{$tag} = \@v;
+ Exporter::export_ok_tags($tag);
+}
+
+package Catacomb::PRPClass;
+use Carp;
+
+sub eblk {
+ croak("Usage: Catacomb::PRPClass::eblk(pc, k, pt)") unless @_ == 3;
+ my ($pc, $k, $pt) = @_;
+ my $P = $pc->init($k);
+ return $P->eblk($pt);
+}
+
+sub dblk {
+ croak("Usage: Catacomb::PRPClass::dblk(pc, k, ct)") unless @_ == 3;
+ my ($pc, $k, $pt) = @_;
+ my $P = $pc->init($k);
+ return $P->dblk($ct);
+}
+
+package Catacomb::CipherClass;
+use Carp;
+
+sub encrypt {
+ croak("Usage: Catacomb::CipherClass::encrypt(cc, k, [iv], plain)")
+ if @_ < 3 || @_ > 4;
+ my ($cc, $k, $iv, $p) = @_;
+ if (@_ == 3) {
+ $p = $iv;
+ $iv = undef;
+ }
+ my $c = $cc->init($k);
+ $c->setiv($iv) if defined($iv);
+ return $c->encrypt($p);
+}
+
+sub decrypt {
+ croak("Usage: Catacomb::CipherClass::decrypt(cc, k, [iv], cipher)")
+ if @_ < 3 || @_ > 4;
+ my ($cc, $k, $iv, $p) = @_;
+ if (@_ == 3) {
+ $p = $iv;
+ $iv = undef;
+ }
+ my $c = $cc->init($k);
+ $c->setiv($iv) if defined($iv);
+ return $c->decrypt($p);
+}
+
+package Catacomb::HashClass;
+use Carp;
+
+sub hash {
+ croak("Usage: Catacomb::HashClass::hash(hc, p)") unless @_ == 2;
+ my ($hc, $p) = @_;
+ my $h = $hc->init();
+ $h->hash($p);
+ return $h->done();
+}
+
+package Catacomb::MACClass;
+use Carp;
+
+sub mac {
+ croak("Usage: Catacomb::MACClass::mac(mc, k, p)") unless @_ == 3;
+ my ($mc, $k, $p) = @_;
+ my $m = $mc->key($k);
+ return $m->hash($p);
+}
+
+package Catacomb::MAC;
+use Carp;
+
+sub hash {
+ croak("Usage: Catacomb::MAC::hash(m, p)") unless @_ == 2;
+ my ($m, $p) = @_;
+ my $h = $m->init();
+ $h->hash($p);
+ return $h->done();
+}
+
+#----- DSA and KCDSA signing ------------------------------------------------
+
+package Catacomb::DSA;
+use Carp;
+sub new {
+ croak("Usage: ${me}::new(me, info)") unless @_ == 2;
+ my ($me, $info) = @_;
+ return bless $info, $me;
+}
+
+*Catacomb::KCDSA::new = \&new;
+
+foreach my $i (qw(DSA KCDSA)) {
+ @{"Catacomb::${i}::Public::ISA"} = ("Catacomb::${i}");
+ @{"Catacomb::${i}::Private::ISA"} = ("Catacomb::${i}::Public");
+}
+
+#----- RSA signing and encryption -------------------------------------------
+
+package Catacomb::RSA::Pad;
+use Carp;
+
+sub new {
+ croak("Usage: ${me}::new(me, info)") unless @_ == 2;
+ my ($me, $info) = @_;
+ return bless $info, $me;
+}
+
+foreach my $i (qw(PKCS1Crypt PKCS1Sign OAEP PSS)) {
+ @{"Catacomb::RSA::${i}::ISA"} = qw(Catacomb::RSA::Pad);
+}
+
+package Catacomb::RSA::Public;
+use Carp;
+use Catacomb::Base;
+use Catacomb::MP;
+
+sub encrypt {
+ croak("Usage: Catacomb::RSA::Public::encrypt(pub, pad, msg)")
+ unless @_ == 3;
+ my ($pub, $pad, $msg) = @_;
+ my $n = $pub->n();
+ my $r = $pad->pad($msg, $n->octets(), $n->bits());
+ return undef unless defined($r);
+ return $pub->op($r);
+}
+
+sub verify {
+ croak("Usage: Catacomb::RSA::Public::verify(pub, pad, sig, [msg])")
+ unless @_ >= 3 && @_ <= 4;
+ my ($pub, $pad, $sig, $msg) = @_;
+ my $n = $pub->n();
+ my $rc = $pad->unpad($pub->op($sig), $msg, $n->octets(), $n->bits());
+ return undef unless defined($rc);
+ if (defined($msg)) {
+ return undef unless $rc eq "" || $rc eq $msg;
+ return 1;
+ } else {
+ return $rc;
+ }
+}
+
+package Catacomb::RSA::Private;
+use Carp;
+use Catacomb::Base;
+use Catacomb::MP;
+
+sub sign {
+ croak("Usage: Catacomb::RSA::Private::sign(priv, pad, msg, [rng]")
+ unless @_ >= 3 && @_ <= 4;
+ my ($priv, $pad, $msg, $rng) = @_;
+ my $n = $priv->n();
+ my $r = $pad->pad($msg, $n->octets(), $n->bits());
+ return undef unless defined($r);
+ return $priv->op($r, $rng);
+}
+
+sub decrypt {
+ croak("Usage: Catacomb::RSA::Private::decrypt(priv, pad, ct, [rng]")
+ unless @_ >= 3 && @_ <= 4;
+ my ($priv, $pad, $ct, $rng) = @_;
+ my $n = $priv->n();
+ return $pad->unpad($priv->op($ct, $rng), $n->octets(), $n->bits());
+}
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Elliptic curves
+#
+# (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.
+
+#----- Elliptic curves ------------------------------------------------------
+
+package Catacomb::EC::Curve;
+use Carp;
+use Catacomb::Base;
+use Catacomb::Cache;
+use Catacomb::Field;
+
+$cache = Catacomb::Cache->new();
+
+sub intern {
+ croak("Usage: Catacomb::EC::Curve::intern(c)") unless @_ == 1;
+ my ($c) = @_;
+ return $cache->intern($c);
+}
+
+sub pt {
+ croak("Usage: Catacomb::EC::Curve::pt(c, [x, y | p])")
+ unless @_ >= 1 && @_ <= 3;
+ return Catacomb::EC::Pt->new(@_);
+}
+
+sub a {
+ croak("Usage: Catacomb::EC::Curve::a(c)") unless @_ == 1;
+ my ($c) = @_;
+ return $c->field()->elt($c->_a());
+}
+
+sub b {
+ croak("Usage: Catacomb::EC::Curve::b(c)") unless @_ == 1;
+ my ($c) = @_;
+ return $c->field()->elt($c->_b());
+}
+
+sub inf {
+ croak("Usage: Catacomb::EC::Curve::inf(c)") unless @_ == 1;
+ return Catacomb::EC::Pt->new($_[0]);
+}
+
+sub getraw {
+ croak("Usage: Catacomb::EC::Curve::getraw(c, s)") unless @_ == 2;
+ my ($c, $s) = @_;
+ my ($p, $rest) = $c->_getraw($s);
+ $p = Catacomb::EC::Pt->new($c, $p);
+ return !wantarray() ? $p : ($p, $rest);
+}
+
+sub find {
+ croak("Usage: Catacomb::EC::Curve::find(c, x)") unless @_ == 2;
+ my ($c, $x) = @_;
+ my $p = $c->_find($x);
+ return undef unless defined $p;
+ return Catacomb::EC::Pt->new($c, $p);
+}
+
+sub rand {
+ croak("Usage: Catacomb::EC::Curve::rand(c, [rng])")
+ unless @_ >= 1 && @_ <= 2;
+ my ($c, $rng) = @_;
+ $rng ||= $Catacomb::random;
+ my $p = $c->_rand($rng);
+ return Catacomb::EC::Pt->new($c, $p);
+}
+
+sub mmul {
+ croak("Usage: Catacomb::EC::Curve::mmul(c, p_0, x_0, p_1, x_1, ...)")
+ unless @_ >= 3 && @_ % 2 == 1;
+ my $c = pop(@_);
+ my $i;
+ my @v = ();
+ my @r = ();
+ for ($i = 0; $i < @_; $i += 2) {
+ my $p = $_[$i];
+ my $n = $_[$i + 1];
+ if (UNIVERSAL::isa($p, Catacomb::EC::Pt)) {
+ $p->[1] == $c or croak("curve mismatch");
+ @r or @r = @$p[1, 2, 3, 4];
+ $p = $p->[0];
+ } elsif (UNIVERSAL::isa($p, Catacomb::EC::Point)) {
+ $p = $c->in($p);
+ } else {
+ croak("not a curve point");
+ }
+ push(@v, $p, $n);
+ }
+ unless (@r) {
+ my ($cr, $f, $fr);
+ ($c, $cr) = $c->intern();
+ ($f, $fr) = $c->field()->intern();
+ @r = ($c, $cr, $f, $fr);
+ }
+ return Catacomb::EC::Pt::_pt(immul($c, @v), $c, $cr, $f, $fr);
+}
+
+sub getinfo {
+ croak("Usage: Catacomb::EC::Curve::getinfo(me, spec)") unless @_ == 2;
+ my ($me, $spec) = @_;
+ my ($c, $p, $r, $h) = _getinfo($me, $spec);
+ my $cr;
+ ($c, $cr) = $c->intern();
+ return $c, $c->pt($p), $r, $h;
+}
+
+sub ecgroup {
+ croak("Usage: Catacomb::EC::Curve::ecgroup(c, p, r, h)") unless @_ == 4;
+ return Catacomb::Group->ec(@_);
+}
+
+#----- Elliptic curve points ------------------------------------------------
+
+package Catacomb::EC::Point;
+
+sub tostring {
+ croak("Usage: Catacomb::EC::Point::tostring(p)") unless @_ == 1;
+ my ($p) = @_;
+ if ($p->atinfp()) {
+ return "inf";
+ } else {
+ return "0x" . $p->x()->tostring(16) . ", 0x" . $p->y()->tostring(16);
+ }
+}
+
+package Catacomb::EC::Pt;
+use Carp;
+use Catacomb::Base;
+use Catacomb::Field;
+
+sub _pt { bless [@_], Catacomb::EC::Pt; }
+
+sub _convert {
+ my ($c, $cr, $f, $fr, $x) = @_;
+ if (UNIVERSAL::isa($x, Catacomb::EC::Pt)) {
+ croak("curve mismatch") unless $c == $x->[1];
+ return $x;
+ }
+ if (UNIVERSAL::isa($x, Catacomb::EC::Point)) {
+ return _pt($x, $c, $cr, $f, $fr);
+ }
+ croak("can't convert to curve point");
+}
+
+sub new {
+ croak("Usage: Catacomb::EC::Pt::new(me, c, [x, y | p])")
+ unless @_ >= 2 && @_ <= 4;
+ my ($me, $c, $p);
+ if (@_ == 2) {
+ ($me, $c) = @_;
+ $p = Catacomb::EC::Point->new();
+ } elsif (@_ == 3) {
+ ($me, $c, $p) = @_;
+ if (UNIVERSAL::isa($p, Catacomb::EC::Pt)) {
+ $p = $p->point();
+ } elsif (!UNIVERSAL::isa($p, Catacomb::EC::Point)) {
+ croak("not a curve point");
+ }
+ } else {
+ my ($x, $y);
+ ($me, $c, $x, $y) = @_;
+ $p = Catacomb::EC::Point->new($x, $y);
+ }
+ my ($cr, $f, $fr);
+ ($c, $cr) = $c->intern();
+ ($f, $fr) = $c->field()->intern();
+ return _pt($c->in($p), $c, $cr, $f, $fr);
+}
+
+sub point {
+ croak("Usage: Catacomb::EC::Pt::point(p)") unless @_ == 1;
+ return $_[0][1]->out($_[0][0]);
+}
+
+sub curve {
+ croak("Usage: Catacomb::EC::Pt::curve(p)") unless @_ == 1;
+ return $_[0][1];
+}
+
+sub field {
+ croak("Usage: Catacomb::EC::Pt::field(p)") unless @_ == 1;
+ return $_[0][3];
+}
+
+sub atinfp {
+ croak("Usage: Catacomb::EC::Pt::atinfp(p)") unless @_ == 1;
+ return $_[0]->point()->atinfp();
+}
+
+sub x {
+ croak("Usage: Catacomb::EC::Pt::x(p)") unless @_ == 1;
+ return $_[0][3]->elt($_[0]->point()->x());
+}
+
+sub y {
+ croak("Usage: Catacomb::EC::Pt::y(p)") unless @_ == 1;
+ return $_[0][3]->elt($_[0]->point()->y());
+}
+
+sub check {
+ croak("Usage: Catacomb::EC::Curve::check(c)") unless @_ == 1;
+ return $_[0][1]->check($_[0][0]);
+}
+
+sub pt {
+ croak("Usage: Catacomb::EC::Pt::pt(pp, [x, y | p])")
+ unless @_ >= 1 && @_ <= 3;
+ my ($pp, $p);
+ if (@_ == 1) {
+ ($pp) = @_;
+ $p = Catacomb::EC::Point->new();
+ } elsif (@_ == 2) {
+ ($pp, $p) = @_;
+ if (UNIVERSAL::isa($p, Catacomb::EC::Pt)) {
+ $p = $p->point();
+ } elsif (!UNIVERSAL::isa($p, Catacomb::EC::Point)) {
+ croak("not a curve point");
+ }
+ } else {
+ my ($x, $y);
+ ($pp, $x, $y) = @_;
+ $p = Catacomb::EC::Point->new($x, $y);
+ }
+ my (undef, $c, $cr, $f, $fr) = @$pp;
+ return _pt($c->in($p), $c, $cr, $f, $fr);
+}
+
+sub _binop {
+ my ($op, $x, $y, $swap) = @_;
+ my (undef, $c, $cr, $f, $fr) = @$x;
+ $y = _convert($c, $cr, $f, $fr, $y);
+ my $z = $swap ?
+ &$op($c, $x->[0], $y->[0]) :
+ &$op($c, $y->[0], $x->[0]);
+ return _pt($z, $c, $cr, $f, $fr);
+}
+
+sub _unop {
+ my ($op, $x) = @_;
+ my (undef, $c, $cr, $f, $fr) = @$x;
+ my $z = &$op($c, $x->[0]);
+ return _pt($z, $c, $cr, $f, $fr);
+}
+
+sub _eq {
+ my ($x, $y) = @_;
+ my (undef, $c, $cr, $f, $fr) = @$x;
+ $y = _convert($c, $cr, $f, $fr, $y);
+ return Catacomb::EC::Point::eq($c->out($x), $c->out($y));
+}
+
+sub mul {
+ croak("Usage: Catacomb::EC::Pt::mul(p, n)") unless @_ == 2;
+ my ($p, $x) = @_;
+ my ($pp, $c, $cr, $f, $fr) = @$p;
+ return _pt($c->imul($pp, $x), $c, $cr, $f, $fr);
+}
+
+use overload
+ '+' => sub { _binop(\&Catacomb::EC::Curve::iadd, @_); },
+ '-' => sub { _binop(\&Catacomb::EC::Curve::isub, @_); },
+ '*' => sub { mul($_[0], $_[1]); },
+ '==' => sub { _eq(@_); },
+ '!=' => sub { !_eq(@_); },
+ 'eq' => sub { _eq(@_); },
+ 'ne' => sub { !_eq(@_); },
+ '""' => sub { $_[0]->point()->tostring(); },
+ '0+' => sub { $_[0]->point()->x()->toint(); },
+ 'neg' => sub { _unop(\&Catacomb::EC::Curve::ineg, @_); };
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-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 ----------------------------------------------------
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Binary polynomial arithmetic
+#
+# (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.
+
+#----- Binary polynomials ---------------------------------------------------
+
+package Catacomb::GF;
+use Catacomb::Base;
+use Catacomb::MP;
+use Carp;
+
+@ISA = qw(Catacomb::MP);
+
+sub gf { new(Catacomb::GF, $_[0]); }
+sub gf_loadb { loadb(Catacomb::GF, $_[0]); }
+sub gf_loadl { loadl(Catacomb::GF, $_[0]); }
+sub gf_fromstring { fromstring(Catacomb::GF, $_[0]); }
+
+use overload
+ '+' => sub { _binop(\&add, @_); },
+ '-' => sub { _binop(\&add, @_); },
+ '*' => sub { _binop(\&mul, @_); },
+ '/' => sub { _binop(\&div, @_); },
+ '%' => sub { _binop(\&mod, @_); },
+ '&' => sub { _binop(\&Catacomb::MP::and, @_); },
+ '|' => sub { _binop(\&Catacomb::MP::or, @_); },
+ '^' => sub { _binop(\&Catacomb::MP::xor, @_); },
+ '**' => sub { _binop(\&pow, @_); },
+ '>>' => sub { new(undef, &Catacomb::MP::lsr(@_[0, 1])); },
+ '<<' => sub { new(undef, &Catacomb::MP::lsl(@_[0, 1])); },
+ '~' => sub { new(undef, &Catacomb::MP::not($_[0])) },
+ '==' => sub { _binop(\&Catacomb::MP::eq, @_); },
+ '!=' => sub { !_binop(\&Catacomb::MP::eq, @_); },
+ 'eq' => sub { _binop(\&Catacomb::MP::eq, @_); },
+ 'ne' => sub { !_binop(\&Catacomb::MP::eq, @_); },
+ '""' => sub { "0x" . &Catacomb::MP::tostring($_[0], 16); },
+ 'neg' => sub { $_[0]; },
+ '0+' => sub { &Catacomb::MP::toint($_[0]); };
+
+sub binpolyfield {
+ croak("Usage: Catacomb::GF::binpolyfield(p)") unless @_ == 1;
+ return Catacomb::Field->binpoly($_[0]);
+}
+
+sub binnormfield {
+ croak("Usage: Catacomb::GF::binnormfield(p, beta)") unless @_ == 2;
+ return Catacomb::Field->binnormfield($_[0], $_[1]);
+}
+
+sub binpolygroup {
+ croak("Usage: Catacomb::GF::binpolygroup(p, g, q)") unless @_ == 3;
+ return Catacomb::Group->binary(@_);
+}
+
+sub mod { (&div($_[0], $_[1]))[1]; }
+
+sub pow {
+ croak("Usage: Catacomb::GF::pow(a, b)") unless @_ == 2;
+ my ($a, $b) = @_;
+ my $r = Catacomb::GF->new(1);
+ while ($b) {
+ $r *= $a if $b & 1;
+ $a = sqr($a);
+ $b >>= 1;
+ }
+ return $r;
+}
+
+sub _binop {
+ my ($func, $a, $b, $flag) = @_;
+ return new(undef, $flag ? &$func($b, $a) : &$func($a, $b));
+}
+
+sub modexp {
+ croak("Usage: Catacomb::GF::modexp(p, g, x)") unless @_ == 3;
+ my ($p, $g, $x) = @_;
+ my $r = Catacomb::GF::Reduce->new($p);
+ $g = $r->reduce($g);
+ return $r->exp($g, $x);
+}
+
+sub modinv {
+ croak("Usage: Catacomb::GF::modinv(p, g)") unless @_ == 3;
+ my ($g, undef, $i) = gcd($_[0], $_[1]);
+ croak("Arguments aren't coprime in Catacomb::GF::modinv") unless $g == 1;
+ return $i;
+}
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Abstract groups
+#
+# (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 groups ------------------------------------------------------
+
+package Catacomb::Group;
+use Carp;
+use Catacomb::Base;
+use Catacomb::Cache;
+
+$cache = Catacomb::Cache->new();
+
+sub intern {
+ croak("Usage: Catacomb::Group::intern(c)") unless @_ == 1;
+ my ($c) = @_;
+ return $cache->intern($c);
+}
+
+sub elt {
+ croak("Usage: Catacomb::Group::elt(g, [x])")
+ unless @_ >= 1 && @_ <= 2;
+ return Catacomb::Group::Elt->new(@_);
+}
+
+sub id {
+ croak("Usage: Catacomb::Group::id(g)") unless @_ == 1;
+ return Catacomb::Group::Elt->new($_[0]);
+}
+
+sub g {
+ croak("Usage: Catacomb::Group::g(g)") unless @_ == 1;
+ return Catacomb::Group::Elt->new($_[0], $_[0]->_g());
+}
+
+sub _cvt {
+ croak("Usage: Catacomb::Group::$_[1](g, x)") unless @_ == 4;
+ my ($op, $name, $g, $x) = @_;
+ $x = &$op(&g, $x);
+ return undef unless defined($x);
+ return elt($g, &$op(&g, $x));
+}
+sub fromint { _cvt(\&_fromint, "fromint", @_); }
+sub fromec { _cvt(\&_fromec, "fromec", @_); }
+
+sub _strcvt {
+ croak("Usage: Catacomb::Group::$_[1](g, sv)") unless @_ == 4;
+ my ($op, $name, $g, $sv) = @_;
+ my ($x, $rest) = &$op($g, $sv);
+ return undef unless defined($x);
+ $x = elt($g, $x);
+ return $x unless wantarray();
+ return ($x, $rest);
+}
+sub frombuf { _strcvt(\&_getbuf, "frombuf", @_); }
+sub fromraw { _strcvt(\&_getraw, "fromraw", @_); }
+sub fromstring { _strcvt(\&_fromstring, "fromstring", @_); }
+
+sub mexp {
+ croak("Usage: Catacomb::Group::mexp(g, x_0, n_0, x_1, n_1, ...)")
+ unless @_ >= 3 && @_ % 2 == 1;
+ my $g = pop(@_);
+ my $i;
+ my @v = ();
+ my $gr;
+ ($g, $gr) = $g->intern();
+ for ($i = 0; $i < @_; $i += 2) {
+ my $x = Catacomb::Group::Elt::_convert($g, $gr, $_[$i]);
+ my $n = $_[$i + 1];
+ push(@v, $x, $n);
+ }
+ return Catacomb::Group::Elt::_elt($g->mexp(@v), $g, $gr);
+}
+
+#----- Group elements -------------------------------------------------------
+
+package Catacomb::Group::Elt;
+use Carp;
+use Catacomb::Base;
+
+sub DESTROY {
+ my ($x) = @_;
+ $x->[1]->_destroyelement($x->[0]);
+ undef $x->[0];
+}
+
+sub _elt { bless [@_], Catacomb::Group::Elt; }
+
+sub new {
+ croak("Usage: Catacomb::Group::Elt::new(me, g, [x])")
+ unless @_ >= 2 && @_ <= 3;
+ my ($me, $g, $x);
+ if (@_ == 2) {
+ ($me, $g) = @_;
+ $x = $g->_i();
+ } else {
+ ($me, $g, $x) = @_;
+ if (UNIVERSAL::isa($x, Catacomb::Group::Elt)) {
+ croak("group mismatch") unless $x->[1] == $g;
+ } elsif (UNIVERSAL::isa($x, Catacomb::EC::Pt)) {
+ my $pt = $x->point();
+ $x = $g->_fromec($pt);
+ } elsif (UNIVERSAL::isa($x, Catacomb::EC::Point)) {
+ $x = $g->_fromec($x);
+ } elsif (UNIVERSAL::isa($x, Catacomb::Group::Element)) {
+ # cool
+ } else {
+ $x = $g->_fromint($x);
+ }
+ return undef unless defined($x);
+ }
+ my $gr;
+ ($g, $gr) = $g->intern();
+ return _elt($x, $g, $gr);
+}
+
+sub _convert {
+ my ($g, $gr, $x) = @_;
+ if (UNIVERSAL::isa($x, Catacomb::Group::Elt)) {
+ $x->[1] == $g or croak("group mismatch");
+ return $x;
+ }
+ $x == 0 and return _elt($g->_i(), $g, $gr);
+ croak("can't convert to group element");
+}
+
+sub _out {
+ croak("Usage: Catacomb::Group::Elt::$_[1](x)") unless @_ == 3;
+ my ($op, $name, $x) = @_;
+ return &$op($x->[1], $x->[0]);
+}
+sub toint { _out(\&Catacomb::Group::_toint, "toint", @_); }
+sub toec { _out(\&Catacomb::Group::_toec, "toec", @_); }
+sub tobuf { _out(\&Catacomb::Group::_putbuf, "tobuf", @_); }
+sub toraw { _out(\&Catacomb::Group::_putraw, "toraw", @_); }
+sub tostring { _out(\&Catacomb::Group::_tostring, "tostring", @_); }
+
+sub group {
+ croak("Usage: Catacomb::Group::Elt::group(x)") unless @_ == 1;
+ return $_[0][1];
+}
+
+sub identp { _out(\&Catacomb::Group::_identp, "identp", @_); }
+sub check { _out(\&Catacomb::Group::_checkelt, "check", @_); }
+
+sub _binop {
+ my ($op, $x, $y, $swap) = @_;
+ my (undef, $g, $gr) = @$x;
+ $y = _convert($g, $gr, $y);
+ my $z = $swap ?
+ &$op($c, $x->[0], $y->[0]) :
+ &$op($c, $y->[0], $x->[0]);
+ return _elt($z, $g, $gr);
+}
+
+sub _unop {
+ my ($op, $x) = @_;
+ my (undef, $g, $gr) = @$x;
+ my $z = &$op($c, $x->[0]);
+ return _elt($z, $g, $gr);
+}
+
+sub _eq {
+ my ($x, $y) = @_;
+ my (undef, $g, $gr) = @$x;
+ $y = _convert($g, $gr, $y);
+ return Catacomb::Group::_eq($x->[0], $y->[0]);
+}
+
+sub exp {
+ croak("Usage: Catacomb::Group::Elt::exp(x, n)") unless @_ == 2;
+ my ($x, $n) = @_;
+ my ($xx, $g, $gr) = @$x;
+ return _elt($g->_exp($xx, $n), $g, $gr);
+}
+
+sub inv {
+ croak("Usage: Catacomb::Group::Elt::inv(x)") unless @_ == 1;
+ _unop(\&Catacomb::Group::inv, @_);
+}
+
+use overload
+ '*' => sub { _binop(\&Catacomb::Group::_mul, @_); },
+ '/' => sub { _binop(\&Catacomb::Group::_div, @_); },
+ '**' => sub { &exp($_[0], $_[1]); },
+ '==' => sub { _eq(@_); },
+ '!=' => sub { !_eq(@_); },
+ 'eq' => sub { _eq(@_); },
+ 'ne' => sub { !_eq(@_); },
+ '""' => sub { tostring($_[0]); },
+ '0+' => sub { toint($_[0]); };
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Key management
+#
+# (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.
+
+#----- Key data -------------------------------------------------------------
+
+package Catacomb::Key::StructData;
+use Carp;
+use Catacomb::Base;
+
+sub TIEHASH { bless [$_[1], []], $_[0]; }
+sub FETCH { Catacomb::Key::Data::StructItem->new($_[0][0], $_[1]); }
+sub EXISTS { !!$_[0][0]->_get->structfind($_[1]); }
+sub DELETE { $_[0][0]->_get->structdel($_[1]); }
+sub CLEAR { $_[0][0]->_get()->setstruct(); }
+sub STORE {
+ my ($me, $k, $v) = @_;
+ $me->[0]->_get()->structcreate($k)->set($v);
+}
+sub FIRSTKEY {
+ my ($me) = @_;
+ my $kd = $me->[0]->_get();
+ my $i = $kd->structiter();
+ my @k = ();
+ while (my $k = $i->next()) {
+ push(@k, $k);
+ }
+ $me->[1] = \@k;
+ return shift(@k);
+}
+sub NEXTKEY { shift(@{$_[0][1]}); }
+
+package Catacomb::Key::DataRef;
+use Carp;
+use Catacomb::Base;
+use Catacomb::MP;
+use Catacomb::EC;
+sub _adopt {
+ my $kd = shift;
+ defined($kd) or return;
+ $kd = bless [$kd], Catacomb::Key::Data;
+ return wantarray ? ($kd, @_) : $kd;
+}
+sub new { my $me = shift(@_); bless [@_], $me; }
+sub _proxy { my ($op, $kd, @args) = @_; &$op($kd->_get(), @args); }
+
+sub setbinary { _proxy(\&Catacomb::Key::DataImpl::setbinary, @_); }
+sub setencrypted { _proxy(\&Catacomb::Key::DataImpl::setencrypted, @_); }
+sub setmp { _proxy(\&Catacomb::Key::DataImpl::setec, @_); }
+sub setstring { _proxy(\&Catacomb::Key::DataImpl::setstring, @_); }
+sub setec { _proxy(\&Catacomb::Key::DataImpl::setec, @_); }
+
+sub flags { _proxy(\&Catacomb::Key::DataImpl::flags, @_); }
+
+sub getbinary { _proxy(\&Catacomb::Key::DataImpl::getbinary, @_); }
+sub getencrypted { _proxy(\&Catacomb::Key::DataImpl::getencrypted, @_); }
+sub getmp { _proxy(\&Catacomb::Key::DataImpl::getmp, @_); }
+sub getstring { _proxy(\&Catacomb::Key::DataImpl::getstring, @_); }
+sub getec { _proxy(\&Catacomb::Key::DataImpl::getec, @_); }
+
+sub setstruct { _proxy(\&Catacomb::Key::DataImpl::setstruct, @_); }
+sub structfind { Catacomb::Key::Data::StructItem->new($_[0], $_[1]); }
+sub structcreate {
+ _proxy(\&Catacomb::Key::DataImpl::structcreate, @_);
+ Catacomb::Key::Data::StructItem->new($_[0], $_[1]);
+}
+sub structiter { _proxy(\&Catacomb::Key::DataImpl::structiter, @_); }
+sub structdel { _proxy(\&Catacomb::Key::DataImpl::structdel, @_); }
+sub structopen { my %h; tie %h, Catacomb::Key::StructData, $_[0]; \%h; }
+
+sub copy {
+ croak("Usage: Catacomb::Key::Data::Ref::copy(kd, kkd, [filter])")
+ unless @_ >= 2 && @_ <= 3;
+ my $kd = Catacomb::Key::Data->new();
+ $kd->_get()->set($_[0]->_get(), $_[1]);
+ return $kd;
+}
+sub lock { _adopt(_proxy(\&Catacomb::Key::DataImpl::lock, @_)); }
+sub unlock { _adopt(_proxy(\&Catacomb::Key::DataImpl::unlock, @_)); }
+sub plock { _adopt(_proxy(\&Catacomb::Key::DataImpl::plock, @_)); }
+sub punlock { _adopt(_proxy(\&Catacomb::Key::DataImpl::punlock, @_)); }
+sub read { _adopt(Catacomb::Key::DataImpl::read(@_)); }
+sub write { _proxy(\&Catacomb::Key::DataImpl::write, @_); }
+sub decode { _adopt(Catacomb::Key::DataImpl::decode(@_)); }
+sub encode { _proxy(\&Catacomb::Key::DataImpl::encode, @_); }
+
+package Catacomb::Key::Data;
+use Carp;
+@ISA = qw(Catacomb::Key::DataRef);
+sub _get { $_[0][0]; }
+## Perl will randomly zap my reference during cleanup. Just pretend
+## we didn't notice.
+sub DESTROY { $_[0][0]->free() if defined $_[0][0]; }
+sub new {
+ croak("Usage: Catacomb::Key::Data::new(me)") unless @_ == 1;
+ Catacomb::Key::DataRef::_adopt(Catacomb::Key::DataImpl->new());
+}
+
+package Catacomb::Key::Data::StructItem;
+@ISA = qw(Catacomb::Key::DataRef);
+sub _get { $_[0][0]->_get()->structfind($_[0][1]); }
+
+package Catacomb::Key::Data::KeyData;
+@ISA = qw(Catacomb::Key::DataRef);
+sub _get { $_[0][0]->_data(); }
+
+#----- Actual keys ----------------------------------------------------------
+
+package Catacomb::Key::Attrs;
+use Carp;
+
+sub TIEHASH { bless [$_[1], []], $_[0]; }
+sub FETCH { $_[0][0]->getattr($_[1]); }
+sub EXISTS { defined($_[0][0]->getattr($_[1])); }
+sub STORE { $_[0][0]->putattr($_[1], $_[2]); }
+sub DELETE { $_[0][0]->putattr($_[1]); }
+sub FIRSTKEY {
+ my ($me) = @_;
+ my $k = $me->[0];
+ my $i = $k->attriter();
+ my @a;
+ while (my $a = $i->next()) { push(@a, $a); }
+ $me->[1] = \@a;
+ return shift(@a);
+}
+sub NEXTKEY { shift(@{$_[0][1]}); }
+
+package Catacomb::Key;
+
+sub attrs {
+ croak("Usage: Catacomb::Key::attrs(k)") unless @_ == 1;
+ my %a;
+ tie %a, Catacomb::Key::Attrs, @_;
+ return \%a;
+}
+
+sub data {
+ croak("Usage: Catacomb::Key::data(k)") unless @_ == 1;
+ return Catacomb::Key::Data::KeyData->new($_[0]);
+}
+
+package Catacomb::Key::File;
+use Carp;
+use Catacomb::Base;
+
+sub qtag {
+ croak("Usage: Catacomb::Key::File::qtag(kf, tag)") unless @_ == 2;
+ my ($kf, $tag) = @_;
+ my @q = ();
+ if ($tag =~ /^([^.]*)\.(.*)$/) {
+ $tag = $1;
+ @q = split(/\./, $2);
+ }
+ my $k = $kf->bytag($tag) or return;
+ my $d = $k->data();
+ my $f = $k->fulltag();
+ foreach my $t (@q) {
+ $d = $d->structfind($t) or return;
+ $f .= "." . $t;
+ }
+ return $k, $d, $f;
+}
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Catacomb multiprecision integer interface
+#
+# (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.
+
+#----- Multiprecision arithmetic --------------------------------------------
+
+package Catacomb::MP;
+use Catacomb::Base;
+use Catacomb::Rand;
+use Catacomb::Field;
+use Carp;
+
+sub mp { new(Catacomb::MP, $_[0]); }
+sub mp_loadb { loadb(Catacomb::MP, $_[0]); }
+sub mp_loadl { loadl(Catacomb::MP, $_[0]); }
+sub mp_loadb2c { loadb2c(Catacomb::MP, $_[0]); }
+sub mp_loadl2c { loadl2c(Catacomb::MP, $_[0]); }
+sub mp_fromstring { fromstring(Catacomb::MP, $_[0]); }
+
+sub mod { (&div($_[0], $_[1]))[1]; }
+
+sub _binop {
+ my ($func, $a, $b, $flag) = @_;
+ return $flag ? &$func($b, $a) : &$func($a, $b);
+}
+
+sub _mul {
+ my ($a, $b, $flag) = @_;
+ if (UNIVERSAL::isa($b, Catacomb::EC::Pt)) {
+ return $b->mul($a);
+ }
+ mul($a, $b);
+}
+
+use overload
+ '+' => sub { _binop(\&add, @_); },
+ '-' => sub { _binop(\&sub, @_); },
+ '*' => \&_mul,
+ '/' => sub { _binop(\&div, @_); },
+ '%' => sub { _binop(\&mod, @_); },
+ '&' => sub { _binop(\&and2c, @_); },
+ '|' => sub { _binop(\&or2c, @_); },
+ '^' => sub { _binop(\&xor2c, @_); },
+ '**' => sub { _binop(\&exp, @_); },
+ '>>' => sub { &lsr2c(@_[0, 1]); },
+ '<<' => sub { &lsl2c(@_[0, 1]); },
+ '~' => sub { ¬2c($_[0]) },
+ '==' => sub { _binop(\&eq, @_); },
+ 'eq' => sub { _binop(\&eq, @_); },
+ '<=>' => sub { _binop(\&cmp, @_); },
+ 'cmp' => sub { _binop(\&cmp, @_); },
+ '""' => sub { &tostring($_[0]); },,
+ '0+' => sub { &toint($_[0]); },
+ 'sqrt' => sub { &sqrt($_[0]); },
+ 'neg' => sub { &neg($_[0]); };
+
+sub import {
+ my ($me, @imp) = @_;
+ for my $i (@imp) {
+ if ($i eq ":constant") {
+ overload::constant integer => sub { new(undef, $_[0]); };
+ } else {
+ croak("unknown import for Catacomb::MP: `$i'");
+ }
+ }
+}
+
+sub modexp {
+ croak("Usage: Catacomb::MP::modexp(p, g, x)") unless @_ == 3;
+ my ($p, $g, $x) = @_;
+ $g = $p - $g if $g < 0;
+ $g = $g % $p if $g > $p;
+ if ($p & 1) {
+ my $mm = $p->mont();
+ return $mm->exp($g, $x);
+ } else {
+ my $mb = $p->barrett();
+ return $mb->exp($g, $x);
+ }
+}
+
+sub primefield {
+ croak("Usage: Catacomb::MP::primefield(p)") unless @_ == 1;
+ return Catacomb::Field->prime($_[0]);
+}
+
+sub niceprimefield {
+ croak("Usage: Catacomb::MP::niceprimefield(p)") unless @_ == 1;
+ return Catacomb::Field->niceprime($_[0]);
+}
+
+sub primegroup {
+ croak("Usage: Catacomb::MP::primegroup(p, g, q)") unless @_ == 3;
+ return Catacomb::Group->prime(@_);
+}
+
+sub filter {
+ croak("Usage: Catacomb::MP::filter(p)") unless @_ == 1;
+ return Catacomb::MP::Prime::Filter->new($_[0]);
+}
+
+sub modinv {
+ croak("Usage: Catacomb::MP::modinv(p, x)") unless @_ == 2;
+ my ($g, undef, $i) = gcd($_[0], $_[1]);
+ croak("Arguments aren't coprime in Catacomb::MP::modinv") unless $g == 1;
+ return $i;
+}
+
+sub jac {
+ # Reverse arguments for object-oriented syntax.
+ croak("Usage: Catacomb::MP::jac(n, a)") unless @_ == 2;
+ jacobi($_[1], $_[0]);
+}
+
+sub mont {
+ croak("Usage: Catacomb::MP::mont(x)") unless @_ == 1;
+ return Catacomb::MP::Mont->new($_[0]);
+}
+
+sub barrett {
+ croak("Usage: Catacomb::MP::barrett(x)") unless @_ == 1;
+ return Catacomb::MP::Mont->new($_[0]);
+}
+
+sub mkreduce {
+ croak("Usage: Catacomb::MP::mkreduce(x)") unless @_ == 1;
+ return Catacomb::MP::Reduce->new($_[0]);
+}
+
+sub rabin {
+ croak("Usage: Catacomb::MP::rabin(x)") unless @_ == 1;
+ return Catacomb::MP::Prime::Rabin->new($_[0]);
+}
+
+sub newprime {
+ croak("Usage: Catacomb::MP::newprime(nbits, [rng]")
+ unless @_ >= 1 && @_ <= 2;
+ my ($nbits, $rng) = @_;
+ $rng ||= $Catacomb::random;
+ return Catacomb::MP::Prime->gen
+ ("p", $rng->mp($nbits, 1), 0,
+ Catacomb::MP::Prime::Filter->stepper(2),
+ Catacomb::MP::Prime::Rabin->ntests($nbits),
+ Catacomb::MP::Prime::Rabin->tester());
+}
+
+sub jumper {
+ croak("Usage: Catacomb::MP::jumper(p)") unless @_ == 1;
+ return Catacomb::MP::Prime::Filter->jumper($_[0]);
+}
+
+package Catacomb::MP::Mont;
+
+*out = \&reduce;
+
+package Catacomb::MP::Prime::Filter;
+
+package Catacomb::MP::Prime::Filter;
+
+sub filterstepper { &stepper(Catacomb::MP::Prime::Filter, @_); }
+sub filterjumper { &jumper(Catacomb::MP::Prime::Filter, @_); }
+
+package Catacomb::MP::Prime;
+
+sub primegen { &gen(Catacomb::MP::Prime, @_); }
+sub limleegen { &limlee(Catacomb::MP::Prime, @_); }
+
+package Catacomb::MP::Prime::Rabin;
+
+sub rabintester { &tester(Catacomb::MP::Prime::Rabin, @_); }
+
+{
+ my $cmpg = "Catacomb::MP::Prime::Gen";
+ foreach my $i (qw(FilterStepper JumpStepper RabinTester)) {
+ @{"${cmpg}::${i}::ISA"} = ("${cmpg}::MagicProc");
+ }
+ @{"${cmpg}::MagicProc::ISA"} = ("${cmpg}::Proc");
+}
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+# -*-perl-*-
+#
+# $Id$
+#
+# Random number generators
+#
+# (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.
+
+#----- Random number generators ---------------------------------------------
+
+package Catacomb;
+use Catacomb::Base;
+
+foreach my $i (qw(True Fib LC DSA RC4 SEAL MGF Counter OFB Magic)) {
+ @{"Catacomb::Rand::${i}::ISA"} = qw(Catacomb::Rand);
+}
+
+$Catacomb::random = Catacomb::Rand::True->_global();
+$Catacomb::random->noisesrc();
+$Catacomb::random->seed(160);
+
+#----- That's all, folks ----------------------------------------------------
+
+1;
--- /dev/null
+=head1 NAME
+
+Catacomb::MP - Multiprecision integer arithmetic
+
+=head1 SYNOPSIS
+
+ use Catacomb qw(:const :mp :random :pgen);
+
+ $x = Catacomb::MP->new($str, [$radix]);
+ $x = Catacomb::MP->new($i);
+ $x = Catacomb::MP->loadb($bytes);
+ $x = Catacomb::MP->loadl($bytes);
+ $x = Catacomb::MP->loadb2c($bytes);
+ $x = Catacomb::MP->loadl2c($bytes);
+ ($x, $rest) = Catacomb::MP->fromstring($str, [$radix]);
+ $x = mp($str, [$radix]);
+ $x = mp($i);
+ ($x, $rest) = mp_fromstring($str, [$radix]);
+ $a = $b + $c;
+ $a = $b - $c;
+ $a = $b * $c;
+ $a = $b / $c;
+ $a = $b % $c;
+ $a = $b ** $n;
+ $a = $b << $n;
+ $a = $b >> $n;
+ $a = $b & $c;
+ $a = $b | $c;
+ $a = $b ^ $c;
+ $a = ~$b;
+ $p = $b == $c;
+ $p = $b != $c;
+ $p = $b < $c;
+ $p = $b > $c;
+ $p = $b <= $c;
+ $p = $b >= $c;
+ $a = sqrt($b);
+ $a = -$b;
+ $a = $b->add($c);
+ $a = $b->sub($c);
+ $a = $b->mul($c);
+ ($q, $r) = $a->div($b);
+ $a = $b->sqr();
+ $a = $b->exp($c);
+ $a = $b->sqrt();
+ $a = $b->neg();
+ $a = $b->not();
+ $a = $b->not2c();
+ $a = $b->mod($c);
+ $p = $b->eq($c);
+ $cmp = $b->cmp($c);
+ $a = $b->and($c);
+ $a = $b->and2c($c);
+ $a = $b->or($c);
+ $a = $b->or2c($c);
+ $a = $b->xor($c);
+ $a = $b->xor2c($c);
+ $a = $b->nand($c);
+ $a = $b->nand2c($c);
+ $a = $b->nor($c);
+ $a = $b->nor2c($c);
+ $a = $b->not();
+ $a = $b->not2c();
+ $a = $b->lsl($n);
+ $a = $b->lsl2c($n);
+ $a = $b->lsr($n);
+ $a = $b->lsr2c($n);
+ $a = $b->setbit($n);
+ $a = $b->setbit2c($n);
+ $a = $b->clearbit($n);
+ $a = $b->clearbit2c($n);
+ $p = $b->testbit($n);
+ $p = $b->testbit2c($n);
+ $x = $y->copy(); # largely useless
+ $g = $a->gcd($b);
+ ($g, $u, $v) = $a->gcd($b);
+ ($s, $t) = $m->odd(); # m = 2^s t
+ $a = $p->modexp($x, $e);
+ $a = $p->modinv($b);
+ $r = $p->modsqrt($x);
+ $q = $n->jac($a);
+ $p = $x->primep([$rng]);
+ $nbits = $x->bits();
+ $nbytes = $x->octets();
+ $bytes = $x->storeb([$nbytes]);
+ $bytes = $x->storel([$nbytes]);
+ $bytes = $x->storeb2c([$nbytes]);
+ $bytes = $x->storel2c([$nbytes]);
+ $str = $x->tostring([$radix]);
+ $n = $x->toint();
+
+ $barrett = Catacomb::MP::Barrett->new($p);
+ $barrett = $p->barrett();
+ $p = $barrett->m();
+ $x = $barrett->reduce($y);
+ $a = $barrett->exp($x, $y);
+
+ $mont = Catacomb::MP::Mont->new($p);
+ $mont = $p->mont();
+ $r = $mont->r();
+ $r2 = $mont->r2();
+ $p = $mont->m();
+ $x = $mont->in($y);
+ $a = $mont->mul($x, $y);
+ $a = $mont->expr($x, $y);
+ $a = $mont->mexpr($x0, $e0, $x1, $e1, ...);
+ $x = $mont->reduce($y);
+ $x = $mont->out($y);
+ $a = $mont->exp($x, $y);
+ $a = $mont->mexp($x0, $e0, $x1, $e1, ...);
+
+ $reduce = Catacomb::MP::Reduce->new($p);
+ $reduce = $p->mkreduce();
+ $p = $reduce->m();
+ $x = $reduce->reduce($y);
+ $a = $barrett->exp($x, $y);
+
+ $crt = Catacomb::MP::CRT->new(@n);
+ $n = $crt->product();
+ @n = $crt->moduli();
+ $x = $crt->solve(@r);
+
+=head1 DESCRIPTION
+
+This is a full-featured multiprecision maths library. Integer objects
+belong to the class C<Catacomb::MP>. Most standard arithmetic operators
+are overloaded and do the Right Thing. See below for more details.
+
+Note that multiprecision integers are I<immutable>. No operation can
+change the value of an integer.
+
+=head2 Constructors
+
+=over
+
+=item B<Catacomb::MP-E<gt>new(>i<int>B<)>
+
+=item B<mp(>I<int>B<)>
+
+Return the multiprecision integer whose value is I<int>.
+
+=item B<Catacomb::MP-E<gt>new(>I<string>, [I<radix>]B<)>
+
+=item B<mp(>I<string>, [I<radix>]B<)>
+
+Returns the multiprecision integer whose value is represented by
+I<string>, in the given I<radix>. If I<radix> is 0, as it is by
+default, then I<string> may have a prefix giving its radix: it may be
+B<0> for octal, B<0x> for hex, or I<r>B<_> for radix I<r>. If the
+argument is invalid, B<undef> is returned.
+
+=item B<Catacomb::MP-E<gt>loadb(>I<bytes>B<)>
+
+=item B<Catacomb::MP-E<gt>loadl(>I<bytes>B<)>
+
+=item B<mp_loadb(>I<bytes>B<)>
+
+=item B<mp_loadl(>I<bytes>B<)>
+
+Returns the multiprecision integer whose value is represented in big- or
+little-endian base-256 form by I<bytes>. This will always be
+nonnegative.
+
+Returns the multiprecision integer whose value is represented in
+little-endian base-256 form by I<bytes>. This will always be
+nonnegative.
+
+=item B<Catacomb::MP-E<gt>loadb2c(>I<bytes>B<)>
+
+=item B<Catacomb::MP-E<gt>loadl2c(>I<bytes>B<)>
+
+=item B<mp_loadb2c(>I<bytes>B<)>
+
+=item B<mp_loadl2c(>I<bytes>B<)>
+
+Returns the multiprecision integer whose value is represented in
+two's complement big- or little-endian base-256 form by I<bytes>.
+
+=item B<Catacomb::MP-E<gt>fromstring(>I<string>, [I<radix>]B<)>
+
+=item B<mp_fromstring(>I<string>, [I<radix>]B<)>
+
+Returns the multiprecision integer whose value is represented by
+I<string>, and (in a list context) the remainder of I<string>. If
+I<radix> is 0 then I<string> may have a prefix, as for B<new()>. If
+I<string> is invalid, an empty list is returned.
+
+=back
+
+=head2 Methods
+
+The B<Catacomb::MP> package overloads the standard arithmetic
+operators. As long as one operand is a B<Catacomb::MP> object, the
+other may be any argument acceptable to B<new()>. As a special
+exception, either argument to B<*> may be a B<Catacomb::EC::Pt> object,
+to perform elliptic curve point multiplication.
+
+=over
+
+=item I<a>B<-E<gt>add(>I<b>B<)>
+
+=item I<a>B<-E<gt>sub(>I<b>B<)>
+
+=item I<a>B<-E<gt>mul(>I<b>B<)>
+
+=item I<a>B<-E<gt>div(>I<b>B<)>
+
+=item I<a>B<-E<gt>mod(>I<b>B<)>
+
+The basic algorithms. The argument I<b> may be any value acceptable to
+the B<new()> constructor.
+
+In an array context, the B<div()> method returns a two values: the
+quotient and remainder. The quotient returned is the I<floor> of the
+true quotient: the remainder therefore has the same sign as the divisor.
+This is usually the right result for number-theoretic purposes.
+
+=item I<a>B<-E<gt>sqr()>
+
+Returns the square of its argument. Usually faster than multiplying it
+by itself.
+
+=item I<a>B<-E<gt>exp(>I<b>B<)>
+
+Returns the result I<a>^I<b>. Theoretically, I<b> can be a
+multiprecision integer, but the result will be impossibly huge if this
+is the case. The exponent I<b> may not be negative.
+
+=item I<a>B<-E<gt>sqrt()>
+
+Returns the integer square-root of I<a> -- i.e., the largest integer
+less than or equal to the true square root.
+
+=item I<a>B<-E<gt>eq(>I<b>B<)>
+
+Returns true if I<a> and I<b> are equal; or false otherwise.
+
+=item I<a>B<-E<gt>cmp(>I<b>B<)>
+
+Returns -1, 0 or +1 according to whether I<a> is less than, equal to or
+greater than I<b>.
+
+=item I<a>B<-E<gt>and(>I<b>B<)>
+
+=item I<a>B<-E<gt>and2c(>I<b>B<)>
+
+=item I<a>B<-E<gt>or(>I<b>B<)>
+
+=item I<a>B<-E<gt>or2c(>I<b>B<)>
+
+=item I<a>B<-E<gt>xor(>I<b>B<)>
+
+=item I<a>B<-E<gt>xor2c(>I<b>B<)>
+
+=item I<a>B<-E<gt>nand(>I<b>B<)>
+
+=item I<a>B<-E<gt>nand2c(>I<b>B<)>
+
+=item I<a>B<-E<gt>nor(>I<b>B<)>
+
+=item I<a>B<-E<gt>nor2c(>I<b>B<)>
+
+=item I<a>B<-E<gt>not()>
+
+=item I<a>B<-E<gt>not2c()>
+
+Standard bitwise operators. The unadorned methods ignore the sign of
+their operands and use only the absolute values. The B<2c> versions use
+a two's complement representation, with the sign bit repeated
+infinitely.
+
+=item I<a>B<-E<gt>lsl(>I<n>B<)>
+
+=item I<a>B<-E<gt>lsl2c(>I<n>B<)>
+
+=item I<a>B<-E<gt>lsr(>I<n>B<)>
+
+=item I<a>B<-E<gt>lsr2c(>I<n>B<)>
+
+Standard shifting operators. The unadorned methods treat only absolute
+values, while the B<2c> versions use a two's complement representation,
+with the sign bit repeated infinitely.
+
+=item I<a>B<-E<gt>setbit(>I<n>B<)>
+
+=item I<a>B<-E<gt>setbit2c(>I<n>B<)>
+
+=item I<a>B<-E<gt>clearbit(>I<n>B<)>
+
+=item I<a>B<-E<gt>clearbit2c(>I<n>B<)>
+
+Returns a copy of the argument I<a> with bit I<n> set or clear. The
+unadorned methods treat only absolute values, while the B<2c> variants
+use a two's complement representation with the sign bit repeated
+infinitely.
+
+=item I<a>B<-E<gt>testbit(>I<n>B<)>
+
+=item I<a>B<-E<gt>testbit2c(>I<n>B<)>
+
+Returns true or false according to whether I<a> has bit I<n> set or
+clear. The unadorned methods treat only absolute values, while the
+B<2c> variant uses a two's complement representation with the sign bit
+repeated infinitely.
+
+=item I<a>B<-E<gt>copy()>
+
+Returns a copy of I<a>. Not useful: use assignment instead.
+
+=item I<a>B<-E<gt>gcd(>I<b>B<)>
+
+Returns the greatest common divisor of I<a> and I<b>. This will never
+be negative. In a list context, it also returns two further results,
+I<u> and I<v>: if the GCD is I<g> then we have I<a> I<u> + I<b> I<v> =
+I<g>. Furthermore, I<v> will have the same sign as I<b>.
+
+=item I<a>B<-E<gt>odd()>
+
+Returns a pair of numbers I<s> and I<t>, so that I<a> = I<t> << I<s>,
+with I<t> odd and I<s> as large as possible. I<t> will be
+multiprecision; I<s> will be a standard Perl integer.
+
+=item I<a>B<-E<gt>modexp(>I<b>B<,> I<n>B<)>
+
+Returns I<b>^I<n> mod I<a>.
+
+=item I<a>B<-E<gt>modinv(>I<b>B<)>
+
+Returns the inverse of I<b> modulo I<a>. If no inverse exists then
+report an error.
+
+=item I<a>B<-E<gt>modsqrt(>I<b>B<)>
+
+If I<a> is prime, and I<b> is a quadratic residue mod I<a>, then return
+a square root of I<b> mod I<a>. If I<a> is not prime, does something
+arbitrary; if I<b> is a nonresidue then report an error.
+
+=item I<a>B<-E<gt>jac(>I<b>B<)>
+
+Returns the Jacobi symbol (I<b>/I<a>). If I<a> is prime, then this is
+I<b>^((I<a> - 1)/2), i.e., 0 if I<b> is a multiple of I<a>, +1 if I<b>
+is a quadratic residue modulo I<a>, or -1 if I<b> is a quadratic
+nonresidue mod I<a>.
+
+=item I<a>B<-E<gt>primep(>[I<rng>]I<)>
+
+Returns true or false, depending on whether I<a> is (probably) prime.
+If I<rng> is specified, it must be a random number generator -- see
+Catacomb::Crypto(3).
+
+=item I<a>B<-E<gt>bits()>
+
+Returns the smallest number of bits required to represent the integer
+I<a>.
+
+=item I<a>B<-E<gt>octets()>
+
+Returns the smallest number of bytes required to represent the integer
+I<a>, ignoring sign.
+
+=item I<a>B<-E<gt>octets2c()>
+
+Returns the smallest number of bytes required to represent the integer
+I<a> as two's complement. This may be one greater than the result
+returned by B<octets()> in the case where the top bit of I<a> is the top
+bit of an octet.
+
+=item I<a>B<-E<gt>storeb(>[I<nbytes>]B<)>
+
+=item I<a>B<-E<gt>storel(>[I<nbytes>]B<)>
+
+Return (the absolute value of) I<a> as a raw base-256 string in big- or
+little-endian order. The returned string has length I<nbytes>, which
+defaults to the smallest nonzero length necessary to represent the
+argument. If I<nbytes> is too small, more significant bits are silently
+discarded. The sign is ignored.
+
+=item I<a>B<-E<gt>storeb2c(>[I<nbytes>]B<)>
+
+=item I<a>B<-E<gt>storel2c(>[I<nbytes>]B<)>
+
+Return I<a> as a raw two's complement base-256 string in big- or
+little-endian order. The returned string has length I<nbytes>, which
+defaults to the smallest nonzero length necessary to represent the
+argument. If I<nbytes> is too small, more significant bits are silently
+discarded. An alternative way to look at this operation is that the
+returned value is congruent to I<a> modulo 2^(8 I<nbytes>).
+
+=item I<a>B<-E<gt>tostring(>[I<radix>]B<)>
+
+Return I<a> expressed as a base-I<radix> string. The default I<radix>
+is 10. The result may be preceded by a minus sign if I<a> is negative.
+No leading zeroes or other radix prefix are prepended.
+
+=item I<a>B<-E<gt>toint()>
+
+Returns I<a> as a Perl integer. If I<a> cannot be represented as a Perl
+integer then an undefined result is returned.
+
+=back
+
+=head2 Barrett reduction
+
+Barrett reduction is an efficient way of doing modular reduction on
+numbers which aren't too much bigger than the modulus. Barrett
+reduction isn't as efficient as Montgomery reduction (see below) but is
+simpler and works on even moduli.
+
+The precomputed information used to perform Barrett reduction are stored
+in an object of type B<Catacomb::MP::Barrett>.
+
+=over
+
+=item B<Catacomb::MP::Barrett-E<gt>new(>I<m>B<)>
+
+=item I<m>B<-E<gt>barrett()>
+
+Create a new Barrett reduction context, set up for reducing modulo I<m>.
+
+=item I<b>B<-E<gt>m()>
+
+Returns the modulus stored in the reduction context I<b>.
+
+=item I<b>B<-E<gt>reduce(>I<x>B<)>
+
+Let I<m> be the modulus stored in the reduction context I<b>. Then, if
+I<x> is nonnegative and less then I<m>^2, returns I<x> mod I<m>.
+Otherwise the return value is undefined.
+
+=item I<b>B<-E<gt>exp(>I<x>B<,> I<n>B<)>
+
+Let I<m> be the modulus stored in the reduction context I<b>. Then
+return I<x>^I<n> mod I<m>. If I<n> is negative then I<x> must have an
+inverse modulo I<m>; otherwise you'll get a big mess.
+
+=back
+
+=head2 Montgomery reduction
+
+Montgomery reduction is a clever and efficient way of doing modular
+reduction on numbers which aren't too much bigger than the modulus. It
+only works if the modulus is positive and odd, and it's a little
+complicated.
+
+Let I<m> be the modulus in question. There is a value I<R> which is
+computed in some way from I<m>. The Montgomery reduction operation,
+given a number I<x>, actually returns I<x> I<R>^(-1) mod I<m>, which
+doesn't sound useful. However, if you multiply all your numbers by a
+factor of I<R> then the cleverness becomes clear: if you reduce I<x>
+I<y> I<R>^2, you get I<x> I<y> I<R> mod I<m>. Indeed, there's an
+efficient multiply-and-reduce operation which takes two operands, each
+with a factor of I<R> and returns a result with the factor of I<R>. One
+more reduction step drops off the final factor of I<R> to give you the
+real answer. Getting numbers into the required form involves
+multiplying by I<R>^2 mod I<m> and reducing: conveniently, I<R>^2 mod
+I<m> is precomputed. Addition and subtraction leave the factor of I<R>
+where it was, so you can just test-and-subtract to reduce. One final
+tip, if you're just multiplying two numbers, multiply them together
+first, and then multiply the result by I<R>^2 to fix the answer.
+
+If that all sounded too difficult, then you can use the B<in()> method to
+convert to internal form, B<mul()> to multiply numbers in internal form,
+B<expr()> and B<mexpr()> to do modular exponentiation, and B<out()> to
+convert the result to external form.
+
+The precomputed information used to perform Montgomery reduction are
+stored in an object of type B<Catacomb::MP::Mont>.
+
+=over
+
+=item B<Catacomb::MP::Mont-E<gt>new(>I<m>B<)>
+
+=item I<m>B<-E<gt>mont()>
+
+Constructs a Montgomery reduction context for reduction modulo I<m>.
+Returns B<undef> unless I<m> is an odd positive integer.
+
+=item I<mm>B<-E<gt>r()>
+
+Returns the Montgomery reduction factor I<R>.
+
+=item I<mm>B<-E<gt>r2()>
+
+Returns the Montgomerization factor I<R>^2.
+
+=item I<mm>B<-E<gt>m()>
+
+Returns the modulus I<m>.
+
+=item I<mm>B<-E<gt>in(>I<x>B<)>
+
+Returns the Montgomerized form of I<x>, i.e., I<x> I<R> mod I<m>. I<x>
+can be any integer.
+
+=item I<mm>B<-E<gt>mul(>I<x>B<,> I<y>B<)>
+
+Montgomery multiplication. If I<x> and I<y> are Montgomerized, then
+returns their Montgomerized product; i.e., I<x> I<y> I<R>^(-1) mod I<m>.
+
+=item I<mm>B<-E<gt>expr(>I<x>B<,> I<n>B<)>
+
+Montgomery exponentiation. If I<x> is Montgomerized, then returns the
+Montgomerized value of I<x>^I<n> mod I<m>; i.e., if I<x> = I<x'> I<R>,
+it returns I<x'>^I<n> I<R> mod I<m>. Here, if I<n> is negative, then
+I<x> must have an inverse modulo I<m>; otherwise there'll be a big mess.
+
+=item I<mm>B<-E<gt>mexpr(>I<x0>B<,> I<n0>B<,> I<x1>B<,> I<n1>B<,> ...B<)>
+
+Simultaneous Montgomery exponentiation. If the I<xi> are Montgomerized,
+then returns the Montgomerized value of I<x0>^I<n0> I<x1>^I<n1> ... mod
+I<m>; i.e., if I<xi> = I<xi'> I<R>, it returns I<x0'>^I<n0> I<x1'>^I<n1>
+... I<R> mod I<m>. Here, if some I<ni> is negative, then the
+corresponding I<xi> must have an inverse modulo I<m>; otherwise there'll
+be a big mess.
+
+=item I<mm>B<-E<gt>reduce(>I<x>B<)>
+
+=item I<mm>B<-E<gt>out(>I<x>B<)>
+
+Returns the unMontgomerized form of I<x>; i.e., I<x> I<R>^(-1) mod I<m>.
+
+=item I<mm>B<-E<gt>expr(>I<x>B<,> I<n>B<)>
+
+Modular exponentiation. Returns I<x>^I<n> mod I<m>. Here, if I<n> is
+negative, then I<x> must have an inverse modulo I<m>; otherwise there'll
+be a big mess.
+
+=item I<mm>B<-E<gt>mexpr(>I<x0>B<,> I<n0>B<,> I<x1>B<,> I<n1>B<,> ...B<)>
+
+Simultaneous modular exponentiation. Returns I<x0>^I<n0> I<x1>^I<n1>
+... mod I<m>. Here, if some I<ni> is negative, then the corresponding
+I<xi> must have an inverse modulo I<m>; otherwise there'll be a big
+mess.
+
+=back
+
+=head2 Nice prime reduction
+
+For some numbers, we can do modular reduction quite rapidly.
+Specifically, these are numbers of the form
+
+=over
+
+2^I<n0> - 2^I<n1> +/- 2^I<n2> +/- ... +/- 2^I<nk>
+
+=back
+
+where I<n0> > I<n1> > ... I<nk>, for small values of I<k>. We call such
+numbers `nice' (that's specific to Catacomb, not a term in general use).
+Usually, numbers of interest to us will be prime; hence, we shall speak
+of `nice primes'.
+
+Information for efficient reduction modulo a nice number is stored in an
+object of type B<Catacomb::MP::Reduce>.
+
+=over
+
+=item B<Catacomb::MP::Reduce-E<gt>new(>I<m>B<)>
+
+=item I<m>B<-E<gt>mkreduce()>
+
+Create a new nice-modulus reduction context, set up for reducing modulo
+I<m>.
+
+=item I<r>B<-E<gt>m()>
+
+Returns the modulus stored in the reduction context I<r>.
+
+=item I<r>B<-E<gt>reduce(>I<x>B<)>
+
+Let I<m> be the modulus stored in the reduction context I<r>. Then, if
+I<x>, returns I<x> mod I<m>. Otherwise the return value is undefined.
+
+=item I<r>B<-E<gt>exp(>I<x>B<,> I<n>B<)>
+
+Let I<m> be the modulus stored in the reduction context I<r>. Then
+return I<x>^I<n> mod I<m>. If I<n> is negative then I<x> must have an
+inverse modulo I<m>; otherwise you'll get a big mess.
+
+=back
+
+=head2 Chinese Remainder Theorem solution
+
+Catacomb can solve simultaneous congruence problems, i.e., of the form
+I<x> = I<ri> (mod I<ni>) using the Chinese Remainder Theorem (CRT). It
+is required that the I<ni> be positive and pairwise relatively prime;
+otherwise you'll get an unpleasant mess.
+
+=over
+
+=item B<Catacomb::MP::CRT-E<gt>new(>I<n0>B<,> I<n1>B<,> ...B<)>
+
+Construct a new CRT solving context, for solving congruences mod the
+I<ni>, and return it.
+
+=item I<crt>B<-E<gt>product()>
+
+Returns the product of the moduli I<ni>. In a scalar context, return
+the number of moduli.
+
+=item I<crt>B<-E<gt>moduli()>
+
+Returns a list of the I<ni>, as passed to B<new()>.
+
+=item I<crt>B<-E<gt>solve(>I<r0>B<,> I<r1>B<,>, ...B<)>
+
+Returns the unique answer I<x> (modulo the product of the I<ni>) to the
+congruences I<x> = I<ri> (mod I<ni>). You will get an unhelpful answer
+if any I<ri> >= I<ni>, and an error if you pass the wrong number of
+I<ri> arguments.
+
+=back
+
+=head1 SEE ALSO
+
+Catacomb(3).
+
+=head1 AUTHOR
+
+Mark Wooding, <mdw@nsict.org>
+
--- /dev/null
+=head1 NAME
+
+Catacomb::MP::Prime - prime number generation
+
+=head1 SYNOPSIS
+
+ use Catacomb qw(:const :mp :random :pgen);
+
+ $p = newprime($nbits, [$rng]);
+
+ $filt = Catacomb::MP::Prime::Filter->new($x);
+ $filt = $x->filter();
+ $rc = $filt->status();
+ $x = $filt->m();
+ $rc = $filt->step($n);
+ $rc = $filt->jump($jfilt);
+ $newfilt = $filt->muladd($mul, $add); # integers
+
+ $stepper = Catacomb::MP::Prime::Filter->stepper($step); # integer
+ $stepper = filterstepper($step);
+ $jumper = Catacomb::MP::Prime::Filter->stepper($jump); # MP
+ $jumper = filterjumper($jump);
+
+ $rabin = Catacomb::MP::Prime::Rabin->new($m);
+ $rabin = $p->rabin();
+ $m = $rabin->m();
+ $rc = $rabin->test($wit);
+ $n = $rabin->iters();
+ $n = Catacomb::MP::Prime::Rabin->ntests($bits);
+ $tester = Catacomb::MP::Prime::Rabin->tester();
+ $tester = $rabintester;
+
+ $events = Catacomb::MP::Prime::Gen::Proc->ev();
+ $events = Catacomb::MP::Prime::Gen::Proc->evspin();
+ $events = Catacomb::MP::Prime::Gen::Proc->subev();
+
+ $p = Catacomb::MP::Prime->gen
+ ($name, $x, $nsteps, $stepper, $ntests, $tester, [$events]);
+ $p = primegen
+ ($name, $x, $nsteps, $stepper, $ntests, $tester, [$events]);
+ if (($x, $j) = Catacomb::MP::Prime->strongprime_setup
+ ($name, $nbits, [$rng], [$nsteps], [$subevents])) {
+ $p = Catacomb::MP::Prime->gen
+ ($name, $x, $nsteps, $j, $ntests, $tester, [$events]);
+ }
+ ($p, @f) = Catacomb::MP::Prime->limlee
+ ($name, $qbits, $pbits, [$rng], [$on], [$oev], [$iev]);
+ ($p, @f) = limleegen
+ ($name, $qbits, $pbits, [$rng], [$on], [$oev], [$iev]);
+
+ package MyPrimeGenObject;
+ sub new { ... };
+ sub BEGIN { ... };
+ sub TRY { ... };
+ sub FAIL { ... };
+ sub PASS { ... };
+ sub DONE { ... };
+ sub ABORT { ... };
+ $name = $ev->name();
+ $x = $ev->m([$xx]);
+ $rng = $ev->rand();
+
+=head1 DESCRIPTION
+
+The B<Catacomb::MP::Prime> and related packages provide a framework for
+generating prime numbers of various special forms. Read Catacomb::MP(3)
+for more information about Catacomb's multiprecision integer support.
+
+=head2 Simple functions
+
+=over
+
+=item B<newprime(>I<nbits>B<,> [I<rng>]B<)>
+
+Returns a random prime between 2^I<nbits> and 2^(I<nbits>+1) (unless
+you're very unlucky). Here, I<rng> must be a random number generator
+object: see Catacomb::Crypto(3).
+
+=back
+
+=head2 Result codes
+
+The following result codes are used by various of the prime-number
+generation functions. They may be imported using the B<:consts> tag.
+
+=over
+
+=item B<PGEN_BEGIN>
+
+About to test a new candidate prime discovered by filtering. This
+shouldn't be returned by functions, but it is used as part of the
+event-handling system.
+
+=item B<PGEN_TRY>
+
+A new candidate has been found by a filter, but has not yet passed a
+primality test.
+
+=item B<PGEN_FAIL>
+
+The number is definitely composite.
+
+=item B<PGEN_PASS>
+
+The number has passed at least one primality test, and is therefore
+likely to be prime.
+
+=item B<PGEN_DONE>
+
+The number is definitely prime.
+
+=item B<PGEN_ABORT>
+
+The search for a prime number has been aborted.
+
+=back
+
+=head2 Filtering for small primes
+
+The class B<Catacomb::MP::Prime::Filter> implements a relatively
+efficient technique for finding numbers with no small factors.
+
+=over
+
+=item I<m>B<-E<gt>smallfactor()>
+
+Returns B<PGEN_DONE> if I<m> is definitely prime (and therefore fairly
+small), B<PGEN_FAIL> if it has some small factor, or B<PGEN_TRY> if it
+has no small factors but might be composite anyway.
+
+=item B<Catacomb::MP::Prime::Filter-E<gt>new(>I<m>B<)>
+
+=item I<m>B<-E<gt>filter()>
+
+Returns a new small-primes filter, initially looking at the number
+I<m>.
+
+=item I<filt>B<-E<gt>m()>
+
+Returns the current number I<m> in the filter.
+
+=item I<filt>B<-E<gt>status()>
+
+Returns the state (a B<PGEN> code) for the current number I<m> in the
+filter. This will usually be B<PGEN_FAIL> if I<m> has a small factor,
+or B<PGEN_TRY> if not; though B<PGEN_PASS> is also possible if I<m> is
+small enough.
+
+=item I<filt>B<-E<gt>step(>I<n>B<)>
+
+Advances the number in the filter by a small step I<n>, returning
+the new status.
+
+=item I<filt>B<-E<gt>jump(>I<jfilt>B<)>
+
+Advances the number in the filter by a large jump, as represented by
+another filter I<jfilt>. This is useful for finding a prime which has
+the form I<n> I<q> + I<k> for some other prime I<q> -- store 2 I<q> in
+a filter and use it as a jump to search for another prime.
+
+=item I<filt>B<-E<gt>muladd(>I<mul>B<,> I<add>B<)>
+
+Returns a new filter whose number is I<m> I<mul> + I<add>.
+
+=back
+
+=head2 Miller-Rabin primality tests
+
+Catacomb's main primality test is the Miller-Rabin test. It is a
+probabilistic test, with a 1/4 probability that any particular test will
+fail to recognize a given number as being composite. However, it is
+important to observe that this is not the same as the probability that a
+random number is composite given that it passed a test -- this latter is
+much smaller.
+
+=over
+
+=item B<Catacomb::MP::Prime::Rabin-E<gt>new(>I<m>B<)>
+
+=item I<m>B<-E<gt>rabin()>
+
+Constructs a new Rabin-Miller testing context for the purpose of testing
+the candidate I<m>. Returns B<undef> if I<m> is negative or even.
+
+=item I<rabin>B<-E<gt>m()>
+
+Returns the integer under test in the given context.
+
+=item I<rabin>B<-E<gt>test(>I<wit>B<)>
+
+Tests I<m> with witness I<wit>. Returns B<PGEN_FAIL> or B<PGEN_PASS>.
+The witness should usually be chosen randomly.
+
+=item I<rabin>B<-E<gt>iters()>
+
+Returns the recommended number of tests for the candidate under test,
+assuming that we came across the candidate at random.
+
+=item B<Catacomb::MP::Prime::Rabin-E<gt>ntests(>I<bits>B<)>
+
+Returns the recommended number of tests for a candidate which is
+I<nbits> bits long, assuming that we came across the candidate at
+random.
+
+=back
+
+=head2 Prime generation concepts
+
+The prime generator is based on the concepts of I<steppers>, I<filters>
+and I<event handlers>.
+
+=over
+
+=item *
+
+Steppers are responsible for producing candidate primes, and (usually)
+testing them for small factors (e.g., using B<smallfactor()>). A
+stepper is expected to be relatively fast, and leave the heavy lifting
+to testers.
+
+=item *
+
+Testers are responsible for applying primality tests to candidates.
+
+=item *
+
+Event handlers report interesting events during prime generation, to
+maintain a progress display or similar.
+
+=back
+
+These various kinds of objects all have essentially the same interface,
+which is built from I<events>. An event contains all the useful
+information about the current progress of a prime generation task.
+Events are objects of type B<Catacomb::MP::Prime::Gen::Event>, though
+fortunately one rarely needs to type this. Event objects can't be
+created by Perl code.
+
+=over
+
+=item I<ev>B<-E<gt>name()>
+
+Returns the name of the prime being generated.
+
+=item I<ev>B<-E<gt>m(>[I<x>]B<)>
+
+Returns the current candidate prime. If I<x> is supplied then it
+sets a new candidate prime. This is used by the stepper interface.
+
+=item I<ev>B<-E<gt>steps()>
+
+Returns the number of steps remaining before the generation task fails.
+
+=item I<ev>B<-E<gt>tests()>
+
+Returns the name of tests remaining before the generation task succeeds.
+
+=item I<ev>B<-E<gt>rand()>
+
+Returns a pseudorandom number generator which is likely to be fast but
+not cryptographically strong.
+
+=back
+
+=head2 Built-in steppers and testers
+
+=over
+
+=item B<Catacomb::MP::Prime::Filter-E<gt>stepper(>I<step>B<)>
+
+=item B<filterstepper(>I<step>B<)>
+
+Returns a stepper object which steps on by I<step> (a small Perl
+integer) until it finds a number with no small prime factors.
+
+=item B<Catacomb::MP::Prime::Filter-E<gt>jumper(>I<jump>B<)>
+
+=item I<jump>B<-E<gt>jumper()>
+
+Returns a jumper object which jumps on by I<jump> (a large
+multiprecision integer) until it finds a number with no small prime
+factors.
+
+=item B<Catacomb::MP::Prime::Rabin-E<gt>tester()>
+
+Returns a tester object which applies an iteration of the Miller-Rabin
+probabilistic primality test. In fact, there only needs to be one of
+these, so it's called B<$rabintester>.
+
+=item B<Catacomb::MP::Prime::Gen::Proc-E<gt>ev()>
+
+A standard event handler which prints the name of the prime being
+generated and a string of C<.> and C<+> signs for failures and
+successes, such as is relatively commonplace. In fact, there only needs
+to be one of these, so it's called B<$pg_events>.
+
+=item B<Catacomb::MP::Prime::Gen::Proc-E<gt>evspin()>
+
+An event handler which shows a spinning baton while it works. This is
+mainly used as the subsidiary event handler when generating Lim-Lee
+primes. There only needs to be one of these, so it's called
+B<$pg_evspin>.
+
+=item B<Catacomb::MP::Prime::Gen::Proc-E<gt>subev()>
+
+An event handler which works like B<ev()> above, but puts square
+brackets around its output. Also suitable for use in Lim-Lee
+generation. There only needs to be one of these, so it's called
+B<$pg_subev>.
+
+=back
+
+=head2 Prime generation
+
+Prime generation is driven by the procedure
+B<Catacomb::MP::Prime-E<gt>gen()>, which is also named B<primegen()> for
+convenience.
+
+=over
+
+=item B<Catacomb::MP::Prime-E<gt>gen(>I<name>B<,> I<m>B<,> I<nsteps>B<,> I<stepper>B<,> I<ntests>B<,> I<tester>B<,> [I<events>]B<)>
+
+=item B<primegen(>I<name>B<,> I<m>B<,> I<nsteps>B<,> I<stepper>B<,> I<ntests>B<,> I<tester>B<,> [I<events>]B<)>
+
+Generates a prime number. It will start with the integer I<m>, and run
+the I<stepper> for at most I<nsteps> times (infinitely if I<nsteps> is
+zero), returning B<undef> if it fails. Each time the stepper reports a
+plausible candidate, it runs the tester up to I<ntests> times; it
+returns the candidate if all these tests succeeded. It will call the
+event handler after each step and test.
+
+=back
+
+=head2 Writing your own steppers, testers and event handlers
+
+As mentioned, steppers, testers and event handlers have similar
+interfaces. Each is represented by an object whose class is a
+descendent (via B<@ISA>) of B<Catacomb::MP::Prime::Gen::Proc>. The
+prime generator will call methods on your object as required.
+
+Event handlers are the easiest, so we deal with them first. All methods
+are called with one argument which is the event object. The methods
+called are as follows.
+
+=over
+
+=item B<PG_BEGIN>
+
+Prime generation has begun.
+
+=item B<PG_TRY>
+
+About to start testing a new number.
+
+=item B<PG_PASS>
+
+Number passed a primality test.
+
+=item B<PG_FAIL>
+
+Number failed a primality test.
+
+=item B<PG_DONE>
+
+Prime number found successfully.
+
+=item B<PG_ABORT>
+
+No prime number found; we gave up.
+
+=back
+
+Any of these methods may return B<PGEN_ABORT> (-1) to abandon prime
+searching. This is intended to be used, for example, by a progress
+dialogue box if its cancel button is pressed. Any other value is
+ignored.
+
+Here's a simple example of an event handler.
+
+ package Strange::Events;
+ @ISA = qw(Catacomb::MP::Prime::Gen::Proc);
+
+ sub new { bless {}, $_[0]; }
+
+ sub PG_BEGIN {
+ my ($me, $ev) = @_;
+ local $| = 1;
+ print $ev->name(), " [";
+ }
+
+ sub PG_PASS { local $| = 1; print "*"; }
+ sub PG_FAIL { local $| = 1; print "."; }
+ sub PG_ABORT { local $| = 1; print "] :-(\n"; }
+ sub PG_DONE { local $| = 1; print "]\n"; }
+
+Steppers use fewer methods, but are a bit more involved.
+
+=over
+
+=item B<PG_BEGIN>
+
+Initialize the stepper. Read the starting point from the event, or
+store a new starting point, as appropriate. Return B<PGEN_DONE> if the
+starting point is satisfactory, B<PGEN_ABORT> for failure, or B<PGEN_TRY>
+to run the tester.
+
+=item B<PG_TRY>
+
+Advance the stepper. Write the new number to the event. Return as for
+B<PG_BEGIN>.
+
+=item B<PG_DONE>
+
+All is over. Tidy up.
+
+=back
+
+Testers are similar.
+
+=over
+
+=item B<PG_BEGIN>
+
+Initialize the tester. Read the starting point from the event. Return
+B<PGEN_DONE> if the starting point is satisfactory, B<PGEN_PASS> if
+you've actually run a successful test, B<PGEN_FAIL> to reject the
+candidate, or B<PGEN_TRY> to proceed to testing.
+
+=item B<PG_TRY>
+
+Run a test. Return B<PGEN_DONE> if the number is satisfactory,
+B<PGEN_PASS> if it passed a test, or B<PGEN_FAIL> if it failed.
+
+=item B<PG_DONE>
+
+Testing is done. Tidy up.
+
+=back
+
+Finally, any method can return B<PGEN_ABORT> to stop prime generation in
+its tracks almost immediately. (The B<PG_DONE> methods are still called
+for the stepper, and for the tester if it's active.)
+
+It's probably best to do tidying in B<PG_DONE> rather than leaving it
+until B<DESTROY>, since testers and steppers and things may get left
+around for a while, espectially if they're simple.
+
+Since steppers and testers often work together, here's an example of a
+pair for generating I<Sophie Germain primes>. A prime number I<q> is
+Sophie-Germain prime if 2 I<q> + 1 is also prime. We work by
+maintaining separate filters and testing contexts for I<q> and 2 I<q> +
+1, and checking both in parallel. Generating Sophie Germain primes is a
+long job.
+
+ package SophieGermain::Stepper;
+ use Catacomb qw(:const :mp :pgen);
+ @ISA = qw(Catacomb::MP::Prime::Gen::Proc);
+
+ sub new { bless [undef, undef], $_[0]; }
+
+ sub _step {
+ my ($me, $ev) = @_;
+ while ($me->[0]->status() == PGEN_FAIL ||
+ $me->[1]->status() == PGEN_FAIL) {
+ $me->[0]->step(2);
+ $me->[1]->step(4);
+ }
+ $ev->m($me->[0]->m());
+ return PGEN_TRY;
+ }
+
+ sub PG_BEGIN {
+ my ($me, $ev) = @_;
+ my $x = $ev->m();
+ $me->[0] = $x->filter();
+ $me->[1] = (2*$x + 1)->filter();
+ _step($me, $ev);
+ }
+
+ sub PG_TRY {
+ my ($me, $ev) = @_;
+ $me->[0]->step(2);
+ $me->[1]->step(4);
+ _step($me, $ev);
+ }
+
+ sub PG_DONE {
+ my ($me, $ev) = @_;
+ $me->[0] = $me->[1] = undef;
+ }
+
+ package SophieGermain::Tester;
+ use Catacomb qw(:const :mp :pgen);
+ @ISA = qw(Catacomb::MP::Prime::Gen::Proc);
+
+ sub new { bless [undef, undef], $_[0]; }
+
+ sub PG_BEGIN {
+ my ($me, $ev) = @_;
+ my $x = $ev->m();
+ $me->[0] = $x->rabin();
+ $me->[1] = (2*$x + 1)->rabin();
+ return PGEN_TRY;
+ }
+
+ sub _test {
+ my ($r, $rabin) = @_;
+ my $w = $r->mprange($rabin->m());
+ return $rabin->test($w) == PGEN_PASS;
+ }
+
+ sub PG_TRY {
+ my ($me, $ev) = @_;
+ my $r = $ev->rand();
+ my $w = $r->mprange($me->[0]->m());
+ return _test($r, $me->[0]) && _test($r, $me->[1]) ?
+ PGEN_PASS : PGEN_FAIL;
+ }
+
+ sub PG_DONE {
+ my ($me, $ev) = @_;
+ $me->[0] = $me->[1] = undef;
+ }
+
use ExtUtils::MakeMaker;
use Config;
+sub pmfix {
+ my $h = {};
+ foreach my $i (@_) {
+ my $f = $i;
+ $f =~ s!::!/!;
+ $f .= ".pm";
+ $h->{$f} = "\$(INST_LIBDIR)/$f";
+ }
+ return $h;
+}
+
WriteMakefile(NAME => "Catacomb",
DISTNAME => "catacomb-perl",
AUTHOR => "Mark Wooding (mdw\@nsict.org)",
@{[qw(algs mpstuff catacomb algstuff
keystuff pgproc utils)]}),
CONFIGURE => \&configure,
+ PM => pmfix(Catacomb, Catacomb::Base, Catacomb::Cache,
+ Catacomb::MP, Catacomb::Field, Catacomb::EC,
+ Catacomb::Group, Catacomb::GF, Catacomb::Rand,
+ Catacomb::Crypto, Catacomb::Key),
+ PERL_MALLOC_OK => 1,
PL_FILES => { 'algs.PL' => 'algs.c' },
depend => { '$(MAKEFILE)' => '$(VERSION_FROM)',
'catacomb.c' =>
join(" ", grep { s/$/.xs/ }
@{[qw(catacomb algorithms mp field ec
- gf misc pgen key)]})
+ gf misc pgen key group pubkey)]})
},
VERSION_FROM => "Catacomb.pm");
# along with Catacomb/Perl; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-MODULE = Catacomb PACKAGE = Catacomb::CipherClass
-
-PROTOTYPES: DISABLE
+MODULE = Catacomb PACKAGE = Catacomb::PRPClass
-gccipher *
+PRPClass *
find(me, name)
SV *me
char *name
- CODE:
- RETVAL = (gccipher *)gcipher_byname(name);
+ PREINIT:
+ int i;
+ CODE:
+ RETVAL = 0;
+ for (i = 0; prptab[i]; i++) {
+ if (strcmp(name, prptab[i]->name) == 0) {
+ RETVAL = prptab[i];
+ break;
+ }
+ }
OUTPUT:
RETVAL
list(me)
SV *me
PREINIT:
- const gccipher *const *cc;
- SV *sv;
+ int i;
PPCODE:
- for (cc = gciphertab; *cc; cc++)
- XPUSHs(RET((gccipher *)*cc, "Catacomb::CipherClass"));
+ for (i = 0; prptab[i]; i++)
+ XPUSHs(RET(prptab[i], "Catacomb::PRPClass"));
+
+keysize *
+keysz(p)
+ PRPClass *p
+ CODE:
+ RETVAL = p->ksz;
+ OUTPUT:
+ RETVAL
+
+char *
+name(p)
+ PRPClass *p
+ CODE:
+ RETVAL = p->name;
+ OUTPUT:
+ RETVAL
+
+UV
+blksz(p)
+ PRPClass *p
+ CODE:
+ RETVAL = p->blksz;
+ OUTPUT:
+ RETVAL
+
+PRP *
+init(p, k)
+ PRPClass *p
+ SV *k
+ PREINIT:
+ char *pp;
+ STRLEN len;
+ CODE:
+ pp = SvPV(k, len);
+ if (keysz(len, p->ksz) != len)
+ croak("key size mismatch");
+ RETVAL = sub_alloc(sizeof(PRP) + p->ctxsz);
+ RETVAL->c = p;
+ p->init(RETVAL + 1, pp, len);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::PRP
+
+SV *
+DESTROY(p)
+ PRP *p
+ CODE:
+ sub_free(p, sizeof(PRP) + p->c->ctxsz);
+ XSRETURN_YES;
+
+SV *
+eblk(p, x)
+ PRP *p
+ SV *x
+ PREINIT:
+ char *pp;
+ STRLEN len;
+ CODE:
+ pp = SvPV(x, len);
+ if (len != p->c->blksz)
+ croak("block size mismatch");
+ RETVAL = NEWSV(0, p->c->blksz);
+ p->c->eblk(p + 1, pp, SvPVX(RETVAL));
+ SvPOK_on(RETVAL);
+ SvCUR_set(RETVAL, p->c->blksz);
+ OUTPUT:
+ RETVAL
+
+SV *
+dblk(p, x)
+ PRP *p
+ SV *x
+ PREINIT:
+ char *pp;
+ STRLEN len;
+ CODE:
+ pp = SvPV(x, len);
+ if (len != p->c->blksz)
+ croak("block size mismatch");
+ RETVAL = NEWSV(0, p->c->blksz);
+ p->c->dblk(p + 1, pp, SvPVX(RETVAL));
+ SvPOK_on(RETVAL);
+ SvCUR_set(RETVAL, p->c->blksz);
+ OUTPUT:
+ RETVAL
+
+PRPClass *
+class(p)
+ PRP *p
+ CODE:
+ RETVAL = p->c;
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::CipherClass
+
+PROTOTYPES: DISABLE
+
+gccipher *
+find(me, name)
+ SV *me
+ char *name
+ CODE:
+ RETVAL = (gccipher *)gcipher_byname(name);
+ OUTPUT:
+ RETVAL
keysize *
keysz(cc)
gcipher *c
CODE:
c->ops->destroy(c);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
encrypt(c, plain)
c->ops->c->name, (unsigned long)c->ops->c->blksz);
}
c->ops->setiv(c, p);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
bdry(c)
gcipher *c
CODE:
c->ops->bdry(c);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
gccipher *
class(c)
OUTPUT:
RETVAL
-SV *
-list(me)
- SV *me
- PREINIT:
- const gchash *const *hc;
- SV *sv;
- PPCODE:
- for (hc = ghashtab; *hc; hc++)
- XPUSHs(RET((gchash *)*hc, "Catacomb::HashClass"));
-
size_t
hashsz(hc)
gchash *hc
ghash *h
CODE:
h->ops->destroy(h);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
hash(h, sv)
CODE:
p = SvPV(sv, len);
h->ops->hash(h, p, len);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
done(h)
SV *me
PREINIT:
const gcMAC *const *mc;
- SV *sv;
PPCODE:
for (mc = gmactab; *mc; mc++)
XPUSHs(RET((gcMAC *)*mc, "Catacomb::MACClass"));
gMAC *m
CODE:
m->ops->destroy(m);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
ghash *
init(m)
if (!r->ops->misc(r, GRAND_CHECK, GRAND_SEEDUINT32))
croak("rng `%s' doesn't support `seedint'", r->ops->name);
r->ops->misc(r, GRAND_SEEDUINT32, seed);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
seedblock(r, seed)
croak("rng `%s' doesn't support `seedblock'", r->ops->name);
p = SvPV(seed, len);
r->ops->misc(r, GRAND_SEEDBLOCK, p, len);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
seedmp(r, seed)
if (!r->ops->misc(r, GRAND_CHECK, GRAND_SEEDMP))
croak("rng `%s' doesn't support `seedmp'", r->ops->name);
r->ops->misc(r, GRAND_SEEDMP, seed);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
seedrand(r, seed)
if (!r->ops->misc(r, GRAND_CHECK, GRAND_SEEDRAND))
croak("rng `%s' doesn't support `seedrand'", r->ops->name);
r->ops->misc(r, GRAND_SEEDRAND, seed);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
U32
raw(r)
Rand_True *r
CODE:
r->ops->misc(r, RAND_GATE);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
stretch(r)
Rand_True *r
CODE:
r->ops->misc(r, RAND_STRETCH);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
key(r, k)
CODE:
p = SvPV(k, len);
r->ops->misc(r, RAND_KEY, p, len);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
noisesrc(r)
Rand_True *r
CODE:
r->ops->misc(r, RAND_NOISESRC, &noise_source);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
seed(r, bits = 160)
int bits
CODE:
r->ops->misc(r, RAND_SEED, bits);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
MODULE = Catacomb PACKAGE = Catacomb::Rand::Fib
unsigned n
CODE:
r->ops->misc(r, DSARAND_PASSES, n);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
SV *
seed(r)
MODULE = Catacomb PACKAGE = Catacomb::Rand::MGF
SV *
-new(name, k)
+new(me, name, k)
+ SV *me
char *name
SV *k
CODE:
OUTPUT:
RETVAL
-void
-list(me)
- SV *me
- PPCODE:
- listrand(mgftab);
-
MODULE = Catacomb PACKAGE = Catacomb::Rand::Counter
SV *
-new(name, k)
+new(me, name, k)
+ SV *me
char *name
SV *k
CODE:
OUTPUT:
RETVAL
-void
-list(me)
- SV *me
- PPCODE:
- listrand(ctrtab);
-
MODULE = Catacomb PACKAGE = Catacomb::Rand::OFB
SV *
-new(name, k)
+new(me, name, k)
+ SV *me
char *name
SV *k
CODE:
OUTPUT:
RETVAL
-void
-list(me)
- SV *me
- PPCODE:
- listrand(ofbtab);
-
MODULE = Catacomb PACKAGE = Catacomb::Rand::Magic
SV *
DESTROY(r)
grand *r
CODE:
- XSRETURN_UNDEF;
+ XSRETURN_YES;
#----- That's all, folks ----------------------------------------------------
return @$x;
}
-open OUT, "> $ARGV[0]" or die "couldn't write `$ARGV[0].c': $!";
+open OUT, "> $ARGV[0]" or die "couldn't write `$ARGV[0]': $!";
print OUT <<EOF;
/* -*-c-*-
#include "catacomb-perl.h"
EOF
+print OUT cross("#include <catacomb/", \@cipher, ".h>\n"), "\n";
print OUT cross("#include <catacomb/", \@cipher, "-",
[qw(counter ofb)], ".h>\n"), "\n";
print OUT cross("#include <catacomb/", \@hash, "-mgf.h>\n"), "\n";
};
EOF
+foreach my $i (@cipher) {
+ my $I = uc($i);
+ print OUT <<EOF;
+
+static void init_$i(void *ctx, const void *k, size_t ksz) {
+ ${i}_init(ctx, k, ksz);
+}
+static void eblk_$i(const void *ctx, const void *in, void *out) {
+ uint32 w[${I}_BLKSZ / 4];
+ BLKC_LOAD(${I}, w, in);
+ ${i}_eblk(ctx, w, w);
+ BLKC_STORE(${I}, out, w);
+}
+static void dblk_$i(const void *ctx, const void *in, void *out) {
+ uint32 w[${I}_BLKSZ / 4];
+ BLKC_LOAD(${I}, w, in);
+ ${i}_dblk(ctx, w, w);
+ BLKC_STORE(${I}, out, w);
+}
+static PRPClass prp_$i = {
+ "$i",
+ ${i}_keysz, sizeof(${i}_ctx), ${I}_BLKSZ,
+ init_$i, eblk_$i, dblk_$i
+};
+EOF
+}
+
+print OUT <<EOF;
+
+PRPClass *const prptab[] = {
+EOF
+foreach my $i (@cipher) {
+ print OUT " &prp_$i,\n";
+}
+print OUT " 0\n};\n";
+
#----- That's all, folks ----------------------------------------------------
/* -*-c-*-
*
- * $Id: algstuff.c,v 1.2 2004/04/08 01:36:21 mdw Exp $
+ * $Id$
*
* Support stuff for algorithms
*
dSP;
for (; rt->name; rt++)
XPUSHs(sv_2mortal(newSVpvn((char *)rt->name, strlen(rt->name))));
+ PUTBACK;
}
/*----- That's all, folks -------------------------------------------------*/
/*----- Header files ------------------------------------------------------*/
+#include <assert.h>
+
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
-#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <catacomb/blkc.h>
#include <catacomb/gcipher.h>
#include <catacomb/ghash.h>
#include <catacomb/gmac.h>
#include <catacomb/rand.h>
#include <catacomb/noise.h>
+#include <catacomb/share.h>
+#include <catacomb/gfshare.h>
+
#include <catacomb/key.h>
#include <catacomb/passphrase.h>
#include <catacomb/mp.h>
#include <catacomb/gf.h>
#include <catacomb/ec.h>
+#include <catacomb/rsa.h>
+#include <catacomb/dh.h>
+#include <catacomb/dsa.h>
+#include <catacomb/gdsa.h>
+#include <catacomb/gkcdsa.h>
#include <catacomb/field.h>
#include <catacomb/group.h>
#include <catacomb/mpint.h>
struct consttab { const char *name; UV val; };
+typedef struct cursor {
+ unsigned f;
+ union {
+ HV *hv;
+ struct { AV *av; unsigned i; } a;
+ } u;
+} cursor;
+#define CF_ARRAY 0u
+#define CF_HASH 1u
+#define CF_MUST 1u
+
extern U32 findconst(const struct consttab *cc,
const char *pkg, const char *name);
extern void ptrtosv(SV **sv, void *p, const char *type);
extern void *ptrfromsv(SV *sv, const char *type, const char *what, ...);
+extern void *ptrfromsvdflt(SV *sv, const char *type, void *dflt,
+ const char *what);
+extern void c_init(cursor *c, SV *sv);
+extern void c_skip(cursor *c);
+extern SV *c_get(cursor *c, const char *tag, unsigned f);
+extern ge *groupelt(SV *sv, const char *what);
+extern mp *fieldelt(SV *sv, const char *what);
+extern ec *ecpt(SV *sv, const char *what);
+
#define SET(sv, ob, ty) sv_setref_pv((sv), (char *)(ty), (void *)(ob))
#define MAKE(ob, ty) SET(NEWSV(0, 0), ob, ty)
#define RET(ob, ty) SET(sv_newmortal(), ob, ty)
+#define C_MP(c, tag) mp_fromsv(c_get(c, tag, CF_MUST), tag, 0, 0)
+#define C_PTR(c, tag, type) ptrfromsv(c_get(c, tag, CF_MUST), type, tag)
+#define C_PTRDFLT(c, tag, type, def) \
+ ptrfromsvdflt(c_get(c, tag, 0), type, def, tag)
+#define C_GE(c, tag) groupelt(c_get(c, tag, CF_MUST), tag)
+#define C_FE(c, tag) fieldelt(c_get(c, tag, CF_MUST), tag)
+#define C_EC(c, tag) ecpt(c_get(c, tag, CF_MUST), tag)
+extern void hvput(HV *hv, const char *k, SV *val);
/*----- Crypto algorithms -------------------------------------------------*/
+typedef struct PRPClass {
+ char *name;
+ const octet *ksz;
+ size_t ctxsz;
+ size_t blksz;
+ void (*init)(void *ctx, const void *k, size_t sz);
+ void (*eblk)(const void *ctx, const void *in, void *out);
+ void (*dblk)(const void *ctx, const void *in, void *out);
+} PRPClass;
+
+typedef struct PRP {
+ PRPClass *c;
+} PRP;
+
+extern PRPClass *const prptab[];
+
struct randtab { const char *name; grand *(*rand)(const void *, size_t); };
typedef const octet keysize;
typedef grand Rand_True, Rand_DSA;
+typedef rsa_pubctx RSA_Public;
+typedef rsa_privctx RSA_Private;
+
+typedef gfshare Share_GF;
+typedef share Share_Prime;
+
extern const struct randtab mgftab[], ctrtab[], ofbtab[];
+extern void gdsa_privfromsv(gdsa *g, SV *sv);
+extern void gdsa_pubfromsv(gdsa *g, SV *sv);
extern SV *findrand(const struct randtab *rt, const char *cls,
const char *name, SV *k);
extern void listrand(const struct randtab *rt);
/*------ Key mangling -----------------------------------------------------*/
+typedef struct Key_File {
+ unsigned ref;
+ key_file kf;
+} Key_File;
+
typedef struct Key {
- key_file *kf;
+ Key_File *kf;
key *k;
} Key;
+typedef struct Key_AttrIter {
+ Key_File *kf;
+ key_attriter i;
+} Key_AttrIter;
typedef int KeyErr;
-typedef key_data Key_Data;
-typedef key_file Key_File;
-
-extern void warn_keyreporter(const char *file, int line,
- const char *err, void *p);
+typedef key_data Key_DataImpl;
+typedef struct Key_FileIter {
+ Key_File *kf;
+ key_iter i;
+} Key_FileIter;
+typedef sym_iter Key_StructIter;
+typedef key_filter Key_Filter;
+
+extern void keyreport(const char *file, int line, const char *err, void *p);
extern SV *keyerr(int rc);
/*------ Multiprecision maths ---------------------------------------------*/
typedef mpreduce MP_Reduce;
typedef gfreduce GF_Reduce;
-typedef ec EC_Point;
typedef ec_curve EC_Curve;
typedef field Field;
+typedef mp fe;
+
+typedef group Group;
#define XSINTERFACE_FUNC_SETMP(cv, f) \
CvXSUBANY(cv).any_dptr = (void (*) _((void *)))(mp_##f)
CvXSUBANY(cv).any_dptr = (void (*) _((void *)))(gf_##f)
#define SET_MP(sv, x) SET(sv, x, "Catacomb::MP")
+#define MAKE_MP(x) MAKE(x, "Catacomb::MP")
#define RET_MP(x) RET(x, "Catacomb::MP")
#define SET_GF(sv, x) SET(sv, x, "Catacomb::GF")
+#define MAKE_GF(x) MAKE(x, "Catacomb::GF")
#define RET_GF(x) RET(x, "Catacomb::GF")
extern mp *mp_fromiv(mp *d, IV iv);
extern IV mp_toiv(mp *x);
extern mp *mp_readsv(mp *m, SV *sv, STRLEN *off, int radix);
extern int mp_writesv(mp *m, SV *sv, int radix);
-extern mp *mp_fromsv(SV *sv, const char *what, const char *ty,
- int radix, int keep, ...);
+extern mp *mp_fromsv(SV *sv, const char *what, int radix, int keep, ...);
+extern int group_writesv(group *g, ge *x, SV *sv);
/*----- Prime generation --------------------------------------------------*/
/*----- Other gear --------------------------------------------------------*/
+extern void names(const char *name);
+
+extern SV *info_field(field *f);
+extern SV *info_curve(ec_curve *c);
+extern SV *info_group(group *g);
+
extern field *copy_field(field *f);
extern ec_curve *copy_curve(ec_curve *c);
extern group *copy_group(group *g);
#include "catacomb-perl.h"
+const struct consttab ct[] = {
+#define C(x) { #x, x }
+ C(GRAND_CRYPTO),
+ C(PGEN_BEGIN), C(PGEN_TRY), C(PGEN_FAIL), C(PGEN_PASS),
+ C(PGEN_DONE), C(PGEN_ABORT),
+ C(DH_SUBGROUP),
+ C(KF_ENCMASK), C(KENC_BINARY), C(KENC_MP), C(KENC_STRUCT),
+ C(KENC_ENCRYPT), C(KENC_STRING), C(KENC_EC),
+ C(KF_CATMASK), C(KCAT_SYMM), C(KCAT_PRIV), C(KCAT_PUB),
+ C(KCAT_SHARE), C(KF_NONSECRET),
+ C(KF_BURN), C(KF_TEMP), C(KF_OPT),
+ C(KOPEN_READ), C(KOPEN_WRITE), C(KOPEN_MASK), C(KOPEN_NOFILE),
+ C(KEXP_FOREVER), C(KEXP_EXPIRE),
+ C(KERR_OK), C(KERR_BADTAG), C(KERR_BADTYPE), C(KERR_BADCOMMENT),
+ C(KERR_DUPID), C(KERR_DUPTAG), C(KERR_READONLY),
+ C(KERR_WILLEXPIRE), C(KERR_EXPIRED), C(KERR_BADFLAGS),
+ C(KERR_BADPASS), C(KERR_WRONGTYPE), C(KERR_NOTFOUND),
+ C(KERR_NOTFOUND), C(KERR_BADATTR), C(KERR_MALFORMED),
+ C(KERR_IO),
+ C(KWRITE_OK), C(KWRITE_FAIL), C(KWRITE_BROKEN),
+ C(FTY_PRIME), C(FTY_BINARY),
+#undef C
+ { 0, 0 },
+};
+
MODULE = Catacomb PACKAGE = Catacomb
U32
-const(name)
+_const(name)
char *name
PREINIT:
- const struct consttab ct[] = {
-#define C(x) { #x, x }
- C(GRAND_CRYPTO),
- C(PGEN_BEGIN), C(PGEN_TRY), C(PGEN_FAIL), C(PGEN_PASS),
- C(PGEN_DONE), C(PGEN_ABORT),
- C(KF_ENCMASK), C(KENC_BINARY), C(KENC_MP), C(KENC_STRUCT),
- C(KENC_ENCRYPT), C(KENC_STRING), C(KENC_EC),
- C(KF_CATMASK), C(KCAT_SYMM), C(KCAT_PRIV), C(KCAT_PUB),
- C(KCAT_SHARE), C(KF_NONSECRET),
- C(KF_BURN), C(KF_TEMP), C(KF_OPT),
- C(KOPEN_READ), C(KOPEN_WRITE), C(KOPEN_MASK), C(KOPEN_NOFILE),
- C(KEXP_FOREVER), C(KEXP_EXPIRE),
- C(KERR_OK), C(KERR_BADTAG), C(KERR_BADTYPE), C(KERR_BADCOMMENT),
- C(KERR_DUPID), C(KERR_DUPTAG), C(KERR_READONLY),
- C(KERR_WILLEXPIRE), C(KERR_EXPIRED), C(KERR_BADFLAGS),
- C(KERR_BADPASS), C(KERR_WRONGTYPE), C(KERR_NOTFOUND),
- C(KERR_NOTFOUND), C(KERR_BADATTR),
- C(KWRITE_OK), C(KWRITE_FAIL), C(KWRITE_BROKEN),
- C(FTY_PRIME), C(FTY_BINARY),
-#undef C
- { 0, 0 },
- };
CODE:
RETVAL = findconst(ct, "Catacomb", name);
OUTPUT:
RETVAL
+void
+_constants()
+ PREINIT:
+ int i;
+ PPCODE:
+ for (i = 0; ct[i].name; i++)
+ XPUSHs(sv_2mortal(newSVpv(ct[i].name, 0)));
+
+void
+list(name)
+ const char *name
+ PPCODE:
+ PUTBACK;
+ names(name);
+ SPAGAIN;
+
PROTOTYPES: DISABLE
INCLUDE: algorithms.xs
INCLUDE: gf.xs
INCLUDE: field.xs
INCLUDE: ec.xs
+INCLUDE: group.xs
+INCLUDE: pubkey.xs
INCLUDE: misc.xs
INCLUDE: pgen.xs
INCLUDE: key.xs
MODULE = Catacomb PACKAGE = Catacomb::EC::Point PREFIX = ec_
-EC_Point *
-new(x = 0, y = 0, z = 0)
+ec *
+new(me, x = 0, y = 0, z = 0)
+ SV *me
mp *x
mp *y
mp *z
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
if (x && y) {
RETVAL->x = MP_COPY(x);
bool
atinfp(p)
- EC_Point *p
+ ec *p
CODE:
RETVAL = EC_ATINF(p);
OUTPUT:
mp *
x(p)
- EC_Point *p
+ ec *p
CODE:
RETVAL = p->x ? MP_COPY(p->x) : 0;
OUTPUT:
mp *
y(p)
- EC_Point *p
+ ec *p
CODE:
RETVAL = p->y ? MP_COPY(p->y) : 0;
OUTPUT:
mp *
z(p)
- EC_Point *p
+ ec *p
CODE:
RETVAL = p->z ? MP_COPY(p->z) : 0;
OUTPUT:
bool
ec_eq(p, q)
- EC_Point *p
- EC_Point *q
+ ec *p
+ ec *q
SV *
DESTROY(p)
- EC_Point *p
+ ec *p
CODE:
EC_DESTROY(p);
DESTROY(p);
XSRETURN_YES;
+SV *
+put(p)
+ ec *p
+ PREINIT:
+ buf b;
+ size_t n = EC_ATINF(p) ? 2 : 4 + mp_octets(p->x) + mp_octets(p->y);
+ CODE:
+ RETVAL = NEWSV(0, n);
+ buf_init(&b, SvPVX(RETVAL), n);
+ if (buf_putec(&b, p))
+ croak("unexpected failure in Catacomb::EC::Point::put");
+ SvCUR_set(RETVAL, BLEN(&b));
+ OUTPUT:
+ RETVAL
+
+void
+get(s)
+ SV *s
+ PREINIT:
+ ec *p;
+ buf b;
+ char *q;
+ STRLEN n;
+ CODE:
+ q = SvPV(s, n);
+ buf_init(&b, q, n);
+ p = CREATE(ec);
+ EC_CREATE(p);
+ if (buf_getec(&b, p))
+ DESTROY(p);
+ else {
+ XPUSHs(RET(p, "Catacomb::EC::Point"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(BCUR(&b), BLEFT(&b))));
+ }
+
MODULE = Catacomb PACKAGE = Catacomb::EC::Curve PREFIX = ec_
EC_Curve *
-ec_prime(me, f, a, b)
+prime(me, f, a, b)
SV *me
Field *f
mp *a
mp *b
- C_ARGS:
- f, a, b
+ CODE:
+ RETVAL = ec_prime(f, a, b);
+ OUTPUT:
+ RETVAL
EC_Curve *
-ec_primeproj(me, f, a, b)
+primeproj(me, f, a, b)
SV *me
Field *f
mp *a
mp *b
- C_ARGS:
- f, a, b
+ CODE:
+ RETVAL = ec_primeproj(f, a, b);
+ OUTPUT:
+ RETVAL
EC_Curve *
-ec_bin(me, f, a, b)
+bin(me, f, a, b)
SV *me
Field *f
gf *a
gf *b
- C_ARGS:
- f, a, b
+ CODE:
+ RETVAL = ec_bin(f, a, b);
+ OUTPUT:
+ RETVAL
EC_Curve *
-ec_binproj(me, f, a, b)
+binproj(me, f, a, b)
SV *me
Field *f
gf *a
gf *b
- C_ARGS:
- f, a, b
+ CODE:
+ RETVAL = ec_binproj(f, a, b);
+ OUTPUT:
+ RETVAL
char *
name(c)
OUTPUT:
RETVAL
+mp *
+_a(c)
+ EC_Curve *c
+ CODE:
+ RETVAL = F_OUT(c->f, MP_NEW, c->a);
+ OUTPUT:
+ RETVAL
+
+mp *
+_b(c)
+ EC_Curve *c
+ CODE:
+ RETVAL = F_OUT(c->f, MP_NEW, c->a);
+ OUTPUT:
+ RETVAL
+
+Field *
+field(c)
+ EC_Curve *c
+ CODE:
+ RETVAL = copy_field(c->f);
+ OUTPUT:
+ RETVAL
+
+SV *
+get(c)
+ EC_Curve *c
+ CODE:
+ RETVAL = info_curve(c);
+ OUTPUT:
+ RETVAL
+
bool
ec_samep(me, c)
EC_Curve *me
EC_Curve *c
-EC_Point *
-find(c, x)
+SV *
+putraw(c, p)
EC_Curve *c
- mp *x
+ ec *p
+ PREINIT:
+ buf b;
+ size_t n = c->f->noctets * 2 + 1;
+ CODE:
+ RETVAL = NEWSV(0, n);
+ buf_init(&b, SvPVX(RETVAL), n);
+ if (ec_putraw(c, &b, p))
+ croak("unexpected failure in Catacomb::EC::Curve::putraw");
+ SvCUR_set(RETVAL, BLEN(&b));
+ OUTPUT:
+ RETVAL
+
+void
+_getraw(c, s)
+ EC_Curve *c
+ SV *s
+ PREINIT:
+ ec *p;
+ buf b;
+ char *q;
+ STRLEN n;
CODE:
- RETVAL = CREATE(EC_Point);
+ q = SvPV(s, n);
+ buf_init(&b, q, n);
+ p = CREATE(ec);
+ EC_CREATE(p);
+ if (ec_getraw(c, &b, &p))
+ DESTROY(p);
+ else {
+ XPUSHs(RET(p, "Catacomb::EC::Point"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(BCUR(&b), BLEFT(&b))));
+ }
+
+ec *
+_find(c, x)
+ EC_Curve *c
+ fe *x
+ CODE:
+ RETVAL = CREATE(ec);
+ EC_CREATE(RETVAL);
if (!ec_find(c, RETVAL, x)) {
DESTROY(RETVAL);
RETVAL = 0;
OUTPUT:
RETVAL
-EC_Point *
-rand(c, r = &rand_global)
+ec *
+_rand(c, r = &rand_global)
EC_Curve *c
grand *r
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
+ EC_CREATE(RETVAL);
ec_rand(c, RETVAL, r);
OUTPUT:
RETVAL
-EC_Point *
+ec *
neg(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_neg(c, RETVAL, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
add(c, p, q)
EC_Curve *c
- EC_Point *p
- EC_Point *q
+ ec *p
+ ec *q
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_add(c, RETVAL, p, q);
OUTPUT:
RETVAL
-EC_Point *
+ec *
sub(c, p, q)
EC_Curve *c
- EC_Point *p
- EC_Point *q
+ ec *p
+ ec *q
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_sub(c, RETVAL, p, q);
OUTPUT:
RETVAL
-EC_Point *
+ec *
dbl(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_dbl(c, RETVAL, p);
OUTPUT:
RETVAL
-bool
-ec_check(c, p)
+SV *
+check(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
+ CODE:
+ if (ec_check(c, p))
+ XSRETURN_UNDEF;
+ XSRETURN_YES;
-EC_Point *
+ec *
mul(c, p, x)
EC_Curve *c
- EC_Point *p
+ ec *p
mp *x
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_mul(c, RETVAL, p, x);
OUTPUT:
RETVAL
-EC_Point *
-mmul(c, ...)
- EC_Curve *c
- PREINIT:
- ec_mulfactor *v;
- size_t i, j, n;
- CODE:
- if (items < 3 || !(items & 1)) {
- croak("Usage: Catacomb::EC::Curve::mmul"
- "(c, p_0, x_0, p_1, x_1, ...");
- }
- n = (items - 1)/2;
- v = xmalloc(n * sizeof(mp_expfactor));
- for (i = 1, j = 0; i < items; i += 2, j++) {
- v[j].base = *(ec *)ptrfromsv(ST(i), "Catacomb::EC::Point", "p_i");
- v[j].exp = mp_fromsv(ST(i + 1), "x_i", "Catacomb::MP", 0, 0);
- }
- RETVAL = CREATE(RETVAL);
- EC_CREATE(RETVAL);
- ec_mmul(c, RETVAL, v, n);
- xfree(v);
- OUTPUT:
- RETVAL
-
-EC_Point *
+ec *
in(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_IN(c, RETVAL, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
out(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_OUT(c, RETVAL, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
fix(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_FIX(c, RETVAL, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
ifind(c, x)
EC_Curve *c
mp *x
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
if (!EC_FIND(c, RETVAL, x)) {
DESTROY(RETVAL);
RETVAL = 0;
OUTPUT:
RETVAL
-EC_Point *
+ec *
ineg(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_NEG(c, RETVAL, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
iadd(c, p, q)
EC_Curve *c
- EC_Point *p
- EC_Point *q
+ ec *p
+ ec *q
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_ADD(c, RETVAL, p, q);
OUTPUT:
RETVAL
-EC_Point *
+ec *
isub(c, p, q)
EC_Curve *c
- EC_Point *p
- EC_Point *q
+ ec *p
+ ec *q
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_SUB(c, RETVAL, p, q);
OUTPUT:
RETVAL
-EC_Point *
+ec *
idbl(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
EC_DBL(c, RETVAL, p);
OUTPUT:
bool
icheck(c, p)
EC_Curve *c
- EC_Point *p
+ ec *p
CODE:
RETVAL = EC_CHECK(c, p);
OUTPUT:
RETVAL
-EC_Point *
+ec *
imul(c, p, x)
EC_Curve *c
- EC_Point *p
+ ec *p
mp *x
CODE:
- RETVAL = CREATE(EC_Point);
+ RETVAL = CREATE(ec);
EC_CREATE(RETVAL);
ec_imul(c, RETVAL, p, x);
OUTPUT:
RETVAL
-EC_Point *
+ec *
immul(c, ...)
EC_Curve *c
PREINIT:
n = (items - 1)/2;
v = xmalloc(n * sizeof(mp_expfactor));
for (i = 1, j = 0; i < items; i += 2, j++) {
- v[j].base = *(ec *)ptrfromsv(ST(i), "Catacomb::EC::Point", "p_i");
- v[j].exp = mp_fromsv(ST(i + 1), "x_i", "Catacomb::MP", 0, 0);
+ v[j].base = *ecpt(ST(i), "p_i");
+ v[j].exp = mp_fromsv(ST(i + 1), "x_i", 0, 0);
}
RETVAL = CREATE(RETVAL);
EC_CREATE(RETVAL);
RETVAL
void
-getinfo(me, p)
+_getinfo(me, p)
+ SV *me
char *p
PREINIT:
ec_info i;
const char *e;
- EC_Point *pt;
+ ec *pt;
PPCODE:
if ((e = ec_getinfo(&i, p)) != 0)
croak("bad curve spec: %s", e);
- pt = CREATE(EC_Point);
+ pt = CREATE(ec);
*pt = i.g;
XPUSHs(RET(i.c, "Catacomb::EC::Curve"));
XPUSHs(RET(pt, "Catacomb::EC::Point"));
XPUSHs(RET(i.r, "Catacomb::MP"));
XPUSHs(RET(i.h, "Catacomb::MP"));
+const char *
+checkinfo(c, g, r, h, rng = &rand_global)
+ EC_Curve *c
+ ec *g
+ mp *r
+ mp *h
+ grand *rng
+ PREINIT:
+ ec_info ei;
+ CODE:
+ ei.c = c;
+ ei.g = *g;
+ ei.r = r;
+ ei.h = h;
+ RETVAL = ec_checkinfo(&ei, rng);
+ OUTPUT:
+ RETVAL
OUTPUT:
RETVAL
-mp *
-zero(f)
+fe *
+_zero(f)
Field *f
CODE:
RETVAL = MP_COPY(f->zero);
OUTPUT:
RETVAL
-mp *
-one(f)
+fe *
+_one(f)
Field *f
CODE:
RETVAL = MP_COPY(f->one);
OUTPUT:
RETVAL
-mp *
+fe *
m(f)
Field *f
CODE:
OUTPUT:
RETVAL
+fe *
+q(f)
+ Field *f
+ CODE:
+ RETVAL = MP_COPY(f->q);
+ OUTPUT:
+ RETVAL
+
UV
nbits(f)
Field *f
OUTPUT:
RETVAL
-mp *
-rand(f, r = &rand_global)
+fe *
+_rand(f, r = &rand_global)
Field *f
grand *r
CODE:
OUTPUT:
RETVAL
-mp *
+fe *
in(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_IN(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
out(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_OUT(f, MP_NEW, x);
OUTPUT:
bool
zerop(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_ZEROP(f, x);
OUTPUT:
RETVAL
-mp *
+fe *
neg(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_NEG(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
add(f, x, y)
Field *f
- mp *x
- mp *y
+ fe *x
+ fe *y
CODE:
RETVAL = F_ADD(f, MP_NEW, x, y);
OUTPUT:
RETVAL
-mp *
+fe *
sub(f, x, y)
Field *f
- mp *x
- mp *y
+ fe *x
+ fe *y
CODE:
RETVAL = F_SUB(f, MP_NEW, x, y);
OUTPUT:
RETVAL
-mp *
+fe *
mul(f, x, y)
Field *f
- mp *x
- mp *y
+ fe *x
+ fe *y
CODE:
RETVAL = F_MUL(f, MP_NEW, x, y);
OUTPUT:
RETVAL
-mp *
+fe *
sqr(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_SQR(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
inv(f, x)
Field *f
- mp *x
+ fe *x
CODE:
+ if (F_ZEROP(f, x))
+ croak("division by zero");
RETVAL = F_INV(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
reduce(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_REDUCE(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
sqrt(f, x)
Field *f
- mp *x
+ fe *x
CODE:
RETVAL = F_SQRT(f, MP_NEW, x);
OUTPUT:
RETVAL
-mp *
+fe *
quadsolve(f, x)
Field *f
- mp *x
+ fe *x
CODE:
if (F_TYPE(f) != FTY_BINARY)
croak("quadsolve only works on binary fields");
OUTPUT:
RETVAL
-mp *
+fe *
dbl(f, x)
Field *f
- mp *x
+ fe *x
CODE:
if (F_TYPE(f) != FTY_PRIME)
croak("dbl only works on prime fields");
OUTPUT:
RETVAL
-mp *
+fe *
tpl(f, x)
Field *f
- mp *x
+ fe *x
CODE:
if (F_TYPE(f) != FTY_PRIME)
croak("tpl only works on prime fields");
OUTPUT:
RETVAL
-mp *
+fe *
qdl(f, x)
Field *f
- mp *x
+ fe *x
CODE:
if (F_TYPE(f) != FTY_PRIME)
croak("qdl only works on prime fields");
OUTPUT:
RETVAL
-mp *
+fe *
hlv(f, x)
Field *f
- mp *x
+ fe *x
CODE:
if (F_TYPE(f) != FTY_PRIME)
croak("hlv only works on prime fields");
OUTPUT:
RETVAL
+SV *
+get(f)
+ Field *f
+ CODE:
+ RETVAL = info_field(f);
+ OUTPUT:
+ RETVAL
--- /dev/null
+use ExtUtils::testlib;
+use Catacomb;
+
+package Report;
+
+sub new { bless [], $_[0]; }
+sub report { my ($me, @info) = @_; push(@$me, \@info); }
+sub done {
+ my ($me) = @_;
+ if (@$me) {
+ print STDERR "Errors reading key file:\n";
+ foreach my $i (@$me) {
+ printf STDERR " %s:%d: %s\n", @$i;
+ }
+ exit(1);
+ }
+}
+
+package main;
+
+my $fn = shift || "keyring";
+my $rep = Report->new();
+$kf = Catacomb::Key::File->new($fn, KFILE_READ, $rep)
+ or die("error opening keyring: $!");
+$rep->done();
+$hcn = shift || "rmd160";
+$hc = Catacomb::HashClass->find($hcn) or die("no hash algorithm `$hcn'");
+$filt = Catacomb::Key::Filter->new("-secret");
+for (my $i = $kf->iterate(); my $k = $i->next(); ) {
+ $h = $hc->init();
+ $fp = $k->fingerprint($h, $filt);
+ print unpack("H*", $h->done()), " ", $k->fulltag(), "\n";
+}
SV *sv
int radix
CODE:
- RETVAL = sv ? mp_fromsv(sv, "sv", "Catacomb::GF", radix, 1) : MP_ZERO;
+ RETVAL = sv ? mp_fromsv(sv, "sv", radix, 1) : MP_ZERO;
OUTPUT:
RETVAL
OUTPUT:
RETVAL
-int
-metrics(m)
- gf *m
- INTERFACE_MACRO:
- XSINTERFACE_FUNC
- XSINTERFACE_FUNC_SETMP
- INTERFACE:
- octets bits
-
-SV *
-storeb(m, i = -1)
- gf *m
- int i
- PREINIT:
- size_t sz;
- CODE:
- sz = (i < 0) ? mp_octets(m) : i;
- RETVAL = NEWSV(0, sz ? sz : 1);
- mp_storeb(m, SvPVX(RETVAL), sz);
- SvCUR_set(RETVAL, sz);
- SvPOK_on(RETVAL);
- OUTPUT:
- RETVAL
-
-SV *
-storel(m, i = -1)
- gf *m
- int i
- PREINIT:
- size_t sz;
- CODE:
- sz = (i < 0) ? mp_octets(m) : i;
- RETVAL = NEWSV(0, sz ? sz : 1);
- mp_storel(m, SvPVX(RETVAL), sz);
- SvCUR_set(RETVAL, sz);
- SvPOK_on(RETVAL);
- OUTPUT:
- RETVAL
-
-SV *
-tostring(m, radix = 16)
- gf *m
- int radix
- CODE:
- RETVAL = NEWSV(0, 0);
- mp_writesv(m, RETVAL, radix);
- OUTPUT:
- RETVAL
-
-SV *
-toint(m)
- gf *m
- CODE:
- RETVAL = newSViv(mp_toiv(m));
- OUTPUT:
- RETVAL
-
-SV *
-DESTROY(m)
- gf *m
- CODE:
- mp_drop(m);
- XSRETURN_UNDEF;
-
mp *
gf_sqr(a)
gf *a
INTERFACE:
add sub mul
+mp *
+logop(a, b)
+ gf *a
+ gf *b
+ C_ARGS:
+ MP_NEW, a, b
+ INTERFACE_MACRO:
+ XSINTERFACE_FUNC
+ XSINTERFACE_FUNC_SETMP
+ INTERFACE:
+ and or xor nand nor
+
+mp *
+unop(a)
+ gf *a
+ C_ARGS:
+ MP_NEW, a
+ INTERFACE_MACRO:
+ XSINTERFACE_FUNC
+ XSINTERFACE_FUNC_SETMP
+ INTERFACE:
+ not
+
gf *
shiftop(a, n)
- mp *a
+ gf *a
int n
C_ARGS:
MP_NEW, a, n
INTERFACE:
lsl lsr
-int
-gf_eq(a, b)
+gf *
+flipbits(a, n)
gf *a
- gf *b
- CODE:
- RETVAL = mp_eq(a, b);
- OUTPUT:
- RETVAL
+ unsigned long n
+ C_ARGS:
+ MP_NEW, a, n
+ INTERFACE_MACRO:
+ XSINTERFACE_FUNC
+ XSINTERFACE_FUNC_SETMP
+ INTERFACE:
+ setbit clearbit
int
gf_irreduciblep(a)
break;
}
-GF_Reduce *
-makereduce(x)
- gf *x
- CODE:
- RETVAL = CREATE(GF_Reduce);
- gfreduce_create(RETVAL, x);
- OUTPUT:
- RETVAL
-
MODULE = Catacomb PACKAGE = Catacomb::GF::Reduce PREFIX = gfreduce_
GF_Reduce *
--- /dev/null
+# ---?---
+#
+# $Id$
+#
+# Abstract groups
+#
+# (c) 2001 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.
+
+MODULE = Catacomb PACKAGE = Catacomb::Group PREFIX = group_
+
+Group *
+prime(me, p, g, q)
+ SV *me
+ mp *p
+ mp *g
+ mp *q
+ PREINIT:
+ gprime_param gp;
+ CODE:
+ gp.p = p;
+ gp.q = q;
+ gp.g = g;
+ RETVAL = group_prime(&gp);
+ OUTPUT:
+ RETVAL
+
+Group *
+binary(me, p, g, q)
+ SV *me
+ mp *p
+ mp *g
+ mp *q
+ PREINIT:
+ gbin_param gb;
+ CODE:
+ gb.p = p;
+ gb.q = q;
+ gb.g = g;
+ RETVAL = group_binary(&gb);
+ OUTPUT:
+ RETVAL
+
+Group *
+ec(me, c, g, r, h)
+ SV *me
+ EC_Curve *c
+ ec *g
+ mp *r
+ mp *h
+ PREINIT:
+ ec_info ei;
+ CODE:
+ ei.c = copy_curve(c);
+ EC_CREATE(&ei.g);
+ EC_COPY(&ei.g, g);
+ ei.r = MP_COPY(r);
+ ei.h = MP_COPY(h);
+ RETVAL = group_ec(&ei);
+ OUTPUT:
+ RETVAL
+
+Group *
+byname(me, n)
+ SV *me
+ char *n
+ PREINIT:
+ const char *e;
+ CODE:
+ if ((e = group_fromstring(n, &RETVAL)) != 0)
+ croak("bad group name: `%s'", e);
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(g)
+ Group *g
+ CODE:
+ G_DESTROYGROUP(g);
+ XSRETURN_YES;
+
+ge *
+_i(g)
+ Group *g
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_COPY(g, RETVAL, g->i);
+ OUTPUT:
+ RETVAL
+
+ge *
+_g(g)
+ Group *g
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_COPY(g, RETVAL, g->g);
+ OUTPUT:
+ RETVAL
+
+mp *
+r(g)
+ Group *g
+ CODE:
+ RETVAL = MP_COPY(g->r);
+ OUTPUT:
+ RETVAL
+
+mp *
+h(g)
+ Group *g
+ CODE:
+ RETVAL = MP_COPY(g->h);
+ OUTPUT:
+ RETVAL
+
+bool
+group_samep(g, h)
+ Group *g
+ Group *h
+
+void
+check(g, rng = &rand_global)
+ Group *g
+ grand *rng
+ PREINIT:
+ const char *e;
+ PPCODE:
+ e = G_CHECK(g, rng);
+ if (!e)
+ XSRETURN_YES;
+ XPUSHs(&PL_sv_undef);
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpv(e, 0)));
+
+SV *
+_checkelt(g, x)
+ Group *g
+ ge *x
+ CODE:
+ if (group_check(g, x))
+ XSRETURN_UNDEF;
+ else
+ XSRETURN_YES;
+
+SV *
+_destroyelement(g, x)
+ Group *g
+ ge *x
+ CODE:
+ G_DESTROY(g, x);
+ XSRETURN_YES;
+
+bool
+_identp(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = G_IDENTP(g, x);
+ OUTPUT:
+ RETVAL
+
+SV *
+get(g)
+ Group *g
+ CODE:
+ RETVAL = info_group(g);
+ OUTPUT:
+ RETVAL
+
+bool
+_eq(g, x, y)
+ Group *g
+ ge *x
+ ge *y
+ CODE:
+ RETVAL = G_EQ(g, x, y);
+ OUTPUT:
+ RETVAL
+
+ge *
+_mul(g, x, y)
+ Group *g
+ ge *x
+ ge *y
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_MUL(g, RETVAL, x, y);
+ OUTPUT:
+ RETVAL
+
+ge *
+_sqr(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_SQR(g, RETVAL, x);
+ OUTPUT:
+ RETVAL
+
+ge *
+_inv(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_INV(g, RETVAL, x);
+ OUTPUT:
+ RETVAL
+
+ge *
+_div(g, x, y)
+ Group *g
+ ge *x
+ ge *y
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_DIV(g, RETVAL, x, y);
+ OUTPUT:
+ RETVAL
+
+ge *
+_exp(g, x, n)
+ Group *g
+ ge *x
+ mp *n
+ CODE:
+ RETVAL = G_CREATE(g);
+ G_EXP(g, RETVAL, x, n);
+ OUTPUT:
+ RETVAL
+
+ge *
+_mexp(g, ...)
+ Group *g
+ PREINIT:
+ group_expfactor *v;
+ size_t i, j, n;
+ CODE:
+ if (items < 3 || !(items & 1)) {
+ croak("Usage: Catacomb::Group::mexp"
+ "(g, x_0, n_0, x_1, n_1, ...");
+ }
+ n = (items - 1)/2;
+ v = xmalloc(n * sizeof(group_expfactor));
+ for (i = 1, j = 0; i < items; i += 2, j++) {
+ v[j].base = ptrfromsv(ST(i), "Catacomb::Group::Element", "p_i");
+ v[j].exp = mp_fromsv(ST(i + 1), "x_i", 0, 0);
+ }
+ RETVAL = G_CREATE(g);
+ G_MEXP(g, RETVAL, v, n);
+ xfree(v);
+ OUTPUT:
+ RETVAL
+
+mp *
+_toint(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = G_TOINT(g, MP_NEW, x);
+ OUTPUT:
+ RETVAL
+
+ge *
+_fromint(g, x)
+ Group *g
+ mp *x
+ CODE:
+ RETVAL = G_CREATE(g);
+ if (G_FROMINT(g, RETVAL, x)) {
+ G_DESTROY(g, RETVAL);
+ RETVAL = 0;
+ }
+ OUTPUT:
+ RETVAL
+
+ec *
+_toec(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = CREATE(ec);
+ EC_CREATE(RETVAL);
+ if (G_TOEC(g, RETVAL, x)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
+ OUTPUT:
+ RETVAL
+
+ge *
+_fromec(g, x)
+ Group *g
+ ec *x
+ CODE:
+ RETVAL = G_CREATE(g);
+ if (G_FROMEC(g, RETVAL, x)) {
+ G_DESTROY(g, RETVAL);
+ RETVAL = 0;
+ }
+ OUTPUT:
+ RETVAL
+
+SV *
+_putbuf(g, x)
+ Group *g
+ ge *x
+ PREINIT:
+ buf b;
+ size_t n = g->noctets + 8; /* Guess */
+ CODE:
+ RETVAL = NEWSV(0, n);
+ buf_init(&b, SvPVX(RETVAL), n);
+ if (G_TOBUF(g, &b, x))
+ croak("unexpected failure in Catacomb::Group::putbuf");
+ SvCUR_set(RETVAL, BLEN(&b));
+ OUTPUT:
+ RETVAL
+
+void
+_getbuf(g, s)
+ Group *g
+ SV *s
+ PREINIT:
+ ge *x;
+ buf b;
+ char *q;
+ STRLEN n;
+ CODE:
+ q = SvPV(s, n);
+ buf_init(&b, q, n);
+ x = G_CREATE(g);
+ if (G_FROMBUF(g, &b, x))
+ G_DESTROY(g, x);
+ else {
+ XPUSHs(RET(x, "Catacomb::Group::Element"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(BCUR(&b), BLEFT(&b))));
+ }
+
+SV *
+_putraw(g, x)
+ Group *g
+ ge *x
+ PREINIT:
+ buf b;
+ size_t n = g->noctets;
+ CODE:
+ RETVAL = NEWSV(0, n);
+ buf_init(&b, SvPVX(RETVAL), n);
+ if (G_TORAW(g, &b, x))
+ croak("unexpected failure in Catacomb::Group::putraw");
+ SvCUR_set(RETVAL, BLEN(&b));
+ OUTPUT:
+ RETVAL
+
+void
+_getraw(g, s)
+ Group *g
+ SV *s
+ PREINIT:
+ ge *x;
+ buf b;
+ char *q;
+ STRLEN n;
+ CODE:
+ q = SvPV(s, n);
+ buf_init(&b, q, n);
+ x = G_CREATE(g);
+ if (G_FROMRAW(g, &b, x))
+ G_DESTROY(g, x);
+ else {
+ XPUSHs(RET(x, "Catacomb::Group::Element"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(BCUR(&b), BLEFT(&b))));
+ }
+
+SV *
+_tostring(g, x)
+ Group *g
+ ge *x
+ CODE:
+ RETVAL = NEWSV(0, 64);
+ if (group_writesv(g, x, RETVAL)) {
+ SvREFCNT_dec(RETVAL);
+ XSRETURN_UNDEF;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+_fromstring(g, s)
+ Group *g
+ SV *s
+ PREINIT:
+ mptext_stringctx ms;
+ STRLEN len;
+ ge *x;
+ PPCODE:
+ ms.buf = SvPV(s, len);
+ ms.lim = ms.buf + len;
+ x = G_CREATE(g);
+ if (G_READ(g, x, &mptext_stringops, &ms))
+ G_DESTROY(g, x);
+ else {
+ XPUSHs(RET(x, "Catacomb::Group::Element"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(ms.buf, ms.lim - ms.buf)));
+ }
MODULE = Catacomb PACKAGE = Catacomb::Key PREFIX = key_
+SV *
+DESTROY(k)
+ Key *k
+ CODE:
+ keyfile_dec(k->kf);
+ DESTROY(k);
+ XSRETURN_YES;
+
bool
key_chkident(me, p)
SV *me
OUTPUT:
RETVAL
-Key_Data *
-data(k)
+Key_DataImpl *
+_data(k)
Key *k
CODE:
RETVAL = &k->k->k;
Key *k
char *p
C_ARGS:
- k->kf, k->k, p
+ &k->kf->kf, k->k, p
KeyErr
key_settag(k, p)
Key *k
char *p
C_ARGS:
- k->kf, k->k, p
+ &k->kf->kf, k->k, p
KeyErr
key_delete(k)
Key *k
C_ARGS:
- k->kf, k->k
+ &k->kf->kf, k->k
SV *
fulltag(k)
dstr d = DSTR_INIT;
CODE:
key_fulltag(k->k, &d);
- RETVAL = newSVpv(d.buf, d.len);
+ RETVAL = newSVpvn(d.buf, d.len);
dstr_destroy(&d);
OUTPUT:
RETVAL
Key *k
char *a
C_ARGS:
- k->kf, k->k, a
+ &k->kf->kf, k->k, a
KeyErr
-key_putattr(k, a, v)
+putattr(k, a, v = &PL_sv_undef)
Key *k
char *a
- char *v
- C_ARGS:
- k->kf, k->k, a, v
+ SV *v
+ PREINIT:
+ char *vv;
+ STRLEN len;
+ CODE:
+ if (!SvOK(v))
+ vv = 0;
+ else
+ vv = SvPV(v, len);
+ RETVAL = key_putattr(&k->kf->kf, k->k, a, vv);
+ OUTPUT:
+ RETVAL
-void
-attrlist(k)
+Key_AttrIter *
+attriter(k)
Key *k
- PREINIT:
- key_attriter i;
- const char *a, *v;
- PPCODE:
- for (key_mkattriter(&i, k->k); key_nextattr(&i, &a, &v); )
- XPUSHs(sv_2mortal(newSVpv((char *)a, strlen(a))));
+ CODE:
+ RETVAL = CREATE(Key_AttrIter);
+ key_mkattriter(&RETVAL->i, k->k);
+ RETVAL->kf = k->kf;
+ k->kf->ref++;
+ OUTPUT:
+ RETVAL
bool
expiredp(k)
key_expire(k)
Key *k
C_ARGS:
- k->kf, k->k
+ &k->kf->kf, k->k
KeyErr
key_used(k, t)
Key *k
time_t t
C_ARGS:
- k->kf, k->k, t
+ &k->kf->kf, k->k, t
bool
-fingerprint(k, h, kfiltstr)
+key_fingerprint(k, h, kf = 0)
Key *k
ghash *h
- char *kfiltstr
- PREINIT:
- key_filter kfilt;
- dstr d = DSTR_INIT;
- CODE:
- if (!kfiltstr)
- kfilt.f = kfilt.m = 0;
- else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
- croak("bad filter string `%s'", kfiltstr);
- RETVAL = key_fingerprint(k->k, h, &kfilt);
- OUTPUT:
- RETVAL
+ Key_Filter *kf
+ C_ARGS:
+ k->k, h, kf
const char *
key_strerror(me, err)
C_ARGS:
err
-MODULE = Catacomb PACKAGE = Catacomb::Key::Data PREFIX = key_
+MODULE = Catacomb PACKAGE = Catacomb::Key::AttrIter
+
+void
+next(i)
+ Key_AttrIter *i
+ PREINIT:
+ const char *a, *v;
+ PPCODE:
+ if (key_nextattr(&i->i, &a, &v)) {
+ XPUSHs(sv_2mortal(newSVpv(a, 0)));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpv(v, 0)));
+ }
+
+SV *
+DESTROY(i)
+ Key_AttrIter *i
+ CODE:
+ keyfile_dec(i->kf);
+ DESTROY(i);
+ XSRETURN_YES;
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::Filter
+
+Key_Filter *
+new(me, f = 0, m = 0)
+ SV *me
+ SV *f
+ SV *m
+ PREINIT:
+ char *p;
+ STRLEN len;
+ CODE:
+ RETVAL = CREATE(Key_Filter);
+ if (!f || !SvOK(f))
+ RETVAL->f = RETVAL->m = 0;
+ else if (m) {
+ RETVAL->f = SvUV(f);
+ RETVAL->m = SvUV(m);
+ } else {
+ p = SvPV(f, len);
+ if (key_readflags(p, 0, &RETVAL->f, &RETVAL->m)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(kf)
+ Key_Filter *kf
+ CODE:
+ if (!kf)
+ XSRETURN_UNDEF;
+ DESTROY(kf);
+ XSRETURN_YES;
+
+SV *
+tostring(kf)
+ Key_Filter *kf
+ PREINIT:
+ dstr d = DSTR_INIT;
+ CODE:
+ if (!kf)
+ XSRETURN_UNDEF;
+ key_writeflags(kf->f, &d);
+ RETVAL = newSVpvn(d.buf, d.len);
+ dstr_destroy(&d);
+ OUTPUT:
+ RETVAL
+
+UV
+f(kf)
+ Key_Filter *kf
+ CODE:
+ RETVAL = kf ? kf->f : 0;
+ OUTPUT:
+ RETVAL
-Key_Data *
-_new(me)
+UV
+m(kf)
+ Key_Filter *kf
+ CODE:
+ RETVAL = kf ? kf->m : 0;
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::DataImpl PREFIX = key_
+
+Key_DataImpl *
+new(me)
SV *me
CODE:
RETVAL = CREATE(key_data);
RETVAL
SV *
-destroy(kd)
- Key_Data *kd
+free(kd)
+ Key_DataImpl *kd
+ CODE:
+ key_destroy(kd);
+ DESTROY(kd);
+ XSRETURN_YES;
+
+SV *
+clear(kd)
+ Key_DataImpl *kd
CODE:
key_destroy(kd);
+ kd->e = 0;
+ kd->u.k.k = 0;
+ kd->u.k.sz = 0;
XSRETURN_YES;
SV *
setbinary(kd, sv)
- Key_Data *kd
+ Key_DataImpl *kd
SV *sv
PREINIT:
char *p;
STRLEN len;
CODE:
p = SvPV(sv, len);
+ key_destroy(kd);
key_binary(kd, p, len);
XSRETURN_YES;
SV *
setencrypted(kd, sv)
- Key_Data *kd
+ Key_DataImpl *kd
SV *sv
PREINIT:
char *p;
STRLEN len;
CODE:
p = SvPV(sv, len);
+ key_destroy(kd);
key_encrypted(kd, p, len);
XSRETURN_YES;
SV *
setmp(kd, x)
- Key_Data *kd
+ Key_DataImpl *kd
mp *x
CODE:
+ key_destroy(kd);
key_mp(kd, x);
XSRETURN_YES;
SV *
setstring(kd, p)
- Key_Data *kd
+ Key_DataImpl *kd
char *p
CODE:
+ key_destroy(kd);
key_string(kd, p);
XSRETURN_YES;
SV *
setec(kd, p)
- Key_Data *kd
- EC_Point *p
+ Key_DataImpl *kd
+ ec *p
CODE:
+ key_destroy(kd);
key_ec(kd, p);
XSRETURN_YES;
U32
flags(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
RETVAL = kd->e;
OUTPUT:
RETVAL
SV *
+setflags(kd, f)
+ Key_DataImpl *kd
+ U32 f
+ CODE:
+ if (f & KF_ENCMASK)
+ croak("can't change encoding flags");
+ kd->e = (kd->e & KF_ENCMASK) | (f & ~KF_ENCMASK);
+ XSRETURN_YES;
+
+SV *
getbinary(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
if ((kd->e & KF_ENCMASK) != KENC_BINARY)
croak("key is not binary");
- RETVAL = newSVpv(kd->u.k.k, kd->u.k.sz);
+ RETVAL = newSVpvn(kd->u.k.k, kd->u.k.sz);
OUTPUT:
RETVAL
SV *
getencrypted(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
if ((kd->e & KF_ENCMASK) != KENC_ENCRYPT)
croak("key is not encrypted");
- RETVAL = newSVpv(kd->u.k.k, kd->u.k.sz);
+ RETVAL = newSVpvn(kd->u.k.k, kd->u.k.sz);
OUTPUT:
RETVAL
mp *
getmp(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
if ((kd->e & KF_ENCMASK) != KENC_MP)
croak("key is not bignum");
- RETVAL = kd->u.m;
+ RETVAL = MP_COPY(kd->u.m);
OUTPUT:
RETVAL
-EC_Point *
+ec *
getec(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
if ((kd->e & KF_ENCMASK) != KENC_EC)
croak("key is not a curve point");
char *
getstring(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
if ((kd->e & KF_ENCMASK) != KENC_STRING)
croak("key is not string");
SV *
setstruct(kd)
- Key_Data *kd
+ Key_DataImpl *kd
CODE:
+ key_destroy(kd);
key_structure(kd);
XSRETURN_YES;
-Key_Data *
+Key_DataImpl *
key_structfind(kd, tag)
- Key_Data *kd
+ Key_DataImpl *kd
char *tag
+ INIT:
+ if ((kd->e & KF_ENCMASK) != KENC_STRUCT)
+ XSRETURN_UNDEF;
-Key_Data *
+Key_DataImpl *
key_structcreate(kd, tag)
- Key_Data *kd
+ Key_DataImpl *kd
char *tag
+ INIT:
+ if ((kd->e & KF_ENCMASK) != KENC_STRUCT)
+ croak("key is not structured");
-void
-getstruct(kd)
- Key_Data *kd
- PREINIT:
- sym_iter i;
- key_struct *ks;
- PPCODE:
+Key_StructIter *
+structiter(kd)
+ Key_DataImpl *kd
+ CODE:
if ((kd->e & KF_ENCMASK) != KENC_STRUCT)
croak("key is not structured");
- for (sym_mkiter(&i, &kd->u.s); ks = sym_next(&i); )
- XPUSHs(RET(&ks->k, "Catacomb::Key::Data"));
+ RETVAL = CREATE(Key_StructIter);
+ sym_mkiter(RETVAL, &kd->u.s);
+ OUTPUT:
+ RETVAL
SV *
structdel(kd, tag)
- Key_Data *kd
+ Key_DataImpl *kd
char *tag
PREINIT:
key_struct *ks;
croak("key is not structured");
if ((ks = sym_find(&kd->u.s, tag, -1, 0, 0)) == 0)
XSRETURN_UNDEF;
+ key_destroy(&ks->k);
sym_remove(&kd->u.s, ks);
XSRETURN_YES;
-void
-readflags(me, p)
- SV *me
- char *p
- PREINIT:
- unsigned f, m;
- PPCODE:
- if (key_readflags(p, &p, &f, &m) || *p)
- croak("bad flags string");
- XPUSHs(sv_2mortal(newSVuv(m)));
- XPUSHs(sv_2mortal(newSVuv(f)));
+bool
+key_match(kd, kf)
+ Key_DataImpl *kd
+ Key_Filter *kf
-SV *
-getflags(me, f)
- SV *me
- U32 f
+bool
+set(kd, kkd, kf = 0)
+ Key_DataImpl *kd
+ Key_DataImpl *kkd
+ Key_Filter *kf
+ CODE:
+ key_destroy(kd);
+ kd->e = 0;
+ kd->u.k.k = 0;
+ kd->u.k.sz = 0;
+ RETVAL = key_copy(kd, kkd, kf);
+ OUTPUT:
+ RETVAL
+
+Key_DataImpl *
+lock(kd, key)
+ Key_DataImpl *kd
+ SV *key
PREINIT:
- dstr d = DSTR_INIT;
+ STRLEN len;
+ char *p;
CODE:
- key_writeflags(f, &d);
- RETVAL = newSVpv(d.buf, d.len);
- dstr_destroy(&d);
+ if ((kd->e & KF_ENCMASK) == KENC_ENCRYPT)
+ croak("already encrypted");
+ RETVAL = CREATE(Key_DataImpl);
+ p = SvPV(key, len);
+ key_lock(RETVAL, kd, p, len);
OUTPUT:
RETVAL
-Key_Data *
-copy(kd, kfiltstr = 0)
- Key_Data *kd
- char *kfiltstr
+Key_DataImpl *
+unlock(kd, key)
+ Key_DataImpl *kd
+ SV *key
PREINIT:
- key_filter kfilt;
+ STRLEN len;
+ char *p;
+ int rc;
CODE:
- if (!kfiltstr)
- kfilt.f = kfilt.m = 0;
- else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
- croak("bad filter string `%s'", kfiltstr);
- RETVAL = CREATE(key_data);
- if (!key_copy(RETVAL, kd, &kfilt)) {
+ if ((kd->e & KF_ENCMASK) != KENC_ENCRYPT)
+ croak("not encrypted");
+ RETVAL = CREATE(Key_DataImpl);
+ p = SvPV(key, len);
+ if ((rc = key_unlock(RETVAL, kd, p, len)) != 0) {
DESTROY(RETVAL);
+ keyerr(rc);
RETVAL = 0;
}
OUTPUT:
RETVAL
-Key_Data *
+Key_DataImpl *
plock(kd, tag)
- Key_Data *kd
+ Key_DataImpl *kd
char *tag
+ PREINIT:
+ int rc;
CODE:
- RETVAL = CREATE(Key_Data);
- if (key_plock(tag, kd, RETVAL)) {
+ if ((kd->e & KF_ENCMASK) == KENC_ENCRYPT)
+ croak("already encrypted");
+ RETVAL = CREATE(Key_DataImpl);
+ if ((rc = key_plock(tag, kd, RETVAL)) != 0) {
DESTROY(RETVAL);
+ keyerr(rc);
RETVAL = 0;
}
OUTPUT:
RETVAL
-Key_Data *
+Key_DataImpl *
punlock(kd, tag)
- Key_Data *kd
+ Key_DataImpl *kd
char *tag
+ PREINIT:
+ int rc;
CODE:
- RETVAL = CREATE(Key_Data);
- if (key_punlock(tag, kd, RETVAL)) {
+ if ((kd->e & KF_ENCMASK) != KENC_ENCRYPT)
+ croak("not encrypted");
+ RETVAL = CREATE(Key_DataImpl);
+ if ((rc = key_punlock(tag, kd, RETVAL)) != 0) {
DESTROY(RETVAL);
+ keyerr(rc);
RETVAL = 0;
}
OUTPUT:
RETVAL
-Key_Data *
+void
read(me, p)
SV *me
char *p
- CODE:
- RETVAL = CREATE(key_data);
- if (key_read(p, RETVAL, 0)) {
- DESTROY(RETVAL);
- RETVAL = 0;
+ PREINIT:
+ key_data *kd;
+ char *pp;
+ PPCODE:
+ kd = CREATE(key_data);
+ if (key_read(p, kd, &pp))
+ DESTROY(kd);
+ else {
+ XPUSHs(RET(kd, "Catacomb::Key::DataImpl"));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(pp, strlen(pp))));
}
- OUTPUT:
- RETVAL
SV *
-write(kd, kfiltstr = 0)
- Key_Data *kd
- char *kfiltstr
+write(kd, kf = 0)
+ Key_DataImpl *kd
+ Key_Filter *kf
PREINIT:
- key_filter kfilt;
dstr d = DSTR_INIT;
CODE:
- if (!kfiltstr)
- kfilt.f = kfilt.m = 0;
- else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
- croak("bad filter string `%s'", kfiltstr);
- if (key_write(kd, &d, &kfilt))
- RETVAL = newSVpv(d.buf, d.len);
+ if (key_write(kd, &d, kf))
+ RETVAL = newSVpvn(d.buf, d.len);
else
RETVAL = &PL_sv_undef;
dstr_destroy(&d);
OUTPUT:
RETVAL
-Key_Data *
+Key_DataImpl *
decode(me, sv)
SV *me
SV *sv
RETVAL
SV *
-encode(kd, kfiltstr = 0)
- Key_Data *kd
- char *kfiltstr
+encode(kd, kf = 0)
+ Key_DataImpl *kd
+ Key_Filter *kf
PREINIT:
- key_filter kfilt;
dstr d = DSTR_INIT;
CODE:
- if (!kfiltstr)
- kfilt.f = kfilt.m = 0;
- else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
- croak("bad filter string `%s'", kfiltstr);
- if (key_encode(kd, &d, &kfilt))
- RETVAL = newSVpv(d.buf, d.len);
+ if (key_encode(kd, &d, kf))
+ RETVAL = newSVpvn(d.buf, d.len);
else
RETVAL = &PL_sv_undef;
dstr_destroy(&d);
OUTPUT:
RETVAL
+MODULE = Catacomb PACKAGE = Catacomb::Key::StructIter
+
+SV *
+next(i)
+ Key_StructIter *i
+ PREINIT:
+ key_struct *s;
+ CODE:
+ if ((s = sym_next(i)) == 0)
+ XSRETURN_UNDEF;
+ RETVAL = newSVpvn(SYM_NAME(s), SYM_LEN(s));
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(i)
+ Key_StructIter *i
+ CODE:
+ DESTROY(i);
+ XSRETURN_YES;
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data
+
+void
+readflags(me, p)
+ SV *me
+ char *p
+ PREINIT:
+ unsigned f, m;
+ PPCODE:
+ if (key_readflags(p, &p, &f, &m) || *p)
+ croak("bad flags string");
+ XPUSHs(sv_2mortal(newSVuv(m)));
+ XPUSHs(sv_2mortal(newSVuv(f)));
+
+SV *
+getflags(me, f)
+ SV *me
+ U32 f
+ PREINIT:
+ dstr d = DSTR_INIT;
+ CODE:
+ key_writeflags(f, &d);
+ RETVAL = newSVpvn(d.buf, d.len);
+ dstr_destroy(&d);
+ OUTPUT:
+ RETVAL
+
MODULE = Catacomb PACKAGE = Catacomb::Key::File PREFIX = key_
Key_File *
-new(me, file, how)
+new(me, file, how = KOPEN_READ, report = &PL_sv_undef)
SV *me
char *file
unsigned how
+ SV *report
CODE:
RETVAL = CREATE(key_file);
- if (key_open(RETVAL, file, how, warn_keyreporter, 0)) {
+ if (key_open(&RETVAL->kf, file, how, keyreport, report)) {
DESTROY(RETVAL);
RETVAL = 0;
}
DESTROY(kf)
Key_File *kf
CODE:
- key_close(kf);
- DESTROY(kf);
+ keyfile_dec(kf);
XSRETURN_UNDEF;
KeyErr
-merge(kf, name, fp)
+merge(kf, name, fp, report = &PL_sv_undef)
Key_File *kf
char *name
FILE *fp
+ SV *report
CODE:
- RETVAL = key_merge(kf, name, fp, warn_keyreporter, 0);
+ RETVAL = key_merge(&kf->kf, name, fp, keyreport, report);
OUTPUT:
RETVAL
bool
-extract(kf, k, fp, kfiltstr = 0)
+key_extract(kf, k, fp, kfilt = 0)
Key_File *kf
Key *k
FILE *fp
- char *kfiltstr
- PREINIT:
- key_filter kfilt;
- CODE:
- if (!kfiltstr)
- kfilt.f = kfilt.m = 0;
- else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
- croak("bad filter string `%s'", kfiltstr);
- RETVAL = key_extract(kf, k->k, fp, &kfilt);
- OUTPUT:
- RETVAL
+ Key_Filter *kfilt
+ C_ARGS:
+ &kf->kf, k->k, fp, kfilt
int
key_save(kf)
Key_File *kf
-
-void
-qtag(kf, tag)
- Key_File *kf
- char *tag
- PREINIT:
- dstr d = DSTR_INIT;
- Key *k;
- key_data *kd;
- PPCODE:
- k = CREATE(Key);
- kd = CREATE(key_data);
- if (key_qtag(kf, tag, &d, &k->k, &kd)) {
- DESTROY(k);
- DESTROY(kd);
- XPUSHs(&PL_sv_undef);
- XPUSHs(&PL_sv_undef);
- XPUSHs(&PL_sv_undef);
- } else {
- k->kf = kf;
- XPUSHs(sv_2mortal(newSVpv(d.buf, d.len)));
- XPUSHs(RET(k, "Catacomb::Key"));
- XPUSHs(RET(k, "Catacomb::Key::Data"));
- }
- dstr_destroy(&d);
+ C_ARGS:
+ &kf->kf
Key *
bytype(kf, type)
char *type
CODE:
RETVAL = CREATE(Key);
- if ((RETVAL->k = key_bytype(kf, type)) != 0)
+ if ((RETVAL->k = key_bytype(&kf->kf, type)) != 0) {
+ kf->ref++;
RETVAL->kf = kf;
- else {
+ } else {
DESTROY(RETVAL);
RETVAL = 0;
}
U32 id
CODE:
RETVAL = CREATE(Key);
- if ((RETVAL->k = key_byid(kf, id)) != 0)
+ if ((RETVAL->k = key_byid(&kf->kf, id)) != 0) {
+ kf->ref++;
RETVAL->kf = kf;
- else {
+ } else {
DESTROY(RETVAL);
RETVAL = 0;
}
char *tag
CODE:
RETVAL = CREATE(Key);
- if ((RETVAL->k = key_bytag(kf, tag)) != 0)
+ if ((RETVAL->k = key_bytag(&kf->kf, tag)) != 0) {
+ kf->ref++;
RETVAL->kf = kf;
- else {
+ } else {
DESTROY(RETVAL);
RETVAL = 0;
}
OUTPUT:
RETVAL
-void
-list(kf)
+Key *
+newkey(kf, id, type, exp)
Key_File *kf
+ U32 id
+ const char *type
+ time_t exp
PREINIT:
- key_iter i;
- key *k;
- Key *kk;
- PPCODE:
- for (key_mkiter(&i, kf); k = key_next(&i); ) {
- kk = CREATE(Key);
- kk->kf = kf;
- kk->k = k;
- XPUSHs(RET(kk, "Catacomb::Key"));
+ int err;
+ CODE:
+ RETVAL = CREATE(Key);
+ if ((RETVAL->k = key_new(&kf->kf, id, type, exp, &err)) == 0) {
+ DESTROY(RETVAL);
+ keyerr(err);
+ RETVAL = 0;
+ } else {
+ kf->ref++;
+ RETVAL->kf = kf;
+ }
+ OUTPUT:
+ RETVAL
+
+
+Key_FileIter *
+iterate(kf)
+ Key_File *kf
+ CODE:
+ RETVAL = CREATE(Key_FileIter);
+ key_mkiter(&RETVAL->i, &kf->kf);
+ RETVAL->kf = kf;
+ kf->ref++;
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::FileIter
+
+Key *
+next(ki)
+ Key_FileIter *ki
+ CODE:
+ RETVAL = CREATE(Key);
+ if ((RETVAL->k = key_next(&ki->i)) == 0) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ } else {
+ RETVAL->kf = ki->kf;
+ ki->kf->ref++;
}
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(ki)
+ Key_FileIter *ki
+ CODE:
+ keyfile_dec(ki->kf);
+ DESTROY(ki);
+ XSRETURN_YES;
#----- That's all, folks ----------------------------------------------------
/*----- Main code ---------------------------------------------------------*/
-void warn_keyreporter(const char *file, int line, const char *err, void *p)
+void keyreport(const char *file, int line, const char *err, void *p)
{
- warn("%s:%i: keyfile error: %s", file, line, err);
+ SV *sv = p;
+ dSP;
+
+ if (!SvOK(sv))
+ warn("%s:%i: keyfile error: %s", file, line, err);
+ else {
+ ENTER; SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv);
+ XPUSHs(sv_2mortal(newSVpv(file, 0)));
+ XPUSHs(sv_2mortal(newSViv(line)));
+ XPUSHs(sv_2mortal(newSVpv(err, 0)));
+ PUTBACK;
+
+ call_method("report", G_DISCARD | G_EVAL | G_KEEPERR);
+ if (SvTRUE(ERRSV)) {
+ STRLEN len;
+ warn("reporter raised error (ignoring): %s", SvPV(ERRSV, len));
+ }
+
+ FREETMPS; LEAVE;
+ }
}
SV *keyerr(int rc)
return (&PL_sv_undef);
}
+void keyfile_dec(Key_File *kf)
+{
+ kf->ref--;
+ if (!kf->ref) {
+ key_discard(&kf->kf);
+ DESTROY(kf);
+ }
+}
+
+
+
/*----- That's all, folks -------------------------------------------------*/
# ---?---
#
-# $Id: misc.xs,v 1.2 2004/04/08 01:36:21 mdw Exp $
+# $Id$
#
# Miscellaneous function interfaces
#
# along with Catacomb/Perl; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+MODULE = Catacomb PACKAGE = Catacomb::Share::GF PREFIX = gfshare_
+
+Share_GF *
+new(me, t, sz)
+ SV *me
+ UV t
+ UV sz
+ CODE:
+ RETVAL = CREATE(Share_GF);
+ if (t < 1 || t > 255)
+ croak("share threshhold out of range");
+ gfshare_create(RETVAL, t, sz);
+ OUTPUT:
+ RETVAL
+
+UV
+sz(s)
+ Share_GF *s
+ CODE:
+ RETVAL = s->sz;
+ OUTPUT:
+ RETVAL
+
+UV
+t(s)
+ Share_GF *s
+ CODE:
+ RETVAL = s->t;
+ OUTPUT:
+ RETVAL
+
+UV
+i(s)
+ Share_GF *s
+ CODE:
+ RETVAL = s->i;
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(s)
+ Share_GF *s
+ CODE:
+ gfshare_destroy(s);
+ DESTROY(s);
+ XSRETURN_YES;
+
+SV *
+mkshares(s, x, r = &rand_global)
+ Share_GF *s
+ SV *x
+ grand *r
+ PREINIT:
+ char *p;
+ STRLEN len;
+ CODE:
+ p = SvPV(x, len);
+ if (len != s->sz)
+ croak("secret length mismatch");
+ gfshare_mkshares(s, r, p);
+ s->i = ~0u;
+ XSRETURN_YES;
+
+SV *
+get(s, i)
+ Share_GF *s
+ UV i
+ CODE:
+ if (i >= 255)
+ croak("share index out of range");
+ if (s->i != ~0u)
+ croak("not making shares");
+ RETVAL = NEWSV(0, s->sz);
+ SvPOK_on(RETVAL);
+ gfshare_get(s, i, SvPVX(RETVAL));
+ SvCUR_set(RETVAL, s->sz);
+ OUTPUT:
+ RETVAL
+
+unsigned
+add(s, i, x)
+ Share_GF *s
+ UV i
+ SV *x
+ PREINIT:
+ char *p;
+ STRLEN len;
+ CODE:
+ p = SvPV(x, len);
+ if (len != s->sz)
+ croak("secret length mismatch");
+ if (i == ~0u)
+ croak("making shares");
+ if (i >= 255)
+ croak("share index out of range");
+ if (s->i >= s->t)
+ croak("too many shares");
+ RETVAL = gfshare_add(s, i, p);
+ OUTPUT:
+ RETVAL
+
+SV *
+combine(s)
+ Share_GF *s
+ CODE:
+ if (s->i == ~0u)
+ croak("making shares");
+ if (s->i != s->t)
+ croak("not enough shares yet");
+ RETVAL = NEWSV(0, s->sz);
+ SvPOK_on(RETVAL);
+ gfshare_combine(s, SvPVX(RETVAL));
+ SvCUR_set(RETVAL, s->sz);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Share::Prime PREFIX = share_
+
+Share_Prime *
+new(me, t, p = &PL_sv_undef)
+ SV *me
+ UV t
+ SV *p
+ CODE:
+ RETVAL = CREATE(Share_Prime);
+ if (t < 1 || t > MPW_MAX)
+ croak("share threshhold out of range");
+ share_create(RETVAL, t);
+ if (SvOK(p))
+ RETVAL->p = mp_fromsv(p, "p", 0, 1);
+ OUTPUT:
+ RETVAL
+
+mp *
+p(s)
+ Share_Prime *s
+ CODE:
+ if (!s->p)
+ XSRETURN_UNDEF;
+ RETVAL = MP_COPY(s->p);
+ OUTPUT:
+ RETVAL
+
+UV
+t(s)
+ Share_Prime *s
+ CODE:
+ RETVAL = s->t;
+ OUTPUT:
+ RETVAL
+
+UV
+i(s)
+ Share_Prime *s
+ CODE:
+ RETVAL = s->i;
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(s)
+ Share_Prime *s
+ CODE:
+ share_destroy(s);
+ DESTROY(s);
+ XSRETURN_YES;
+
+SV *
+mkshares(s, x, r = &rand_global)
+ Share_Prime *s
+ mp *x
+ grand *r
+ CODE:
+ if (s->p && MP_CMP(s->p, <=, x))
+ croak("secret out of range");
+ share_mkshares(s, r, x);
+ s->i = ~0u;
+ XSRETURN_YES;
+
+mp *
+share_get(s, i)
+ Share_Prime *s
+ UV i
+ INIT:
+ if (i >= MPW_MAX)
+ croak("share index out of range");
+ if (s->i != ~0u)
+ croak("not making shares");
+ C_ARGS:
+ s, MP_NEW, i
+
+unsigned
+share_add(s, i, x)
+ Share_Prime *s
+ UV i
+ mp *x
+ INIT:
+ if (!s->p)
+ croak("no prime set");
+ if (i == ~0u)
+ croak("making shares");
+ if (i >= MPW_MAX)
+ croak("share index out of range");
+ if (s->i >= s->t)
+ croak("too many shares");
+ C_ARGS:
+ s, i, x
+
+mp *
+share_combine(s)
+ Share_Prime *s
+ INIT:
+ if (s->i == ~0u)
+ croak("making shares");
+ if (s->i != s->t)
+ croak("not enough shares yet");
+
MODULE = Catacomb PACKAGE = Catacomb::Passphrase
SV *
char *tag
CODE:
passphrase_cancel(tag);
- XSRETURN_UNDEF;
+ XSRETURN_YES;
MODULE = Catacomb PACKAGE = Catacomb::KeySize
OUTPUT:
RETVAL
+void
+expand(ksz)
+ keysize *ksz
+ PREINIT:
+ int i;
+ PPCODE:
+ switch (ksz[0]) {
+ case KSZ_ANY:
+ XPUSHs(sv_2mortal(newSVpv("ANY", 0)));
+ XPUSHs(sv_2mortal(newSViv(ksz[1])));
+ break;
+ case KSZ_RANGE:
+ XPUSHs(sv_2mortal(newSVpv("RANGE", 0)));
+ for (i = 1; i < 5; i++)
+ XPUSHs(sv_2mortal(newSViv(ksz[i])));
+ break;
+ case KSZ_SET:
+ XPUSHs(sv_2mortal(newSVpv("SET", 0)));
+ for (i = 1; ksz[i]; i++)
+ XPUSHs(sv_2mortal(newSViv(ksz[i])));
+ break;
+ default:
+ abort();
+ }
+
#----- That's all, folks ----------------------------------------------------
SV *sv
int radix
CODE:
- RETVAL = sv ? mp_fromsv(sv, "sv",
- "Catacomb::MP", radix, 1) : MP_ZERO;
+ RETVAL = sv ? mp_fromsv(sv, "sv", radix, 1) : MP_ZERO;
OUTPUT:
RETVAL
OUTPUT:
RETVAL
+mp *
+loadb2c(me, sv)
+ SV *me
+ SV *sv
+ PREINIT:
+ char *p;
+ STRLEN len;
+ CODE:
+ p = SvPV(sv, len);
+ RETVAL = mp_loadb2c(MP_NEW, p, len);
+ OUTPUT:
+ RETVAL
+
+mp *
+loadl2c(me, sv)
+ SV *me
+ SV *sv
+ PREINIT:
+ char *p;
+ STRLEN len;
+ CODE:
+ p = SvPV(sv, len);
+ RETVAL = mp_loadl2c(MP_NEW, p, len);
+ OUTPUT:
+ RETVAL
+
int
metrics(m)
mp *m
XSINTERFACE_FUNC
XSINTERFACE_FUNC_SETMP
INTERFACE:
- octets bits
+ octets bits octets2c
SV *
storeb(m, i = -1)
PREINIT:
size_t sz;
CODE:
- sz = (i < 0) ? mp_octets(m) : i;
+ if (i >= 0)
+ sz = i;
+ else {
+ sz = mp_octets(m);
+ if (!sz)
+ sz = 1;
+ }
RETVAL = NEWSV(0, sz ? sz : 1);
mp_storeb(m, SvPVX(RETVAL), sz);
SvCUR_set(RETVAL, sz);
RETVAL
SV *
+storeb2c(m, i = -1)
+ mp *m
+ int i
+ PREINIT:
+ size_t sz;
+ CODE:
+ sz = (i < 0) ? mp_octets2c(m) : i;
+ RETVAL = NEWSV(0, sz ? sz : 1);
+ mp_storeb(m, SvPVX(RETVAL), sz);
+ SvCUR_set(RETVAL, sz);
+ SvPOK_on(RETVAL);
+ OUTPUT:
+ RETVAL
+
+SV *
+storel2c(m, i = -1)
+ mp *m
+ int i
+ PREINIT:
+ size_t sz;
+ CODE:
+ sz = (i < 0) ? mp_octets2c(m) : i;
+ RETVAL = NEWSV(0, sz ? sz : 1);
+ mp_storel(m, SvPVX(RETVAL), sz);
+ SvCUR_set(RETVAL, sz);
+ SvPOK_on(RETVAL);
+ OUTPUT:
+ RETVAL
+
+SV *
tostring(m, radix = 10)
mp *m
int radix
OUTPUT:
RETVAL
+void
+fromstring(me, s, radix = 10)
+ SV *me
+ SV *s
+ int radix
+ PREINIT:
+ mptext_stringctx ms;
+ STRLEN len;
+ mp *x;
+ PPCODE:
+ ms.buf = SvPV(s, len);
+ ms.lim = ms.buf + len;
+ x = mp_read(MP_NEW, radix, &mptext_stringops, &ms);
+ if (x) {
+ XPUSHs(RET_MP(x));
+ if (GIMME_V == G_ARRAY)
+ XPUSHs(sv_2mortal(newSVpvn(ms.buf, ms.lim - ms.buf)));
+ }
+
SV *
toint(m)
mp *m
XSINTERFACE_FUNC
XSINTERFACE_FUNC_SETMP
INTERFACE:
- not sqr sqrt
+ not not2c sqr sqrt
mp *
neg(a)
XSINTERFACE_FUNC
XSINTERFACE_FUNC_SETMP
INTERFACE:
- add sub mul and2c or2c nand2c nor2c xor2c and or nand nor xor
+ add sub mul and2c or2c nand2c nor2c xor2c and or nand nor xor exp
mp *
shiftop(a, n)
mp_modsqrt(p, x)
mp *p
mp *x
+ INIT:
+ if (!MP_POSP(p) || !MP_ODDP(p))
+ croak("p is not positive and odd");
+ if (mp_jacobi(x, p) != 1)
+ croak("x not a quadratic residue mod p");
C_ARGS:
MP_NEW, x, p
case G_VOID:
break;
default:
- mp_div(&q, &r, a, b);
+ mp_div(&q, 0, a, b);
EXTEND(SP, 1);
PUSHs(RET_MP(q));
break;
PPCODE:
t = mp_odd(MP_NEW, m, &s);
EXTEND(SP, 2);
- PUSHs(RET_MP(t));
PUSHs(sv_2mortal(newSViv(s)));
+ PUSHs(RET_MP(t));
-int
-smallfactor(x)
- mp *x
- CODE:
- RETVAL = pfilt_smallfactor(x);
- OUTPUT:
- RETVAL
+MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pgen_
-MP_Reduce *
-makereduce(x)
+bool
+pgen_primep(x, r = &rand_global)
mp *x
- CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::makereduce must be positive");
- RETVAL = CREATE(MP_Reduce);
- mpreduce_create(RETVAL, x);
- OUTPUT:
- RETVAL
+ grand *r
-MP_Mont *
-mont(x)
- mp *x
- CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::mont must be positive");
- if (!MP_ODDP(x))
- croak("Argument to Catacomb::MP::mont must be odd");
- RETVAL = CREATE(MP_Mont);
- mpmont_create(RETVAL, x);
- OUTPUT:
- RETVAL
+MODULE = Catacomb PACKAGE = Catacomb::MP PREFIX = pfilt_
-MP_Barrett *
-barrett(x)
+int
+pfilt_smallfactor(x)
mp *x
- CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::barrett must be positive");
- RETVAL = CREATE(mpbarrett);
- mpbarrett_create(RETVAL, x);
- OUTPUT:
- RETVAL
-
-MP_Prime_Rabin *
-rabin(x)
- mp *x
- CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::rabin must be positive");
- if (!MP_ODDP(x))
- croak("Argument to Catacomb::MP::rabin must be odd");
- RETVAL = CREATE(MP_Prime_Rabin);
- rabin_create(RETVAL, x);
- OUTPUT:
- RETVAL
MODULE = Catacomb PACKAGE = Catacomb::MP::Mont PREFIX = mpmont_
SV *me
mp *x
CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::Mont::new must be positive");
- if (!MP_ODDP(x))
- croak("Argument to Catacomb::MP::Mont::new must be odd");
- RETVAL = CREATE(MP_Mont);
- mpmont_create(RETVAL, x);
+ RETVAL = CREATE(MP_Mont);
+ if (mpmont_create(RETVAL, x)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
OUTPUT:
RETVAL
mm, MP_NEW, x, y
mp *
+in(mm, x)
+ MP_Mont *mm
+ mp *x
+ CODE:
+ RETVAL = MP_NEW;
+ mp_div(0, &RETVAL, x, mm->m);
+ RETVAL = mpmont_mul(mm, RETVAL, RETVAL, mm->r2);
+ OUTPUT:
+ RETVAL
+
+mp *
mpmont_expr(mm, g, x)
MP_Mont *mm
mp *g
n = (items - 1)/2;
v = xmalloc(n * sizeof(mp_expfactor));
for (i = 1, j = 0; i < items; i += 2, j++) {
- v[j].base = mp_fromsv(ST(i), "g_i", "Catacomb::MP", 0, 0);
- v[j].exp = mp_fromsv(ST(i + 1), "x_i", "Catacomb::MP", 0, 0);
+ v[j].base = mp_fromsv(ST(i), "g_i", 0, 0);
+ v[j].exp = mp_fromsv(ST(i + 1), "x_i", 0, 0);
}
RETVAL = mpmont_mexpr(mm, MP_NEW, v, n);
xfree(v);
n = (items - 1)/2;
v = xmalloc(n * sizeof(mp_expfactor));
for (i = 1, j = 0; i < items; i += 2, j++) {
- v[j].base = mp_fromsv(ST(i), "g_%lu",
- "Catacomb::MP", 0, 0, (unsigned long)i);
- v[j].exp = mp_fromsv(ST(i + 1), "x_%lu",
- "Catacomb::MP", 0, 0, (unsigned long)i);
+ v[j].base = mp_fromsv(ST(i), "g_%lu", 0, 0, (unsigned long)i);
+ v[j].exp = mp_fromsv(ST(i + 1), "x_%lu", 0, 0, (unsigned long)i);
}
RETVAL = mpmont_mexp(mm, MP_NEW, v, n);
xfree(v);
SV *me
mp *x
CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::Barrett::new must be positive");
RETVAL = CREATE(mpbarrett);
- mpbarrett_create(RETVAL, x);
+ if (mpbarrett_create(RETVAL, x)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
OUTPUT:
RETVAL
SV *me
mp *x
CODE:
- if (!MP_POSP(x))
- croak("Argument to Catacomb::MP::Reduce::new must be positive");
- RETVAL = CREATE(mpreduce);
- mpreduce_create(RETVAL, x);
+ RETVAL = CREATE(MP_Reduce);
+ if (mpreduce_create(RETVAL, x)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
OUTPUT:
RETVAL
v = xmalloc(n * sizeof(mpcrt_mod));
for (i = 0; i < n; i++) {
v[i].m = mp_copy(mp_fromsv(ST(i + 1), "n_%lu",
- "Catacomb::MP", 0, 0,
- (unsigned long)i));
+ 0, 0, (unsigned long)i));
+ v[i].n = v[i].ni = v[i].nni = 0;
}
RETVAL = CREATE(MP_CRT);
mpcrt_create(RETVAL, v, n, 0);
OUTPUT:
RETVAL
+mp *
+product(mc)
+ MP_CRT *mc
+ CODE:
+ RETVAL = MP_COPY(mc->mb.m);
+ OUTPUT:
+ RETVAL
+
+void
+moduli(mc)
+ MP_CRT *mc
+ PREINIT:
+ size_t n, i;
+ PPCODE:
+ n = mc->k;
+ if (GIMME_V == G_SCALAR)
+ XPUSHs(sv_2mortal(newSViv(n)));
+ else for (i = 0; i < n; i++)
+ XPUSHs(RET_MP(MP_COPY(mc->v[i].m)));
+
SV *
DESTROY(mc)
MP_CRT *mc
n = mc->k;
if (items - 1 != n)
croak("Wrong number of residues for this CRT context");
- for (i = 0; i < n; i++) {
- v[i] = mp_fromsv(ST(i + 1), "r_%lu", "Catacomb::MP",
- 0, 0, (unsigned long)i);
- }
+ v = xmalloc(n * sizeof(mp *));
+ for (i = 0; i < n; i++)
+ v[i] = mp_fromsv(ST(i + 1), "r_%lu", 0, 0, (unsigned long)i);
RETVAL = mpcrt_solve(mc, MP_NEW, v);
xfree(v);
OUTPUT:
return (m);
}
+int group_writesv(group *g, ge *x, SV *sv)
+{
+ mptext_svctx c;
+ int rc;
+ STRLEN len;
+ sv_setpvn(sv, "", 0);
+ c.sv = sv;
+ rc = G_WRITE(g, x, &mptext_svops, &c);
+ return (rc);
+}
+
int mp_writesv(mp *m, SV *sv, int radix)
{
mptext_svctx c;
int rc;
STRLEN len;
- SvPV(sv, len);
+ sv_setpvn(sv, "", 0);
c.sv = sv;
rc = mp_write(m, radix, &mptext_svops, &c);
return (rc);
/* --- Conversion to and from SVs --- */
-mp *mp_fromsv(SV *sv, const char *what, const char *ty,
- int radix, int keep, ...)
+mp *mp_fromsv(SV *sv, const char *what, int radix, int keep, ...)
{
mp *m;
if (SvROK(sv)) {
SV *t = sv_newmortal();
va_start(ap, keep);
sv_vsetpvfn(t, what, strlen(what), &ap, 0, 0, 0);
- croak("%s is not of type %s", SvPVX(t), ty);
+ croak("%s is not of type Catacomb::MP", SvPVX(t));
}
if (m && keep)
MP_COPY(m);
else
m = mp_readsv(MP_NEW, sv, 0, radix);
if (m && !keep)
- RET(m, ty); /* Kill temporary later */
+ RET_MP(m); /* Kill temporary later */
}
return (m);
}
# -*-fundamental-*-
#
-# $Id: pgen.xs,v 1.2 2004/04/08 01:36:21 mdw Exp $
+# $Id$
#
# Prime generation gubbins
#
U32 a
CODE:
if (m > MPW_MAX)
- croak("multiplier too large in Catacomb::MP::Prime::Filter::muladd");
+ croak("multiplier too large");
if (a > MPW_MAX)
- croak("step too large in Catacomb::MP::Prime::Filter::muladd");
+ croak("step too large");
RETVAL = CREATE(MP_Prime_Filter);
RETVAL->rc = pfilt_muladd(&RETVAL->pf, &pf->pf, m, a);
OUTPUT:
U32 n
CODE:
if (n > MPW_MAX)
- croak("step too large in Catacomb::MP::Prime::Filter::step");
+ croak("step too large");
RETVAL = pf->rc = pfilt_step(&pf->pf, n);
OUTPUT:
RETVAL
SV *me
mp *x
CODE:
- if (x->f & MP_NEG)
- croak("Argument to Catacomb::MP::Prime::Rabin must be positive");
- if (x->v == x->vl || !(x->v[0] & 1u))
- croak("Argument to Catacomb::MP::Prime::Rabin must be odd");
RETVAL = CREATE(MP_Prime_Rabin);
- rabin_create(RETVAL, x);
+ if (rabin_create(RETVAL, x)) {
+ DESTROY(RETVAL);
+ RETVAL = 0;
+ }
OUTPUT:
RETVAL
MP_Prime_Rabin *r
mp *g
+mp *
+m(r)
+ MP_Prime_Rabin *r
+ CODE:
+ RETVAL = MP_COPY(r->mm.m);
+ OUTPUT:
+ RETVAL
+
int
rabin_iters(r)
MP_Prime_Rabin *r
mp_bits(r->mm.m)
int
-ntests(bits)
+ntests(me, bits)
+ SV *me
int bits
CODE:
RETVAL = rabin_iters(bits);
OUTPUT:
RETVAL
+int
+PG_BEGIN(me, ev)
+ SV *me
+ MP_Prime_Gen_Event *ev
+ ALIAS:
+ PG_TRY = 0
+ PG_PASS = 1
+ PG_FAIL = 2
+ PG_ABORT = 3
+ PG_DONE = 4
+ CODE:
+ RETVAL = 0;
+ OUTPUT:
+ RETVAL
+
MODULE = Catacomb PACKAGE = Catacomb::MP::Prime
mp *
-gen(name, m, steps, stepper, tests, tester, events = &PL_sv_undef)
+gen(me, name, m, steps, stepper, tests, tester, events = &PL_sv_undef)
+ SV *me
char *name
mp *m
MP_Prime_Gen_NullProc *events
RETVAL
void
-strongprime_setup(name, bits, r = &rand_global, n = 0, events = &PL_sv_undef)
+strongprime_setup(me, name, bits, r = &rand_global, n = 0, events = &PL_sv_undef)
+ SV *me
char *name
unsigned bits
grand *r
j = CREATE(MP_Prime_Gen_JumpStepper);
d = strongprime_setup(name, MP_NEW, &j->pf, bits, r, n, ev, ectx);
EXTEND(SP, 2);
- if (!d) {
+ if (!d)
DESTROY(j);
- PUSHs(&PL_sv_undef);
- PUSHs(&PL_sv_undef);
- } else {
+ else {
j->j.j = &j->pf;
j->mg.p = pgen_jump;
j->mg.ctx = &j->j;
}
void
-limlee(name, qbits, pbits, r = &rand_global, on = 0, oevents = &PL_sv_undef, ievents = &PL_sv_undef)
+limlee(me, name, qbits, pbits, r = &rand_global, on = 0, oevents = &PL_sv_undef, ievents = &PL_sv_undef)
+ SV *me
char *name
unsigned qbits
unsigned pbits
if (GIMME_V == G_SCALAR) {
x = limlee(name, MP_NEW, MP_NEW, qbits, pbits, r, on,
oev, oec, iev, iec, 0, 0);
+ if (!x) return;
EXTEND(SP, 1);
PUSHs(RET_MP(x));
} else {
x = limlee(name, MP_NEW, MP_NEW, qbits, pbits, r, on,
oev, oec, iev, iec, &nf, &f);
+ if (!x) return;
EXTEND(SP, 1 + nf);
PUSHs(RET_MP(x));
for (i = 0; i < nf; i++)
RETVAL
mp *
-mp(ev, m = 0)
+m(ev, x = &PL_sv_undef)
MP_Prime_Gen_Event *ev
- mp *m
+ SV *x
+ PREINIT:
+ mp *y;
CODE:
RETVAL = mp_copy(ev->m);
- if (items > 1) {
+ if (SvOK(x)) {
+ if ((y = mp_fromsv(x, "x", 0, 1)) == 0)
+ croak("bad integer");
mp_drop(ev->m);
- ev->m = mp_copy(m);
+ ev->m = y;
}
OUTPUT:
RETVAL
+int
+steps(ev)
+ MP_Prime_Gen_Event *ev
+ CODE:
+ RETVAL = ev->steps;
+ OUTPUT:
+ RETVAL
+
+int
+tests(ev)
+ MP_Prime_Gen_Event *ev
+ CODE:
+ RETVAL = ev->tests;
+ OUTPUT:
+ RETVAL
+
SV *
rand(ev)
MP_Prime_Gen_Event *ev
/* -*-c-*-
*
- * $Id: pgproc.c,v 1.2 2004/04/08 01:36:21 mdw Exp $
+ * $Id$
*
* Prime generation procedures
*
dSP;
switch (rq) {
- case PGEN_BEGIN: meth = "pgen_begin"; break;
- case PGEN_TRY: meth = "pgen_try"; break;
- case PGEN_FAIL: meth = "pgen_fail"; break;
- case PGEN_PASS: meth = "pgen_pass"; break;
- case PGEN_DONE: meth = "pgen_done"; break;
- case PGEN_ABORT: meth = "pgen_abort"; break;
+ case PGEN_BEGIN: meth = "PG_BEGIN"; break;
+ case PGEN_TRY: meth = "PG_TRY"; break;
+ case PGEN_FAIL: meth = "PG_FAIL"; break;
+ case PGEN_PASS: meth = "PG_PASS"; break;
+ case PGEN_DONE: meth = "PG_DONE"; break;
+ case PGEN_ABORT: meth = "PG_ABORT"; break;
default:
abort();
}
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv);
- XPUSHs(sv_setref_pv(sv_newmortal(), "Catacomb::MP::Prime::Gen::Event",
- (void *)e));
+ XPUSHs(RET(e, "Catacomb::MP::Prime::Gen::Event"));
PUTBACK;
n = perl_call_method(meth, G_SCALAR);
assert(n == 1);
--- /dev/null
+# ---?---
+#
+# $Id$
+#
+# Key-management interface
+#
+# (c) 2001 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.
+
+MODULE = Catacomb PACKAGE = Catacomb::PubKey
+
+void
+gen_dh(me, ql, pl, steps = 0, r = &rand_global, events = &PL_sv_undef)
+ SV *me
+ unsigned ql
+ unsigned pl
+ unsigned steps
+ grand *r
+ MP_Prime_Gen_NullProc *events
+ PREINIT:
+ dh_param dp;
+ pgen_proc *evproc;
+ void *evctx;
+ PPCODE:
+ pgproc_get(events, &evproc, &evctx);
+ if (dh_gen(&dp, ql, pl, steps, r, evproc, evctx))
+ XSRETURN_EMPTY;
+ XPUSHs(RET_MP(dp.p));
+ XPUSHs(RET_MP(dp.g));
+ XPUSHs(RET_MP(dp.q));
+
+void
+gen_limlee(me, ql, pl, flags = 0, steps = 0, r = &rand_global, oevents = &PL_sv_undef, ievents = &PL_sv_undef)
+ SV *me
+ unsigned ql
+ unsigned pl
+ unsigned flags
+ unsigned steps
+ grand *r
+ MP_Prime_Gen_NullProc *oevents
+ MP_Prime_Gen_NullProc *ievents
+ PREINIT:
+ dh_param dp;
+ pgen_proc *oev, *iev;
+ void *oec, *iec;
+ size_t nf;
+ mp **f;
+ size_t i;
+ PPCODE:
+ pgproc_get(oevents, &oev, &oec);
+ pgproc_get(ievents, &iev, &iec);
+ if (dh_limlee(&dp, ql, pl, flags, steps, r,
+ oev, oec, iev, iec, &nf, &f))
+ XSRETURN_EMPTY;
+ XPUSHs(RET_MP(dp.p));
+ XPUSHs(RET_MP(dp.g));
+ XPUSHs(RET_MP(dp.q));
+ for (i = 0; i < nf; i++)
+ XPUSHs(RET_MP(f[i]));
+ xfree(f);
+
+void
+gen_dsa(me, ql, pl, steps = 0, k = &PL_sv_undef, events = &PL_sv_undef)
+ SV *me
+ unsigned ql
+ unsigned pl
+ unsigned steps
+ SV *k
+ MP_Prime_Gen_NullProc *events
+ PREINIT:
+ char *kp;
+ STRLEN ksz;
+ dsa_seed ds;
+ dsa_param dp;
+ pgen_proc *evproc;
+ void *evctx;
+ char buf[20];
+ PPCODE:
+ if (SvOK(k))
+ kp = SvPV(k, ksz);
+ else {
+ kp = buf;
+ ksz = 20;
+ rand_get(RAND_GLOBAL, kp, ksz);
+ }
+ pgproc_get(events, &evproc, &evctx);
+ if (dsa_gen(&dp, ql, pl, steps, kp, ksz, &ds, evproc, evctx))
+ XSRETURN_EMPTY;
+ XPUSHs(RET_MP(dp.p));
+ XPUSHs(RET_MP(dp.g));
+ XPUSHs(RET_MP(dp.q));
+ XPUSHs(sv_2mortal(newSVpvn(ds.p, ds.sz)));
+ XPUSHs(sv_2mortal(newSViv(ds.count)));
+ xfree(ds.p);
+
+MODULE = Catacomb PACKAGE = Catacomb::DSA
+
+ghash *
+beginhash(c)
+ SV *c
+ PREINIT:
+ gdsa g;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ RETVAL = gdsa_beginhash(&g);
+ OUTPUT:
+ RETVAL
+
+SV *
+endhash(c, h)
+ SV *c
+ ghash *h
+ PREINIT:
+ gdsa g;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ gdsa_endhash(&g, h);
+ XSRETURN_YES;
+
+MODULE = Catacomb PACKAGE = Catacomb::DSA::Private
+
+void
+sign(c, m, k = 0)
+ SV *c
+ SV *m
+ mp *k
+ PREINIT:
+ gdsa g;
+ gdsa_sig s = GDSA_SIG_INIT;
+ char *p;
+ STRLEN len;
+ PPCODE:
+ gdsa_privfromsv(&g, c);
+ p = SvPV(m, len);
+ if (len != g.h->hashsz)
+ croak("bad message length");
+ gdsa_sign(&g, &s, p, k);
+ XPUSHs(MAKE_MP(s.r));
+ XPUSHs(MAKE_MP(s.s));
+
+MODULE = Catacomb PACKAGE = Catacomb::DSA::Public
+
+bool
+verify(c, m, r, s)
+ SV *c
+ mp *r
+ mp *s
+ SV *m
+ PREINIT:
+ gdsa g;
+ gdsa_sig ss = GDSA_SIG_INIT;
+ char *p;
+ STRLEN len;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ p = SvPV(m, len);
+ if (len != g.h->hashsz)
+ croak("bad message length");
+ ss.r = r;
+ ss.s = s;
+ RETVAL = !gdsa_verify(&g, &ss, p);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::KCDSA
+
+ghash *
+beginhash(c)
+ SV *c
+ PREINIT:
+ gkcdsa g;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ RETVAL = gkcdsa_beginhash(&g);
+ OUTPUT:
+ RETVAL
+
+SV *
+endhash(c, h)
+ SV *c
+ ghash *h
+ PREINIT:
+ gkcdsa g;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ gkcdsa_endhash(&g, h);
+ XSRETURN_YES;
+
+MODULE = Catacomb PACKAGE = Catacomb::KCDSA::Private
+
+void
+sign(c, m, k = 0)
+ SV *c
+ SV *m
+ mp *k
+ PREINIT:
+ gkcdsa g;
+ gkcdsa_sig s = GKCDSA_SIG_INIT;
+ char *p;
+ STRLEN len;
+ PPCODE:
+ gdsa_privfromsv(&g, c);
+ p = SvPV(m, len);
+ if (len != g.h->hashsz)
+ croak("bad message length");
+ gkcdsa_sign(&g, &s, p, k);
+ XPUSHs(sv_2mortal(newSVpvn(s.r, g.h->hashsz)));
+ XPUSHs(RET_MP(s.s));
+ xfree(s.r);
+
+MODULE = Catacomb PACKAGE = Catacomb::KCDSA::Public
+
+bool
+verify(c, m, r, s)
+ SV *c
+ SV *r
+ mp *s
+ SV *m
+ PREINIT:
+ gkcdsa g;
+ gkcdsa_sig ss = GKCDSA_SIG_INIT;
+ char *p;
+ STRLEN len;
+ CODE:
+ gdsa_pubfromsv(&g, c);
+ p = SvPV(m, len);
+ if (len != g.h->hashsz)
+ croak("bad message length");
+ ss.r = SvPV(r, len);
+ if (len != g.h->hashsz)
+ croak("bad signature (r) length");
+ ss.s = s;
+ RETVAL = !gkcdsa_verify(&g, &ss, p);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::Public PREFIX = rsa_
+
+RSA_Public *
+new(me, sv)
+ SV *me
+ SV *sv
+ PREINIT:
+ cursor c;
+ rsa_pub *rp;
+ CODE:
+ rp = CREATE(rsa_pub);
+ c_init(&c, sv);
+ rp->n = C_MP(&c, "n");
+ rp->e = C_MP(&c, "e");
+ RETVAL = CREATE(rsa_pubctx);
+ rsa_pubcreate(RETVAL, rp);
+ OUTPUT:
+ RETVAL
+
+mp *
+n(rp)
+ RSA_Public *rp
+ CODE:
+ RETVAL = MP_COPY(rp->rp->n);
+ OUTPUT:
+ RETVAL
+
+HV *
+extract(rp)
+ RSA_Public *rp
+ CODE:
+ RETVAL = newHV();
+ hvput(RETVAL, "n", MAKE_MP(rp->rp->n));
+ hvput(RETVAL, "e", MAKE_MP(rp->rp->e));
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(rp)
+ RSA_Public *rp
+ PREINIT:
+ rsa_pub *rrp;
+ CODE:
+ rrp = rp->rp;
+ rsa_pubdestroy(rp);
+ DESTROY(rp);
+ rsa_pubfree(rrp);
+ DESTROY(rrp);
+ XSRETURN_YES;
+
+mp *
+op(rp, p)
+ RSA_Public *rp
+ mp *p
+ CODE:
+ RETVAL = rsa_pubop(rp, MP_NEW, p);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::Private PREFIX = rsa_
+
+RSA_Private *
+new(me, sv)
+ SV *me
+ SV *sv
+ PREINIT:
+ cursor c;
+ rsa_priv *rp;
+ CODE:
+ c_init(&c, sv);
+ rp = CREATE(rsa_priv);
+ rp->n = C_MP(&c, "n");
+ rp->e = C_MP(&c, "e");
+ rp->d = C_MP(&c, "d");
+ rp->p = C_MP(&c, "p");
+ rp->q = C_MP(&c, "q");
+ rp->dp = C_MP(&c, "dp");
+ rp->dq = C_MP(&c, "dq");
+ rp->q_inv = C_MP(&c, "qi");
+ if (rsa_recover(rp))
+ croak("insuffcient values in Catacomb::RSA::Private::new");
+ RETVAL = CREATE(rsa_privctx);
+ rsa_privcreate(RETVAL, rp, &rand_global);
+ OUTPUT:
+ RETVAL
+
+RSA_Private *
+generate(me, nbits, r = &rand_global, n = 0, events = &PL_sv_undef)
+ SV *me
+ unsigned nbits
+ grand *r
+ unsigned n
+ MP_Prime_Gen_NullProc *events
+ PREINIT:
+ pgen_proc *ev;
+ void *ec;
+ rsa_priv *rp;
+ CODE:
+ rp = CREATE(rsa_priv);
+ pgproc_get(events, &ev, &ec);
+ if (rsa_gen(rp, nbits, r, n, ev, ec)) {
+ DESTROY(rp);
+ XSRETURN_UNDEF;
+ }
+ RETVAL = CREATE(rsa_privctx);
+ rsa_privcreate(RETVAL, rp, &rand_global);
+ OUTPUT:
+ RETVAL
+
+HV *
+extract(rp)
+ RSA_Private *rp
+ CODE:
+ RETVAL = newHV();
+ hvput(RETVAL, "n", MAKE_MP(rp->rp->n));
+ hvput(RETVAL, "e", MAKE_MP(rp->rp->e));
+ hvput(RETVAL, "d", MAKE_MP(rp->rp->d));
+ hvput(RETVAL, "p", MAKE_MP(rp->rp->p));
+ hvput(RETVAL, "q", MAKE_MP(rp->rp->q));
+ hvput(RETVAL, "dp", MAKE_MP(rp->rp->dp));
+ hvput(RETVAL, "dq", MAKE_MP(rp->rp->dq));
+ hvput(RETVAL, "qi", MAKE_MP(rp->rp->q_inv));
+ OUTPUT:
+ RETVAL
+
+mp *
+n(rp)
+ RSA_Private *rp
+ CODE:
+ RETVAL = MP_COPY(rp->rp->n);
+ OUTPUT:
+ RETVAL
+
+SV *
+DESTROY(rp)
+ RSA_Private *rp
+ PREINIT:
+ rsa_priv *rrp;
+ CODE:
+ rp->r = &rand_global;
+ rrp = rp->rp;
+ rsa_privdestroy(rp);
+ DESTROY(rp);
+ rsa_privfree(rrp);
+ DESTROY(rrp);
+ XSRETURN_YES;
+
+mp *
+op(rp, p, r = &PL_sv_undef)
+ RSA_Private *rp
+ mp *p
+ SV *r
+ CODE:
+ rp->r = SvOK(r) ? ptrfromsv(r, "Catacomb::Rand", "r") : 0;
+ RETVAL = rsa_privop(rp, MP_NEW, p);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::PKCS1Crypt
+
+mp *
+pad(c, m, sz, nbits)
+ SV *c
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pkcs1 pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ CODE:
+ pkcs1_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ RETVAL = pkcs1_cryptencode(MP_NEW, mm, msz, b, sz, nbits, &pc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+SV *
+unpad(c, m, sz, nbits)
+ SV *c
+ mp *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pkcs1 pc;
+ void *b;
+ int rc;
+ CODE:
+ pkcs1_fromsv(&pc, c);
+ b = xmalloc(sz);
+ rc = pkcs1_cryptdecode(m, b, sz, nbits, &pc);
+ if (rc < 0)
+ RETVAL = &PL_sv_undef;
+ else
+ RETVAL = newSVpvn(b, rc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::PKCS1Sign
+
+mp *
+pad(c, m, sz, nbits)
+ SV *c
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pkcs1 pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ CODE:
+ pkcs1_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ RETVAL = pkcs1_sigencode(MP_NEW, mm, msz, b, sz, nbits, &pc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+SV *
+unpad(c, s, m, sz, nbits)
+ SV *c
+ mp *s
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pkcs1 pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ int rc;
+ CODE:
+ pkcs1_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ rc = pkcs1_sigdecode(s, mm, msz, b, sz, nbits, &pc);
+ if (rc < 0) XSRETURN_UNDEF;
+ RETVAL = newSVpvn(b, rc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::OAEP
+
+mp *
+pad(c, m, sz, nbits)
+ SV *c
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ oaep pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ CODE:
+ oaep_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ RETVAL = oaep_encode(MP_NEW, mm, msz, b, sz, nbits, &pc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+SV *
+unpad(c, m, sz, nbits)
+ SV *c
+ mp *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ oaep pc;
+ void *b;
+ int rc;
+ CODE:
+ oaep_fromsv(&pc, c);
+ b = xmalloc(sz);
+ rc = oaep_decode(m, b, sz, nbits, &pc);
+ if (rc < 0)
+ RETVAL = &PL_sv_undef;
+ else
+ RETVAL = newSVpvn(b, rc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::RSA::PSS
+
+mp *
+pad(c, m, sz, nbits)
+ SV *c
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pss pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ CODE:
+ pss_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ RETVAL = pss_encode(MP_NEW, mm, msz, b, sz, nbits, &pc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+SV *
+unpad(c, s, m, sz, nbits)
+ SV *c
+ mp *s
+ SV *m
+ size_t sz
+ unsigned long nbits
+ PREINIT:
+ pss pc;
+ void *b;
+ void *mm;
+ STRLEN msz;
+ int rc;
+ CODE:
+ pss_fromsv(&pc, c);
+ mm = SvPV(m, msz);
+ b = xmalloc(sz);
+ rc = pss_decode(s, mm, msz, b, sz, nbits, &pc);
+ if (rc < 0) XSRETURN_UNDEF;
+ RETVAL = newSVpvn(b, rc);
+ xfree(b);
+ OUTPUT:
+ RETVAL
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+#! /usr/bin/perl
+
+use Catacomb qw(:random);
+use Getopt::Long qw(:config gnu_getopt);
+
+$help = 0;
+$dict = undef;
+GetOptions("dict=s" => \$dict, "help" => \$help) or exit 1;
+
+DICT: {
+ last DICT if defined $dict;
+ $dict = $ENV{"DICT"}; last DICT if defined $dict;
+ $dict = "/usr/share/dict/words"; last DICT if -r $dict;
+ -r $dict or $dict = "/usr/dict/words"; last DICT if -r $dict;
+ die "no appropriate word list";
+}
+open DICT, "$dict" or die "can't open $dict: $!";
+
+sub filter { 1; }
+$filter = shift();
+if (defined $filter) {
+ eval "sub filter { $filter };";
+ die $@ if $@;
+}
+
+$rng = Catacomb::Rand::Counter->new("blowfish", $random->fill(32));
+
+$word = undef;
+$i = 1;
+WORD: while (<DICT>) {
+ chomp();
+ next WORD unless filter;
+ $rng->range($i) == 0 and $word = $_;
+ $i++;
+}
+close DICT;
+print "$word\n";
+
--- /dev/null
+# -*-mode: perl; comment-column: 68-*-
+use Test;
+BEGIN { plan tests => 19; }
+use Catacomb qw(:const mp);
+
+sub dumphash {
+ my ($n, $h) = @_;
+ print "# $n\n";
+ foreach my $k (keys %$h) {
+ print "# $k -> $h->{$k}\n";
+ }
+}
+
+sub checkhash {
+ my ($t, $r) = @_;
+ my @t = sort keys(%$t);
+ my @r = sort keys(%$r);
+ unless (@t == @r) {
+ print "# key count: ", scalar(@t), " != ", scalar(@r), "\n";
+ dumphash "t", $t;
+ dumphash "r", $r;
+ return undef;
+ }
+ for (my $i = 0; $i < @t; $i++) {
+ unless ($t[$i] eq $r[$i] && $t->{$t[$i]} eq $r->{$r[$i]}) {
+ print "# hash: $t[$i] -> $t->{$t[$i]} != $r[$i] -> $r->{$r[$i]}\n";
+ dumphash "t", $t;
+ dumphash "r", $r;
+ return undef;
+ }
+ }
+ return 1;
+}
+
+# Simple stuff
+$f = Catacomb::Key::File->new("keyring"); ok defined $f; #t 1
+$k = $f->bytag("tux"); ok defined $k; #t 2
+$d = $k->data(); ok defined $d; #t 3
+ok $d->flags() == KENC_STRUCT; #t 4
+$h = $d->structopen();
+ok exists $h->{"p"}; #t 5
+ok !exists $h->{"bogus"}; #t 6
+
+($C, undef, $r) =
+ Catacomb::EC::Curve->getinfo($h->{"curve"}->getstring());
+$p = $C->pt($h->{"p"}->getec());
+ok +($p * $r)->atinfp(); #t 7
+
+$h = $k->attrs;
+ok checkhash $h, { #t 8
+ "hash" => "sha256",
+ "mac" => "sha256-hmac/128",
+ "cipher" => "blowfish-cbc"
+};
+
+
+($k, $d, $n) = $f->qtag("rsa.private");
+ok $k->type, "rsa"; #t 9
+ok $d->flags == KENC_ENCRYPT; #t 10
+ok $n, sprintf("%08x:rsa.private", $k->id); #t 11
+
+$h = $f->bytag("rsa")->data()->structfind("private")
+ ->unlock("pass")->structopen();
+ok defined $h; #t 12
+
+
+# Key data
+($kd, $rest) = Catacomb::Key::Data->read
+ ("struct:[p=integer,public:23,q=integer,public:11],zqzqv");
+ok $rest, ",zqzqv"; #t 13
+ok defined $kd; #t 14
+$h = $kd->structopen(); ok defined $h; #t 15
+ok $h->{"p"}->getmp() == 23; #t 16
+ok $h->{"q"}->getmp() == 11; #t 17
+$pkd = $kd->lock("passphrase");
+ok !defined $pkd->unlock("wrong"); #t 18
+$ukd = $pkd->unlock("passphrase"); ok defined $ukd; #t 19
--- /dev/null
+# -*-mode: perl; comment-column: 68-*-
+use Test;
+BEGIN { plan tests => 121; }
+use Catacomb qw(:const mp);
+
+# Addition
+ok mp("5") + mp("4") == mp("9"); #t 1
+ok mp("5") + mp("-4") == mp("1"); #t 2
+ok mp("-5") + mp("4") == mp("-1"); #t 3
+ok mp("-5") + mp("-4") == mp("-9"); #t 4
+ok mp("0xffffffff") + mp("1") == mp("0x100000000"); #t 5
+
+# Subtraction
+ok mp("5") - mp("4") == mp("1"); #t 6
+ok mp("5") - mp("-4") == mp("9"); #t 7
+ok mp("-5") - mp("4") == mp("-9"); #t 8
+ok mp("-5") - mp("-4") == mp("-1"); #t 9
+ok mp("4") - mp("5") == mp("-1"); #t 10
+ok mp("4") - mp("-5") == mp("9"); #t 11
+ok mp("-4") - mp("5") == mp("-9"); #t 12
+ok mp("-4") - mp("-5") == mp("1"); #t 13
+
+# Squaring
+ok mp("5")->sqr() == mp("25"); #t 14
+ok mp("-5")->sqr() == mp("25"); #t 15
+ok mp("56309812098453")->sqr()==mp("3170794938563083851364993209"); #t 16
+
+# Multiplication
+ok mp("5") * mp("4") == mp("20"); #t 17
+ok mp("5") * mp("-4") == mp("-20"); #t 18
+ok mp("-5") * mp("4") == mp("-20"); #t 19
+ok mp("-5") * mp("-4") == mp("20"); #t 20
+ok mp("0x10000") * mp("0x10000") == mp("0x100000000"); #t 21
+
+# Division
+sub divtest {
+ my ($x, $y, $q, $r) = @_;
+ my ($qq, $rr) = Catacomb::MP::div($x, $y);
+ ok $qq == $q && $rr == $r;
+}
+divtest "9", "4", "2", "1"; #t 22
+divtest "-9", "4", "-3", "3"; #t 23
+divtest "9", "-4", "-3", "-3"; #t 24
+divtest "-9", "-4", "2", "-1"; #t 25
+divtest #t 26
+ "-3", "6277101735386680763835789423207666416083908700390324961279",
+ "-1", "6277101735386680763835789423207666416083908700390324961276";
+divtest #t 27
+ "3131675836296406071791252329528905062261497366991742517193",
+ "1110875761630725856340142297645383444629395595869672555585",
+ "2", "909924313034954359110967734238138173002706175252397406023";
+divtest #t 28
+ "3131675836296406071791252329528905062261497366991742517193", "53",
+ "59088223326347284373419855274130284193613157867768726739", "26";
+ok mp("-9") / mp("-4") == mp("2"); #t 29
+ok mp("-9") % mp("-4") == mp("-1"); #t 30
+
+# Exponentiation
+ok mp("4") ** mp("0") == mp("1"); #t 31
+ok mp("4") ** mp("1") == mp("4"); #t 32
+ok mp("7") ** mp("2") == mp("49"); #t 33
+ok mp("3") ** mp("64") == mp("3433683820292512484657849089281"); #t 34
+
+# Bit ops tests
+ok ~mp("6") == mp("-7"); #t 35
+ok ~mp("-7") == mp("6"); #t 36
+
+ok +(mp("5") & mp("3")) == mp("1"); #t 37
+ok +(mp("5") | mp("3")) == mp("7"); #t 38
+ok +(mp("5") ^ mp("3")) == mp("6"); #t 39
+ok +(mp("45") | mp("-7")) == mp("-3"); #t 40
+ok +(mp("0x343cd5") ^ mp("-0x6a49c")) == mp("-0x32984f"); #t 41
+
+ok +(mp("-1") >> 5) == mp("-1"); #t 42
+ok +(mp("1") >> 5) == mp("0"); #t 43
+ok +(mp("-6") >> 2) == mp("-2"); #t 44
+ok +(mp("5") >> 0) == mp("5"); #t 45
+ok +(mp("-4") >> 0) == mp("-4"); #t 46
+ok +(mp("7") >> 2) == mp("1"); #t 47
+ok +(mp("-7") >> 2) == mp("-2"); #t 48
+ok +(mp("-7") >> 20) == mp("-1"); #t 49
+
+ok +(mp("-1") << 5) == mp("-32"); #t 50
+ok +(mp("5") << 0) == mp("5"); #t 51
+ok +(mp("-4") << 0) == mp("-4"); #t 52
+ok +(mp("7") << 2) == mp("28"); #t 53
+ok +(mp("-7") << 2) == mp("-28"); #t 54
+ok +(mp("0xc0000000") << 1) == mp("0x180000000"); #t 55
+ok +(mp("-0xc0000000") << 1) == mp("-0x180000000"); #t 56
+ok +(mp("-1") << 32) == mp("-0x100000000"); #t 57
+
+ok mp("0")->setbit2c(40) == mp("0x10000000000"); #t 58
+ok mp("0x87348")->setbit2c(40) == mp("0x10000087348"); #t 59
+ok mp("5")->setbit2c(1) == mp("7"); #t 60
+ok mp("7")->setbit2c(1) == mp("7"); #t 61
+ok mp("-3")->setbit2c(1) == mp("-1"); #t 62
+
+ok mp("0x10000000000")->clearbit2c(40) == mp("0"); #t 63
+ok mp("0x87348")->clearbit2c(40) == mp("0x87348"); #t 64
+ok mp("5")->clearbit2c(1) == mp("5"); #t 65
+ok mp("7")->clearbit2c(1) == mp("5"); #t 66
+ok mp("-1")->clearbit2c(1) == mp("-3"); #t 67
+
+# Negation
+ok -mp("0") == mp("0"); #t 68
+ok -mp("15") == mp("-15"); #t 69
+ok -mp("-15") == mp("15"); #t 70
+
+# Extraction of even powers
+sub oddtest {
+ my ($x, $s, $t) = @_;
+ my ($ss, $tt) = mp($x)->odd();
+ ok $ss == $s && $tt == $t;
+}
+oddtest "1", 0, "1"; #t 71
+oddtest "2", 1, "1"; #t 72
+oddtest "4", 2, "1"; #t 73
+oddtest "12", 2, "3"; #t 74
+oddtest "0x10000000000000", 52, "1"; #t 75
+oddtest "0x10000000400000", 22, "0x40000001"; #t 76
+
+# Integer square root
+ok mp("0")->sqrt() == mp("0"); #t 77
+ok mp("1")->sqrt() == mp("1"); #t 78
+ok mp("4")->sqrt() == mp("2"); #t 79
+ok mp("9")->sqrt() == mp("3"); #t 80
+ok mp("16")->sqrt() == mp("4"); #t 81
+ok mp("99")->sqrt() == mp("9"); #t 82
+ok mp("100")->sqrt() == mp("10"); #t 83
+ok mp("101")->sqrt() == mp("10"); #t 84
+ok mp("120")->sqrt() == mp("10"); #t 85
+ok mp("121")->sqrt() == mp("11"); #t 86
+ok mp("10106623487257186586")->sqrt() == mp("3179091613"); #t 87
+ok mp("14565040310136678240")->sqrt() == mp("3816417208"); #t 88
+
+# Greatest common divisor
+
+ok Catacomb::MP::gcd("16", "12") == mp("4"); #t 89
+ok mp("90980984098081324")->modinv("4398082908043") == #t 90
+ mp("58497120524729235");
+
+sub gcdtest {
+ my ($u, $v, $g, $x, $y) = @_;
+ my ($gg, $xx, $yy) = Catacomb::MP::gcd($u, $v);
+ ok $g == $gg && $x == $xx && $y == $yy;
+}
+gcdtest "16", "12", "4", "-11", "15"; #t 91
+gcdtest "12", "16", "4", "-1", "1"; #t 92
+gcdtest "693", "609", "21", "-7", "8"; #t 93
+gcdtest #t 94
+ "4398082908043", "90980984098081324",
+ "1", "-32483863573352089", "1570292150447";
+
+gcdtest "16", "-12", "4", "-11", "-15"; #t 95
+gcdtest "-16", "12", "4", "11", "15"; #t 96
+gcdtest "-12", "-16", "4", "1", "-1"; #t 97
+gcdtest "-12", "16", "4", "1", "1"; #t 98
+gcdtest "-693", "609", "21", "7", "8"; #t 99
+gcdtest "693", "-609", "21", "-7", "-8"; #t 100
+
+gcdtest "15", "0", "15", "1", "0"; #t 101
+gcdtest "0", "15", "15", "0", "1"; #t 102
+gcdtest "-5", "0", "5", "-1", "0"; #t 103
+gcdtest "0", "-5", "5", "0", "-1"; #t 104
+gcdtest "0", "0", "0", "0", "0"; #t 105
+
+gcdtest #t 106
+ "829561629303257626084392170900075",
+ "32498098450983560651904114638965",
+ "5",
+ "-29340810037249902802634060204608",
+ "748967211613630574419802053172497";
+
+# Jacobi symbol
+ok mp("5")->jac("4") == 1; #t 107
+ok mp("7")->jac("6") == -1; #t 108
+ok mp("27")->jac("15") == 0; #t 109
+ok mp("98729378979237498798347932749951") #t 110
+ ->jac("2132498039840981") == 1;
+
+# Modular square-root
+sub modsqrttest {
+ my ($p, $x, $r) = @_;
+ my $rr = mp($p)->modsqrt($x);
+ ok $rr == $r || $rr == mp($p) - $r;
+}
+modsqrttest "3", "1", "1"; #t 111
+modsqrttest "5", "4", "3"; #t 112
+modsqrttest #t 113
+ "13391974640168007623", "9775592058107450692", "3264570455655810730";
+
+# Factorial
+ok +Catacomb::MP->factorial(0) == mp("1"); #t 114
+ok +Catacomb::MP->factorial(5) == mp("120"); #t 115
+ok +Catacomb::MP->factorial(30) == #t 116
+ mp("265252859812191058636308480000000");
+
+# Parsing
+sub parsetest {
+ my ($str, $rx, $x, $r) = @_;
+ my ($xx, $rr) = Catacomb::MP->fromstring($str, $rx);
+ ok defined($x) ? ($xx == $x && $rr eq $r) : !defined($xx);
+}
+parsetest "0", 10, mp("0"), ""; #t 117
+parsetest "0z", 10, mp("0"), "z"; #t 118
+parsetest "z", 10, undef, ""; #t 119
+parsetest "8_27785", 0, mp("191"), "85"; #t 120
+parsetest "8_27785", 10, mp("8"), "_27785"; #t 121
--- /dev/null
+# -*-mode: perl; comment-column: 68-*-
+use Test;
+BEGIN { plan tests => 11; }
+use Catacomb qw(:const $random);
+
+$sec = $random->mp(256);
+$sh = Catacomb::Share::Prime->new(3);
+ok $sh->t == 3; #t 1
+ok !defined $sh->p; #t 2
+@sh = ();
+$sh->mkshares($sec);
+$p = $sh->p();
+ok defined $p; #t 3
+for (my $i = 0; $i < 5; $i++) {
+ $sh[$i] = $sh->get($i);
+}
+$sh = Catacomb::Share::Prime->new(3, $p);
+ok $sh->p == $p; #t 4
+$sh->add(2, $sh[2]);
+ok $sh->add(4, $sh[4]) == 1; #t 5
+ok $sh->i == 2; #t 6
+$sh->add(1, $sh[1]);
+$r = $sh->combine();
+ok $r == $sec; #t 7
+undef $sec;
+undef $sh;
+undef @sh;
+undef $p;
+undef $r;
+
+$sec = $random->fill(16);
+$sh = Catacomb::Share::GF->new(3, 16);
+ok $sh->t == 3; #t 8
+ok $sh->sz == 16; #t 9
+@sh = ();
+$sh->mkshares($sec);
+for (my $i = 0; $i < 5; $i++) {
+ $sh[$i] = $sh->get($i);
+}
+$sh = Catacomb::Share::GF->new(3, 16);
+$sh->add(2, $sh[2]);
+ok $sh->add(3, $sh[3]) == 1; #t 10
+$sh->add(0, $sh[0]);
+$r = $sh->combine();
+ok $r, $sec; #t 11
+undef $sec;
+undef $sh;
+undef @sh;
+undef $r;
+++ /dev/null
-use Catacomb qw(:const);
-
-($c, $g, $r, $h) = Catacomb::EC::Curve->getinfo("secp160r1");
-print $g->atinfp(), ": ", $g->x, ", ", $g->y, "\n";
-$p = $c->mul($g, $r);
-print $p->atinfp(), "\n";
mp * T_MP
gf * T_MP
-GE * T_CATSTRUCT
-EC_Point * T_CATSTRUCT
EC_Curve * T_CATSTRUCT
EC_Info * T_CATSTRUCT
Field * T_CATSTRUCT
grand * T_GALG
keysize * T_KEYSZ
+fe * T_FIELDELT
+ec * T_ECPT
+ge * T_GROUPELT
+
Rand_True * T_CATSTRUCT
Rand_DSA * T_CATSTRUCT
+Share_GF * T_CATSTRUCT
+Share_Prime * T_CATSTRUCT
+
+PRP * T_CATSTRUCT
+PRPClass * T_CATSTRUCT
+
MP_Mont * T_CATSTRUCT
MP_Barrett * T_CATSTRUCT
MP_Mul * T_CATSTRUCT
MP_Prime_Gen_RabinTester * T_CATSTRUCT
Key_File * T_CATSTRUCT
-Key_Data * T_CATSTRUCT
+Key_DataImpl * T_CATSTRUCT
+Key_AttrIter * T_CATSTRUCT
+Key_StructIter * T_CATSTRUCT
+Key_FileIter * T_CATSTRUCT
+Key_Filter * T_CATSTRUCTUNDEF
Key * T_CATSTRUCT
-
KeyErr T_KEYERR
+RSA_Public * T_CATSTRUCT
+RSA_Private * T_CATSTRUCT
+
INPUT
T_MP
- $var = mp_fromsv($arg, \"$var\", \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::\U$1/; $ntt =~ s/_/::/g; \$ntt}\", 0, 0)
+ $var = mp_fromsv($arg, \"$var\", 0, 0)
T_CATSTRUCT
$var = ptrfromsv($arg, \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::$1/; $ntt =~ s/_/::/g; \$ntt}\", \"$var\")
+T_CATSTRUCTUNDEF
+ $var = SvOK($arg) ? ptrfromsv($arg, \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::$1/; $ntt =~ s/_/::/g; \$ntt}\", \"$var\") : 0
+T_FIELDELT
+ $var = fieldelt($arg, \"$var\")
+T_GROUPELT
+ $var = groupelt($arg, \"$var\")
+T_ECPT
+ $var = ecpt($arg, \"$var\")
T_GALG
$var = ptrfromsv($arg, \"${my $ntt = $ntype; $ntt =~ s/^g(.*)Ptr$/Catacomb::\u$1/; \$ntt}\", \"$var\")
T_GCALG
ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::\U$1/; $ntt =~ s/_/::/g; \$ntt}\");
T_CATSTRUCT
ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::$1/; $ntt =~ s/_/::/g; \$ntt}\");
+T_CATSTRUCTUNDEF
+ ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^(.*)Ptr$/Catacomb::$1/; $ntt =~ s/_/::/g; \$ntt}\");
+T_FIELDELT
+ ptrtosv(&$arg, $var, \"Catacomb::MP\");
+T_GROUPELT
+ ptrtosv(&$arg, $var, \"Catacomb::Group::Element\");
+T_ECPT
+ ptrtosv(&$arg, $var, \"Catacomb::EC::Point\");
T_GALG
ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^g(.*)Ptr$/Catacomb::\u$1/; \$ntt}\");
T_GCALG
- ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^g(.*)Ptr$/Catacomb::\u$1Class/; \$ntt}\");
+ ptrtosv(&$arg, $var, \"${my $ntt = $ntype; $ntt =~ s/^gc(.*)Ptr$/Catacomb::\u$1Class/; \$ntt}\");
T_KEYSZ
ptrtosv(&$arg, (octet *)$var, \"Catacomb::KeySize\");
T_PGENPROC
#include <catacomb/ec-guts.h>
#include <catacomb/group-guts.h>
#include <catacomb/field-guts.h>
+#include <catacomb/ectab.h>
+#include <catacomb/ptab.h>
+#include <catacomb/bintab.h>
-/*----- Main code ---------------------------------------------------------*/
+/*----- Lists of things ---------------------------------------------------*/
+
+#define LISTS(LI) \
+ LI(list, lists[i].name, lists[i].name) \
+ LI(hash, ghashtab[i], ghashtab[i]->name) \
+ LI(prp, prptab[i], prptab[i]->name) \
+ LI(cipher, gciphertab[i], gciphertab[i]->name) \
+ LI(mac, gmactab[i], gmactab[i]->name) \
+ LI(mgfrand, mgftab[i].name, mgftab[i].name) \
+ LI(counterrand, ctrtab[i].name, ctrtab[i].name) \
+ LI(ofbrand, ofbtab[i].name, ofbtab[i].name) \
+ LI(ec, ectab[i].name, ectab[i].name) \
+ LI(prime, ptab[i].name, ptab[i].name) \
+ LI(bin, bintab[i].name, bintab[i].name)
+
+#define XLISTFN(what, endp, name) \
+ static void list##what(void) \
+ { \
+ int i; \
+ dSP; \
+ for (i = 0; endp; i++) \
+ XPUSHs(sv_2mortal(newSVpv(name, 0))); \
+ PUTBACK; \
+ }
+
+#define ENTRY(what, endp, name) { #what, list##what },
+
+struct listent {
+ const char *name;
+ void (*list)(void);
+};
+
+static const struct listent lists[];
+
+LISTS(XLISTFN)
+
+static const struct listent lists[] = {
+ LISTS(ENTRY)
+ { 0, 0 }
+};
+
+void names(const char *name)
+{
+ int i;
+
+ for (i = 0; lists[i].name; i++) {
+ if (strcmp(name, lists[i].name) == 0) {
+ lists[i].list();
+ return;
+ }
+ }
+ croak("unknown list `%s'", name);
+}
+
+/*----- Miscellaneous things ----------------------------------------------*/
U32 findconst(const struct consttab *cc, const char *pkg, const char *name)
{
return (void *)SvIV((SV *)SvRV(sv));
}
+void *ptrfromsvdflt(SV *sv, const char *type, void *dflt, const char *what)
+{
+ if (!SvOK(sv))
+ return (dflt);
+ else
+ return (ptrfromsv(sv, type, "%s", what));
+}
+
+/*----- Cursor reading stuff ----------------------------------------------*/
+
+void c_init(cursor *c, SV *sv)
+{
+ if (!SvROK(sv))
+ croak("not a reference");
+ sv = SvRV(sv);
+ switch (SvTYPE(sv)) {
+ case SVt_PVAV:
+ c->f = CF_ARRAY;
+ c->u.a.av = (AV *)sv;
+ c->u.a.i = 0;
+ break;
+ case SVt_PVHV:
+ c->f = CF_HASH;
+ c->u.hv = (HV *)sv;
+ break;
+ default:
+ croak("must be hash ref or array ref");
+ }
+}
+
+void c_skip(cursor *c)
+{
+ if (!(c->f & CF_HASH))
+ c->u.a.i++;
+}
+
+SV *c_get(cursor *c, const char *tag, unsigned f)
+{
+ SV **sv;
+
+ if (c->f & CF_HASH)
+ sv = hv_fetch(c->u.hv, tag, strlen(tag), 0);
+ else {
+ sv = av_fetch(c->u.a.av, c->u.a.i, 0);
+ if (sv) c->u.a.i++;
+ }
+ if ((f & CF_MUST) && !sv)
+ croak("missing entry `%s'", tag);
+ return (sv ? *sv : &PL_sv_undef);
+}
+
+void hvput(HV *hv, const char *k, SV *val)
+{
+ SV **sv = hv_fetch(hv, k, strlen(k), 1);
+ if (!sv)
+ croak("couldn't set hash key %s", k);
+ *sv = val;
+}
+
+/*----- Wrapped objects ---------------------------------------------------*/
+
+static SV *firstelt(SV *sv, const char *what)
+{
+ AV *av;
+ SV **svp;
+
+ if (!SvROK(sv))
+ croak("%s is not a reference", what);
+ sv = SvRV(sv);
+ if (SvTYPE(sv) != SVt_PVAV)
+ croak("%s is not an array reference", what);
+ av = (AV *)sv;
+ svp = av_fetch(av, 0, 0);
+ if (!svp)
+ croak("%s is empty", what);
+ return (*svp);
+}
+
+ge *groupelt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::Group::Elt"))
+ sv = firstelt(sv, what);
+ return (ptrfromsv(sv, "Catacomb::Group::Element", what));
+}
+
+mp *fieldelt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::Field::Elt"))
+ sv = firstelt(sv, what);
+ return (mp_fromsv(sv, what, 0, 0));
+}
+
+ec *ecpt(SV *sv, const char *what)
+{
+ if (sv_derived_from(sv, "Catacomb::EC::Pt"))
+ sv = firstelt(sv, what);
+ return (ptrfromsv(sv, "Catacomb::EC::Point", what));
+}
+
+/*----- DSA contexts ------------------------------------------------------*/
+
+void gdsa_privfromsv(gdsa *g, SV *sv)
+{
+ cursor c;
+
+ c_init(&c, sv);
+ g->g = C_PTR(&c, "G", "Catacomb::Group");
+ g->p = C_GE(&c, "p");
+ g->u = C_MP(&c, "u");
+ g->h = C_PTR(&c, "h", "Catacomb::HashClass");
+ g->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void gdsa_pubfromsv(gdsa *g, SV *sv)
+{
+ cursor c;
+
+ c_init(&c, sv);
+ g->g = C_PTR(&c, "G", "Catacomb::Group");
+ g->p = C_GE(&c, "p");
+ c_skip(&c);
+ g->h = C_PTR(&c, "h", "Catacomb::HashClass");
+ g->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+/*----- RSA padding contexts ----------------------------------------------*/
+
+void pkcs1_fromsv(pkcs1 *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ t = c_get(&c, "ep", 0);
+ if (SvOK(t)) {
+ p->ep = SvPV(t, len);
+ p->epsz = len;
+ } else {
+ p->ep = 0;
+ p->epsz = 0;
+ }
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void oaep_fromsv(oaep *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ p->cc = C_PTR(&c, "c", "Catacomb::CipherClass");
+ p->ch = C_PTR(&c, "h", "Catacomb::HashClass");
+ t = c_get(&c, "ep", 0);
+ if (SvOK(t)) {
+ p->ep = SvPV(t, len);
+ p->epsz = len;
+ } else {
+ p->ep = 0;
+ p->epsz = 0;
+ }
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
+void pss_fromsv(pss *p, SV *sv)
+{
+ cursor c;
+ STRLEN len;
+ SV *t;
+
+ c_init(&c, sv);
+ p->cc = C_PTR(&c, "c", "Catacomb::CipherClass");
+ p->ch = C_PTR(&c, "h", "Catacomb::HashClass");
+ t = c_get(&c, "ssz", 0);
+ p->ssz = SvOK(t) ? SvUV(t) : p->ch->hashsz;
+ p->r = C_PTRDFLT(&c, "rng", "Catacomb::Rand", &rand_global);
+}
+
/*----- Reconstructing various objects ------------------------------------*/
+static SV *collect(SV *thing, ...)
+{
+ va_list ap;
+ AV *av;
+
+ va_start(ap, thing);
+ av = newAV();
+ while (thing) {
+ av_push(av, thing);
+ thing = va_arg(ap, SV *);
+ }
+ va_end(ap);
+ return (newRV_noinc((SV *)av));
+}
+
/* --- Somewhat unpleasant, really --- */
+SV *info_field(field *f)
+{
+ const char *n = F_NAME(f);
+
+ if (strcmp(n, "prime") == 0 || strcmp(n, "niceprime") == 0 ||
+ strcmp(n, "binpoly") == 0)
+ return (collect(newSVpv(n, 0), MAKE_MP(MP_COPY(f->m)), (SV *)0));
+ else if (strcmp(n, "binnorm") == 0) {
+ fctx_binnorm *fc = (fctx_binnorm *)f;
+ return (collect(newSVpv(n, 0),
+ MAKE_MP(MP_COPY(f->m)),
+ MAKE_MP(MP_COPY(fc->ntop.r[fc->ntop.n - 1])),
+ (SV *)0));
+ } else
+ return (&PL_sv_undef);
+}
+
field *copy_field(field *f)
{
if (strcmp(F_NAME(f), "prime") == 0)
return (f);
}
+SV *info_curve(ec_curve *c)
+{
+ field *f = c->f;
+ const char *n = EC_NAME(c);
+ SV *fsv;
+ mp *a, *b;
+
+ fsv = info_field(f);
+ if (!SvOK(fsv))
+ return (&PL_sv_undef);
+ a = F_OUT(f, MP_NEW, c->a);
+ b = F_OUT(f, MP_NEW, c->b);
+ if (strcmp(n, "prime") == 0 || strcmp(n, "primeproj") == 0 ||
+ strcmp(n, "bin") == 0 || strcmp(n, "binproj") == 0)
+ return (collect(newSVpv(n, 0), fsv, MAKE_MP(a), MAKE_MP(b), (SV *)0));
+ else {
+ MP_DROP(a);
+ MP_DROP(b);
+ SvREFCNT_dec(fsv);
+ return (&PL_sv_undef);
+ }
+}
+
ec_curve *copy_curve(ec_curve *c)
{
field *f;
c = ec_prime(f, a, b);
else if (strcmp(EC_NAME(c), "primeproj") == 0)
c = ec_primeproj(f, a, b);
- if (strcmp(EC_NAME(c), "bin") == 0)
+ else if (strcmp(EC_NAME(c), "bin") == 0)
c = ec_bin(f, a, b);
else if (strcmp(EC_NAME(c), "binproj") == 0)
c = ec_binproj(f, a, b);
return (c);
}
+SV *info_group(group *g)
+{
+ const char *n = G_NAME(g);
+
+ if (strcmp(n, "prime") == 0) {
+ gctx_prime *gc = (gctx_prime *)g;
+ return (collect(newSVpv(n, 0),
+ MAKE_MP(MP_COPY(gc->mm.m)),
+ MAKE_MP(G_TOINT(g, MP_NEW, g->g)),
+ MAKE_MP(MP_COPY(gc->g.r)),
+ (SV *)0));
+ } else if (strcmp(n, "bin") == 0) {
+ gctx_bin *gc = (gctx_bin *)g;
+ return (collect(newSVpv(n, 0),
+ MAKE_MP(MP_COPY(gc->r.p)),
+ MAKE_GF(G_TOINT(g, MP_NEW, g->g)),
+ MAKE_MP(MP_COPY(gc->g.r)),
+ (SV *)0));
+ } else if (strcmp(n, "ec") == 0) {
+ gctx_ec *gc = (gctx_ec *)g;
+ SV *csv = info_curve(gc->ei.c);
+ ec *gen;
+ if (!SvOK(csv))
+ return (&PL_sv_undef);
+ gen = CREATE(ec);
+ EC_CREATE(gen);
+ EC_COPY(gen, &gc->ei.g);
+ return (collect(newSVpv(n, 0),
+ csv,
+ MAKE(gen, "Catacomb::EC::Point"),
+ MAKE_MP(MP_COPY(gc->ei.r)),
+ MAKE_MP(MP_COPY(gc->ei.h)),
+ (SV *)0));
+ } else
+ return (&PL_sv_undef);
+}
+
group *copy_group(group *g)
{
if (strcmp(G_NAME(g), "prime") == 0) {
gp.q = gc->g.r;
g = group_prime(&gp);
MP_DROP(gp.g);
+ } else if (strcmp(G_NAME(g), "bin") == 0) {
+ gctx_bin *gc = (gctx_bin *)g;
+ gbin_param gb;
+ gb.g = G_TOINT(g, MP_NEW, g->g);
+ gb.p = gc->r.p;
+ gb.q = gc->g.r;
+ g = group_binary(&gb);
+ MP_DROP(gb.g);
} else if (strcmp(G_NAME(g), "ec") == 0) {
gctx_ec *gc = (gctx_ec *)g;
ec_info ei;