on 504ca38 help sign in
bridge/src/lib/walletgen.js
117 lines 3.3 kB history raw
1import ob from 'urbit-ob';
2import kg from 'urbit-key-generation';
3import * as more from 'more-entropy';
4import { chunk, flatMap, zipWith } from 'lodash';
5import { wrap } from 'comlink';
6import { shas } from 'lib/networkCode';
8import {
9 MIN_STAR,
10 MIN_PLANET,
11 SEED_ENTROPY_BITS,
12 GALAXY_ENTROPY_BITS,
13 STAR_ENTROPY_BITS,
14 PLANET_ENTROPY_BITS,
15 ZOD,
16} from './constants';
17import { stripHexPrefix } from './utils/address';
19const worker = wrap(
20 new Worker('../worker/worker.js', { type: 'module' })
21);
23const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8;
25const getTicketBitSize = point =>
26 point < MIN_STAR
27 ? GALAXY_ENTROPY_BITS
28 : point < MIN_PLANET
29 ? STAR_ENTROPY_BITS
30 : PLANET_ENTROPY_BITS;
32// returns a promise for a ticket string
33export const makeTicket = point => {
34 const bits = getTicketBitSize(point);
36 const bytes = bits / 8;
37 const some = new Uint8Array(bytes);
38 window.crypto.getRandomValues(some);
40 const gen = new more.Generator();
42 return new Promise((resolve, reject) => {
43 gen.generate(bits, result => {
44 const chunked = chunk(result, 2);
45 const desired = chunked.slice(0, bytes); // only take required entropy
46 const more = flatMap(desired, arr => arr[0] ^ arr[1]);
47 const entropy = zipWith(some, more, (x, y) => x ^ y);
48 const buf = Buffer.from(entropy);
49 const patq = ob.hex2patq(buf.toString('hex'));
50 resolve(patq);
51 reject('Entropy generation failed');
52 });
53 });
54};
56export const makeDeterministicTicket = (point, seed) => {
57 const bits = getTicketBitSize(point);
59 const bytes = bits / 8;
61 const pointSalt = Buffer.concat([
62 Buffer.from(point.toString()),
63 Buffer.from('invites'),
64 ]);
65 const normalizedSeed = stripHexPrefix(seed);
66 const entropy = shas(Buffer.from(normalizedSeed, 'hex'), pointSalt);
68 const buf = entropy.slice(0, bytes);
69 const patq = ob.hex2patq(buf.toString('hex'));
70 return patq;
71};
73// return a wallet object
74export const generateWallet = async (point, ticket, boot, revision = 0) => {
75 const config = {
76 ticket: ticket,
77 seedSize: SEED_LENGTH_BYTES,
78 ship: point,
79 password: '',
80 revision,
81 boot: boot,
82 };
84 // This is here to notify anyone who opens console because the thread
85 // hangs, blocking UI updates so this cannot be done in the UI
86 console.log('Generating Wallet for point address: ', point);
88 return new Promise(async resolve => {
89 // Use a web worker to process the data
90 const processed = await worker.generateWallet(JSON.stringify(config));
92 resolve(processed);
93 });
94};
96export const generateOwnershipWallet = async (ship, ticket) => {
97 return kg.generateOwnershipWallet({ ship, ticket });
98};
100// temporary wallets need to be derivable from just the ticket,
101// so we always use ~zod as the wallet point.
102export const generateTemporaryOwnershipWallet = ticket =>
103 generateOwnershipWallet(ZOD, ticket);
105export const generateTemporaryTicketAndWallet = async point => {
106 const ticket = await makeTicket(point);
107 const owner = await generateOwnershipWallet(ZOD, ticket);
109 return { ticket, owner };
110};
112export const generateTemporaryDeterministicWallet = async (point, seed) => {
113 const ticket = makeDeterministicTicket(point, seed);
114 const owner = await generateOwnershipWallet(ZOD, ticket);
116 return { ticket, owner };
117};