@@ -6,8 +6,9 @@ import * as noun from '../nockjs/noun';
66import * as serial from '../nockjs/serial';
77import * as kg from 'urbit-key-generation/dist';
88
9−import { BRIDGE_ERROR } from './error';
10−import { WALLET_TYPES, eqAddr } from './wallet';
9+import { eqAddr, addHexPrefix } from './wallet';
10+
11+const NETWORK_KEY_CURVE_PARAMETER = '42';
1112
1213// ctsy joemfb
1314const b64 = buf => {
@@ -50,9 +51,20 @@ const jam = seed => {
5051 return Buffer.from(pad, 'hex').reverse();
5152};
5253
53−const 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
54+// simple alias to avoid importing kg into component scope
55+export const deriveNetworkKeys = seed => kg.deriveNetworkKeys(seed);
56+
57+/**
58+ * @param {object} pair
59+ * @param {number} point
60+ * @param {number} revision
61+ * @return {string}
62+ */
63+export const compileNetworkingKey = (pair, point, revision) => {
64+ const bnsec = new BN(
65+ pair.crypt.private + pair.auth.private + NETWORK_KEY_CURVE_PARAMETER,
66+ 'hex'
67+ );
5668
5769 const sed = noun.dwim(
5870 noun.Atom.fromInt(point),
@@ -64,68 +76,93 @@ const genKey = (networkSeed, point, revision) => {
6476 return b64(jam(sed));
6577};
6678
67−// 'next' refers to setting the next set of keys
68−// if false, we use revision - 1
69−const attemptNetworkSeedDerivation = async (next, args) => {
70− const { walletType, urbitWallet, authMnemonic } = args;
71−
72− // NB (jtobin):
73− //
74− // following code is intentionally verbose for sake of clarity
75−
76− const point = need.point(args.pointCursor);
77− const pointDetails = need.fromPointCache(args.pointCache, point);
78−
79− const revision =
80− next === true
81− ? parseInt(pointDetails.keyRevisionNumber)
82− : parseInt(pointDetails.keyRevisionNumber) - 1;
83−
84− let managementSeed = '';
85−
86− const ticketLike = [WALLET_TYPES.TICKET, WALLET_TYPES.SHARDS];
87−
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− });
95−
96− managementSeed = uwal.management.seed;
97− } else if (walletType === WALLET_TYPES.MNEMONIC) {
98− const walProxy = need.addressFromWallet(args.wallet);
79+/**
80+ * @param {Maybe<any>} urbitWallet
81+ * @param {number} revision
82+ * @return {Promise<Maybe<string>>}
83+ */
84+export const deriveNetworkSeedFromUrbitWallet = async (
85+ urbitWallet,
86+ revision = 1
87+) => {
88+ const _urbitWallet = need.wallet(urbitWallet);
89+ return deriveNetworkSeedFromSeed(_urbitWallet.management.seed, revision);
90+};
9991
100− const mnemonic = authMnemonic.matchWith({
101− Just: mnem => mnem.value,
102− Nothing: _ => {
103− throw BRIDGE_ERROR.MISSING_MNEMONIC;
104− },
105− });
92+/**
93+ * @param {Maybe<any>} wallet
94+ * @param {Maybe<string>} authMnemonic
95+ * @param {object} details
96+ * @param {number} revision
97+ * @return {Promise<Maybe<string>>}
98+ */
99+export const deriveNetworkSeedFromMnemonic = async (
100+ wallet,
101+ authMnemonic,
102+ details,
103+ revision = 1
104+) => {
105+ const _wallet = need.wallet(wallet);
106+ const _mnemonic = need.authMnemonic(authMnemonic);
107+ const isManagementProxy = eqAddr(_wallet.address, details.managementProxy);
108+
109+ if (isManagementProxy) {
110+ return await deriveNetworkSeedFromSeed(_mnemonic, revision);
111+ }
106112
107− const chainProxy = pointDetails.managementProxy;
113+ return Nothing();
114+};
108115
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);
116+/**
117+ * @param {string} seed
118+ * @param {number} revision
119+ * @return {Promise<Maybe<string>>}
120+ */
121+const deriveNetworkSeedFromSeed = async (seed, revision) => {
122+ const networkSeed = await kg.deriveNetworkSeed(seed, '', revision);
123+ // apparently deriveNetworkSeed can return empty string
124+ // and perhaps even malformed
125+ return networkSeed === '' ? Nothing() : Just(networkSeed);
126+};
112127
113− if (networkSeedDerivable === true) {
114− managementSeed = mnemonic;
115− }
128+/**
129+ * @return {Promise<Maybe<string>>}
130+ */
131+export const attemptNetworkSeedDerivation = async ({
132+ urbitWallet,
133+ wallet,
134+ authMnemonic,
135+ details,
136+ revision,
137+}) => {
138+ if (Just.hasInstance(urbitWallet)) {
139+ return await deriveNetworkSeedFromUrbitWallet(urbitWallet, revision);
116140 }
117141
118− if (managementSeed !== '') {
119− const seed = await kg.deriveNetworkSeed(managementSeed, '', revision);
120−
121− if (seed === '') {
122− return Nothing();
123− }
124−
125− return Just(seed);
142+ if (Just.hasInstance(wallet) && Just.hasInstance(authMnemonic)) {
143+ return await deriveNetworkSeedFromMnemonic(
144+ wallet,
145+ authMnemonic,
146+ details,
147+ revision
148+ );
126149 }
127150
128151 return Nothing();
129152};
130153
131−export { genKey, attemptNetworkSeedDerivation };
154+/**
155+ *
156+ * @param {object} pair
157+ * @param {object} details
158+ * @return {boolean}
159+ */
160+export const keysMatchChain = (pair, details) => {
161+ const { crypt, auth } = pair;
162+ const { encryptionKey, authenticationKey } = details;
163+
164+ return (
165+ encryptionKey === addHexPrefix(crypt.public) &&
166+ authenticationKey === addHexPrefix(auth.public)
167+ );
168+};