@ellcrys/spell
Version:
The official JavaScript library for Ellcrys
478 lines • 24.5 kB
JavaScript
"use strict";
/**
* @module Key
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var crypto = require("crypto");
var SHA3 = require("sha3").SHA3;
var RIPEMD160 = require("ripemd160");
var b58 = require("bs58check");
var create_hmac_1 = __importDefault(require("create-hmac"));
var tweetnacl_1 = __importDefault(require("tweetnacl"));
var errors_1 = __importDefault(require("./errors"));
exports.AddressVersion = Buffer.from([92]);
exports.PublicKeyVersion = Buffer.from([93]);
exports.PrivateKeyVersion = Buffer.from([94]);
var HARDENED_OFFSET = 0x80000000;
var ED25519_CURVE = "ed25519 seed";
var pathRegex = new RegExp("^m(\\/[0-9]+')+$");
var replaceDerive = function (val) { return val.replace("'", ""); };
/**
* PrivateKey represents an Ed25519
* key use for constructing an Ellcrys
* address, signing and verifying a
* signed messages.
*
* @export
* @class PrivateKey
*/
var PrivateKey = /** @class */ (function () {
/**
* Creates an instance of PrivateKey.
* @param {Buffer} seed 32-byte seed used to create the key
* @memberof PrivateKey
*/
function PrivateKey(seed) {
// If seed is not provided, we go
// on to generate a random seed
if (!seed || seed.length === 0) {
seed = crypto.randomBytes(32);
}
var keypair = tweetnacl_1.default.sign.keyPair.fromSeed(seed);
this.keypair = {
privateKey: Buffer.from(keypair.secretKey),
publicKey: Buffer.from(keypair.publicKey),
};
}
/**
* Instantiate a PrivateKey from a base58
* encoded private key string
*
* @static
* @param {string} str The base58 encoded private keys
* @returns {PrivateKey}
* @throws InvalidPrivateKeyChecksum|InvalidPrivateKeyVersion|InvalidPrivateKeySize
* @memberof PrivateKey
*/
PrivateKey.from = function (str) {
var decoded;
try {
decoded = b58.decode(str);
}
catch (e) {
throw errors_1.default.InvalidPrivateKeyChecksum;
}
if (decoded[0] !== exports.PrivateKeyVersion[0]) {
throw errors_1.default.InvalidPrivateKeyVersion;
}
if (decoded.length !== 65) {
throw errors_1.default.InvalidPrivateKeySize;
}
var pk = decoded.slice(33);
var o = new PrivateKey();
o.keypair.privateKey.set(decoded.slice(1));
o.keypair.publicKey.set(pk);
return o;
};
/**
* Instantiate a PrivateKey from a buffer.
* The buffer's 0th index must contain the
* private key version.
*
* @static
* @param {Buffer} buf
* @returns {PrivateKey}
* @memberof PrivateKey
*/
PrivateKey.fromBuffer = function (buf) {
if (buf[0] !== exports.PrivateKeyVersion[0]) {
throw errors_1.default.InvalidPrivateKeyVersion;
}
if (buf.length !== 65) {
throw errors_1.default.InvalidPrivateKeySize;
}
var pk = buf.slice(33);
var o = new PrivateKey();
o.keypair.privateKey.set(buf.slice(1));
o.keypair.publicKey.set(pk);
return o;
};
/**
* Sign a message
*
* @param {Buffer} data The message
* @returns {Buffer}
* @memberof PrivateKey
*/
PrivateKey.prototype.sign = function (data) {
return Buffer.from(tweetnacl_1.default.sign.detached(data, this.keypair.privateKey));
};
/**
* Returns an address derived from
* the private key
*
* @returns {Address}
* @memberof PrivateKey
*/
PrivateKey.prototype.toAddress = function () {
return this.publicKey().toAddress();
};
/**
* Returns the public key.
*
* @returns {PublicKey}
* @memberof PrivateKey
*/
PrivateKey.prototype.publicKey = function () {
return PublicKey.fromBuffer(Buffer.concat([exports.PublicKeyVersion, this.keypair.publicKey]));
};
/**
* Returns base58 encode string of the private key
*
* @returns {string}
* @memberof PrivateKey
*/
PrivateKey.prototype.toBase58 = function () {
return b58.encode(Buffer.concat([exports.PrivateKeyVersion, this.keypair.privateKey]));
};
/**
* Returns the private key as a buffer.
* The base58 version is added as the 0th
* byte in the returned buffer
*
* @returns {Buffer}
* @memberof PrivateKey
*/
PrivateKey.prototype.toBuffer = function () {
return Buffer.concat([exports.PrivateKeyVersion, this.keypair.privateKey]);
};
return PrivateKey;
}());
exports.PrivateKey = PrivateKey;
/**
* PublicKey represents an ED25519
* public key
*
* @export
* @class PublicKey
*/
// tslint:disable-next-line:max-classes-per-file
var PublicKey = /** @class */ (function () {
function PublicKey() {
}
/**
* Instantiate a PublicKey from a buffer.
* The buffer's 0th index must contain the
* public key version.
*
* @static
* @param {Buffer} buf
* @returns {PublicKey}
* @memberof PublicKey
*/
PublicKey.fromBuffer = function (buf) {
if (buf[0] !== exports.PublicKeyVersion[0]) {
throw errors_1.default.InvalidPublicKeyVersion;
}
if (buf.length !== 33) {
throw errors_1.default.InvalidPublicKeySize;
}
var o = new PublicKey();
o.pk = buf.slice(1);
return o;
};
/**
* Instantiate a PublicKey from a base58
* encoded public key string
*
* @static
* @param {string} str
* @returns {PublicKey}
* @throws InvalidPublicKeyChecksum|InvalidPublicKeyVersion|InvalidPublicKeySize
* @memberof PublicKey
*/
PublicKey.from = function (str) {
var decoded;
try {
decoded = b58.decode(str);
}
catch (e) {
throw errors_1.default.InvalidPublicKeyChecksum;
}
if (decoded[0] !== exports.PublicKeyVersion[0]) {
throw errors_1.default.InvalidPublicKeyVersion;
}
if (decoded.length !== 33) {
throw errors_1.default.InvalidPublicKeySize;
}
var o = new PublicKey();
o.pk = decoded.slice(1);
return o;
};
/**
* Returns base58 encode string of the public key
*
* @returns {string}
* @memberof PublicKey
*/
PublicKey.prototype.toBase58 = function () {
return b58.encode(Buffer.concat([exports.PublicKeyVersion, this.pk]));
};
/**
* Returns the public key as a buffer.
* The public key version is added as the 0th
* byte in the returned buffer
*
* @returns {Buffer}
* @memberof PublicKey
*/
PublicKey.prototype.toBuffer = function () {
return Buffer.concat([exports.PublicKeyVersion, this.pk]);
};
/**
* Returns an address derived from
* the public key
*
* @returns {Address}
* @memberof PublicKey
*/
PublicKey.prototype.toAddress = function () {
var hash = new SHA3(256);
hash.update(this.pk);
var ripHash = new RIPEMD160().update(hash.digest()).digest();
var addr = b58.encode(Buffer.concat([exports.AddressVersion, ripHash]));
return Address.from(addr);
};
/**
* Verify a signature
*
* @param {Buffer} msg The message that was signed
* @param {Buffer} sig The message's signature
* @returns {boolean}
* @memberof PublicKey
*/
PublicKey.prototype.verify = function (msg, sig) {
return tweetnacl_1.default.sign.detached.verify(msg, sig, this.pk);
};
return PublicKey;
}());
exports.PublicKey = PublicKey;
/**
* Address represents a compressed
* equivalent of a public key used
* as an address for transacting.
*
* @class Address
*/
// tslint:disable-next-line:max-classes-per-file
var Address = /** @class */ (function () {
function Address() {
var _this = this;
/**
* Return a string format of the address
*
* @memberof Address
*/
this.toString = function () {
return _this.address;
};
}
/**
* Check whether an address is valid
*
* @static
* @param {string} address The address to check
* @returns {boolean}
* @memberof Address
*/
Address.isValid = function (address) {
try {
var decoded = b58.decode(address);
if (decoded[0] !== exports.AddressVersion[0] || decoded.length !== 21) {
return false;
}
return true;
}
catch (error) {
return false;
}
};
/**
* Check whether a given address is valid.
* If not valid, the specific validation error
* is returned. It returns null if the address
* is valid.
*
* @static
* @param {string} address The address to check
* @returns {(null | Error)} InvalidAddressVersion |
* InvalidAddressSize }| InvalidAddressFormat
* @memberof Address
*/
Address.getValidationError = function (address) {
try {
var decoded = b58.decode(address);
if (decoded[0] !== exports.AddressVersion[0]) {
return errors_1.default.InvalidAddressVersion;
}
if (decoded.length !== 21) {
return errors_1.default.InvalidAddressSize;
}
return null;
}
catch (error) {
return errors_1.default.InvalidAddressFormat;
}
};
/**
* Instantiate an Address instance from
* a given address string
*
* @static
* @param {string} address
* @returns {Address}
* @throws InvalidAddress
* @memberof Address
*/
Address.from = function (address) {
if (!this.isValid(address)) {
throw errors_1.default.InvalidAddress;
}
var addr = new Address();
addr.address = address;
return addr;
};
return Address;
}());
exports.Address = Address;
/**
* Checks whether an HDKey path is
* valid
*
* @export
* @param {string} path The path to check
* @returns {boolean}
*/
function isValidPath(path) {
if (!pathRegex.test(path)) {
return false;
}
return !path
.split("/")
.slice(1)
.map(replaceDerive)
.some(isNaN);
}
exports.isValidPath = isValidPath;
/**
* HDKey provides the ability to create
* hierarchical deterministic keys.
*
* @export
* @class HDKey
*/
// tslint:disable-next-line:max-classes-per-file
var HDKey = /** @class */ (function () {
/**
* Creates an instance of HDKey.
* @param {Buffer} key Left half of the hmac digest
* @param {Buffer} chainCode Right half of the hmac digest
* @memberof HDKey
*/
function HDKey(key, chainCode) {
this.mKey = key;
this.mChainCode = chainCode;
}
/**
* Create an HDKey from a seed.
*
* @static
* @param {Buffer} seed
* @returns {Node}
* @memberof HDKey
*/
HDKey.fromMasterSeed = function (seed) {
var hmac = create_hmac_1.default("sha512", ED25519_CURVE);
var I = hmac.update(seed).digest();
var IL = I.slice(0, 32);
var IR = I.slice(32);
hmac.end();
return new HDKey(IL, IR);
};
/**
* Return the derived key
*
* @returns {Buffer}
* @memberof HDKey
*/
HDKey.prototype.key = function () {
return this.mKey;
};
/**
* Return the derived chain code
*
* @returns {Buffer}
* @memberof HDKey
*/
HDKey.prototype.chainCode = function () {
return this.mChainCode;
};
/**
* Child key derivation function
*
* @param {Buffer} key The parent key
* @param {Buffer} chainCode The parent chain code
* @param {number} index The key index
* @returns {HDKey}
* @memberof HDKey
*/
HDKey.prototype.ckd = function (key, chainCode, index) {
var indexBuffer = Buffer.allocUnsafe(4);
indexBuffer.writeUInt32BE(index, 0);
var data = Buffer.concat([Buffer.alloc(1, 0), key, indexBuffer]);
var I = create_hmac_1.default("sha512", chainCode)
.update(data)
.digest();
var IL = I.slice(0, 32);
var IR = I.slice(32);
return new HDKey(IL, IR);
};
/**
* Given a path, derive a child key. Path
* must contain only hardened indices
*
* @param {string} path The derivation path
* @returns {HDKey}
* @memberof HDKey
*/
HDKey.prototype.derive = function (path) {
var _this = this;
if (!isValidPath(path)) {
throw new Error("Invalid derivation path");
}
var segments = path
.split("/")
.slice(1)
.map(replaceDerive)
.map(function (el) { return parseInt(el, 10); });
return segments.reduce(function (parentKey, segment) {
return _this.ckd(parentKey.mKey, parentKey.mChainCode, segment + HARDENED_OFFSET);
}, this);
};
/**
* Get the private key created using the
* derived key
*
* @returns {PrivateKey}
* @memberof HDKey
*/
HDKey.prototype.privateKey = function () {
return new PrivateKey(this.mKey);
};
return HDKey;
}());
exports.HDKey = HDKey;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2xpYi9rZXkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOzs7OztBQUVILCtCQUFrQztBQUMxQixJQUFBLDJCQUFJLENBQXFCO0FBQ2pDLElBQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUN2QyxJQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDakMsNERBQXFDO0FBQ3JDLHdEQUE2QjtBQUU3QixvREFBOEI7QUFFakIsUUFBQSxjQUFjLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDbkMsUUFBQSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNyQyxRQUFBLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRW5ELElBQU0sZUFBZSxHQUFHLFVBQVUsQ0FBQztBQUNuQyxJQUFNLGFBQWEsR0FBRyxjQUFjLENBQUM7QUFDckMsSUFBTSxTQUFTLEdBQUcsSUFBSSxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztBQUNqRCxJQUFNLGFBQWEsR0FBRyxVQUFDLEdBQVcsSUFBYSxPQUFBLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxFQUFwQixDQUFvQixDQUFDO0FBRXBFOzs7Ozs7OztHQVFHO0FBQ0g7SUF1RUM7Ozs7T0FJRztJQUNILG9CQUFZLElBQWE7UUFDeEIsaUNBQWlDO1FBQ2pDLCtCQUErQjtRQUMvQixJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQy9CLElBQUksR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQzlCO1FBRUQsSUFBTSxP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