#define _GNU_SOURCE 1 #include "secp256k1.h" #include "secp256k1_ecdh.h" #include "onion_key.h" #include #include #include #include #include #include #include /* Not really! */ static void random_bytes(void *dst, size_t n) { size_t i; unsigned char *d = dst; for (i = 0; i < n; i++) d[i] = random() % 256; } /* Compressed key would start with 0x3? Subtract from group. Thanks * Greg Maxwell. */ static void flip_key(struct seckey *seckey) { int i; bool carry = 0; const int64_t group[] = { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFEULL, 0xBAAEDCE6AF48A03BULL, 0xBFD25E8CD0364141ULL }; for (i = 3; i >= 0; i--) { uint64_t v = be64_to_cpu(seckey->u.be64[i]); if (carry) { /* Beware wrap if v == 0xFFFF.... */ carry = (group[i] <= v); v++; } else carry = (group[i] < v); v = group[i] - v; seckey->u.be64[i] = cpu_to_be64(v); } } #if 0 int main(int argc, char *argv[]) { struct seckey k; k.u.be64[0] = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL); k.u.be64[1] = cpu_to_be64(0xFFFFFFFFFFFFFFFEULL); k.u.be64[2] = cpu_to_be64(0xBAAEDCE6AF48A03BULL); k.u.be64[3] = cpu_to_be64(0xBFD25E8CD0364141ULL); flip_key(&k); assert(k.u.be64[0] == 0); assert(k.u.be64[1] == 0); assert(k.u.be64[2] == 0); assert(k.u.be64[3] == 0); flip_key(&k); assert(k.u.be64[0] == cpu_to_be64(0xFFFFFFFFFFFFFFFFULL)); assert(k.u.be64[1] == cpu_to_be64(0xFFFFFFFFFFFFFFFEULL)); assert(k.u.be64[2] == cpu_to_be64(0xBAAEDCE6AF48A03BULL)); assert(k.u.be64[3] == cpu_to_be64(0xBFD25E8CD0364141ULL)); k.u.be64[0] = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL); k.u.be64[1] = cpu_to_be64(0xFFFFFFFFFFFFFFFEULL); k.u.be64[2] = cpu_to_be64(0xBAAEDCE6AF48A03BULL); k.u.be64[3] = cpu_to_be64(0xBFD25E8CD0364142ULL); flip_key(&k); assert(k.u.be64[0] == 0xFFFFFFFFFFFFFFFFULL); assert(k.u.be64[1] == 0xFFFFFFFFFFFFFFFFULL); assert(k.u.be64[2] == 0xFFFFFFFFFFFFFFFFULL); assert(k.u.be64[3] == 0xFFFFFFFFFFFFFFFFULL); flip_key(&k); assert(k.u.be64[0] == cpu_to_be64(0xFFFFFFFFFFFFFFFFULL)); assert(k.u.be64[1] == cpu_to_be64(0xFFFFFFFFFFFFFFFEULL)); assert(k.u.be64[2] == cpu_to_be64(0xBAAEDCE6AF48A03BULL)); assert(k.u.be64[3] == cpu_to_be64(0xBFD25E8CD0364142ULL)); return 0; } #endif static void random_key(secp256k1_context *ctx, struct seckey *seckey, secp256k1_pubkey *pkey) { do { random_bytes(seckey->u.u8, sizeof(seckey->u)); } while (!secp256k1_ec_pubkey_create(ctx, pkey, seckey->u.u8)); } /* We don't want to spend a byte encoding sign, so make sure it's 0x2 */ static void gen_keys(secp256k1_context *ctx, struct seckey *seckey, struct onion_pubkey *pubkey) { unsigned char tmp[33]; secp256k1_pubkey pkey; size_t len; random_key(ctx, seckey, &pkey); secp256k1_ec_pubkey_serialize(ctx, tmp, &len, &pkey, SECP256K1_EC_COMPRESSED); assert(len == sizeof(tmp)); if (tmp[0] == 0x3) flip_key(seckey); memcpy(pubkey, tmp+1, sizeof(*pubkey)); } void print_keypair(int pub, int priv) { secp256k1_context *ctx; struct seckey seckey; struct onion_pubkey pubkey; char sechex[hex_str_size(sizeof(seckey))]; char pubhex[hex_str_size(sizeof(pubkey))]; assert(pub || priv); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); gen_keys(ctx, &seckey, &pubkey); hex_encode(&seckey, sizeof(seckey), sechex, sizeof(sechex)); hex_encode(&pubkey, sizeof(pubkey), pubhex, sizeof(pubhex)); if (pub && priv) { printf("%s:%s\n", sechex, pubhex); } else { printf("%s\n", (priv ? sechex : pubhex)); } } int main(int argc, char *argv[]) { int pub = 1, priv = 1; if (argc >= 1) { if (strcmp(argv[1], "--pub") == 0) { pub = 1; priv = 0; argc--; argv++; } else if (strcmp(argv[1], "--priv") == 0) { pub = 0; priv = 1; argc--; argv++; } } if (argc <= 1) { srandom(time(NULL) + getpid()); print_keypair(pub, priv); } else { int i; for (i = 1; i < argc; i++) { srandom(atoi(argv[i])); print_keypair(pub, priv); } } return 0; }