ref: d457a43461852636db313c4854590b2c62a21e23
dir: /sys/src/cmd/btc/sign.c/
#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, *bpout; 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; } if(args[i][0] == '['){ k = strtol(args[i] + 1, &s, 0); b = mallocz(k, 1); hexdec(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){ varenc(ti->scoldlen, &s); 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++ = 1; *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], c; afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0) sysfatal("open: %r"); rpc = auth_allocrpc(afd); bp = malloc(sizeof(*bp)); Binit(bp, 0, OREAD); bpout = malloc(sizeof(*bpout)); Binit(bpout, 1, OWRITE); 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); for(n = 0; n < 16; n++){ c = ti->prev[n]; ti->prev[n] = ti->prev[31-n]; ti->prev[31-n] = c; } 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); sig[0] = ++n; sig[n++] = 1; 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++){ Bprint(bpout, "%.2x", buf[i]); if((i%4)==3) Bputc(bpout, ' '); if((i%32)==31) Bputc(bpout, '\n'); } if((i%32)!=0) Bputc(bpout, '\n'); Bterm(bpout); } 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}, };