prototype of trustless mining

This commit is contained in:
dzwdz 2022-11-05 17:37:47 +01:00
parent d202229a43
commit bd3b8d5881
5 changed files with 277 additions and 11 deletions

View file

@ -3,6 +3,32 @@
This tool generates vanity ed25519 ([hidden service version 3][v3],
formely known as proposal 224) onion addresses.
### What is this fork?
This is my shot at implementing [trustless mining](https://github.com/cathugger/mkp224o/issues/60).
It's a garbage implementation, but it (kinda?) works.
#### Usage
```
$ ./mkp224o --genbase out/base.priv out/base.pub
writing private base key to 'out/base.priv'
writing public base key to 'out/base.pub'
done.
$ ./mkp224o -n 1 -d out -Z --basekey out/base.pub zzz
$ ./mkp224o --combine out/base.priv out/zzz*.onion/hs_ed25519_secret_key
new pk: [...]
saving to out/zzzkzmpje34nnp2yvgz7slr7rgpajzlpihsr3rpzgmekrjosnpprf2id.onion/hs_ed25519_secret_key.fixed
$ cp out/zzz*.onion/hs_ed25519_secret_key.fixed /var/lib/tor/hidden_service/hs_ed25519_secret_key
```
#### the ugly
* i'm an amateur, the math might not check out
* horrible code organization - i'm not familiar with this style of codebases at all
* depends on ed25519-donna
* only works with slow key generation (-Z)
### Requirements
* C99 compatible compiler (gcc and clang should work)

200
main.c
View file

@ -132,6 +132,13 @@ static void printhelp(FILE *out,const char *progname)
#endif
" --rawyaml raw (unprefixed) public/secret keys for -y/-Y\n"
" (may be useful for tor controller API)\n"
" --basekey base.pub\n"
" trustless mining: the private keys found will need\n"
" to be --combine'd with base.priv before use\n"
" --genbase base.priv base.pub\n"
" generate base keys for trustless mining\n"
" --combine base.priv hs_secret_key\n"
" combine a mined hs_secret key with a base key\n"
" -h, --help, --usage print help to stdout and quit\n"
" -V, --version print version information to stdout and exit\n"
,progname,progname);
@ -262,11 +269,160 @@ enum worker_type {
WT_BATCH,
};
// i'm so sorry for including an implementation header
// i didn't find another way to get access to the functions
#include "ed25519/ed25519_impl_pre.h"
static void genbase(const char *privpath, const char *pubpath)
{
u8 base_sk[32];
u8 base_pk[32];
hash_512bits base_extsk;
ge25519 ALIGN(16) A;
bignum256modm ALIGN(16) base;
FILE *fp;
randombytes(base_sk, sizeof base_sk);
ed25519_seckey_expand(base_extsk, base_sk);
expand256_modm(base, base_extsk, 32);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, base);
ge25519_pack(base_pk, &A);
printf("writing private base key to '%s'\n", privpath);
fp = fopen(privpath, "w");
if (!fp) {
perror("couldn't open");
exit(1);
}
if (fwrite(base_sk, 1, 32, fp) != 32) {
perror("write");
exit(1);
}
fclose(fp);
printf("writing public base key to '%s'\n", pubpath);
fp = fopen(pubpath, "w");
if (!fp) {
perror("couldn't open");
exit(1);
}
if (fwrite(base_pk, 1, 32, fp) != 32) {
perror("write");
exit(1);
}
fclose(fp);
puts("done.");
}
static void combine(const char *privpath, const char *hs_secretkey)
{
u8 base_sk[32], secret[96];
FILE *fp;
fp = fopen(hs_secretkey, "r");
if (fp == NULL) {
perror("failed to open hs_secret_key");
exit(1);
}
if (fread(secret, 1, 96, fp) != 96) {
perror("failed to read hs_secret_key");
exit(1);
}
if (memcmp(secret, "== ed25519v1-secret: type0 ==\0\0\0", 32) != 0) {
fprintf(stderr, "invalid hs_secret_key format.\nare you sure you picked the right file?\n");
exit(1);
}
fclose(fp);
fp = fopen(privpath, "r");
if (fp == NULL) {
perror("failed to open base.priv");
exit(1);
}
if (fread(base_sk, 1, sizeof base_sk, fp) != sizeof base_sk) {
perror("failed to read base.priv");
exit(1);
}
fclose(fp);
#if 0
u8 pk[32];
hash_512bits base_extsk;
ed25519_seckey_expand(base_extsk, base_sk);
bignum256modm ALIGN(16) base;
expand256_modm(base, base_extsk, 32);
ge25519 ALIGN(16) A, B;
ge25519_scalarmult_base_niels(&B, ge25519_niels_base_multiples, base);
u8 base_pk[32];
ge25519_pack(base_pk, &B);
ge25519_unpack_negative_vartime(&B, base_pk);
ge25519_pack(base_pk, &B);
ge25519_unpack_negative_vartime(&B, base_pk);
bignum256modm ALIGN(16) a;
expand256_modm(a, &secret[SKPREFIX_SIZE], 32);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);
ge25519_add(&A, &A, &B);
ge25519_pack(pk, &A);
printf("pk from public: ");
for (size_t i = 0; i < sizeof(pk); i++)
printf("%02x ", pk[i]);
puts("");
#endif
hash_512bits base_extsk;
bignum256modm ALIGN(16) a, b;
ge25519 ALIGN(16) A;
u8 pk[32];
expand256_modm(a, &secret[32], 32);
ed25519_seckey_expand(base_extsk, base_sk);
expand256_modm(b, base_extsk, 32);
add256_modm(a, a, b);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);
ge25519_pack(pk, &A);
contract256_modm(&secret[32], a);
expand256_modm(a, &secret[32], 32);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);
ge25519_pack(pk, &A);
printf("new pk: ");
for (size_t i = 0; i < sizeof(pk); i++)
printf("%02x ", pk[i]);
puts("");
char *newname = malloc(strlen(hs_secretkey) + strlen(".fixed") + 1);
strcpy(newname, hs_secretkey);
strcat(newname, ".fixed");
printf("saving to %s\n", newname);
fp = fopen(newname, "w");
if (!fp) {
perror("couldn't open");
exit(1);
}
if (fwrite(secret, 1, sizeof secret, fp) != sizeof secret) {
perror("failed to write fixed privkey");
exit(1);
}
fclose(fp);
}
#include "ed25519/ed25519_impl_post.h"
int main(int argc,char **argv)
{
const char *outfile = 0;
const char *infile = 0;
const char *onehostname = 0;
const char *basekeyfile = 0;
const char *arg;
int ignoreargs = 0;
int dirnameflag = 0;
@ -326,6 +482,28 @@ int main(int argc,char **argv)
printversion();
exit(0);
}
else if (!strcmp(arg,"combine")) {
if (argc != 2) {
printhelp(stdout,progname);
exit(0);
}
combine(argv[0],argv[1]);
exit(0);
}
else if (!strcmp(arg,"genbase")) {
if (argc != 2) {
printhelp(stdout,progname);
exit(0);
}
genbase(argv[0],argv[1]);
exit(0);
}
else if (!strcmp(arg,"basekey")) {
if (argc--)
basekeyfile = *argv++;
else
e_additional();
}
else if (!strcmp(arg,"rawyaml"))
yamlraw = 1;
#ifdef PASSPHRASE
@ -497,6 +675,28 @@ int main(int argc,char **argv)
filters_add(arg);
}
if (wt != WT_SLOW) {
fprintf(stderr,"you're not using -Z. this will probably break.");
}
if (basekeyfile) {
u8 base_pk[32];
FILE *fp = fopen(basekeyfile, "r");
if (!fp) {
perror("couldn't open basekey");
exit(1);
}
if (fread(base_pk, 1, sizeof base_pk, fp) != sizeof base_pk) {
perror("incomplete read of base_pk");
exit(1);
}
fclose(fp);
ed25519_pubkey_setbase(base_pk);
} else {
fprintf(stderr, "This build requires using --basekey.\n");
exit(1);
}
if (yamlinput && yamloutput) {
fprintf(stderr,"both -y and -Y does not make sense\n");
exit(1);

View file

@ -60,6 +60,9 @@ pthread_mutex_t determseed_mutex;
u8 determseed[SEED_LEN];
#endif
static int ed25519_pubkey_onbase(u8 *pk,const u8 *sk);
static void sanitycheck(const u8 *sk, const u8 *pk);
char *makesname(void)
{
@ -88,16 +91,7 @@ static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
pthread_mutex_unlock(&keysgenerated_mutex);
}
// disabled as this was never ever triggered as far as I'm aware
#if 0
// Sanity check that the public key matches the private one.
ge_p3 ALIGN(16) point;
u8 testpk[PUBLIC_LEN];
ge_scalarmult_base(&point,&secret[SKPREFIX_SIZE]);
ge_p3_tobytes(testpk,&point);
if (memcmp(testpk,&pubonion[PKPREFIX_SIZE],PUBLIC_LEN) != 0)
abort();
#endif
sanitycheck(&secret[SKPREFIX_SIZE], &pubonion[PKPREFIX_SIZE]);
if (!yamloutput) {
if (createdir(sname,1) != 0) {
@ -266,3 +260,48 @@ void worker_init(void)
crypto_sign_ed25519_donna_ge_initeightpoint();
#endif
}
// there's not really any good place to add ed25519 functions
// so i just add them there
// i don't understand how this codebase is organized :(
ge25519 ALIGN(16) PUBKEY_BASE = {0};
int pubkey_base_initialized;
void ed25519_pubkey_setbase(const u8 base_pk[32])
{
u8 tmp_pk[32];
ge25519_unpack_negative_vartime(&PUBKEY_BASE, base_pk);
// dumb hack: unpack flips the point. to get the original point
// back, i just pack and unpack it again
ge25519_pack(tmp_pk, &PUBKEY_BASE);
ge25519_unpack_negative_vartime(&PUBKEY_BASE, tmp_pk);
pubkey_base_initialized = 1;
}
static int ed25519_pubkey_onbase(u8 *pk,const u8 *sk)
{
bignum256modm a;
ge25519 ALIGN(16) A;
if (unlikely(pubkey_base_initialized == 0))
abort();
// ge_scalarmult_base(&A, sk);
expand256_modm(a,sk,32);
ge25519_scalarmult_base_niels(&A,ge25519_niels_base_multiples,a);
ge25519_add(&A, &A, &PUBKEY_BASE);
ge25519_pack(pk,&A);
return 0;
}
static void sanitycheck(const u8 *sk, const u8 *pk) {
u8 testpk[PUBLIC_LEN];
ed25519_pubkey_onbase(testpk, sk);
if (memcmp(testpk,pk,PUBLIC_LEN) != 0) {
fprintf(stderr, "Sanity check failed. Either I fucked something up, or you're using an unsupported combination of options. Probably both.\n");
abort();
}
}

View file

@ -36,6 +36,7 @@ extern u8 determseed[SEED_LEN];
#endif
extern void worker_init(void);
extern void ed25519_pubkey_setbase(const u8 base_pk[32]);
extern char *makesname(void);
extern size_t worker_batch_memuse(void);

View file

@ -42,7 +42,7 @@ again:
if (unlikely(endwork))
goto end;
ed25519_pubkey(pk,sk);
ed25519_pubkey_onbase(pk,sk);
#ifdef STATISTICS
++st->numcalc.v;