Commit 0f34237d authored by kenshin-samourai's avatar kenshin-samourai
Browse files

initial commit for v0.1.0

parent 8afb789f
node_modules/
private-tests/
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/test/index.js"
}
]
}
\ No newline at end of file
# bip47
A set of utilities for working with BIP47 and bitcoinjs-lib.
\ No newline at end of file
A set of utilities for working with BIP47 and bitcoinjs-lib.
## Usage
### Mainnet
```
const bip47 = require('bip47');
const b58PCode = 'PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA';
const pcode = bip47.fromBase58(b58PCode);
const notifAddr = pcode.getNotificationAddress();
```
### Testnet
```
const bitcoinjs = require('bitcoinjs-lib');
const bip47 = require('bip47');
const networks = bitcoinjs.networks;
const b58PCode = 'PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA';
const pcode = bip47.fromBase58(b58PCode, networks.testnet);
const notifAddr = pcode.getNotificationAddress();
```
### Browser
The recommended method of using this library and bitcoinjs-lib in your browser is through Browserify. If you're familiar with how to use browserify, ignore this and carry on, otherwise, it is recommended to read the tutorial at [https://browserify.org/](https://browserify.org/).
```
<html>
<head>
<meta charset="utf-8">
<title>Test BIP47 lib</title>
<script src="libs/bip47-bundle.min.js"></script>
</head>
<body>
<script type="text/javascript">
const pcBase58 = 'PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA';
const pcode = bip47.fromBase58(pcBase58);
const notifAddr = pcode.getNotificationAddress();
console.log(notifAddr);
</script>
</body>
</html>
```
This diff is collapsed.
{
"name": "bip47",
"version": "0.1.0",
"description": "A set of utilities for working with BIP47 and bitcoinjs-lib",
"main": "test/index.js",
"scripts": {
"test": "mocha --recursive --reporter spec"
},
"repository": {
"type": "git",
"url": "git+ssh://git@code.samourai.io:dojo/bip47.git"
},
"author": "Katana Cryptographic Ltd.",
"license": "AGPL-3.0-only",
"homepage": "https://code.samourai.io/dojo/bip47",
"dependencies": {
"bitcoinjs-lib": "5.1.4",
"bip32": "2.0.6",
"bs58check": "2.1.2"
},
"devDependencies": {
"mocha": "^7.1.1"
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var bip47 = require("./payment-code");
exports.fromBuffer = bip47.fromBuffer;
exports.fromBase58 = bip47.fromBase58;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const bitcoinjs = require('bitcoinjs-lib');
const bip32 = require('bip32');
const bs58check = require('bs58check');
const p2pkh = bitcoinjs.payments.p2pkh;
const networks = bitcoinjs.networks;
const PC_VERSION = 0x47;
class PaymentCode {
constructor(buf, network) {
network = network || networks.bitcoin;
if (buf.length !== 80)
throw new TypeError('Invalid buffer length');
this.version = buf.slice(0, 1);
if (this.version[0] !== 1)
throw new TypeError('Only payment codes version 1 are supported');
this.buf = buf;
this.network = network;
this.root = bip32.fromPublicKey(this.pubKey, this.chainCode, this.network);
}
get features() {
return this.buf.slice(1, 1);
}
get pubKey() {
return this.buf.slice(2, 2 + 33);
}
get chainCode() {
return this.buf.slice(35, 35 + 32);
}
get paymentCode() {
return this.buf;
}
toBase58() {
const version = Buffer.from([PC_VERSION]);
const buf = Buffer.concat([version, this.buf]);
return bs58check.encode(buf);
}
derive(index) {
return this.root.derive(index);
}
deriveHardened(index) {
return this.root.deriveHardened(index);
}
getNotificationAddress() {
const child = this.derive(0);
return p2pkh({
pubkey: child.publicKey,
network: this.network
}).address;
}
}
function fromBase58(inString, network) {
const buf = bs58check.decode(inString);
const version = buf.slice(0, 1);
if (version[0] !== PC_VERSION)
throw new TypeError('Invalid version');
return new PaymentCode(buf.slice(1), network);
}
exports.fromBase58 = fromBase58;
function fromBuffer(buf, network) {
return new PaymentCode(buf, network);
}
exports.fromBuffer = fromBuffer;
'use strict'
const assert = require('assert')
const bip47 = require('../src')
/**
* Test vectors
*/
const PC_1 = {
pcBase58: 'PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA',
notifAddr: '1JDdmqFLhpzcUwPeinhJbUPw4Co3aWLyzW',
notifPubKey: '0353883a146a23f988e0f381a9507cbdb3e3130cd81b3ce26daf2af088724ce683'
};
const PC_2 = {
pcBase58: 'PM8TJS2JxQ5ztXUpBBRnpTbcUXbUHy2T1abfrb3KkAAtMEGNbey4oumH7Hc578WgQJhPjBxteQ5GHHToTYHE3A1w6p7tU6KSoFmWBVbFGjKPisZDbP97',
notifAddr: '1ChvUUvht2hUQufHBXF8NgLhW8SwE2ecGV',
notifPubKey: '024ce8e3b04ea205ff49f529950616c3db615b1e37753858cc60c1ce64d17e2ad8'
};
const PC_3 = {
pcBase58: 'QM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA',
};
const PC_4 = {
pc: '020002b85034fb08a8bfefd22848238257b252721454bbbfba2c3667f168837ea2cdad671af9f65904632e2dcc0c6ad314e11d53fc82fa4c4ea27a4a14eccecc478fee00000000000000000000000000'
}
describe('payment-code', function() {
describe('fromBase58()', function() {
it('should successfully initialize a PaymentCode from a base58 payment code', function() {
try {
const pc = bip47.fromBase58(PC_1.pcBase58);
assert(true);
} catch(e) {
assert(false);
}
});
it('should reject a version 2 payment code', function() {
try {
const buf = Buffer.from(PC_4.pc, 'hex');
bip47.fromBuffer(buf);
assert(false);
} catch(e) {
assert(true);
}
});
it('should fail to initialize a PaymentCode with an invalid version', function() {
try {
const pc = bip47.fromBase58(PC_3.pcBase58);
assert(false);
} catch(e) {
assert(true);
}
});
});
describe('PaymentCode.toBase58()', function() {
it('should successfully reencode a payment code in base58', function() {
try {
const pc1 = bip47.fromBase58(PC_1.pcBase58);
const pc1_b58 = pc1.toBase58();
assert(pc1_b58 == PC_1.pcBase58);
const pc2 = bip47.fromBase58(PC_2.pcBase58);
const pc2_b58 = pc2.toBase58();
assert(pc2_b58 == PC_2.pcBase58);
} catch(e) {
assert(false);
}
});
});
describe('PaymentCode.getNotificationAddress()', function() {
it('should successfully derive notification addresses', function() {
try {
const pc1 = bip47.fromBase58(PC_1.pcBase58);
const notifAddr1 = pc1.getNotificationAddress();
assert(notifAddr1 == PC_1.notifAddr);
const pc2 = bip47.fromBase58(PC_2.pcBase58);
const notifAddr2 = pc2.getNotificationAddress();
assert(notifAddr2 == PC_2.notifAddr);
} catch(e) {
assert(false);
}
});
});
});
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment