Create abstract UInt class for UInt160, UInt256, ...

This commit is contained in:
Stefan Thomas
2013-02-01 22:38:37 +01:00
parent eeb9598b12
commit 54f4edf5ef
3 changed files with 271 additions and 106 deletions

221
src/js/uint.js Normal file
View File

@@ -0,0 +1,221 @@
var sjcl = require('../../build/sjcl');
var utils = require('./utils');
var config = require('./config');
var jsbn = require('./jsbn');
var BigInteger = jsbn.BigInteger;
var nbi = jsbn.nbi;
var Base = require('./base').Base;
//
// Abstract UInt class
//
// Base class for UInt??? classes
//
var UInt = function () {
// Internal form: NaN or BigInteger
this._value = NaN;
};
UInt.json_rewrite = function (j) {
return this.from_json(j).to_json();
};
// Return a new UInt from j.
UInt.from_generic = function (j) {
if (j instanceof this) {
return j.clone();
} else {
return (new this()).parse_generic(j);
}
};
// Return a new UInt from j.
UInt.from_hex = function (j) {
if (j instanceof this) {
return j.clone();
} else {
return (new this()).parse_hex(j);
}
};
// Return a new UInt from j.
UInt.from_json = function (j) {
if (j instanceof this) {
return j.clone();
} else {
return (new this()).parse_json(j);
}
};
// Return a new UInt from j.
UInt.from_bits = function (j) {
if (j instanceof this) {
return j.clone();
} else {
return (new this()).parse_bits(j);
}
};
// Return a new UInt from j.
UInt.from_bn = function (j) {
if (j instanceof this) {
return j.clone();
} else {
return (new this()).parse_bn(j);
}
};
UInt.is_valid = function (j) {
return this.from_json(j).is_valid();
};
UInt.prototype.clone = function () {
return this.copyTo(new this.constructor());
};
// Returns copy.
UInt.prototype.copyTo = function (d) {
d._value = this._value;
return d;
};
UInt.prototype.equals = function (d) {
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
};
UInt.prototype.is_valid = function () {
return this._value instanceof BigInteger;
};
// value = NaN on error.
UInt.prototype.parse_generic = function (j) {
// Canonicalize and validate
if (config.accounts && j in config.accounts)
j = config.accounts[j].account;
switch (j) {
case undefined:
case "0":
case this.constructor.STR_ZERO:
case this.constructor.ADDRESS_ZERO:
case this.constructor.HEX_ZERO:
this._value = nbi();
break;
case "1":
case this.constructor.STR_ONE:
case this.constructor.ADDRESS_ONE:
case this.constructor.HEX_ONE:
this._value = new BigInteger([1]);
break;
default:
if ('string' !== typeof j) {
this._value = NaN;
}
else if (j[0] === "r") {
this._value = Base.decode_check(Base.VER_ACCOUNT_ID, j);
}
else if (this.constructor.width === j.length) {
this._value = new BigInteger(utils.stringToArray(j), 256);
}
else if ((this.constructor.width*2) === j.length) {
// XXX Check char set!
this._value = new BigInteger(j, 16);
}
else {
this._value = NaN;
}
}
return this;
};
UInt.prototype.parse_hex = function (j) {
if ('string' === typeof j &&
j.length === (this.constructor.width * 2)) {
this._value = new BigInteger(j, 16);
} else {
this._value = NaN;
}
return this;
};
UInt.prototype.parse_bits = function (j) {
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
this._value = NaN;
} else {
var bytes = sjcl.codec.bytes.fromBits(j);
this._value = new BigInteger(bytes, 256);
}
return this;
};
UInt.prototype.parse_json = UInt.prototype.parse_hex;
UInt.prototype.parse_bn = function (j) {
if (j instanceof sjcl.bn &&
j.bitLength() <= this.constructor.width * 8) {
var bytes = sjcl.codec.bytes.fromBits(j.toBits());
this._value = new BigInteger(bytes, 256);
} else {
this._value = NaN;
}
return this;
};
// Convert from internal form.
UInt.prototype.to_bytes = function () {
if (!(this._value instanceof BigInteger))
return null;
var bytes = this._value.toByteArray();
bytes = bytes.map(function (b) { return (b+256) % 256; });
var target = this.constructor.width;
// XXX Make sure only trim off leading zeros.
bytes = bytes.slice(-target);
while (bytes.length < target) bytes.unshift(0);
return bytes;
};
UInt.prototype.to_hex = function () {
if (!(this._value instanceof BigInteger))
return null;
var bytes = this.to_bytes();
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(bytes)).toUpperCase();
};
UInt.prototype.to_json = UInt.prototype.to_hex;
UInt.prototype.to_bits = function () {
if (!(this._value instanceof BigInteger))
return null;
var bytes = this.to_bytes();
return sjcl.codec.bytes.toBits(bytes);
};
UInt.prototype.to_bn = function () {
if (!(this._value instanceof BigInteger))
return null;
var bits = this.to_bits();
return sjcl.bn.fromBits(bits);
};
exports.UInt = UInt;

View File

