on 08b82bf help sign in
bridge/src/lib/keys.js
165 lines 3.6 kB history raw
1import BN from 'bn.js';
2import { Just, Nothing } 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 { eqAddr, addHexPrefix } from './wallet';
11const NETWORK_KEY_CURVE_PARAMETER = '42';
13// ctsy joemfb
14const b64 = buf => {
15 let hex = buf.reverse().toString('hex');
16 let n = new BN(hex, 'hex');
17 let c = [];
18 while (1 === n.cmpn(0)) {
19 c.push(n.andln(0x3f));
20 n = n.shrn(6);
21 }
23 // prettier-ignore
24 const trans = j =>
25 10 > j
26 ? j + 48
27 : 36 > j
28 ? j + 87
29 : 62 > j
30 ? j + 29
31 : 62 === j
32 ? 45
33 : 126;
35 return (
36 '0w' +
37 c.reduce(
38 (a, b, i) =>
39 String.fromCharCode(trans(b)) + (i && 0 === i % 5 ? '.' : '') + a,
40 ''
41 )
42 );
43};
45const jam = seed => {
46 const hex = serial
47 .jam(seed)
48 .toString()
49 .slice(2);
50 const pad = hex.length % 2 === 0 ? hex : '0' + hex;
51 return Buffer.from(pad, 'hex').reverse();
52};
54// simple alias to avoid importing kg into component scope
55export const deriveNetworkKeys = seed => kg.deriveNetworkKeys(seed);
57/**
58 * @param {object} pair
59 * @param {number} point
60 * @param {number} revision
61 * @return {string}
62 */
63export const compileNetworkingKey = (pair, point, revision) => {
64 const bnsec = new BN(
65 pair.crypt.private + pair.auth.private + NETWORK_KEY_CURVE_PARAMETER,
66 'hex'
67 );
69 const sed = noun.dwim(
70 noun.Atom.fromInt(point),
71 noun.Atom.fromInt(revision),
72 noun.Atom.fromString(bnsec.toString()),
73 noun.Atom.yes
74 );
76 return b64(jam(sed));
77};
79/**
80 * @param {object} urbitWallet
81 * @param {number} revision
82 * @return {Promise<Maybe<string>>}
83 */
84export const deriveNetworkSeedFromUrbitWallet = async (
85 urbitWallet,
86 revision = 1
87) => {
88 return deriveNetworkSeedFromSeed(urbitWallet.management.seed, revision);
89};
91/**
92 * @param {Maybe<any>} wallet
93 * @param {Maybe<string>} authMnemonic
94 * @param {object} details
95 * @param {number} revision
96 * @return {Promise<Maybe<string>>}
97 */
98export const deriveNetworkSeedFromMnemonic = async (
99 wallet,
100 authMnemonic,
101 details,
102 revision = 1
103) => {
104 const isManagementProxy = eqAddr(wallet.address, details.managementProxy);
106 if (isManagementProxy) {
107 return await deriveNetworkSeedFromSeed(authMnemonic, revision);
108 }
110 return Nothing();
111};
113/**
114 * @param {string} seed
115 * @param {number} revision
116 * @return {Promise<Maybe<string>>}
117 */
118const deriveNetworkSeedFromSeed = async (seed, revision) => {
119 const networkSeed = await kg.deriveNetworkSeed(seed, '', revision);
120 // apparently deriveNetworkSeed can return empty string
121 // and perhaps even malformed
122 return networkSeed === '' ? Nothing() : Just(networkSeed);
123};
125/**
126 * @return {Promise<Maybe<string>>}
127 */
128export const attemptNetworkSeedDerivation = async ({
129 urbitWallet,
130 wallet,
131 authMnemonic,
132 details,
133 revision,
134}) => {
135 if (Just.hasInstance(urbitWallet)) {
136 return await deriveNetworkSeedFromUrbitWallet(urbitWallet.value, revision);
137 }
139 if (Just.hasInstance(wallet) && Just.hasInstance(authMnemonic)) {
140 return await deriveNetworkSeedFromMnemonic(
141 wallet.value,
142 authMnemonic.value,
143 details,
144 revision
145 );
146 }
148 return Nothing();
149};
151/**
152 *
153 * @param {object} pair
154 * @param {object} details
155 * @return {boolean}
156 */
157export const keysMatchChain = (pair, details) => {
158 const { crypt, auth } = pair;
159 const { encryptionKey, authenticationKey } = details;
161 return (
162 encryptionKey === addHexPrefix(crypt.public) &&
163 authenticationKey === addHexPrefix(auth.public)
164 );
165};