bitmessage-js/docs/address.js.html

285 lines
8.3 KiB
HTML
Raw Normal View History

2015-01-03 17:04:14 +01:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: address.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: address.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* Working with Bitmessage addresses.
* @see {@link https://bitmessage.org/wiki/Address}
* @module bitmessage/address
*/
"use strict";
require("object.assign").shim();
var assert = require("assert");
var bufferEqual = require("buffer-equal");
var bs58 = require("bs58");
var var_int = require("./structs").var_int;
var bmcrypto = require("./crypto");
/**
* Create a new Bitmessage address object.
* @param {?Object} opts - Address options
* @constructor
* @static
*/
function Address(opts) {
if (!(this instanceof Address)) {
return new Address(opts);
}
opts = opts || {};
Object.assign(this, opts);
this.version = this.version || 4;
assert(this.version &lt;= 4, "Version too high");
assert(this.version >= 1, "Version too low");
this.stream = this.stream || 1;
if (this.ripe) {
assertripelen(getripelen(this.ripe), this.version, this.ripe);
if (this.ripe.length &lt; 20) {
var fullripe = new Buffer(20);
fullripe.fill(0);
this.ripe.copy(fullripe, 20 - this.ripe.length);
this.ripe = fullripe;
}
}
}
/**
* Parse Bitmessage address into address object.
* @param {String} str - Address string (with or without `BM-` prefix)
* @return {Address} Decoded address object.
*/
Address.decode = function(str) {
str = str.trim();
if (str.slice(0, 3) === "BM-") {
str = str.slice(3);
}
var bytes = bs58.decode(str);
var data = new Buffer(bytes.slice(0, -4));
var checksum = new Buffer(bytes.slice(-4));
assert(bufferEqual(checksum, getchecksum(data)), "Bad checkum");
var decoded = var_int.decode(data);
var version = decoded.value;
data = decoded.rest;
decoded = var_int.decode(data);
var stream = decoded.value;
var ripe = decoded.rest;
if (version === 4) {
assert(ripe[0] !== 0, "Ripe encode error");
}
return new Address({version: version, stream: stream, ripe: ripe});
};
// Compute the Bitmessage checksum for the given data.
function getchecksum(data) {
return bmcrypto.sha512(bmcrypto.sha512(data)).slice(0, 4);
}
// Get RIPEMD160(SHA512(SIGN_PUBLIC_KEY || ENC_PUBLIC_KEY)).
// Arguments could be either private or public keys. Private keys are
// **always** 32 bytes in length.
function keys2ripe(signKey, encKey) {
var signPublicKey, encPublicKey;
if (signKey.length === 32) {
signPublicKey = bmcrypto.getPublic(signKey);
} else {
signPublicKey = signKey;
}
if (encKey.length === 32) {
encPublicKey = bmcrypto.getPublic(encKey);
} else {
encPublicKey = encKey;
}
var concat = Buffer.concat([signPublicKey, encPublicKey]);
return bmcrypto.ripemd160(bmcrypto.sha512(concat));
}
/**
* Calculate the ripe hash of the address.
* @param {?Object} opts - Options
* @return {Buffer} Resulting ripe hash.
*/
Address.prototype.getRipe = function(opts) {
var ripe;
opts = opts || {};
if (this.ripe) {
ripe = this.ripe;
} else {
var signKey = this.signPrivateKey || this.signPublicKey;
assert(signKey, "No signing key");
var encKey = this.encPrivateKey || this.encPublicKey;
assert(encKey, "No encryption key");
ripe = keys2ripe(signKey, encKey);
}
var ripelen = getripelen(ripe);
assertripelen(ripelen, this.version, ripe);
if (opts.short) {
return ripe.slice(20 - ripelen);
} else {
return ripe;
}
};
// Get truncated ripe hash length.
function getripelen(ripe) {
var zeroes = 0;
for (var i = 0; i &lt; 20, ripe[i] === 0; i++) {
zeroes++;
}
return 20 - zeroes;
}
// Do neccessary checkings of the truncated ripe hash length depending
// on the address version.
function assertripelen(ripelen, version, ripe) {
if (ripe) {
assert(ripe.length &lt;= 20, "Bad ripe");
}
switch (version) {
case 1:
assert(ripelen === 20, "Bad ripe length");
break;
case 2:
case 3:
assert(ripelen >= 18, "Ripe is too short");
assert(ripelen &lt;= 20, "Ripe is too long");
break;
case 4:
assert(ripelen >= 4, "Ripe is too short");
assert(ripelen &lt;= 20, "Ripe is too long");
break;
default:
throw new Error("Bad version");
}
}
// The same as `assertripelen` but return boolean instead of thrown an
// Error.
function checkripelen(ripelen, version) {
try {
assertripelen(ripelen, version);
return true;
} catch(e) {
return false;
}
}
/**
* Encode Bitmessage address object into address string.
* @return {string} Address string.
*/
Address.prototype.encode = function() {
var ripe = this.getRipe({short: true});
var data = Buffer.concat([
var_int.encode(this.version),
var_int.encode(this.stream),
ripe,
]);
var addr = Buffer.concat([data, getchecksum(data)]);
return "BM-" + bs58.encode(addr);
};
function popkey(obj, key) {
var value = obj[key];
delete obj[key];
return value;
}
/**
* Create new Bitmessage address from random encryption and signing
* private keys.
* @param {?Object} opts - Address options
* @return {Address} Generated address object.
*/
Address.fromRandom = function(opts) {
opts = Object.assign({}, opts);
var version = opts.version = opts.version || 4;
var ripelen = popkey(opts, "ripelen") || 19;
assertripelen(ripelen, version);
// Should the generated ripe length be strictly equal to the specified
// (less or equal by default).
var strictripelen = !!popkey(opts, "strictripelen");
// TODO(Kagami): Speed it up using web workers in Browser.
// TODO(Kagami): Bind to C++ version of this code in Node.
var encPrivateKey, encPublicKey, ripe;
var signPrivateKey = bmcrypto.getPrivate();
var signPublicKey = bmcrypto.getPublic(signPrivateKey);
var keysbuf = Buffer(130);
signPublicKey.copy(keysbuf);
while (true) {
encPrivateKey = bmcrypto.getPrivate();
encPublicKey = bmcrypto.getPublic(encPrivateKey);
encPublicKey.copy(keysbuf, 65);
ripe = bmcrypto.ripemd160(bmcrypto.sha512(keysbuf));
var len = getripelen(ripe);
if (
(strictripelen &amp;&amp; len === ripelen) ||
(!strictripelen &amp;&amp; len &lt;= ripelen &amp;&amp; checkripelen(ripelen, version))
) {
// TODO(Kagami): Do we need to put all these properties or compute
// them manually via ECMA5 getters/setters instead?
opts.signPrivateKey = signPrivateKey;
opts.signPublicKey = signPublicKey;
opts.encPrivateKey = encPrivateKey;
opts.encPublicKey = encPublicKey;
opts.ripe = ripe;
return new Address(opts);
}
}
};
module.exports = Address;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-bitmessage.html">bitmessage</a></li><li><a href="module-bitmessage_address.html">bitmessage/address</a></li><li><a href="module-bitmessage_crypto.html">bitmessage/crypto</a></li><li><a href="module-bitmessage_messages.html">bitmessage/messages</a></li><li><a href="module-bitmessage_objects.html">bitmessage/objects</a></li><li><a href="module-bitmessage_pow.html">bitmessage/pow</a></li><li><a href="module-bitmessage_structs.html">bitmessage/structs</a></li><li><a href="module-bitmessage_wif.html">bitmessage/wif</a></li></ul><h3>Classes</h3><ul><li><a href="module-bitmessage_address.Address.html">Address</a></li></ul><h3>Namespaces</h3><ul><li><a href="module-bitmessage_structs.var_int.html">var_int</a></li><li><a href="module-bitmessage_structs.var_int_list.html">var_int_list</a></li><li><a href="module-bitmessage_structs.var_str.html">var_str</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-alpha13</a> on Sat Jan 03 2015 19:33:03 GMT+0300 (MSK)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>