@@ -1,118 +1,35 @@
var sjcl = require('../../build/sjcl');
var utils = require('./utils');
var config = require('./config');
var jsbn = require('./jsbn');
var extend = require('extend');
var BigInteger = jsbn.BigInteger;
var nbi = jsbn.nbi;
var Base = require('./base').Base;
var UInt = require('./uint').UInt,
Base = require('./base').Base;
//
// UInt160 support
//
var UInt160 = function () {
var UInt160 = extend(function () {
// Internal form: NaN or BigInteger
this._value = NaN;
};
}, UInt);
UInt160.width = 20;
UInt160.prototype = extend({}, UInt.prototype);
UInt160.prototype.constructor = UInt160;
UInt160.ZERO = utils.hexToString("0000000000000000000000000000000000000000");
UInt160.ONE = utils.hexToString("0000000000000000000000000000000000000001");
var ADDRESS_ZERO = UInt160.ADDRESS_ZERO = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
var ADDRESS_ONE = UInt160.ADDRESS_ONE = "rrrrrrrrrrrrrrrrrrrrBZbvji";
var HEX_ZERO = UInt160.HEX_ZERO = "0000000000000000000000000000000000000000";
var HEX_ONE = UInt160.HEX_ONE = "0000000000000000000000000000000000000001";
UInt160.json_rewrite = function (j) {
return UInt160.from_json(j).to_json();
};
// Return a new UInt160 from j.
UInt160.from_generic = function (j) {
return 'string' === typeof j
? (new UInt160()).parse_generic(j)
: j.clone();
};
// Return a new UInt160 from j.
UInt160.from_json = function (j) {
if ('string' === typeof j) {
return (new UInt160()).parse_json(j);
} else if (j instanceof UInt160) {
return j.clone();
} else {
return new UInt160();
}
};
UInt160.is_valid = function (j) {
return UInt160.from_json(j).is_valid();
};
UInt160.prototype.clone = function () {
return this.copyTo(new UInt160());
};
// Returns copy.
UInt160.prototype.copyTo = function (d) {
d._value = this._value;
return d;
};
UInt160.prototype.equals = function (d) {
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
};
UInt160.prototype.is_valid = function () {
return this._value instanceof BigInteger;
};
// value = NaN on error.
UInt160.prototype.parse_generic = function (j) {
// Canonicalize and validate
if (config.accounts && j in config.accounts)
j = config.accounts[j].account;
switch (j) {
case undefined:
case "0":
case UInt160.ZERO:
case ADDRESS_ZERO:
case HEX_ZERO:
this._value = nbi();
break;
case "1":
case UInt160.ONE:
case ADDRESS_ONE:
case HEX_ONE:
this._value = new BigInteger([1]);
break;
default:
if ('string' !== typeof j) {
this._value = NaN;
}
else if (j[0] === "r") {
this._value = Base.decode_check(Base.VER_ACCOUNT_ID, j);
}
else if (20 === j.length) {
this._value = new BigInteger(utils.stringToArray(j), 256);
}
else if (40 === j.length) {
// XXX Check char set!
this._value = new BigInteger(j, 16);
}
else {
this._value = NaN;
}
}
return this;
};
var STR_ZERO = UInt160.STR_ZERO = utils.hexToString(HEX_ZERO);
var STR_ONE = UInt160.STR_ONE = utils.hexToString(HEX_ONE);
// value = NaN on error.
UInt160.prototype.parse_json = function (j) {
@@ -133,22 +50,12 @@ UInt160.prototype.parse_json = function (j) {
return this;
};
// Convert from internal form.
// XXX Json form should allow 0 and 1, C++ doesn't currently allow it.
UInt160.prototype.to_json = function () {
if (!(this._value instanceof BigInteger))
return NaN;
var bytes = this._value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0});
var target = 20;
// XXX Make sure only trim off leading zeros.
var array = bytes.length < target
? bytes.length
? [].concat(utils.arraySet(target - bytes.length, 0), bytes)
: utils.arraySet(target, 0)
: bytes.slice(target - bytes.length);
var output = Base.encode_check(Base.VER_ACCOUNT_ID, array);
var output = Base.encode_check(Base.VER_ACCOUNT_ID, this.to_bytes());
return output;
};

37
src/js/uint256.js Normal file
View File

@@ -0,0 +1,37 @@
var sjcl = require('../../build/sjcl');
var utils = require('./utils');
var config = require('./config');
var jsbn = require('./jsbn');
var extend = require('extend');
var BigInteger = jsbn.BigInteger;
var nbi = jsbn.nbi;
var UInt = require('./uint').UInt,
Base = require('./base').Base;
//
// UInt256 support
//
var UInt256 = extend(function () {
// Internal form: NaN or BigInteger
this._value = NaN;
}, UInt);
UInt256.width = 32;
UInt256.prototype = extend({}, UInt.prototype);
UInt256.prototype.constructor = UInt256;
// XXX Generate these constants (or remove them)
var ADDRESS_ZERO = UInt256.ADDRESS_ZERO = "XXX";
var ADDRESS_ONE = UInt256.ADDRESS_ONE = "XXX";
var HEX_ZERO = UInt256.HEX_ZERO = "00000000000000000000000000000000" +
"00000000000000000000000000000000";
var HEX_ONE = UInt256.HEX_ONE = "00000000000000000000000000000000" +
"00000000000000000000000000000001";
var STR_ZERO = UInt256.STR_ZERO = utils.hexToString(HEX_ZERO);
var STR_ONE = UInt256.STR_ONE = utils.hexToString(HEX_ONE);
exports.UInt256 = UInt256;