more bitcoin
This commit is contained in:
parent
baea7ec1e2
commit
42656f38ef
8 changed files with 1219 additions and 21 deletions
|
@ -15,7 +15,8 @@ static char *phasenames[] = {
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
ECpriv p;
|
ECpriv p;
|
||||||
char *sign;
|
uchar buf[100];
|
||||||
|
int n;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -36,11 +37,11 @@ decryptkey(Fsstate *fss, char *key, char *password)
|
||||||
memset(buf, 0, sizeof buf);
|
memset(buf, 0, sizeof buf);
|
||||||
base58enc(keyenc, buf, 37);
|
base58enc(keyenc, buf, 37);
|
||||||
if(keyenc[0] != 0x80)
|
if(keyenc[0] != 0x80)
|
||||||
return failure(fss, "invalid key '%s'", buf);
|
return RpcNeedkey;
|
||||||
sha2_256(keyenc, 33, hash, nil);
|
sha2_256(keyenc, 33, hash, nil);
|
||||||
sha2_256(hash, 32, hash, nil);
|
sha2_256(hash, 32, hash, nil);
|
||||||
if(memcmp(keyenc + 33, hash, 4) != 0)
|
if(memcmp(keyenc + 33, hash, 4) != 0)
|
||||||
return failure(fss, "checksum error");
|
return RpcNeedkey;
|
||||||
st = fss->ps;
|
st = fss->ps;
|
||||||
st->p.d = betomp(keyenc + 1, 32, nil);
|
st->p.d = betomp(keyenc + 1, 32, nil);
|
||||||
st->p.x = mpnew(0);
|
st->p.x = mpnew(0);
|
||||||
|
@ -67,6 +68,7 @@ ecdsainit(Proto *, Fsstate *fss)
|
||||||
dom.h = uitomp(1, nil);
|
dom.h = uitomp(1, nil);
|
||||||
dom.G = strtoec(&dom, "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", nil, nil);
|
dom.G = strtoec(&dom, "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", nil, nil);
|
||||||
}
|
}
|
||||||
|
fss->ps = nil;
|
||||||
if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
|
if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
|
||||||
return failure(fss, nil);
|
return failure(fss, nil);
|
||||||
if(iscli==0)
|
if(iscli==0)
|
||||||
|
@ -91,7 +93,7 @@ ecdsainit(Proto *, Fsstate *fss)
|
||||||
}
|
}
|
||||||
if(key == nil || password == nil)
|
if(key == nil || password == nil)
|
||||||
return RpcNeedkey;
|
return RpcNeedkey;
|
||||||
fss->ps = malloc(sizeof(State));
|
fss->ps = emalloc(sizeof(State));
|
||||||
ret = decryptkey(fss, key, password);
|
ret = decryptkey(fss, key, password);
|
||||||
if(ret != RpcOk)
|
if(ret != RpcOk)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -103,12 +105,11 @@ ecdsainit(Proto *, Fsstate *fss)
|
||||||
return RpcOk;
|
return RpcOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static void
|
||||||
derencode(mpint *r, mpint *s)
|
derencode(mpint *r, mpint *s, uchar *buf, int *n)
|
||||||
{
|
{
|
||||||
uchar buf[100], rk[33], sk[33];
|
uchar rk[33], sk[33];
|
||||||
char *str;
|
int rl, sl;
|
||||||
int rl, sl, i;
|
|
||||||
|
|
||||||
mptobe(r, rk, 32, nil);
|
mptobe(r, rk, 32, nil);
|
||||||
mptobe(s, sk, 32, nil);
|
mptobe(s, sk, 32, nil);
|
||||||
|
@ -132,17 +133,13 @@ derencode(mpint *r, mpint *s)
|
||||||
buf[4 + rl] = 0x02;
|
buf[4 + rl] = 0x02;
|
||||||
buf[5 + rl] = sl;
|
buf[5 + rl] = sl;
|
||||||
memmove(buf + 6 + rl, sk, sl);
|
memmove(buf + 6 + rl, sk, sl);
|
||||||
str = malloc(1024);
|
*n = 6 + rl + sl;
|
||||||
for(i = 0; i < 6 + rl + sl; i++)
|
|
||||||
sprint(str + 2 * i, "%.2x", buf[i]);
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ecdsawrite(Fsstate *fss, void *va, uint n)
|
ecdsawrite(Fsstate *fss, void *va, uint n)
|
||||||
{
|
{
|
||||||
State *st;
|
State *st;
|
||||||
uchar hash[32];
|
|
||||||
mpint *r, *s;
|
mpint *r, *s;
|
||||||
|
|
||||||
st = fss->ps;
|
st = fss->ps;
|
||||||
|
@ -150,12 +147,10 @@ ecdsawrite(Fsstate *fss, void *va, uint n)
|
||||||
default:
|
default:
|
||||||
return phaseerror(fss, "write");
|
return phaseerror(fss, "write");
|
||||||
case CHaveKey:
|
case CHaveKey:
|
||||||
sha2_256(va, n, hash, nil);
|
|
||||||
sha2_256(hash, 32, hash, nil);
|
|
||||||
r = mpnew(0);
|
r = mpnew(0);
|
||||||
s = mpnew(0);
|
s = mpnew(0);
|
||||||
ecdsasign(&dom, &st->p, hash, 32, r, s);
|
ecdsasign(&dom, &st->p, va, n, r, s);
|
||||||
st->sign = derencode(r, s);
|
derencode(r, s, st->buf, &st->n);
|
||||||
mpfree(r);
|
mpfree(r);
|
||||||
mpfree(s);
|
mpfree(s);
|
||||||
fss->phase = CHaveText;
|
fss->phase = CHaveText;
|
||||||
|
@ -166,11 +161,16 @@ ecdsawrite(Fsstate *fss, void *va, uint n)
|
||||||
static int
|
static int
|
||||||
ecdsaread(Fsstate *fss, void *va, uint *n)
|
ecdsaread(Fsstate *fss, void *va, uint *n)
|
||||||
{
|
{
|
||||||
|
State *st;
|
||||||
|
|
||||||
|
st = fss->ps;
|
||||||
switch(fss->phase){
|
switch(fss->phase){
|
||||||
default:
|
default:
|
||||||
return phaseerror(fss, "read");
|
return phaseerror(fss, "read");
|
||||||
case CHaveText:
|
case CHaveText:
|
||||||
*n = snprint(va, *n, ((State *)fss->ps)->sign);
|
if(*n > st->n)
|
||||||
|
*n = st->n;
|
||||||
|
memcpy(va, st->buf, *n);
|
||||||
fss->phase = Established;
|
fss->phase = Established;
|
||||||
return RpcOk;
|
return RpcOk;
|
||||||
}
|
}
|
||||||
|
@ -182,13 +182,13 @@ ecdsaclose(Fsstate *fss)
|
||||||
State *st;
|
State *st;
|
||||||
|
|
||||||
st = fss->ps;
|
st = fss->ps;
|
||||||
|
if(st == nil)
|
||||||
|
return;
|
||||||
if(st->p.x != nil){
|
if(st->p.x != nil){
|
||||||
mpfree(st->p.x);
|
mpfree(st->p.x);
|
||||||
mpfree(st->p.y);
|
mpfree(st->p.y);
|
||||||
mpfree(st->p.d);
|
mpfree(st->p.d);
|
||||||
}
|
}
|
||||||
if(st->sign != nil)
|
|
||||||
free(st->sign);
|
|
||||||
free(st);
|
free(st);
|
||||||
fss->ps = nil;
|
fss->ps = nil;
|
||||||
}
|
}
|
||||||
|
|
28
sys/src/cmd/btc/dat.h
Normal file
28
sys/src/cmd/btc/dat.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
typedef struct Aux Aux;
|
||||||
|
typedef struct DirEntry DirEntry;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TROOT,
|
||||||
|
TADDR,
|
||||||
|
TADDRSUB,
|
||||||
|
TADDRTX,
|
||||||
|
TADDRBALANCE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DirEntry
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
Qid qid;
|
||||||
|
int par;
|
||||||
|
char *(*walk)(Fid *, char *, Qid *);
|
||||||
|
char *(*str)(DirEntry *, Aux *);
|
||||||
|
void (*write)(Req *);
|
||||||
|
int sub[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Aux
|
||||||
|
{
|
||||||
|
char *addr;
|
||||||
|
char *str;
|
||||||
|
};
|
254
sys/src/cmd/btc/fs.c
Normal file
254
sys/src/cmd/btc/fs.c
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "dat.h"
|
||||||
|
|
||||||
|
Reqqueue *queue;
|
||||||
|
|
||||||
|
static char *addrwalk(Fid *, char *, Qid *);
|
||||||
|
char *balancestr(DirEntry *, Aux *);
|
||||||
|
char *txstr(DirEntry *, Aux *);
|
||||||
|
|
||||||
|
DirEntry entr[] = {
|
||||||
|
[TROOT] = {
|
||||||
|
.name = "",
|
||||||
|
.qid = {TROOT, 0, QTDIR},
|
||||||
|
.par = TROOT,
|
||||||
|
.sub = {TADDR},
|
||||||
|
},
|
||||||
|
[TADDR] = {
|
||||||
|
.name = "addr",
|
||||||
|
.qid = {TADDR, 0, QTDIR},
|
||||||
|
.walk = addrwalk,
|
||||||
|
.par = TROOT,
|
||||||
|
},
|
||||||
|
[TADDRSUB] = {
|
||||||
|
.qid = {TADDRSUB, 0, QTDIR},
|
||||||
|
.par = TADDR,
|
||||||
|
.sub = {TADDRBALANCE, TADDRTX},
|
||||||
|
},
|
||||||
|
[TADDRBALANCE] = {
|
||||||
|
.name = "balance",
|
||||||
|
.qid = {TADDRBALANCE, 0, 0},
|
||||||
|
.par = TADDRSUB,
|
||||||
|
.str = balancestr,
|
||||||
|
},
|
||||||
|
[TADDRTX] = {
|
||||||
|
.name = "tx",
|
||||||
|
.qid = {TADDRTX, 0, 0},
|
||||||
|
.par = TADDRSUB,
|
||||||
|
.str = txstr,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
pfree(void **v)
|
||||||
|
{
|
||||||
|
if(*v != nil)
|
||||||
|
free(*v);
|
||||||
|
*v = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcattach(Req *req)
|
||||||
|
{
|
||||||
|
req->ofcall.qid = (Qid){0, 0, QTDIR};
|
||||||
|
req->fid->qid = req->ofcall.qid;
|
||||||
|
req->fid->aux = emalloc9p(sizeof(Aux));
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
addrwalk(Fid *fid, char *name, Qid *qid)
|
||||||
|
{
|
||||||
|
Aux *a;
|
||||||
|
|
||||||
|
a = fid->aux;
|
||||||
|
pfree(&a->addr);
|
||||||
|
a->addr = strdup(name);
|
||||||
|
fid->qid = entr[TADDRSUB].qid;
|
||||||
|
*qid = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
btcwalk1(Fid *fid, char *name, Qid *qid)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
int *s;
|
||||||
|
|
||||||
|
d = entr + (int)fid->qid.path;
|
||||||
|
if(strcmp(name, "..") == 0){
|
||||||
|
fid->qid = entr[d->par].qid;
|
||||||
|
*qid = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(d->walk)
|
||||||
|
return d->walk(fid, name, qid);
|
||||||
|
for(s = d->sub; *s; s++)
|
||||||
|
if(strcmp(entr[*s].name, name) == 0){
|
||||||
|
fid->qid = entr[*s].qid;
|
||||||
|
*qid = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return "directory entry not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
btcclone(Fid *oldfid, Fid *newfid)
|
||||||
|
{
|
||||||
|
Aux *a, *b;
|
||||||
|
|
||||||
|
a = oldfid->aux;
|
||||||
|
b = emalloc9p(sizeof(Aux));
|
||||||
|
memcpy(b, a, sizeof(Aux));
|
||||||
|
if(b->addr)
|
||||||
|
b->addr = strdup(b->addr);
|
||||||
|
newfid->aux = b;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcopenread(Req *req)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
Aux *a;
|
||||||
|
|
||||||
|
d = entr + (int)req->fid->qid.path;
|
||||||
|
a = req->fid->aux;
|
||||||
|
a->str = d->str(d, a);
|
||||||
|
if(a->str == nil)
|
||||||
|
responderror(req);
|
||||||
|
else
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcopen(Req *req)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
|
||||||
|
d = entr + (int)req->fid->qid.path;
|
||||||
|
switch(req->ifcall.mode & 3){
|
||||||
|
case OREAD:
|
||||||
|
if(d->str == nil && (req->fid->qid.type & QTDIR) == 0)
|
||||||
|
goto noperm;
|
||||||
|
reqqueuepush(queue, req, btcopenread);
|
||||||
|
return;
|
||||||
|
case OWRITE:
|
||||||
|
if(d->write == nil)
|
||||||
|
goto noperm;
|
||||||
|
break;
|
||||||
|
case ORDWR:
|
||||||
|
if(d->str == nil || d->write == nil)
|
||||||
|
goto noperm;
|
||||||
|
break;
|
||||||
|
case OEXEC:
|
||||||
|
goto noperm;
|
||||||
|
}
|
||||||
|
respond(req, nil);
|
||||||
|
return;
|
||||||
|
noperm:
|
||||||
|
respond(req, "permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill(Dir *de, int t, Aux *a)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
|
||||||
|
d = entr + t;
|
||||||
|
de->qid = d->qid;
|
||||||
|
if(d->qid.type & QTDIR)
|
||||||
|
de->mode = 0555;
|
||||||
|
else
|
||||||
|
de->mode = (d->str ? 0444 : 0) | (d->write ? 0222 : 0);
|
||||||
|
if(d->name != nil)
|
||||||
|
de->name = strdup(d->name);
|
||||||
|
else if(a->addr != nil)
|
||||||
|
de->name = strdup(a->addr);
|
||||||
|
else
|
||||||
|
de->name = strdup("");
|
||||||
|
de->uid = strdup("satoshi");
|
||||||
|
de->gid = strdup("satoshi");
|
||||||
|
de->muid = strdup("satoshi");
|
||||||
|
de->atime = de->mtime = time(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcstat(Req *req)
|
||||||
|
{
|
||||||
|
fill(&req->d, (int)req->fid->qid.path, req->fid->aux);
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
btcdirgen(int n, Dir *dir, void *aux)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
|
||||||
|
d = entr + (int)((Req*)aux)->fid->qid.path;
|
||||||
|
if(n >= nelem(d->sub) || d->sub[n] == 0)
|
||||||
|
return -1;
|
||||||
|
fill(dir, d->sub[n], ((Req*)aux)->fid->aux);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcread(Req *req)
|
||||||
|
{
|
||||||
|
DirEntry *d;
|
||||||
|
Aux *a;
|
||||||
|
|
||||||
|
d = entr + (int)req->fid->qid.path;
|
||||||
|
a = req->fid->aux;
|
||||||
|
if(req->fid->qid.type & QTDIR){
|
||||||
|
dirread9p(req, btcdirgen, req);
|
||||||
|
respond(req, nil);
|
||||||
|
}else if(d->str && a->str){
|
||||||
|
readstr(req, a->str);
|
||||||
|
respond(req, nil);
|
||||||
|
}else
|
||||||
|
respond(req, "permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcflush(Req *req)
|
||||||
|
{
|
||||||
|
reqqueueflush(queue, req->oldreq);
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
btcdestroyfid(Fid *fid)
|
||||||
|
{
|
||||||
|
Aux *a;
|
||||||
|
|
||||||
|
a = fid->aux;
|
||||||
|
if(a != nil){
|
||||||
|
pfree(&a->addr);
|
||||||
|
pfree(&a->str);
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
fid->aux = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
Srv btcsrv = {
|
||||||
|
.attach = btcattach,
|
||||||
|
.walk1 = btcwalk1,
|
||||||
|
.clone = btcclone,
|
||||||
|
.stat = btcstat,
|
||||||
|
.open = btcopen,
|
||||||
|
.read = btcread,
|
||||||
|
.flush = btcflush,
|
||||||
|
.destroyfid = btcdestroyfid,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
gofs(void)
|
||||||
|
{
|
||||||
|
queue = reqqueuecreate();
|
||||||
|
threadpostmountsrv(&btcsrv, nil, "/mnt/btc", 0);
|
||||||
|
}
|
129
sys/src/cmd/btc/httpfs.c
Normal file
129
sys/src/cmd/btc/httpfs.c
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
void gofs(void);
|
||||||
|
|
||||||
|
char *
|
||||||
|
graburl(char *url)
|
||||||
|
{
|
||||||
|
int fd, fd2, n, rc, size;
|
||||||
|
char buf[2048];
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
fd = open("/mnt/web/clone", ORDWR);
|
||||||
|
if(fd < 0)
|
||||||
|
return nil;
|
||||||
|
if(read(fd, buf, 512) < 0){
|
||||||
|
close(fd);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
n = atoi(buf);
|
||||||
|
sprint(buf, "url %s", url);
|
||||||
|
if(write(fd, buf, strlen(buf)) < 0){
|
||||||
|
close(fd);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
sprint(buf, "/mnt/web/%d/body", n);
|
||||||
|
fd2 = open(buf, OREAD);
|
||||||
|
if(fd2 < 0){
|
||||||
|
close(fd);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
size = 0;
|
||||||
|
res = nil;
|
||||||
|
while((rc = readn(fd2, buf, sizeof buf)) > 0){
|
||||||
|
res = realloc(res, size + rc + 1);
|
||||||
|
memcpy(res + size, buf, rc);
|
||||||
|
size += rc;
|
||||||
|
res[size] = 0;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
close(fd2);
|
||||||
|
if(rc < 0){
|
||||||
|
free(res);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parsetx(String *str, JSON *j, JSON *l)
|
||||||
|
{
|
||||||
|
JSONEl *e;
|
||||||
|
JSON *k;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
for(e = j->first; e != nil; e = e->next){
|
||||||
|
k = jsonbyname(e->val, "prev_out");
|
||||||
|
sprint(buf, "%s %lld ", jsonstr(jsonbyname(k, "addr")), (vlong)jsonbyname(k, "value")->n);
|
||||||
|
s_append(str, buf);
|
||||||
|
}
|
||||||
|
s_append(str, "| ");
|
||||||
|
for(e = l->first; e != nil; e = e->next){
|
||||||
|
sprint(buf, "%s %lld ", jsonstr(jsonbyname(e->val, "addr")), (vlong)jsonbyname(e->val, "value")->n);
|
||||||
|
s_append(str, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
balancestr(DirEntry *, Aux *a)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
sprint(buf, "http://blockchain.info/q/addressbalance/%s", a->addr);
|
||||||
|
s = graburl(buf);
|
||||||
|
if(s == nil)
|
||||||
|
return nil;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
txstr(DirEntry *, Aux *a)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
char buf[512];
|
||||||
|
JSON *j, *k;
|
||||||
|
JSONEl *e;
|
||||||
|
String *str;
|
||||||
|
|
||||||
|
sprint(buf, "http://blockchain.info/rawaddr/%s", a->addr);
|
||||||
|
s = graburl(buf);
|
||||||
|
if(s == nil)
|
||||||
|
return nil;
|
||||||
|
j = jsonparse(s);
|
||||||
|
free(s);
|
||||||
|
if(j == nil)
|
||||||
|
return nil;
|
||||||
|
str = s_new();
|
||||||
|
k = jsonbyname(j, "txs");
|
||||||
|
if(k == nil)
|
||||||
|
goto err;
|
||||||
|
for(e = k->first; e != nil; e = e->next){
|
||||||
|
sprint(buf, "%d %s %d ", (int)(jsonbyname(e->val, "time")->n), jsonstr(jsonbyname(e->val, "hash")), (int)(jsonbyname(e->val, "block_height")->n));
|
||||||
|
s_append(str, buf);
|
||||||
|
parsetx(str, jsonbyname(e->val, "inputs"), jsonbyname(e->val, "out"));
|
||||||
|
s_putc(str, '\n');
|
||||||
|
}
|
||||||
|
s_terminate(str);
|
||||||
|
s = str->base;
|
||||||
|
free(str);
|
||||||
|
jsonfree(j);
|
||||||
|
return s;
|
||||||
|
err:
|
||||||
|
s_free(str);
|
||||||
|
jsonfree(j);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain()
|
||||||
|
{
|
||||||
|
gofs();
|
||||||
|
}
|
326
sys/src/cmd/btc/json.c
Normal file
326
sys/src/cmd/btc/json.c
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
typedef struct Lex Lex;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TEOF,
|
||||||
|
TSTRING = (1<<(8*sizeof(Rune)))+1,
|
||||||
|
TNUM,
|
||||||
|
TNULL,
|
||||||
|
TFALSE,
|
||||||
|
TTRUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Lex
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int t;
|
||||||
|
double n;
|
||||||
|
char buf[4096];
|
||||||
|
Rune peeked;
|
||||||
|
jmp_buf jmp;
|
||||||
|
int canjmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Rune
|
||||||
|
getch(Lex *l)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
if(l->peeked){
|
||||||
|
r = l->peeked;
|
||||||
|
l->peeked = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
l->s += chartorune(&r, l->s);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rune
|
||||||
|
peekch(Lex *l)
|
||||||
|
{
|
||||||
|
if(!l->peeked)
|
||||||
|
l->peeked = getch(l);
|
||||||
|
return l->peeked;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lex(Lex *l)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
r = peekch(l);
|
||||||
|
if(r != 0x20 && r != 0x09 && r != 0x0A && r != 0x0D)
|
||||||
|
break;
|
||||||
|
getch(l);
|
||||||
|
}
|
||||||
|
r = getch(l);
|
||||||
|
if(r == ']' && l->canjmp)
|
||||||
|
longjmp(l->jmp, 1);
|
||||||
|
l->canjmp = 0;
|
||||||
|
if(r == 0 || r == '{' || r == '[' || r == ']' || r == '}' || r == ':' || r == ','){
|
||||||
|
l->t = r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(r >= 0x80 || isalpha(r)){
|
||||||
|
t = l->buf;
|
||||||
|
for(;;){
|
||||||
|
t += runetochar(t, &r);
|
||||||
|
if(t >= l->buf + sizeof(l->buf)){
|
||||||
|
werrstr("json: literal too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
r = peekch(l);
|
||||||
|
if(r < 0x80 && !isalpha(r))
|
||||||
|
break;
|
||||||
|
getch(l);
|
||||||
|
}
|
||||||
|
*t = 0;
|
||||||
|
if(strcmp(l->buf, "true") == 0)
|
||||||
|
l->t = TTRUE;
|
||||||
|
else if(strcmp(l->buf, "false") == 0)
|
||||||
|
l->t = TFALSE;
|
||||||
|
else if(strcmp(l->buf, "null") == 0)
|
||||||
|
l->t = TNULL;
|
||||||
|
else{
|
||||||
|
werrstr("json: invalid literal");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(isdigit(r) || r == '-'){
|
||||||
|
l->n = strtod(l->s-1, &l->s);
|
||||||
|
l->t = TNUM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(r == '"'){
|
||||||
|
t = l->buf;
|
||||||
|
for(;;){
|
||||||
|
r = getch(l);
|
||||||
|
if(r == '"')
|
||||||
|
break;
|
||||||
|
if(r < ' '){
|
||||||
|
werrstr("json: invalid char in string %x", r);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(r == '\\'){
|
||||||
|
r = getch(l);
|
||||||
|
switch(r){
|
||||||
|
case 'n':
|
||||||
|
r = '\n';
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
r = '\r';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
r = '\t';
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
r = '\f';
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
r = '\b';
|
||||||
|
break;
|
||||||
|
case '"': case '/': case '\\':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
werrstr("json: invalid escape sequence \\%C", r);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t += runetochar(t, &r);
|
||||||
|
if(t >= l->buf + sizeof(l->buf)){
|
||||||
|
werrstr("json: string too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*t = 0;
|
||||||
|
l->t = TSTRING;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
werrstr("json: invalid char %C", peekch(l));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSON*
|
||||||
|
jsonobj(Lex *l)
|
||||||
|
{
|
||||||
|
JSON *j;
|
||||||
|
JSONEl *e;
|
||||||
|
JSONEl **ln;
|
||||||
|
int obj;
|
||||||
|
|
||||||
|
j = mallocz(sizeof(*j), 1);
|
||||||
|
if(j == nil)
|
||||||
|
return nil;
|
||||||
|
if(lex(l) < 0){
|
||||||
|
error:
|
||||||
|
free(j);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
switch(l->t){
|
||||||
|
case TEOF:
|
||||||
|
werrstr("json: unexpected eof");
|
||||||
|
goto error;
|
||||||
|
case TNULL:
|
||||||
|
j->t = JSONNull;
|
||||||
|
break;
|
||||||
|
case TTRUE:
|
||||||
|
j->t = JSONBool;
|
||||||
|
j->n = 1;
|
||||||
|
break;
|
||||||
|
case TFALSE:
|
||||||
|
j->t = JSONBool;
|
||||||
|
j->n = 0;
|
||||||
|
break;
|
||||||
|
case TSTRING:
|
||||||
|
j->t = JSONString;
|
||||||
|
j->s = strdup(l->buf);
|
||||||
|
if(j->s == nil)
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
case TNUM:
|
||||||
|
j->t = JSONNumber;
|
||||||
|
j->n = l->n;
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
obj = l->t == '{';
|
||||||
|
ln = &j->first;
|
||||||
|
e = nil;
|
||||||
|
if(obj){
|
||||||
|
j->t = JSONObject;
|
||||||
|
if(lex(l) < 0)
|
||||||
|
goto abort;
|
||||||
|
if(l->t == '}')
|
||||||
|
return j;
|
||||||
|
goto firstobj;
|
||||||
|
}else{
|
||||||
|
j->t = JSONArray;
|
||||||
|
l->canjmp = 1;
|
||||||
|
if(setjmp(l->jmp) > 0){
|
||||||
|
free(e);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(;;){
|
||||||
|
if(obj){
|
||||||
|
if(lex(l) < 0)
|
||||||
|
goto abort;
|
||||||
|
firstobj:
|
||||||
|
if(l->t != TSTRING){
|
||||||
|
werrstr("json: syntax error, not string");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
e = mallocz(sizeof(*e), 1);
|
||||||
|
if(e == nil)
|
||||||
|
goto abort;
|
||||||
|
e->name = strdup(l->buf);
|
||||||
|
if(e->name == nil || lex(l) < 0){
|
||||||
|
free(e);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
if(l->t != ':'){
|
||||||
|
werrstr("json: syntax error, not colon");
|
||||||
|
free(e);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
e = mallocz(sizeof(*e), 1);
|
||||||
|
if(e == nil)
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
e->val = jsonobj(l);
|
||||||
|
if(e->val == nil){
|
||||||
|
free(e);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
*ln = e;
|
||||||
|
ln = &e->next;
|
||||||
|
if(lex(l) < 0)
|
||||||
|
goto abort;
|
||||||
|
if(l->t == (obj ? '}' : ']'))
|
||||||
|
break;
|
||||||
|
if(l->t != ','){
|
||||||
|
werrstr("json: syntax error, neither comma nor ending paren");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
abort:
|
||||||
|
jsonfree(j);
|
||||||
|
return nil;
|
||||||
|
case ']': case '}': case ',': case ':':
|
||||||
|
werrstr("json: unexpected %C", l->t);
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
werrstr("json: the front fell off");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON*
|
||||||
|
jsonparse(char *s)
|
||||||
|
{
|
||||||
|
Lex l;
|
||||||
|
|
||||||
|
memset(&l, 0, sizeof(l));
|
||||||
|
l.s = s;
|
||||||
|
return jsonobj(&l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
jsonfree(JSON *j)
|
||||||
|
{
|
||||||
|
JSONEl *e, *f;
|
||||||
|
|
||||||
|
switch(j->t){
|
||||||
|
case JSONString:
|
||||||
|
if(j->s)
|
||||||
|
free(j->s);
|
||||||
|
break;
|
||||||
|
case JSONArray: case JSONObject:
|
||||||
|
for(e = j->first; e != nil; e = f){
|
||||||
|
if(e->name)
|
||||||
|
free(e->name);
|
||||||
|
jsonfree(e->val);
|
||||||
|
f = e->next;
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON *
|
||||||
|
jsonbyname(JSON *j, char *n)
|
||||||
|
{
|
||||||
|
JSONEl *e;
|
||||||
|
|
||||||
|
if(j->t != JSONObject){
|
||||||
|
werrstr("not an object");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
for(e = j->first; e != nil; e = e->next)
|
||||||
|
if(strcmp(e->name, n) == 0)
|
||||||
|
return e->val;
|
||||||
|
werrstr("key '%s' not found", n);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
jsonstr(JSON *j)
|
||||||
|
{
|
||||||
|
if(j == nil)
|
||||||
|
return nil;
|
||||||
|
if(j->t != JSONString){
|
||||||
|
werrstr("not a string");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return j->s;
|
||||||
|
}
|
32
sys/src/cmd/btc/json.h
Normal file
32
sys/src/cmd/btc/json.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
typedef struct JSONEl JSONEl;
|
||||||
|
typedef struct JSON JSON;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
JSONNull,
|
||||||
|
JSONBool,
|
||||||
|
JSONNumber,
|
||||||
|
JSONString,
|
||||||
|
JSONArray,
|
||||||
|
JSONObject,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JSONEl {
|
||||||
|
char *name;
|
||||||
|
JSON *val;
|
||||||
|
JSONEl *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JSON
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
union {
|
||||||
|
double n;
|
||||||
|
char *s;
|
||||||
|
JSONEl *first;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
JSON* jsonparse(char *);
|
||||||
|
void jsonfree(JSON *);
|
||||||
|
JSON* jsonbyname(JSON *, char *);
|
||||||
|
char* jsonstr(JSON *);
|
17
sys/src/cmd/btc/mkfile
Normal file
17
sys/src/cmd/btc/mkfile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
</$objtype/mkfile
|
||||||
|
|
||||||
|
TARG=httpfs sign
|
||||||
|
|
||||||
|
BIN=/$objtype/bin/btc
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
json.$O\
|
||||||
|
|
||||||
|
HFILES=\
|
||||||
|
dat.h\
|
||||||
|
|
||||||
|
default:V: all
|
||||||
|
|
||||||
|
</sys/src/cmd/mkmany
|
||||||
|
|
||||||
|
$O.httpfs: fs.$O
|
412
sys/src/cmd/btc/sign.c
Normal file
412
sys/src/cmd/btc/sign.c
Normal file
|
@ -0,0 +1,412 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <mp.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libsec.h>
|
||||||
|
#include <auth.h>
|
||||||
|
|
||||||
|
typedef struct TxIn TxIn;
|
||||||
|
typedef struct TxOut TxOut;
|
||||||
|
typedef struct Sig Sig;
|
||||||
|
typedef struct Word Word;
|
||||||
|
|
||||||
|
int afd;
|
||||||
|
AuthRpc *rpc;
|
||||||
|
|
||||||
|
struct Word {
|
||||||
|
char *name;
|
||||||
|
int val;
|
||||||
|
} words[];
|
||||||
|
|
||||||
|
struct Sig {
|
||||||
|
char *priv;
|
||||||
|
int loc;
|
||||||
|
Sig *n;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxIn {
|
||||||
|
uchar prev[36];
|
||||||
|
int scoldlen, sclen;
|
||||||
|
uchar scold[10000];
|
||||||
|
uchar sc[10000];
|
||||||
|
Sig *sig;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxOut {
|
||||||
|
uvlong val;
|
||||||
|
int sclen;
|
||||||
|
uchar sc[10000];
|
||||||
|
};
|
||||||
|
|
||||||
|
Biobuf *bp;
|
||||||
|
|
||||||
|
int nin, nout;
|
||||||
|
TxIn *in[0xFD];
|
||||||
|
TxOut *out[0xFD];
|
||||||
|
uchar buf[65536];
|
||||||
|
|
||||||
|
void
|
||||||
|
varenc(uint i, uchar **b)
|
||||||
|
{
|
||||||
|
if(i < 0xfd)
|
||||||
|
*(*b)++ = i;
|
||||||
|
else if(i <= 0xffff){
|
||||||
|
*(*b)++ = 0xfd;
|
||||||
|
*(*b)++ = i;
|
||||||
|
*(*b)++ = i >> 8;
|
||||||
|
}else{
|
||||||
|
*(*b)++ = 0xfe;
|
||||||
|
*(*b)++ = i;
|
||||||
|
*(*b)++ = i >> 8;
|
||||||
|
*(*b)++ = i >> 16;
|
||||||
|
*(*b)++ = i >> 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
hexdec(char *c, uchar *u, int n)
|
||||||
|
{
|
||||||
|
int i, v;
|
||||||
|
char *b;
|
||||||
|
static char *hexdig = "0123456789abcdef";
|
||||||
|
|
||||||
|
memset(u, 0, n);
|
||||||
|
for(i = 0; i < 2 * n; i++){
|
||||||
|
b = strchr(hexdig, c[i]);
|
||||||
|
if(b == nil)
|
||||||
|
return -1;
|
||||||
|
v = b - hexdig;
|
||||||
|
if(i & 1)
|
||||||
|
u[i>>1] |= v;
|
||||||
|
else
|
||||||
|
u[i>>1] |= v << 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pushdat(uchar **scr, uchar *d, int n)
|
||||||
|
{
|
||||||
|
if(n <= 0x4b)
|
||||||
|
*(*scr)++ = n;
|
||||||
|
else if(n <= 0xff){
|
||||||
|
*(*scr)++ = 0x4c;
|
||||||
|
*(*scr)++ = n;
|
||||||
|
}else if(n <= 0xffff){
|
||||||
|
*(*scr)++ = 0x4d;
|
||||||
|
*(*scr)++ = n;
|
||||||
|
*(*scr)++ = n >> 8;
|
||||||
|
}else{
|
||||||
|
*(*scr)++ = 0x4e;
|
||||||
|
*(*scr)++ = n;
|
||||||
|
*(*scr)++ = n >> 8;
|
||||||
|
*(*scr)++ = n >> 16;
|
||||||
|
*(*scr)++ = n >> 24;
|
||||||
|
}
|
||||||
|
memcpy(*scr, d, n);
|
||||||
|
*scr += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
doscript(char **args, int n, uchar *script, int *len, TxIn *ti)
|
||||||
|
{
|
||||||
|
int i, k;
|
||||||
|
Word *w;
|
||||||
|
uchar *scr;
|
||||||
|
uchar *b;
|
||||||
|
char *s;
|
||||||
|
Sig *si;
|
||||||
|
|
||||||
|
scr = script;
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
for(w = words; w->name; w++)
|
||||||
|
if(strcmp(w->name, args[i]) == 0){
|
||||||
|
*scr++ = w->val;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
if(strncmp(args[i], "sig(", 4) == 0){
|
||||||
|
if(in == nil)
|
||||||
|
sysfatal("sig in out script");
|
||||||
|
si = malloc(sizeof(*si));
|
||||||
|
args[i][strlen(args[i])-1] = 0;
|
||||||
|
si->priv = strdup(args[i] + 4);
|
||||||
|
si->loc = scr - script;
|
||||||
|
si->n = ti->sig;
|
||||||
|
ti->sig = si;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(strncmp(args[i], "h160(", 5) == 0){
|
||||||
|
b = mallocz(25, 1);
|
||||||
|
args[i][strlen(args[i])-1] = 0;
|
||||||
|
base58dec(args[i] + 5, b, 25);
|
||||||
|
pushdat(&scr, b+1, 20);
|
||||||
|
free(b);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(args[i][0] == '('){
|
||||||
|
k = strtol(args[i] + 1, &s, 0);
|
||||||
|
b = mallocz(k, 1);
|
||||||
|
base58dec(s+1, b, k);
|
||||||
|
pushdat(&scr, b, k);
|
||||||
|
free(b);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sysfatal("invalid word %s", args[i]);
|
||||||
|
next: ;
|
||||||
|
}
|
||||||
|
*len = scr - script;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
serialize(uchar *buf, int sig)
|
||||||
|
{
|
||||||
|
uchar *s;
|
||||||
|
TxIn *ti;
|
||||||
|
TxOut *to;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
s = buf;
|
||||||
|
*s++ = 1;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = nin;
|
||||||
|
for(i = 0; i < nin; i++){
|
||||||
|
ti = in[i];
|
||||||
|
memcpy(s, ti->prev, 36);
|
||||||
|
s += 36;
|
||||||
|
if(sig == -1){
|
||||||
|
varenc(ti->sclen, &s);
|
||||||
|
memcpy(s, ti->sc, ti->sclen);
|
||||||
|
s += ti->sclen;
|
||||||
|
}
|
||||||
|
if(sig == i){
|
||||||
|
memcpy(s, ti->scold, ti->scoldlen);
|
||||||
|
s += ti->scoldlen;
|
||||||
|
}
|
||||||
|
*s++ = 0xff;
|
||||||
|
*s++ = 0xff;
|
||||||
|
*s++ = 0xff;
|
||||||
|
*s++ = 0xff;
|
||||||
|
}
|
||||||
|
*s++ = nout;
|
||||||
|
for(i = 0; i < nout; i++){
|
||||||
|
to = out[i];
|
||||||
|
*s++ = to->val;
|
||||||
|
*s++ = to->val >> 8;
|
||||||
|
*s++ = to->val >> 16;
|
||||||
|
*s++ = to->val >> 24;
|
||||||
|
*s++ = to->val >> 32;
|
||||||
|
*s++ = to->val >> 40;
|
||||||
|
*s++ = to->val >> 48;
|
||||||
|
*s++ = to->val >> 56;
|
||||||
|
varenc(to->sclen, &s);
|
||||||
|
memcpy(s, to->sc, to->sclen);
|
||||||
|
s += to->sclen;
|
||||||
|
}
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
if(sig != -1){
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
*s++ = 0;
|
||||||
|
}
|
||||||
|
return s - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sign(uchar *hash, char *priv, uchar *tar, uint *n)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
again:
|
||||||
|
sprint(buf, "proto=ecdsa role=client key=%s", priv);
|
||||||
|
rc = auth_rpc(rpc, "start", buf, strlen(buf));
|
||||||
|
if(rc == ARneedkey || rc == ARbadkey){
|
||||||
|
rerrstr(buf, sizeof buf);
|
||||||
|
if(auth_getkey(buf + 8) < 0)
|
||||||
|
sysfatal("auth_getkey: %r");
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
if(rc != ARok)
|
||||||
|
sysfatal("factotum start: %r");
|
||||||
|
if(auth_rpc(rpc, "write", hash, 32) != ARok)
|
||||||
|
sysfatal("factotum write: %r");
|
||||||
|
if(auth_rpc(rpc, "read", "", 0) != ARok)
|
||||||
|
sysfatal("factotum read: %r");
|
||||||
|
memcpy(tar, rpc->arg, *n = rpc->narg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
int linenum;
|
||||||
|
uint i, n;
|
||||||
|
char *args[256];
|
||||||
|
TxOut *to;
|
||||||
|
TxIn *ti;
|
||||||
|
Sig *si;
|
||||||
|
uchar hash[32];
|
||||||
|
uchar sig[100];
|
||||||
|
|
||||||
|
afd = open("/mnt/factotum/rpc", ORDWR);
|
||||||
|
if(afd < 0)
|
||||||
|
sysfatal("open: %r");
|
||||||
|
rpc = auth_allocrpc(afd);
|
||||||
|
|
||||||
|
bp = malloc(sizeof(*bp));
|
||||||
|
Binit(bp, 0, OREAD);
|
||||||
|
linenum = 0;
|
||||||
|
for(;;){
|
||||||
|
line = Brdstr(bp, '\n', 1);
|
||||||
|
linenum++;
|
||||||
|
if(strcmp(line, "-") == 0)
|
||||||
|
break;
|
||||||
|
if(++nin >= 0xFD)
|
||||||
|
sysfatal("too many inputs");
|
||||||
|
ti = malloc(sizeof(*ti));
|
||||||
|
in[nin-1] = ti;
|
||||||
|
if(tokenize(line, args, nelem(args)) != 2)
|
||||||
|
sysfatal("line %d: invalid data", linenum);
|
||||||
|
hexdec(args[0], ti->prev, 32);
|
||||||
|
i = atoi(args[1]);
|
||||||
|
ti->prev[32] = i;
|
||||||
|
ti->prev[33] = i >> 8;
|
||||||
|
ti->prev[34] = i >> 16;
|
||||||
|
ti->prev[35] = i >> 24;
|
||||||
|
line = Brdstr(bp, '\n', 1);
|
||||||
|
linenum++;
|
||||||
|
i = tokenize(line, args, nelem(args));
|
||||||
|
doscript(args, i, ti->scold, &ti->scoldlen, nil);
|
||||||
|
line = Brdstr(bp, '\n', 1);
|
||||||
|
linenum++;
|
||||||
|
i = tokenize(line, args, nelem(args));
|
||||||
|
doscript(args, i, ti->sc, &ti->sclen, ti);
|
||||||
|
}
|
||||||
|
for(;;){
|
||||||
|
line = Brdstr(bp, '\n', 1);
|
||||||
|
if(line == nil)
|
||||||
|
break;
|
||||||
|
linenum++;
|
||||||
|
if(++nout >= 0xFD)
|
||||||
|
sysfatal("too many outputs");
|
||||||
|
to = malloc(sizeof(*to));
|
||||||
|
out[nout-1] = to;
|
||||||
|
to->val = atoll(line);
|
||||||
|
line = Brdstr(bp, '\n', 1);
|
||||||
|
linenum++;
|
||||||
|
i = tokenize(line, args, nelem(args));
|
||||||
|
doscript(args, i, to->sc, &to->sclen, nil);
|
||||||
|
}
|
||||||
|
for(i = 0; i < nin; i++){
|
||||||
|
ti = in[i];
|
||||||
|
if(ti->sig == nil)
|
||||||
|
continue;
|
||||||
|
n = serialize(buf, i);
|
||||||
|
sha2_256(buf, n, hash, nil);
|
||||||
|
sha2_256(hash, 32, hash, nil);
|
||||||
|
for(si = ti->sig; si != nil; si = si->n){
|
||||||
|
sign(hash, ti->sig->priv, sig + 1, &n);
|
||||||
|
print("%d\n", n);
|
||||||
|
sig[0] = n++;
|
||||||
|
memmove(ti->sc + si->loc + n, ti->sc + si->loc, ti->sclen - si->loc);
|
||||||
|
memmove(ti->sc + si->loc, sig, n);
|
||||||
|
ti->sclen += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = serialize(buf, -1);
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
print("%.2x", buf[i]);
|
||||||
|
if((i%4)==3)
|
||||||
|
print(" ");
|
||||||
|
if((i%32)==31)
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
if((i%16)!=0)
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Word words[] = {
|
||||||
|
{"nop", 97},
|
||||||
|
{"if", 99},
|
||||||
|
{"notif", 100},
|
||||||
|
{"else", 103},
|
||||||
|
{"endif", 104},
|
||||||
|
{"verify", 105},
|
||||||
|
{"return", 106},
|
||||||
|
{"toaltstack", 107},
|
||||||
|
{"fromaltstack", 108},
|
||||||
|
{"2drop", 109},
|
||||||
|
{"2dup", 110},
|
||||||
|
{"3dup", 111},
|
||||||
|
{"2over", 112},
|
||||||
|
{"2rot", 113},
|
||||||
|
{"2swap", 114},
|
||||||
|
{"ifdup", 115},
|
||||||
|
{"depth", 116},
|
||||||
|
{"drop", 117},
|
||||||
|
{"dup", 118},
|
||||||
|
{"nip", 119},
|
||||||
|
{"over", 120},
|
||||||
|
{"pick", 121},
|
||||||
|
{"roll", 122},
|
||||||
|
{"rot", 123},
|
||||||
|
{"swap", 124},
|
||||||
|
{"tuck", 125},
|
||||||
|
{"cat", 126},
|
||||||
|
{"substr", 127},
|
||||||
|
{"left", 128},
|
||||||
|
{"right", 129},
|
||||||
|
{"size", 130},
|
||||||
|
{"invert", 131},
|
||||||
|
{"and", 132},
|
||||||
|
{"or", 133},
|
||||||
|
{"xor", 134},
|
||||||
|
{"equal", 135},
|
||||||
|
{"equalverify", 136},
|
||||||
|
{"1add", 139},
|
||||||
|
{"1sub", 140},
|
||||||
|
{"2mul", 141},
|
||||||
|
{"2div", 142},
|
||||||
|
{"negate", 143},
|
||||||
|
{"abs", 144},
|
||||||
|
{"not", 145},
|
||||||
|
{"0notequal", 146},
|
||||||
|
{"add", 147},
|
||||||
|
{"sub", 148},
|
||||||
|
{"mul", 149},
|
||||||
|
{"div", 150},
|
||||||
|
{"mod", 151},
|
||||||
|
{"lshift", 152},
|
||||||
|
{"rshift", 153},
|
||||||
|
{"booland", 154},
|
||||||
|
{"boolor", 155},
|
||||||
|
{"numequal", 156},
|
||||||
|
{"numequalverify", 157},
|
||||||
|
{"numnotequal", 158},
|
||||||
|
{"lessthan", 159},
|
||||||
|
{"greaterthan", 160},
|
||||||
|
{"lessthanorequal", 161},
|
||||||
|
{"greaterthanorequal", 162},
|
||||||
|
{"min", 163},
|
||||||
|
{"max", 164},
|
||||||
|
{"within", 165},
|
||||||
|
{"ripemd160", 166},
|
||||||
|
{"sha1", 167},
|
||||||
|
{"sha256", 168},
|
||||||
|
{"hash160", 169},
|
||||||
|
{"hash256", 170},
|
||||||
|
{"codeseparator", 171},
|
||||||
|
{"checksig", 172},
|
||||||
|
{"checksigverify", 173},
|
||||||
|
{"checkmultisig", 174},
|
||||||
|
{"checkmultisigverify", 175},
|
||||||
|
{nil, 0},
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue