on b87ca5c help sign in
bridge/src/lib/keys.js
182 lines 4.1 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 } from './wallet';
10// the curve param for the network keys
11export const NETWORK_KEY_CURVE_PARAMETER = '42';
12// the current crypto suite version
13export const CRYPTO_SUITE_VERSION = 1;
15export const CURVE_ZERO_ADDR =
16 '0x0000000000000000000000000000000000000000000000000000000000000000';
18// ctsy joemfb
19const b64 = buf => {
20 let hex = buf.reverse().toString('hex');
21 let n = new BN(hex, 'hex');
22 let c = [];
23 while (1 === n.cmpn(0)) {
24 c.push(n.andln(0x3f));
25 n = n.shrn(6);
26 }
28 // prettier-ignore
29 const trans = j =>
30 10 > j
31 ? j + 48
32 : 36 > j
33 ? j + 87
34 : 62 > j
35 ? j + 29
36 : 62 === j
37 ? 45
38 : 126;
40 return (
41 '0w' +
42 c.reduce(
43 (a, b, i) =>
44 String.fromCharCode(trans(b)) + (i && 0 === i % 5 ? '.' : '') + a,
45 ''
46 )
47 );
48};
50const jam = seed => {
51 const hex = serial
52 .jam(seed)
53 .toString()
54 .slice(2);
55 const pad = hex.length % 2 === 0 ? hex : '0' + hex;
56 return Buffer.from(pad, 'hex').reverse();
57};
59// simple alias to avoid importing kg into component scope
60export const deriveNetworkKeys = seed => kg.deriveNetworkKeys(seed);
62/**
63 * @param {object} pair
64 * @param {number} point
65 * @param {number} revision
66 * @return {string}
67 */
68export const compileNetworkingKey = (pair, point, revision) => {
69 const bnsec = new BN(
70 pair.crypt.private + pair.auth.private + NETWORK_KEY_CURVE_PARAMETER,
71 'hex'
72 );
74 const sed = noun.dwim(
75 noun.Atom.fromInt(point),
76 noun.Atom.fromInt(revision),
77 noun.Atom.fromString(bnsec.toString()),
78 noun.Atom.yes
79 );
81 return b64(jam(sed));
82};
84/**
85 * @param {object} urbitWallet
86 * @param {number} revision
87 * @return {Promise<Maybe<string>>}
88 */
89export const deriveNetworkSeedFromUrbitWallet = async (
90 urbitWallet,
91 revision = 1
92) => {
93 return await deriveNetworkSeedFromMnemonic(
94 urbitWallet.management.seed,
95 revision
96 );
97};
99/**
100 * @param {Maybe<any>} wallet
101 * @param {string} authMnemonic
102 * @param {object} details
103 * @param {number} revision
104 * @return {Promise<Maybe<string>>}
105 */
106export const deriveNetworkSeedFromManagementMnemonic = async (
107 wallet,
108 authMnemonic,
109 details,
110 revision = 1
111) => {
112 const isManagementProxy = eqAddr(wallet.address, details.managementProxy);
114 // the network seed is derivable iff this mnemonic is the management proxy
115 if (isManagementProxy) {
116 return await deriveNetworkSeedFromMnemonic(authMnemonic, revision);
117 }
119 return Nothing();
120};
122/**
123 * @param {string} mnemonic
124 * @param {number} revision
125 * @return {Promise<Maybe<string>>}
126 */
127const deriveNetworkSeedFromMnemonic = async (mnemonic, revision) => {
128 return Just(await kg.deriveNetworkSeed(mnemonic, '', revision));
129};
131/**
132 * @return {Promise<Maybe<string>>}
133 */
134export const attemptNetworkSeedDerivation = async ({
135 urbitWallet,
136 wallet,
137 authMnemonic,
138 details,
139 revision,
140}) => {
141 if (Just.hasInstance(urbitWallet)) {
142 return await deriveNetworkSeedFromUrbitWallet(urbitWallet.value, revision);
143 }
145 if (Just.hasInstance(wallet) && Just.hasInstance(authMnemonic)) {
146 return await deriveNetworkSeedFromManagementMnemonic(
147 wallet.value,
148 authMnemonic.value,
149 details,
150 revision
151 );
152 }
154 return Nothing();
155};
157/**
158 *
159 * @param {object} pair
160 * @param {object} details
161 * @return {boolean}
162 */
163export const keysMatchChain = (pair, details) => {
164 const { crypt, auth } = pair;
165 const { encryptionKey, authenticationKey } = details;
167 return (
168 encryptionKey === addHexPrefix(crypt.public) &&
169 authenticationKey === addHexPrefix(auth.public)
170 );
171};
173export const segmentNetworkKey = hex => {
174 if (hex === CURVE_ZERO_ADDR) {
175 return null;
176 }
178 const sl = i => hex.slice(i, i + 4);
179 const rowFrom = i => `${sl(i)}.${sl(i + 4)}.${sl(i + 8)}.${sl(i + 12)}`;
181 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
182};