X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-perl/blobdiff_plain/f9952aec1cf6c64a5681308eea817b6113a37433..fcd15e0b7a3d0f0ca2f30953573f8d1f6b8e8bd2:/Catacomb::MP.pod diff --git a/Catacomb::MP.pod b/Catacomb::MP.pod new file mode 100644 index 0000000..59a1873 --- /dev/null +++ b/Catacomb::MP.pod @@ -0,0 +1,621 @@ +=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. Most standard arithmetic operators +are overloaded and do the Right Thing. See below for more details. + +Note that multiprecision integers are I. No operation can +change the value of an integer. + +=head2 Constructors + +=over + +=item Bnew(>iB<)> + +=item BIB<)> + +Return the multiprecision integer whose value is I. + +=item Bnew(>I, [I]B<)> + +=item BI, [I]B<)> + +Returns the multiprecision integer whose value is represented by +I, in the given I. If I is 0, as it is by +default, then I may have a prefix giving its radix: it may be +B<0> for octal, B<0x> for hex, or IB<_> for radix I. If the +argument is invalid, B is returned. + +=item Bloadb(>IB<)> + +=item Bloadl(>IB<)> + +=item BIB<)> + +=item BIB<)> + +Returns the multiprecision integer whose value is represented in big- or +little-endian base-256 form by I. This will always be +nonnegative. + +Returns the multiprecision integer whose value is represented in +little-endian base-256 form by I. This will always be +nonnegative. + +=item Bloadb2c(>IB<)> + +=item Bloadl2c(>IB<)> + +=item BIB<)> + +=item BIB<)> + +Returns the multiprecision integer whose value is represented in +two's complement big- or little-endian base-256 form by I. + +=item Bfromstring(>I, [I]B<)> + +=item BI, [I]B<)> + +Returns the multiprecision integer whose value is represented by +I, and (in a list context) the remainder of I. If +I is 0 then I may have a prefix, as for B. If +I is invalid, an empty list is returned. + +=back + +=head2 Methods + +The B package overloads the standard arithmetic +operators. As long as one operand is a B object, the +other may be any argument acceptable to B. As a special +exception, either argument to B<*> may be a B object, +to perform elliptic curve point multiplication. + +=over + +=item IB<-Eadd(>IB<)> + +=item IB<-Esub(>IB<)> + +=item IB<-Emul(>IB<)> + +=item IB<-Ediv(>IB<)> + +=item IB<-Emod(>IB<)> + +The basic algorithms. The argument I may be any value acceptable to +the B constructor. + +In an array context, the B method returns a two values: the +quotient and remainder. The quotient returned is the I 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 IB<-Esqr()> + +Returns the square of its argument. Usually faster than multiplying it +by itself. + +=item IB<-Eexp(>IB<)> + +Returns the result I^I. Theoretically, I can be a +multiprecision integer, but the result will be impossibly huge if this +is the case. The exponent I may not be negative. + +=item IB<-Esqrt()> + +Returns the integer square-root of I -- i.e., the largest integer +less than or equal to the true square root. + +=item IB<-Eeq(>IB<)> + +Returns true if I and I are equal; or false otherwise. + +=item IB<-Ecmp(>IB<)> + +Returns -1, 0 or +1 according to whether I is less than, equal to or +greater than I. + +=item IB<-Eand(>IB<)> + +=item IB<-Eand2c(>IB<)> + +=item IB<-Eor(>IB<)> + +=item IB<-Eor2c(>IB<)> + +=item IB<-Exor(>IB<)> + +=item IB<-Exor2c(>IB<)> + +=item IB<-Enand(>IB<)> + +=item IB<-Enand2c(>IB<)> + +=item IB<-Enor(>IB<)> + +=item IB<-Enor2c(>IB<)> + +=item IB<-Enot()> + +=item IB<-Enot2c()> + +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 IB<-Elsl(>IB<)> + +=item IB<-Elsl2c(>IB<)> + +=item IB<-Elsr(>IB<)> + +=item IB<-Elsr2c(>IB<)> + +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 IB<-Esetbit(>IB<)> + +=item IB<-Esetbit2c(>IB<)> + +=item IB<-Eclearbit(>IB<)> + +=item IB<-Eclearbit2c(>IB<)> + +Returns a copy of the argument I with bit I 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 IB<-Etestbit(>IB<)> + +=item IB<-Etestbit2c(>IB<)> + +Returns true or false according to whether I has bit I 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 IB<-Ecopy()> + +Returns a copy of I. Not useful: use assignment instead. + +=item IB<-Egcd(>IB<)> + +Returns the greatest common divisor of I and I. This will never +be negative. In a list context, it also returns two further results, +I and I: if the GCD is I then we have I I + I I = +I. Furthermore, I will have the same sign as I. + +=item IB<-Eodd()> + +Returns a pair of numbers I and I, so that I = I << I, +with I odd and I as large as possible. I will be +multiprecision; I will be a standard Perl integer. + +=item IB<-Emodexp(>IB<,> IB<)> + +Returns I^I mod I. + +=item IB<-Emodinv(>IB<)> + +Returns the inverse of I modulo I. If no inverse exists then +report an error. + +=item IB<-Emodsqrt(>IB<)> + +If I is prime, and I is a quadratic residue mod I, then return +a square root of I mod I. If I is not prime, does something +arbitrary; if I is a nonresidue then report an error. + +=item IB<-Ejac(>IB<)> + +Returns the Jacobi symbol (I/I). If I is prime, then this is +I^((I - 1)/2), i.e., 0 if I is a multiple of I, +1 if I +is a quadratic residue modulo I, or -1 if I is a quadratic +nonresidue mod I. + +=item IB<-Eprimep(>[I]I<)> + +Returns true or false, depending on whether I is (probably) prime. +If I is specified, it must be a random number generator -- see +Catacomb::Crypto(3). + +=item IB<-Ebits()> + +Returns the smallest number of bits required to represent the integer +I. + +=item IB<-Eoctets()> + +Returns the smallest number of bytes required to represent the integer +I, ignoring sign. + +=item IB<-Eoctets2c()> + +Returns the smallest number of bytes required to represent the integer +I as two's complement. This may be one greater than the result +returned by B in the case where the top bit of I is the top +bit of an octet. + +=item IB<-Estoreb(>[I]B<)> + +=item IB<-Estorel(>[I]B<)> + +Return (the absolute value of) I as a raw base-256 string in big- or +little-endian order. The returned string has length I, which +defaults to the smallest nonzero length necessary to represent the +argument. If I is too small, more significant bits are silently +discarded. The sign is ignored. + +=item IB<-Estoreb2c(>[I]B<)> + +=item IB<-Estorel2c(>[I]B<)> + +Return I as a raw two's complement base-256 string in big- or +little-endian order. The returned string has length I, which +defaults to the smallest nonzero length necessary to represent the +argument. If I 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 modulo 2^(8 I). + +=item IB<-Etostring(>[I]B<)> + +Return I expressed as a base-I string. The default I +is 10. The result may be preceded by a minus sign if I is negative. +No leading zeroes or other radix prefix are prepended. + +=item IB<-Etoint()> + +Returns I as a Perl integer. If I 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. + +=over + +=item Bnew(>IB<)> + +=item IB<-Ebarrett()> + +Create a new Barrett reduction context, set up for reducing modulo I. + +=item IB<-Em()> + +Returns the modulus stored in the reduction context I. + +=item IB<-Ereduce(>IB<)> + +Let I be the modulus stored in the reduction context I. Then, if +I is nonnegative and less then I^2, returns I mod I. +Otherwise the return value is undefined. + +=item IB<-Eexp(>IB<,> IB<)> + +Let I be the modulus stored in the reduction context I. Then +return I^I mod I. If I is negative then I must have an +inverse modulo I; 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 be the modulus in question. There is a value I which is +computed in some way from I. The Montgomery reduction operation, +given a number I, actually returns I I^(-1) mod I, which +doesn't sound useful. However, if you multiply all your numbers by a +factor of I then the cleverness becomes clear: if you reduce I +I I^2, you get I I I mod I. Indeed, there's an +efficient multiply-and-reduce operation which takes two operands, each +with a factor of I and returns a result with the factor of I. One +more reduction step drops off the final factor of I to give you the +real answer. Getting numbers into the required form involves +multiplying by I^2 mod I and reducing: conveniently, I^2 mod +I is precomputed. Addition and subtraction leave the factor of I +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^2 to fix the answer. + +If that all sounded too difficult, then you can use the B method to +convert to internal form, B to multiply numbers in internal form, +B and B to do modular exponentiation, and B to +convert the result to external form. + +The precomputed information used to perform Montgomery reduction are +stored in an object of type B. + +=over + +=item Bnew(>IB<)> + +=item IB<-Emont()> + +Constructs a Montgomery reduction context for reduction modulo I. +Returns B unless I is an odd positive integer. + +=item IB<-Er()> + +Returns the Montgomery reduction factor I. + +=item IB<-Er2()> + +Returns the Montgomerization factor I^2. + +=item IB<-Em()> + +Returns the modulus I. + +=item IB<-Ein(>IB<)> + +Returns the Montgomerized form of I, i.e., I I mod I. I +can be any integer. + +=item IB<-Emul(>IB<,> IB<)> + +Montgomery multiplication. If I and I are Montgomerized, then +returns their Montgomerized product; i.e., I I I^(-1) mod I. + +=item IB<-Eexpr(>IB<,> IB<)> + +Montgomery exponentiation. If I is Montgomerized, then returns the +Montgomerized value of I^I mod I; i.e., if I = I I, +it returns I^I I mod I. Here, if I is negative, then +I must have an inverse modulo I; otherwise there'll be a big mess. + +=item IB<-Emexpr(>IB<,> IB<,> IB<,> IB<,> ...B<)> + +Simultaneous Montgomery exponentiation. If the I are Montgomerized, +then returns the Montgomerized value of I^I I^I ... mod +I; i.e., if I = I I, it returns I^I I^I +... I mod I. Here, if some I is negative, then the +corresponding I must have an inverse modulo I; otherwise there'll +be a big mess. + +=item IB<-Ereduce(>IB<)> + +=item IB<-Eout(>IB<)> + +Returns the unMontgomerized form of I; i.e., I I^(-1) mod I. + +=item IB<-Eexpr(>IB<,> IB<)> + +Modular exponentiation. Returns I^I mod I. Here, if I is +negative, then I must have an inverse modulo I; otherwise there'll +be a big mess. + +=item IB<-Emexpr(>IB<,> IB<,> IB<,> IB<,> ...B<)> + +Simultaneous modular exponentiation. Returns I^I I^I +... mod I. Here, if some I is negative, then the corresponding +I must have an inverse modulo I; 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 - 2^I +/- 2^I +/- ... +/- 2^I + +=back + +where I > I > ... I, for small values of I. 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. + +=over + +=item Bnew(>IB<)> + +=item IB<-Emkreduce()> + +Create a new nice-modulus reduction context, set up for reducing modulo +I. + +=item IB<-Em()> + +Returns the modulus stored in the reduction context I. + +=item IB<-Ereduce(>IB<)> + +Let I be the modulus stored in the reduction context I. Then, if +I, returns I mod I. Otherwise the return value is undefined. + +=item IB<-Eexp(>IB<,> IB<)> + +Let I be the modulus stored in the reduction context I. Then +return I^I mod I. If I is negative then I must have an +inverse modulo I; 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 = I (mod I) using the Chinese Remainder Theorem (CRT). It +is required that the I be positive and pairwise relatively prime; +otherwise you'll get an unpleasant mess. + +=over + +=item Bnew(>IB<,> IB<,> ...B<)> + +Construct a new CRT solving context, for solving congruences mod the +I, and return it. + +=item IB<-Eproduct()> + +Returns the product of the moduli I. In a scalar context, return +the number of moduli. + +=item IB<-Emoduli()> + +Returns a list of the I, as passed to B. + +=item IB<-Esolve(>IB<,> IB<,>, ...B<)> + +Returns the unique answer I (modulo the product of the I) to the +congruences I = I (mod I). You will get an unhelpful answer +if any I >= I, and an error if you pass the wrong number of +I arguments. + +=back + +=head1 SEE ALSO + +Catacomb(3). + +=head1 AUTHOR + +Mark Wooding, +