Use es7 decorator syntax for cached methods

This commit is contained in:
Nicholas Dudfield
2015-08-05 19:07:18 +07:00
parent bcde54d258
commit d26bca3208
6 changed files with 170 additions and 168 deletions

View File

@@ -1,14 +1,10 @@
'use strict';
const util = require('util');
const elliptic = require('elliptic');
const {utils: {parseBytes}} = elliptic;
const Ed25519 = elliptic.eddsa('ed25519');
const {KeyPair, KeyType} = require('./keypair');
const {
Sha512,
cachedProperty
} = require('./utils');
const {Sha512, cached} = require('./utils');
/*
@param {Array} seed bytes
@@ -17,51 +13,51 @@ function deriveEdKeyPairSeed(seed) {
return new Sha512().add(seed).first256();
}
/*
* @class
*/
function Ed25519Pair() {
KeyPair.apply(this, arguments);
this.type = KeyType.ed25519;
}
util.inherits(Ed25519Pair, KeyPair);
/**
* @param {Seed} publicKey - public key in canonical form (0xED + 32 bytes)
* @return {Ed25519Pair} key pair
*/
Ed25519Pair.fromPublic = function(publicKey) {
return new Ed25519Pair({pubBytes: parseBytes(publicKey)});
};
Ed25519Pair.prototype.sign = function(message) {
return this.key().sign(message).toBytes();
};
Ed25519Pair.prototype.verify = function(message, signature) {
return this.key().verify(message, signature);
};
cachedProperty(Ed25519Pair, function key() {
if (this.seedBytes) {
const seed256 = deriveEdKeyPairSeed(this.seedBytes);
return Ed25519.keyFromSecret(seed256);
class Ed25519Pair extends KeyPair {
constructor(options) {
super(options);
this.type = KeyType.ed25519;
}
return Ed25519.keyFromPublic(this.pubKeyCanonicalBytes().slice(1));
});
cachedProperty(Ed25519Pair, function pubKeyCanonicalBytes() {
return [0xED].concat(this.key().pubBytes());
});
/**
* @param {String|Array} publicKey - public key in canonical form
* (0xED + 32 bytes)
* @return {Ed25519Pair} key pair
*/
static fromPublic(publicKey) {
return new Ed25519Pair({pubBytes: parseBytes(publicKey)});
}
/**
* @param {Array<Number>} seedBytes - A 128 bit seed
* @return {Ed25519Pair} key pair
*/
Ed25519Pair.fromSeed = function(seedBytes) {
return new Ed25519Pair({seedBytes});
};
/**
* @param {Array<Number>} seedBytes - A 128 bit seed
* @return {Ed25519Pair} key pair
*/
static fromSeed(seedBytes) {
return new Ed25519Pair({seedBytes});
}
sign(message) {
return this.key().sign(message).toBytes();
}
verify(message, signature) {
return this.key().verify(message, signature);
}
@cached
key() {
if (this.seedBytes) {
const seed256 = deriveEdKeyPairSeed(this.seedBytes);
return Ed25519.keyFromSecret(seed256);
}
return Ed25519.keyFromPublic(this.pubKeyCanonicalBytes().slice(1));
}
@cached
pubKeyCanonicalBytes() {
return [0xED].concat(this.key().pubBytes());
}
}
module.exports = {
Ed25519Pair

View File

@@ -3,7 +3,7 @@
const codec = require('ripple-address-codec');
const {
bytesToHex,
cachedProperty,
cached,
isVirtual,
createAccountID
} = require('./utils');
@@ -13,51 +13,56 @@ const KeyType = {
ed25519: 'ed25519'
};
function KeyPair({seedBytes, pubBytes}) {
this.seedBytes = seedBytes;
this._pubKeyCanonicalBytes = pubBytes;
class KeyPair {
constructor({seedBytes, pubBytes}) {
this.seedBytes = seedBytes;
this._pubKeyCanonicalBytes = pubBytes;
}
/*
* @param {Array} message
*/
@isVirtual
sign() {}
/*
* @param {Array<Byte>} message
* @param {Array<Byte>} signature
*/
@isVirtual
verify() {}
/*
* @return {Array<Byte>} of bytes, in canonical form, for signing
*/
@isVirtual
pubKeyCanonicalBytes() {}
@cached
pubKeyHex() {
return bytesToHex(this.pubKeyCanonicalBytes());
}
@cached
accountBytes() {
return createAccountID(this.pubKeyCanonicalBytes());
}
@cached
accountID() {
return codec.encodeAccountID(this.accountBytes());
}
@cached
seed() {
return codec.encodeSeed(this.seedBytes, this.type);
}
signHex(message) {
return bytesToHex(this.sign(message));
}
}
/*
@param {Array} message
@virtual
*/
KeyPair.prototype.sign = isVirtual;
/*
@param {Array<Byte>} message
@param {Array<Byte>} signature
@virtual
*/
KeyPair.prototype.verify = isVirtual;
/*
@return {Array<Byte>} of bytes, in canonical form, for signing
@virtual
*/
KeyPair.prototype.pubKeyCanonicalBytes = isVirtual;
cachedProperty(KeyPair, function pubKeyHex() {
return bytesToHex(this.pubKeyCanonicalBytes());
});
cachedProperty(KeyPair, function accountBytes() {
return createAccountID(this.pubKeyCanonicalBytes());
});
cachedProperty(KeyPair, function accountID() {
return codec.encodeAccountID(this.accountBytes());
});
cachedProperty(KeyPair, function seed() {
return codec.encodeSeed(this.seedBytes, this.type);
});
KeyPair.prototype.signHex = function(message) {
return bytesToHex(this.sign(message));
};
module.exports = {
KeyPair,
KeyType

View File

@@ -1,14 +1,10 @@
'use strict';
const util = require('util');
const elliptic = require('elliptic');
const secp256k1 = elliptic.ec('secp256k1');
const hashjs = require('hash.js');
const {KeyPair, KeyType} = require('./keypair');
const {
Sha512,
cachedProperty
} = require('./utils');
const {Sha512, cached} = require('./utils');
function deriveScalar(bytes, discrim) {
const order = secp256k1.curve.n;
@@ -65,65 +61,64 @@ function accountPublicFromPublicGenerator(publicGenBytes) {
return offset.encodeCompressed();
}
/*
* @class
*/
function K256Pair({validator}) {
KeyPair.apply(this, arguments);
this.type = KeyType.secp256k1;
this.validator = validator;
class K256Pair extends KeyPair {
constructor(options) {
super(options);
this.type = KeyType.secp256k1;
this.validator = options.validator;
}
static fromSeed(seedBytes, opts={}) {
return new K256Pair({seedBytes, validator: opts.validator});
}
/*
@param {Array<Byte>} message (bytes)
*/
sign(message) {
return this._createSignature(message).toDER();
}
_createSignature(message) {
// The key.sign message silently discards options
return this.key().sign(this.hashMessage(message), {canonical: true});
}
/*
@param {Array<Byte>} message - (bytes)
@return {Array<Byte>} - 256 bit hash of the message
*/
hashMessage(message) {
return hashjs.sha512().update(message).digest().slice(0, 32);
}
/*
@param {Array<Byte>} message - bytes
@param {Array<Byte>} signature - DER encoded signature bytes
*/
verify(message, signature) {
try {
return this.key().verify(this.hashMessage(message), signature);
} catch (e) {
return false;
}
}
@cached
key() {
if (this.seedBytes) {
const options = {validator: this.validator};
return secp256k1.keyFromPrivate(deriveSecret(this.seedBytes, options));
}
return secp256k1.keyFromPublic(this.pubKeyCanonicalBytes());
}
@cached
pubKeyCanonicalBytes() {
return this.key().getPublic().encodeCompressed();
}
}
util.inherits(K256Pair, KeyPair);
/*
@param {Array<Byte>} message (bytes)
*/
K256Pair.prototype.sign = function(message) {
return this._createSignature(message).toDER();
};
K256Pair.prototype._createSignature = function(message) {
// The key.sign message silently discards options
return this.key().sign(this.hashMessage(message), {canonical: true});
};
/*
@param {Array<Byte>} message - (bytes)
@return {Array<Byte>} - 256 bit hash of the message
*/
K256Pair.prototype.hashMessage = function(message) {
return hashjs.sha512().update(message).digest().slice(0, 32);
};
/*
@param {Array<Byte>} message - bytes
@param {Array<Byte>} signature - DER encoded signature bytes
*/
K256Pair.prototype.verify = function(message, signature) {
try {
return this.key().verify(this.hashMessage(message), signature);
} catch (e) {
return false;
}
};
cachedProperty(K256Pair, function key() {
if (this.seedBytes) {
const options = {validator: this.validator};
return secp256k1.keyFromPrivate(deriveSecret(this.seedBytes, options));
}
return secp256k1.keyFromPublic(this.pubKeyCanonicalBytes());
});
cachedProperty(K256Pair, function pubKeyCanonicalBytes() {
return this.key().getPublic().encodeCompressed();
});
K256Pair.fromSeed = function(seedBytes, opts={}) {
return new K256Pair({seedBytes, validator: opts.validator});
};
module.exports = {
K256Pair,
accountPublicFromPublicGenerator

View File

@@ -3,19 +3,21 @@
const hashjs = require('hash.js');
const Sha512 = require('./sha512');
function isVirtual() {
throw new Error('virtual method not implemented ');
function isVirtual(target, name, descriptor) {
descriptor.value = function() {
throw new Error('virtual method not implemented ');
};
}
function cachedProperty(obj, computer) {
const name = computer.name;
function cached(target, name, descriptor) {
const computer = descriptor.value;
const key = '_' + name;
obj.prototype[name] = function() {
let cached = this[key];
if (cached === undefined) {
cached = this[key] = computer.call(this);
descriptor.value = function() {
let value = this[key];
if (value === undefined) {
value = this[key] = computer.call(this);
}
return cached;
return value;
};
}
@@ -45,8 +47,8 @@ function seedFromPhrase(phrase) {
}
module.exports = {
cached,
bytesToHex,
cachedProperty,
createAccountID,
isVirtual,
seedFromPhrase,