ref: 7a7dfee4fab3e9a725422edff93251ef0a717492
dir: /libinterp/ipint.c/
#include "lib9.h"
#include "kernel.h"
#include <isa.h>
#include "interp.h"
#include "runt.h"
#include <mp.h>
#include <libsec.h>
#include "pool.h"
#include "ipint.h"
#include "raise.h"
#include "ipintsmod.h"
enum
{
MaxBigBytes = 1024
};
/* infinite precision integer */
struct IPint
{
IPints_IPint x;
mpint* b;
};
Type *TIPint;
static uchar IPintmap[] = IPints_IPint_map;
#define MP(x) checkIPint((x))
void
ipintsmodinit(void)
{
/* can be called from modinit, Keyring or Crypt */
if(TIPint == nil)
TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
builtinmod("$IPints", IPintsmodtab, IPintsmodlen);
}
//IPints_IPint*
void*
newIPint(mpint* b)
{
Heap *h;
IPint *ip;
if(b == nil)
error(exHeap);
h = heap(TIPint); /* TO DO: caller might lose other values if heap raises error here */
ip = H2D(IPint*, h);
ip->b = b;
return (IPints_IPint*)ip;
}
mpint*
checkIPint(void *a)
{
IPints_IPint *v;
IPint *ip;
v = a;
ip = (IPint*)v;
if(ip == H || ip == nil)
error(exNilref);
if(D2H(ip)->t != TIPint)
error(exType);
return ip->b; /* non-nil by construction */
}
void
freeIPint(Heap *h, int swept)
{
IPint *ip;
USED(swept);
ip = H2D(IPint*, h);
if(ip->b)
mpfree(ip->b);
freeheap(h, 0);
}
void
IPint_iptob64z(void *fp)
{
F_IPint_iptob64 *f;
mpint *b;
char buf[MaxBigBytes]; /* TO DO: should allocate these */
uchar *p;
int n, o;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
b = MP(f->i);
n = (b->top+1)*Dbytes;
p = malloc(n+1);
if(p == nil)
error(exHeap);
n = mptobe(b, p+1, n, nil);
if(n < 0){
free(p);
return;
}
p[0] = 0;
if(n != 0 && (p[1]&0x80)){
/* force leading 0 byte for compatibility with older representation */
o = 0;
n++;
}else
o = 1;
enc64(buf, sizeof(buf), p+o, n);
retstr(buf, f->ret);
free(p);
}
void
IPint_iptob64(void *fp)
{
F_IPint_iptob64 *f;
char buf[MaxBigBytes];
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
mptoa(MP(f->i), 64, buf, sizeof(buf));
retstr(buf, f->ret);
}
void
IPint_iptobytes(void *fp)
{
F_IPint_iptobytes *f;
uchar buf[MaxBigBytes];
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
/* TO DO: two's complement or have ipmagtobe? */
*f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil)); /* for now we'll ignore sign */
}
void
IPint_iptobebytes(void *fp)
{
F_IPint_iptobebytes *f;
uchar buf[MaxBigBytes];
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
*f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil));
}
void
IPint_iptostr(void *fp)
{
F_IPint_iptostr *f;
char buf[MaxBigBytes];
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
mptoa(MP(f->i), f->base, buf, sizeof(buf));
retstr(buf, f->ret);
}
static IPints_IPint*
strtoipint(String *s, int base)
{
char *p, *q;
mpint *b;
p = string2c(s);
b = strtomp(p, &q, base, nil);
if(b == nil)
return H;
while(*q == '=')
q++;
if(q == p || *q != 0){
mpfree(b);
return H;
}
return newIPint(b);
}
void
IPint_b64toip(void *fp)
{
F_IPint_b64toip *f;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
*f->ret = strtoipint(f->str, 64);
}
void
IPint_bytestoip(void *fp)
{
F_IPint_bytestoip *f;
mpint *b;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
if(f->buf == H)
error(exNilref);
b = betomp(f->buf->data, f->buf->len, nil); /* for now we'll ignore sign */
*f->ret = newIPint(b);
}
void
IPint_bebytestoip(void *fp)
{
F_IPint_bebytestoip *f;
mpint *b;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
if(f->mag == H)
error(exNilref);
b = betomp(f->mag->data, f->mag->len, nil);
*f->ret = newIPint(b);
}
void
IPint_strtoip(void *fp)
{
F_IPint_strtoip *f;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
*f->ret = strtoipint(f->str, f->base);
}
/* create a random integer */
void
IPint_random(void *fp)
{
F_IPint_random *f;
mpint *b;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
release();
b = mprand(f->nbits, genrandom, nil);
acquire();
*f->ret = newIPint(b);
}
/* number of bits in number */
void
IPint_bits(void *fp)
{
F_IPint_bits *f;
int n;
f = fp;
*f->ret = 0;
if(f->i == H)
return;
n = mpsignif(MP(f->i));
if(n == 0)
n = 1; /* compatibility */
*f->ret = n;
}
/* create a new IP from an int */
void
IPint_inttoip(void *fp)
{
F_IPint_inttoip *f;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
*f->ret = newIPint(itomp(f->i, nil));
}
void
IPint_iptoint(void *fp)
{
F_IPint_iptoint *f;
f = fp;
*f->ret = 0;
if(f->i == H)
return;
*f->ret = mptoi(MP(f->i));
}
/* modular exponentiation */
void
IPint_expmod(void *fp)
{
F_IPint_expmod *f;
mpint *ret, *mod, *base, *exp;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
base = MP(f->base);
exp = MP(f->exp);
if(f->mod != H)
mod = MP(f->mod);
else
mod = nil;
ret = mpnew(0);
if(ret != nil)
mpexp(base, exp, mod, ret);
*f->ret = newIPint(ret);
}
/* multiplicative inverse */
void
IPint_invert(void *fp)
{
F_IPint_invert *f;
mpint *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
ret = mpnew(0);
if(ret != nil)
mpinvert(MP(f->base), MP(f->mod), ret);
*f->ret = newIPint(ret);
}
/* basic math */
void
IPint_add(void *fp)
{
F_IPint_add *f;
mpint *i1, *i2, *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpadd(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_sub(void *fp)
{
F_IPint_sub *f;
mpint *i1, *i2, *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpsub(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_mul(void *fp)
{
F_IPint_mul *f;
mpint *i1, *i2, *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpmul(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_div(void *fp)
{
F_IPint_div *f;
mpint *i1, *i2, *quo, *rem;
void *v;
f = fp;
v = f->ret->t0;
f->ret->t0 = H;
destroy(v);
v = f->ret->t1;
f->ret->t1 = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
quo = mpnew(0);
if(quo == nil)
error(exHeap);
rem = mpnew(0);
if(rem == nil){
mpfree(quo);
error(exHeap);
}
mpdiv(i1, i2, quo, rem);
f->ret->t0 = newIPint(quo);
f->ret->t1 = newIPint(rem);
}
void
IPint_mod(void *fp)
{
F_IPint_mod *f;
mpint *i1, *i2, *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpmod(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_neg(void *fp)
{
F_IPint_neg *f;
mpint *ret;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
ret = mpcopy(MP(f->i));
if(ret == nil)
error(exHeap);
ret->sign = -ret->sign;
*f->ret = newIPint(ret);
}
/* copy */
void
IPint_copy(void *fp)
{
F_IPint_copy *f;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
*f->ret = newIPint(mpcopy(MP(f->i)));
}
/* equality */
void
IPint_eq(void *fp)
{
F_IPint_eq *f;
f = fp;
*f->ret = mpcmp(MP(f->i1), MP(f->i2)) == 0;
}
/* compare */
void
IPint_cmp(void *fp)
{
F_IPint_eq *f;
f = fp;
*f->ret = mpcmp(MP(f->i1), MP(f->i2));
}
/* shifts */
void
IPint_shl(void *fp)
{
F_IPint_shl *f;
mpint *ret, *i;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i = MP(f->i);
ret = mpnew(0);
if(ret != nil)
mpleft(i, f->n, ret);
*f->ret = newIPint(ret);
}
void
IPint_shr(void *fp)
{
F_IPint_shr *f;
mpint *ret, *i;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i = MP(f->i);
ret = mpnew(0);
if(ret != nil)
mpright(i, f->n, ret);
*f->ret = newIPint(ret);
}
static void
mpand(mpint *b, mpint *m, mpint *res)
{
int i;
res->sign = b->sign;
if(b->top == 0 || m->top == 0){
res->top = 0;
return;
}
mpbits(res, b->top*Dbits);
res->top = b->top;
for(i = b->top; --i >= 0;){
if(i < m->top)
res->p[i] = b->p[i] & m->p[i];
else
res->p[i] = 0;
}
mpnorm(res);
}
static void
mpor(mpint *b1, mpint *b2, mpint *res)
{
mpint *t;
int i;
if(b2->top > b1->top){
t = b1;
b1 = b2;
b2 = t;
}
if(b1->top == 0){
mpassign(b2, res);
return;
}
if(b2->top == 0){
mpassign(b1, res);
return;
}
mpassign(b1, res);
for(i = b2->top; --i >= 0;)
res->p[i] |= b2->p[i];
mpnorm(res);
}
static void
mpxor(mpint *b1, mpint *b2, mpint *res)
{
mpint *t;
int i;
if(b2->top > b1->top){
t = b1;
b1 = b2;
b2 = t;
}
if(b1->top == 0){
mpassign(b2, res);
return;
}
if(b2->top == 0){
mpassign(b1, res);
return;
}
mpassign(b1, res);
for(i = b2->top; --i >= 0;)
res->p[i] ^= b2->p[i];
mpnorm(res);
}
static void
mpnot(mpint *b1, mpint *res)
{
int i;
mpbits(res, Dbits*b1->top);
res->sign = 1;
res->top = b1->top;
for(i = res->top; --i >= 0;)
res->p[i] = ~b1->p[i];
mpnorm(res);
}
/* bits */
void
IPint_and(void *fp)
{
F_IPint_and *f;
mpint *ret, *i1, *i2;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpand(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_ori(void *fp)
{
F_IPint_ori *f;
mpint *ret, *i1, *i2;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpor(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_xor(void *fp)
{
F_IPint_xor *f;
mpint *ret, *i1, *i2;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
i2 = MP(f->i2);
ret = mpnew(0);
if(ret != nil)
mpxor(i1, i2, ret);
*f->ret = newIPint(ret);
}
void
IPint_not(void *fp)
{
F_IPint_not *f;
mpint *ret, *i1;
void *v;
f = fp;
v = *f->ret;
*f->ret = H;
destroy(v);
i1 = MP(f->i1);
ret = mpnew(0);
if(ret != nil)
mpnot(i1, ret);
*f->ret = newIPint(ret);
}
/*
* primes
*/
void
IPints_probably_prime(void *fp)
{
F_IPints_probably_prime *f;
f = fp;
release();
*f->ret = probably_prime(checkIPint(f->n), f->nrep);
acquire();
}
void
IPints_genprime(void *fp)
{
F_IPints_genprime *f;
mpint *p;
void *r;
f = fp;
r = *f->ret;
*f->ret = H;
destroy(r);
p = mpnew(0);
release();
genprime(p, f->nbits, f->nrep);
acquire();
*f->ret = newIPint(p);
}
void
IPints_genstrongprime(void *fp)
{
F_IPints_genstrongprime *f;
mpint *p;
void *r;
f = fp;
r = *f->ret;
*f->ret = H;
destroy(r);
p = mpnew(0);
release();
genstrongprime(p, f->nbits, f->nrep);
acquire();
*f->ret = newIPint(p);
}
void
IPints_gensafeprime(void *fp)
{
F_IPints_gensafeprime *f;
mpint *p, *alpha;
void *v;
f = fp;
v = f->ret->t0;
f->ret->t0 = H;
destroy(v);
v = f->ret->t1;
f->ret->t1 = H;
destroy(v);
p = mpnew(0);
alpha = mpnew(0);
release();
gensafeprime(p, alpha, f->nbits, f->nrep);
acquire();
f->ret->t0 = newIPint(p);
f->ret->t1 = newIPint(alpha);
}
void
IPints_DSAprimes(void *fp)
{
F_IPints_DSAprimes *f;
mpint *p, *q;
Heap *h;
void *v;
f = fp;
v = f->ret->t0;
f->ret->t0 = H;
destroy(v);
v = f->ret->t1;
f->ret->t1 = H;
destroy(v);
v = f->ret->t2;
f->ret->t2 = H;
destroy(v);
h = heaparray(&Tbyte, SHA1dlen);
f->ret->t2 = H2D(Array*, h);
p = mpnew(0);
q = mpnew(0);
release();
DSAprimes(q, p, f->ret->t2->data);
acquire();
f->ret->t0 = newIPint(q);
f->ret->t1 = newIPint(p);
}