on e15c5fd help sign in
bridge/src/lib/keys.js
131 lines 3.2 kB history raw
1import BN from 'bn.js';
2import Maybe from 'folktale/maybe';
3import * as need from './need';
5import * as noun from '../nockjs/noun';
6import * as serial from '../nockjs/serial';
7import * as kg from 'urbit-key-generation/dist';
9import { BRIDGE_ERROR } from './error';
10import { WALLET_TYPES, eqAddr } from './wallet';
12// ctsy joemfb
13const b64 = buf => {
14 let hex = buf.reverse().toString('hex');
15 let n = new BN(hex, 'hex');
16 let c = [];
17 while (1 === n.cmpn(0)) {
18 c.push(n.andln(0x3f));
19 n = n.shrn(6);
20 }
22 // prettier-ignore
23 const trans = j =>
24 10 > j
25 ? j + 48
26 : 36 > j
27 ? j + 87
28 : 62 > j
29 ? j + 29
30 : 62 === j
31 ? 45
32 : 126;
34 return (
35 '0w' +
36 c.reduce(
37 (a, b, i) =>
38 String.fromCharCode(trans(b)) + (i && 0 === i % 5 ? '.' : '') + a,
39 ''
40 )
41 );
42};
44const jam = seed => {
45 const hex = serial
46 .jam(seed)
47 .toString()
48 .slice(2);
49 const pad = hex.length % 2 === 0 ? hex : '0' + hex;
50 return Buffer.from(pad, 'hex').reverse();
51};
53const genKey = (networkSeed, point, revision) => {
54 const pair = kg.deriveNetworkKeys(networkSeed);
55 const bnsec = new BN(pair.crypt.private + pair.auth.private + '42', 'hex'); // '42' is curve parameter
57 const sed = noun.dwim(
58 noun.Atom.fromInt(point),
59 noun.Atom.fromInt(revision),
60 noun.Atom.fromString(bnsec.toString()),
61 noun.Atom.yes
62 );
64 return b64(jam(sed));
65};
67// 'next' refers to setting the next set of keys
68// if false, we use revision - 1
69const attemptNetworkSeedDerivation = async (next, args) => {
70 const { walletType, urbitWallet, authMnemonic } = args;
72 // NB (jtobin):
73 //
74 // following code is intentionally verbose for sake of clarity
76 const point = need.pointCursor(args.pointCursor);
77 const pointDetails = need.fromPointCache(args.pointCache, point);
79 const revision =
80 next === true
81 ? parseInt(pointDetails.keyRevisionNumber)
82 : parseInt(pointDetails.keyRevisionNumber) - 1;
84 let managementSeed = '';
86 const ticketLike = [WALLET_TYPES.TICKET, WALLET_TYPES.SHARDS];
88 if (ticketLike.includes(walletType)) {
89 const uwal = urbitWallet.matchWith({
90 Just: uw => uw.value,
91 Nothing: _ => {
92 throw BRIDGE_ERROR.MISSING_URBIT_WALLET;
93 },
94 });
96 managementSeed = uwal.management.seed;
97 } else if (walletType === WALLET_TYPES.MNEMONIC) {
98 const walProxy = need.addressFromWallet(args.wallet);
100 const mnemonic = authMnemonic.matchWith({
101 Just: mnem => mnem.value,
102 Nothing: _ => {
103 throw BRIDGE_ERROR.MISSING_MNEMONIC;
104 },
105 });
107 const chainProxy = pointDetails.managementProxy;
109 // the network seed is only derivable from mnemonic if the derived
110 // management seed equals the record we have on chain
111 const networkSeedDerivable = eqAddr(walProxy, chainProxy);
113 if (networkSeedDerivable === true) {
114 managementSeed = mnemonic;
115 }
116 }
118 if (managementSeed !== '') {
119 const seed = await kg.deriveNetworkSeed(managementSeed, '', revision);
121 if (seed === '') {
122 return Maybe.Nothing();
123 }
125 return Maybe.Just(seed);
126 }
128 return Maybe.Nothing();
129};
131export { genKey, attemptNetworkSeedDerivation };