on be08dee help sign in
bridge/src/lib/walletgen.js
115 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 { shas } from 'lib/networkCode';
7import {
8 MIN_STAR,
9 MIN_PLANET,
10 SEED_ENTROPY_BITS,
11 GALAXY_ENTROPY_BITS,
12 STAR_ENTROPY_BITS,
13 PLANET_ENTROPY_BITS,
14 ZOD,
15} from './constants';
16import Worker from 'worker';
17import { stripHexPrefix } from './utils/address';
19const worker = new Worker();
21const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8;
23const getTicketBitSize = point =>
24 point < MIN_STAR
25 ? GALAXY_ENTROPY_BITS
26 : point < MIN_PLANET
27 ? STAR_ENTROPY_BITS
28 : PLANET_ENTROPY_BITS;
30// returns a promise for a ticket string
31export const makeTicket = point => {
32 const bits = getTicketBitSize(point);
34 const bytes = bits / 8;
35 const some = new Uint8Array(bytes);
36 window.crypto.getRandomValues(some);
38 const gen = new more.Generator();
40 return new Promise((resolve, reject) => {
41 gen.generate(bits, result => {
42 const chunked = chunk(result, 2);
43 const desired = chunked.slice(0, bytes); // only take required entropy
44 const more = flatMap(desired, arr => arr[0] ^ arr[1]);
45 const entropy = zipWith(some, more, (x, y) => x ^ y);
46 const buf = Buffer.from(entropy);
47 const patq = ob.hex2patq(buf.toString('hex'));
48 resolve(patq);
49 reject('Entropy generation failed');
50 });
51 });
52};
54export const makeDeterministicTicket = (point, seed) => {
55 const bits = getTicketBitSize(point);
57 const bytes = bits / 8;
59 const pointSalt = Buffer.concat([
60 Buffer.from(point.toString()),
61 Buffer.from('invites'),
62 ]);
63 const normalizedSeed = stripHexPrefix(seed);
64 const entropy = shas(Buffer.from(normalizedSeed, 'hex'), pointSalt);
66 const buf = entropy.slice(0, bytes);
67 const patq = ob.hex2patq(buf.toString('hex'));
68 return patq;
69};
71// return a wallet object
72export const generateWallet = async (point, ticket, boot, revision = 0) => {
73 const config = {
74 ticket: ticket,
75 seedSize: SEED_LENGTH_BYTES,
76 ship: point,
77 password: '',
78 revision,
79 boot: boot,
80 };
82 // This is here to notify anyone who opens console because the thread
83 // hangs, blocking UI updates so this cannot be done in the UI
84 console.log('Generating Wallet for point address: ', point);
86 return new Promise(async resolve => {
87 // Use a web worker to process the data
88 const processed = await worker.generateWallet(JSON.stringify(config));
90 resolve(processed);
91 });
92};
94export const generateOwnershipWallet = async (ship, ticket) => {
95 return kg.generateOwnershipWallet({ ship, ticket });
96};
98// temporary wallets need to be derivable from just the ticket,
99// so we always use ~zod as the wallet point.
100export const generateTemporaryOwnershipWallet = ticket =>
101 generateOwnershipWallet(ZOD, ticket);
103export const generateTemporaryTicketAndWallet = async point => {
104 const ticket = await makeTicket(point);
105 const owner = await generateOwnershipWallet(ZOD, ticket);
107 return { ticket, owner };
108};
110export const generateTemporaryDeterministicWallet = async (point, seed) => {
111 const ticket = makeDeterministicTicket(point, seed);
112 const owner = await generateOwnershipWallet(ZOD, ticket);
114 return { ticket, owner };
115};