on bf5080e help sign in
bridge/src/lib/keys.js
151 lines 3.4 kB history raw
1import BN from 'bn.js'
2import Maybe from 'folktale/maybe'
4import * as noun from '../nockjs/noun'
5import * as serial from '../nockjs/serial'
6import * as kg from '../../node_modules/urbit-key-generation/dist/index'
8import { BRIDGE_ERROR } from './error'
9import {
10 addressFromSecp256k1Public,
11 WALLET_NAMES,
12 eqAddr
13 } from './wallet'
15// ctsy joemfb
16const b64 = buf => {
17 let hex = buf.reverse().toString('hex')
18 let n = new BN(hex, 'hex')
19 let c = []
20 while (1 === n.cmpn(0)) {
21 c.push(n.andln(0x3f))
22 n = n.shrn(6)
23 }
25 const trans = j =>
26 10 > j
27 ? j + 48
28 : 36 > j
29 ? j + 87
30 : 62 > j
31 ? j + 29
32 : 62 === j
33 ? 45
34 : 126
36 return '0w' +
37 c.reduce((a, b, i) =>
38 String.fromCharCode(trans(b)) +
39 (( i && 0 === i % 5 ) ? '.' : '') + a,
40 '')
43const jam = seed => {
44 const hex = serial.jam(seed).toString().slice(2)
45 const pad = hex.length % 2 === 0 ? hex : '0' + hex
46 return Buffer.from(pad, 'hex').reverse()
49const genKey = (networkSeed, point, revision) => {
50 const pair = kg.deriveNetworkKeys(networkSeed)
51 const bnsec = new BN(pair.crypt.private + pair.auth.private + '42', 'hex') // '42' is curve parameter
53 const sed = noun.dwim(
54 noun.Atom.fromString(point),
55 noun.Atom.fromInt(revision),
56 noun.Atom.fromString(bnsec.toString()),
57 noun.Atom.yes
58 )
60 return b64(jam(sed))
63// 'next' refers to setting the next set of keys
64// if false, we use revision - 1
65const attemptSeedDerivation = async (next, args) => {
66 const { walletType, wallet, pointCursor, pointCache } = args
67 const { urbitWallet, authMnemonic } = args
69 // NB (jtobin):
70 //
71 // following code is intentionally verbose for sake of clarity
73 const walProxy = wallet.matchWith({
74 Just: wal => addressFromSecp256k1Public(wal.value.publicKey),
75 Nothing: _ => {
76 throw BRIDGE_ERROR.MISSING_WALLET
77 }
78 })
80 const point = pointCursor.matchWith({
81 Just: pt => pt.value,
82 Nothing: _ => {
83 throw BRIDGE_ERROR.MISSING_POINT
84 }
85 })
87 const pointDetails =
88 point in pointCache
89 ? pointCache[point]
90 : (() => { throw BRIDGE_ERROR.MISSING_POINT })()
92 const revision =
93 next === true
94 ? parseInt(pointDetails.keyRevisionNumber)
95 : parseInt(pointDetails.keyRevisionNumber) - 1
97 let managementSeed = ''
99 const ticketLike = [ WALLET_NAMES.TICKET, WALLET_NAMES.SHARDS ]
101 if (ticketLike.includes(walletType)) {
103 const uwal = urbitWallet.matchWith({
104 Just: uw => uw.value,
105 Nothing: _ => {
106 throw BRIDGE_ERROR.MISSING_URBIT_WALLET
107 }
108 })
110 managementSeed = uwal.management.seed
112 } else if (walletType === WALLET_NAMES.MNEMONIC) {
114 const mnemonic = authMnemonic.matchWith({
115 Just: mnem => mnem.value,
116 Nothing: _ => {
117 throw BRIDGE_ERROR.MISSING_MNEMONIC
118 }
119 })
121 const chainProxy = pointDetails.managementProxy
123 // the network seed is only derivable from mnemonic if the derived
124 // management seed equals the record we have on chain
125 const networkSeedDerivable = eqAddr(walProxy, chainProxy)
127 if (networkSeedDerivable === true) {
128 managementSeed = mnemonic
129 }
130 }
132 let networkSeed = Maybe.Nothing()
134 if (managementSeed !== '') {
135 const seed =
136 await kg.deriveNetworkSeed(managementSeed, '', revision)
138 networkSeed = Maybe.Just(seed)
139 }
141 return networkSeed
147export {
148 genKey,
149 attemptSeedDerivation