on b72f345 help sign in
bridge/src/lib/keys.js
174 lines 3.9 kB history raw
1import BN from 'bn.js';
2import { Just, Nothing } from 'folktale/maybe';
4import * as noun from '../nockjs/noun';
5import * as serial from '../nockjs/serial';
6import * as kg from 'urbit-key-generation/dist';
8import { eqAddr, addHexPrefix, CURVE_ZERO_ADDR } from './wallet';
10const NETWORK_KEY_CURVE_PARAMETER = '42';
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};
53// simple alias to avoid importing kg into component scope
54export const deriveNetworkKeys = seed => kg.deriveNetworkKeys(seed);
56/**
57 * @param {object} pair
58 * @param {number} point
59 * @param {number} revision
60 * @return {string}
61 */
62export const compileNetworkingKey = (pair, point, revision) => {
63 const bnsec = new BN(
64 pair.crypt.private + pair.auth.private + NETWORK_KEY_CURVE_PARAMETER,
65 'hex'
66 );
68 const sed = noun.dwim(
69 noun.Atom.fromInt(point),
70 noun.Atom.fromInt(revision),
71 noun.Atom.fromString(bnsec.toString()),
72 noun.Atom.yes
73 );
75 return b64(jam(sed));
76};
78/**
79 * @param {object} urbitWallet
80 * @param {number} revision
81 * @return {Promise<Maybe<string>>}
82 */
83export const deriveNetworkSeedFromUrbitWallet = async (
84 urbitWallet,
85 revision = 1
86) => {
87 return deriveNetworkSeedFromSeed(urbitWallet.management.seed, revision);
88};
90/**
91 * @param {Maybe<any>} wallet
92 * @param {Maybe<string>} authMnemonic
93 * @param {object} details
94 * @param {number} revision
95 * @return {Promise<Maybe<string>>}
96 */
97export const deriveNetworkSeedFromMnemonic = async (
98 wallet,
99 authMnemonic,
100 details,
101 revision = 1
102) => {
103 const isManagementProxy = eqAddr(wallet.address, details.managementProxy);
105 if (isManagementProxy) {
106 return await deriveNetworkSeedFromSeed(authMnemonic, revision);
107 }
109 return Nothing();
110};
112/**
113 * @param {string} seed
114 * @param {number} revision
115 * @return {Promise<Maybe<string>>}
116 */
117const deriveNetworkSeedFromSeed = async (seed, revision) => {
118 const networkSeed = await kg.deriveNetworkSeed(seed, '', revision);
119 // apparently deriveNetworkSeed can return empty string
120 // and perhaps even malformed
121 return networkSeed === '' ? Nothing() : Just(networkSeed);
122};
124/**
125 * @return {Promise<Maybe<string>>}
126 */
127export const attemptNetworkSeedDerivation = async ({
128 urbitWallet,
129 wallet,
130 authMnemonic,
131 details,
132 revision,
133}) => {
134 if (Just.hasInstance(urbitWallet)) {
135 return await deriveNetworkSeedFromUrbitWallet(urbitWallet.value, revision);
136 }
138 if (Just.hasInstance(wallet) && Just.hasInstance(authMnemonic)) {
139 return await deriveNetworkSeedFromMnemonic(
140 wallet.value,
141 authMnemonic.value,
142 details,
143 revision
144 );
145 }
147 return Nothing();
148};
150/**
151 *
152 * @param {object} pair
153 * @param {object} details
154 * @return {boolean}
155 */
156export const keysMatchChain = (pair, details) => {
157 const { crypt, auth } = pair;
158 const { encryptionKey, authenticationKey } = details;
160 return (
161 encryptionKey === addHexPrefix(crypt.public) &&
162 authenticationKey === addHexPrefix(auth.public)
163 );
164};
166export const segmentNetworkKey = hex => {
167 const sl = i => hex.slice(i, i + 4);
168 const rowFrom = i => `${sl(i)}.${sl(i + 4)}.${sl(i + 8)}.${sl(i + 12)}`;
169 if (hex === CURVE_ZERO_ADDR) {
170 return null;
171 }
173 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
174};