urbit-key-generation
Version:
Key derivation and HD wallet generation functions for Urbit.
369 lines (326 loc) • 7.3 kB
JavaScript
/* istanbul ignore file */
var BigInteger = require('jsbn').BigInteger;
function Noun() {
this._mug = 0;
}
Noun.prototype.loob = function () {
throw new Error("Bail");
};
Noun.prototype.toString = function() {
var parts = [];
this.pretty(parts, false);
return parts.join('');
};
Noun.prototype.mug = function () {
if ( 0 === this._mug ) {
this._mug = this.calculateMug();
}
return this._mug;
};
Noun.prototype.mugged = function () {
return 0 !== this._mug;
};
Noun.prototype.deep = false;
Noun.prototype.bump = function () {
throw new Error("Bail");
}
Noun.prototype.equals = function(o) {
if ( this === o ) {
return true;
}
if ( this instanceof Cell ) {
if ( o instanceof Cell) {
return this.unify(o);
}
else {
return false;
}
}
else {
if ( o instanceof Cell ) {
return false;
}
else if (0 === this.number.compareTo(o.number)) {
o.number = this.number;
return true;
}
else {
return false;
}
}
};
function _mug_fnv(has_w) {
return Math.imul(has_w, 16777619);
}
function _mug_out(has_w) {
return (has_w >>> 31) ^ (has_w & 0x7fffffff);
}
function _mug_both(lef_w, rit_w) {
var bot_w = _mug_fnv(lef_w ^ _mug_fnv(rit_w));
var out_w = _mug_out(bot_w);
if ( 0 !== out_w ) {
return out_w;
}
else {
return _mug_both(lef_w, ++rit_w);
}
}
function Cell(head, tail) {
Noun.call(this);
this.head = head;
this.tail = tail;
}
Cell.prototype = Object.create(Noun.prototype);
Cell.prototype.constructor = Cell;
Cell.prototype.deep = true;
Cell.prototype.pretty = function(out, tail) {
if ( !tail ) {
out.push('[');
}
this.head.pretty(out, false);
out.push(' ');
this.tail.pretty(out, true);
if ( !tail ) {
out.push(']');
}
};
Cell.prototype.calculateMug = function() {
return _mug_both(this.head.mug(), this.tail.mug());
};
Cell.prototype.unify = function(o) {
if ( this === o ) {
return true;
}
if ( o.mugged() ) {
if ( this.mugged() ) {
if ( this.mug() !== o.mug() ) {
return false;
}
}
else {
return o.unify(this);
}
}
if ( this.head.equals(o.head) ) {
o.head = this.head;
if ( this.tail.equals(o.tail) ) {
o._mug = this._mug;
o.tail = this.tail;
return true;
}
}
return false;
};
function Atom(number) {
Noun.call(this);
this.number = number;
}
Atom.prototype = Object.create(Noun.prototype);
Atom.prototype.constructor = Atom;
var small = new Array(256);
(function() {
var i, bi;
for ( i = 0; i < 256; ++i ) {
bi = new BigInteger();
bi.fromInt(i);
small[i] = new Atom(bi);
}
})();
var fragCache = {
0: function(a) {
throw new Error("Bail");
},
1: function(a) {
return a;
},
};
var one = small[1];
Noun.fragmenter = function(a) {
var s = a.shortCode();
if ( fragCache.hasOwnProperty(s) ) {
return fragCache[s];
}
else {
for ( var parts = ['a']; !one.equals(a); a = a.mas() ) {
parts.push( ( 2 === a.cap().valueOf() ) ? 'head' : 'tail' );
}
return fragCache[s] =
function(a) {
return parts.join('.');
}
}
}
Noun.prototype.at = function(a) {
return Noun.fragmenter(a)(this);
};
var shortBi = new BigInteger();
shortBi.fromInt(65536);
Atom.prototype.bytes = function() {
var bytes = this.number.toByteArray();
var r = [];
for ( var i = bytes.length-1; i >= 0; --i ) {
r.push(bytes[i]&0xff);
}
return r;
}
Atom.cordToString = function(c) {
var bytes = c.bytes();
var chars = [];
for ( var i = 0; i < bytes.length; ++i ) {
chars.push(String.fromCharCode(bytes[i]));
}
return chars.join('');
};
Atom.prototype.pretty = function(out, tail) {
if ( this.number.compareTo(shortBi) < 0 ) {
return out.push(this.number.toString(10));
}
else {
var tap = [], isTa = true, isTas = true, bytes = this.number.toByteArray();
for ( var i = bytes.length - 1; i >= 0; --i) {
var c = bytes[i];
if ( isTa && ((c < 32) || (c > 127)) ) {
isTa = false;
isTas = false;
break;
}
else if ( isTas && !((c > 47 && c < 58) || // digits
(c > 96 && c < 123) || // lowercase letters
c === 45) ) { // -
isTas = false;
}
tap.push(String.fromCharCode(c));
}
if ( isTas ) {
out.push('%');
out.push.apply(out, tap);
}
else if ( isTa ) {
out.push("'");
out.push.apply(out, tap);
out.push("'");
}
else {
out.push("0x");
out.push(this.number.toString(16));
}
}
};
Atom.prototype.loob = function() {
switch ( this.number.intValue() ) {
case 0:
return true;
case 1:
return false;
default:
throw new Error("Bail");
}
};
Atom.prototype.bump = function() {
return new Atom(this.number.add(BigInteger.ONE));
};
var ida = i(1);
var heda = i(2);
var tala = i(3);
Atom.prototype.cap = function() {
switch (this.number.intValue()) {
case 0:
case 1:
throw new Error("Bail");
default:
return this.number.testBit(this.number.bitLength() - 2) ? tala : heda;
}
};
Atom.prototype.mas = function() {
switch (this.number.intValue()) {
case 0:
case 1:
throw new Error("Bail");
case 2:
case 3:
return ida;
default:
var n = this.number;
var l = n.bitLength() - 2;
var addTop = new BigInteger();
addTop.fromInt(1 << l);
var mask = new BigInteger();
mask.fromInt((1 << l)-1);
return new Atom(n.and(mask).xor(addTop));
}
};
Atom.prototype.calculateMug = function() {
var a = this.number.toByteArray();
var b, c, d, e, f, bot;
for ( e = a.length - 1, b = (2166136261|0); ; ++b ) {
c = b;
bot = ( 0 === a[0] ) ? 1 : 0;
for ( d = e; d >= bot; --d ) {
c = _mug_fnv(c ^ (0xff & a[d]));
}
f = _mug_out(c);
if ( 0 !== f ) {
return f;
}
}
};
Atom.prototype.shortCode = function() {
return this.number.toString(36); // max supported by BigInteger
};
function s(str, radix) {
return new Atom(new BigInteger(str, radix));
}
function i(num) {
if ( num < 256 ) {
return small[num];
}
else {
var bi = new BigInteger();
bi.fromInt(num);
return new Atom(bi);
}
}
function m(str) {
var i, j, octs = new Array(str.length);
for ( i = 0, j = octs.length - 1; i < octs.length; ++i, --j ) {
octs[j] = (str.charCodeAt(i) & 0xff).toString(16);
}
return new Atom(new BigInteger(octs.join(''), 16))
}
function dwim(a) {
var n = (arguments.length === 1 ? a : Array.apply(null, arguments));
if ( n instanceof Noun ) {
return n;
}
if ( typeof n === "number" ) {
return i(n);
}
else if ( Array.isArray(n) ) {
var cel = new Cell(dwim(n[n.length-2]), dwim(n[n.length-1]));
for ( var j = n.length-3; j >= 0; --j ) {
cel = new Cell(dwim(n[j]), cel);
}
return cel;
}
else if ( typeof n === "string" ) {
return m(n);
}
}
Atom.prototype.valueOf = function() {
return this.number.bitLength() <= 32
? this.number.intValue()
: this.number.toString();
};
module.exports = {
dwim: dwim,
Noun: Noun,
Cell: Cell,
Atom: {
Atom: Atom,
yes: i(0),
no: i(1),
fromMote: m,
fromInt: i,
fromString: s,
},
};