forked from alexbosworth/ln-service
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1ff1b56
commit 3fb58cb
Showing
14 changed files
with
1,006 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
const {networks} = require('bitcoinjs-lib'); | ||
|
||
const {p2pkh} = require('./conf/address_versions'); | ||
const {p2sh} = require('./conf/address_versions'); | ||
|
||
/** Address version | ||
{ | ||
network: <Network Name String> | ||
[prefix]: <Bech32 Prefix String> | ||
version: <Bitcoinjs-lib Chain Address Version Number> | ||
} | ||
@throws | ||
<Error> | ||
@returns | ||
{ | ||
version: <BOLT 11 Chain Address Version Number> | ||
} | ||
*/ | ||
module.exports = ({network, prefix, version}) => { | ||
if (!!prefix) { | ||
return {version}; | ||
} | ||
|
||
switch (version) { | ||
case networks[network].pubKeyHash: | ||
return {version: p2pkh}; | ||
|
||
case networks[network].scriptHash: | ||
return {version: p2sh}; | ||
|
||
default: | ||
throw new Error('UnexpectedVersionToDeriveBoltOnChainAddressVersion'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
const chainAddressDetails = require('./chain_address_details'); | ||
const hexAsWords = require('./hex_as_words'); | ||
|
||
/** Convert chain address to bech32 words | ||
{ | ||
address: <Chain Address String> | ||
network: <Network Name String> | ||
} | ||
@returns | ||
{ | ||
words: [<Chain Address Word Number>] | ||
} | ||
*/ | ||
module.exports = ({address, network}) => { | ||
if (!address) { | ||
throw new Error('ExpectedAddressToGetWordsForChainAddress'); | ||
} | ||
|
||
if (!network) { | ||
throw new Error('ExpectedNetworkToGetWordsForChainAddress'); | ||
} | ||
|
||
const {hash, version} = chainAddressDetails({address, network}); | ||
|
||
return {words: [version].concat(hexAsWords({hex: hash}).words)}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
const {address} = require('bitcoinjs-lib'); | ||
const {networks} = require('bitcoinjs-lib'); | ||
|
||
const addressVersion = require('./address_version'); | ||
|
||
const base58 = n => { try { return address.fromBase58Check(n); } catch (e) {}}; | ||
const bech32 = n => { try { return address.fromBech32(n); } catch (e) {}}; | ||
|
||
/** Derive chain address details | ||
{ | ||
address: <Chain Address String> | ||
network: <Network Name String> | ||
} | ||
@throws | ||
<Error> on invalid chain address | ||
@returns | ||
{ | ||
hash: <Address Data Hash Hex String> | ||
version: <Witness or Address Version Number> | ||
} | ||
*/ | ||
module.exports = ({address, network}) => { | ||
if (!address) { | ||
throw new Error('ExpectedAddressToDeriveChainAddressDetails'); | ||
} | ||
|
||
if (!network || !networks[network]) { | ||
throw new Error('ExpectedNetworkToDeriveChainAddressDetails'); | ||
} | ||
|
||
const details = base58(address) || bech32(address); | ||
|
||
// Exit early: address does not parse as a bech32 or base58 address | ||
if (!details) { | ||
throw new Error('ExpectedValidAddressToDeriveChainDetails'); | ||
} | ||
|
||
const {prefix} = details; | ||
const {version} = details; | ||
|
||
return { | ||
hash: (details.data || details.hash).toString('hex'), | ||
version: addressVersion({network, prefix, version}).version, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"multipliers": [ | ||
{ | ||
"letter": "", | ||
"value": "100000000000" | ||
}, | ||
{ | ||
"letter": "m", | ||
"value": "100000000" | ||
}, | ||
{ | ||
"letter": "n", | ||
"value": "100" | ||
}, | ||
{ | ||
"letter": "p", | ||
"value": "10" | ||
}, | ||
{ | ||
"letter": "u", | ||
"value": "100000" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
const {createHash} = require('crypto'); | ||
|
||
const {encode} = require('bech32'); | ||
const {recover} = require('secp256k1'); | ||
|
||
const hexAsWords = require('./hex_as_words'); | ||
const wordsAsBuffer = require('./words_as_buffer'); | ||
|
||
const {isArray} = Array; | ||
const {MAX_SAFE_INTEGER} = Number; | ||
const padding = '0'; | ||
const recoveryFlags = [0, 1, 2, 3]; | ||
|
||
/** Assemble a signed payment request | ||
{ | ||
destination: <Destination Public Key Hex String> | ||
hrp: <Request Human Readable Part String> | ||
signature: <Request Hash Signature Hex String> | ||
tags: [<Request Tag Word Number>] | ||
} | ||
@throws | ||
<Error> | ||
@returns | ||
{ | ||
request: <BOLT 11 Encoded Payment Request String> | ||
} | ||
*/ | ||
module.exports = ({destination, hrp, signature, tags}) => { | ||
if (!destination) { | ||
throw new Error('ExpectedDestinationForSignedPaymentRequest'); | ||
} | ||
|
||
if (!hrp) { | ||
throw new Error('ExpectedHrpForSignedPaymentRequest'); | ||
} | ||
|
||
if (!signature) { | ||
throw new Error('ExpectedRequestSignatureForSignedPaymentRequest'); | ||
} | ||
|
||
try { | ||
hexAsWords({hex: signature}); | ||
} catch (err) { | ||
throw new Error('ExpectedValidSignatureHexForSignedPaymentRequest'); | ||
} | ||
|
||
if (!isArray(tags)) { | ||
throw new Error('ExpectedRequestTagsForSignedPaymentRequest'); | ||
} | ||
|
||
const preimage = Buffer.concat([ | ||
Buffer.from(hrp, 'ascii'), | ||
wordsAsBuffer({words: tags}), | ||
]); | ||
|
||
const hash = createHash('sha256').update(preimage).digest(); | ||
|
||
const destinationKey = Buffer.from(destination, 'hex'); | ||
const sig = Buffer.from(signature, 'hex'); | ||
|
||
// Find the recovery flag that works for this signature | ||
const recoveryFlag = recoveryFlags.find(flag => { | ||
try { | ||
return recover(hash, sig, flag, true).equals(destinationKey); | ||
} catch (err) { | ||
return false; | ||
} | ||
}); | ||
|
||
if (recoveryFlag === undefined) { | ||
throw new Error('ExpectedValidSignatureForSignedPaymentRequest'); | ||
} | ||
|
||
const sigWords = hexAsWords({hex: signature + padding + recoveryFlag}).words; | ||
|
||
const words = [].concat(tags).concat(sigWords); | ||
|
||
return {request: encode(hrp, words, MAX_SAFE_INTEGER)}; | ||
}; |
Oops, something went wrong.