UNPKG

hsd

Version:
159 lines (125 loc) 2.87 kB
/*! * sigcache.js - signature cache for hsd * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License). * https://github.com/handshake-org/hsd */ 'use strict'; const assert = require('bsert'); const {BufferMap} = require('buffer-map'); const secp256k1 = require('bcrypto/lib/secp256k1'); /** @typedef {import('../types').Hash} Hash */ /** * Signature cache. * @alias module:script.SigCache * @property {Number} size * @property {Hash[]} keys * @property {Object} valid */ class SigCache { /** * Create a signature cache. * @constructor * @param {Number} [size=10000] */ constructor(size) { if (size == null) size = 10000; assert((size >>> 0) === size); this.size = size; this.keys = []; this.valid = new BufferMap(); } /** * Resize the sigcache. * @param {Number} size */ resize(size) { assert((size >>> 0) === size); this.size = size; this.keys.length = 0; this.valid.clear(); } /** * Add item to the sigcache. * Potentially evict a random member. * @param {Hash} hash - Sig hash. * @param {Buffer} sig * @param {Buffer} key */ add(hash, sig, key) { if (this.size === 0) return; this.valid.set(hash, new SigCacheEntry(sig, key)); if (this.keys.length >= this.size) { const i = Math.floor(Math.random() * this.keys.length); const k = this.keys[i]; this.valid.delete(k); this.keys[i] = hash; } else { this.keys.push(hash); } } /** * Test whether the sig exists. * @param {Hash} hash - Sig hash. * @param {Buffer} sig * @param {Buffer} key * @returns {Boolean} */ has(hash, sig, key) { const entry = this.valid.get(hash); if (!entry) return false; return entry.equals(sig, key); } /** * Verify a signature, testing * it against the cache first. * @param {Hash} hash * @param {Buffer} sig * @param {Buffer} key * @returns {Boolean} */ verify(hash, sig, key) { if (this.size === 0) return secp256k1.verify(hash, sig, key); if (this.has(hash, sig, key)) return true; const result = secp256k1.verify(hash, sig, key); if (!result) return false; this.add(hash, sig, key); return true; } } /** * Signature Cache Entry * @ignore * @property {Buffer} sig * @property {Buffer} key */ class SigCacheEntry { /** * Create a cache entry. * @constructor * @param {Buffer} sig * @param {Buffer} key */ constructor(sig, key) { this.sig = Buffer.from(sig); this.key = Buffer.from(key); } /** * Compare an entry to a sig and key. * @param {Buffer} sig * @param {Buffer} key * @returns {Boolean} */ equals(sig, key) { return this.sig.equals(sig) && this.key.equals(key); } } /* * Expose */ module.exports = SigCache;