diff --git a/lib/client/preprocessing/api.js b/lib/client/preprocessing/api.js index 09b1a128a..9728bd9b8 100644 --- a/lib/client/preprocessing/api.js +++ b/lib/client/preprocessing/api.js @@ -1,9 +1,12 @@ const LinkedList = require('../../../build/linkedlist.js'); -module.exports = function (jiffClient) { - let isRunning = false; - const userCallbacks = []; - const preprocessingTasks = [new LinkedList()]; +class PreprocessingAPI { + constructor(jiffClient) { + this.jiffClient = jiffClient; + this.isRunning = false; + this.userCallbacks = []; + this.preprocessingTasks = [new LinkedList()]; + } /** * Checks if the given operation uses preprocessed values @@ -13,15 +16,15 @@ module.exports = function (jiffClient) { * @param {string} op - name of the operation to check * @return {boolean} true if the op uses preprocessing, false otherwise */ - jiffClient.has_preprocessing = function (op) { - for (let i = 0; i < jiffClient.extensions.length; i++) { - if (jiffClient.preprocessing_function_map[jiffClient.extensions[i]][op] != null) { + has_preprocessing(op) { + for (let i = 0; i < this.jiffClient.extensions.length; i++) { + if (this.jiffClient.preprocessing_function_map[String(this.jiffClient.extensions[parseInt(i, 10)])][String(op)] != null) { return true; } } return false; - }; + } /** * Get a preprocessed share/value by associated op_id. If value does not exist @@ -32,16 +35,16 @@ module.exports = function (jiffClient) { * @param {string} op_id - the op_id associated with the preprocessed value/share * @return {object} the preprocessed share(s) */ - jiffClient.get_preprocessing = function (op_id) { - const values = jiffClient.preprocessing_table[op_id]; + get_preprocessing(op_id) { + const values = this.jiffClient.preprocessing_table[String(op_id)]; if (values != null) { return values; } - if (jiffClient.crypto_provider === true) { + if (this.jiffClient.crypto_provider === true) { return null; } throw new Error('No preprocessed value(s) that correspond to the op_id "' + op_id + '"'); - }; + } /** * Store a pair of op_id and associated pre-processed value/share @@ -52,11 +55,11 @@ module.exports = function (jiffClient) { * @param {string} op_id - the op_id associated with the preprocessed value/share * @param {SecretShare} share - the share/value to store */ - jiffClient.store_preprocessing = function (op_id, share) { + store_preprocessing(op_id, share) { if (share != null) { - jiffClient.preprocessing_table[op_id] = share; + this.jiffClient.preprocessing_table[String(op_id)] = share; } - }; + } /** * Generate values used for JIFF operations in advance of the computation. @@ -81,39 +84,39 @@ module.exports = function (jiffClient) { * @return {promise} a promise that is resolved when preprocessing is completed, null if this is called by a party that is neither a compute nor receiver party * @see {@link module:jiff-client~JIFFClient#executePreprocessing} */ - jiffClient.preprocessing = function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, id_list, params) { + preprocessing(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, id_list, params) { // defaults! if (receivers_list == null) { receivers_list = []; - for (let p = 1; p <= jiffClient.party_count; p++) { + for (let p = 1; p <= this.jiffClient.party_count; p++) { receivers_list.push(p); } } else { - jiffClient.helpers.sort_ids(receivers_list); + this.jiffClient.helpers.sort_ids(receivers_list); } if (compute_list == null) { compute_list = []; - for (let c = 1; c <= jiffClient.party_count; c++) { + for (let c = 1; c <= this.jiffClient.party_count; c++) { compute_list.push(c); } } else { - jiffClient.helpers.sort_ids(compute_list); + this.jiffClient.helpers.sort_ids(compute_list); } // not a receiver nor a sender - if (receivers_list.indexOf(jiffClient.id) === -1 && compute_list.indexOf(jiffClient.id) === -1) { + if (receivers_list.indexOf(this.jiffClient.id) === -1 && compute_list.indexOf(this.jiffClient.id) === -1) { return null; } // more defaults if (Zp == null) { - Zp = jiffClient.Zp; + Zp = this.jiffClient.Zp; } if (threshold == null) { threshold = receivers_list.length; } if (protocols == null) { - protocols = jiffClient.default_preprocessing_protocols; + protocols = this.jiffClient.default_preprocessing_protocols; } // actual preprocessing @@ -124,7 +127,7 @@ module.exports = function (jiffClient) { params = {}; } if (params['namespace'] == null) { - params['namespace'] = jiffClient.extensions[jiffClient.extensions.length - 1]; + params['namespace'] = this.jiffClient.extensions[this.jiffClient.extensions.length - 1]; } // Create preprocessing tasks @@ -139,13 +142,13 @@ module.exports = function (jiffClient) { id: null, params: params, protocols: protocols, - deferred: jiffClient.helpers.createDeferred() + deferred: new this.jiffClient.helpers.Deferred() }; - preprocessingTasks[preprocessingTasks.length - 1].add(task); + this.preprocessingTasks[this.preprocessingTasks.length - 1].add(task); return task.deferred.promise; - }; + } /** * Ask JIFF to start executing preprocessing for tasks previously added by {@link module:jiff-client~JIFFClient#preprocessing}. @@ -158,34 +161,36 @@ module.exports = function (jiffClient) { * @param callback {!Function} - the callback to execute when preprocessing is finished. * {@link module:jiff-client~JIFFClient#preprocessing} */ - jiffClient.executePreprocessing = function (callback) { - userCallbacks.push(callback); - preprocessingTasks.push(new LinkedList()); + executePreprocessing(callback) { + this.userCallbacks.push(callback); + this.preprocessingTasks.push(new LinkedList()); - if (!isRunning) { - __executePreprocessing(); + if (!this.isRunning) { + this.__executePreprocessing(); } - }; + } // called only when preprocessing can run RIGHT NOW - const __executePreprocessing = function () { - isRunning = true; + __executePreprocessing() { + this.isRunning = true; - jiffClient.currentPreprocessingTasks = preprocessingTasks.shift(); - const currentCallback = userCallbacks.shift(); + this.jiffClient.currentPreprocessingTasks = this.preprocessingTasks.shift(); + const currentCallback = this.userCallbacks.shift(); - jiffClient.preprocessingCallback = function () { + this.jiffClient.preprocessingCallback = () => { + //Check if (currentCallback != null) { currentCallback.apply(null, currentCallback); } - if (userCallbacks.length > 0) { - __executePreprocessing(); + if (this.userCallbacks.length > 0) { + this.__executePreprocessing(); } else { - isRunning = false; + this.isRunning = false; } }; - jiffClient.preprocessingDaemon(); - }; -}; + this.jiffClient.preprocess.daemon.preprocessingDaemon(); + } +} +module.exports = PreprocessingAPI; diff --git a/lib/client/preprocessing/daemon.js b/lib/client/preprocessing/daemon.js index 1debd7781..846dda427 100644 --- a/lib/client/preprocessing/daemon.js +++ b/lib/client/preprocessing/daemon.js @@ -1,14 +1,18 @@ -module.exports = function (jiffClient) { - const LinkedList = require('../../../build/linkedlist.js'); - let currentBatchLoad = 0; - let suspendedTasks = 0; +const LinkedList = require('../../../build/linkedlist.js'); - const getFirstTask = function (task) { +class PreprocessDaemon { + constructor(jiffClient) { + this.jiffClient = jiffClient; + this.currentBatchLoad = 0; + this.suspendedTasks = 0; + } + + getFirstTask(task) { if (task.count > 1) { const remainingTasks = Object.assign({}, task); - const deferred1 = jiffClient.helpers.createDeferred(); - const deferred2 = jiffClient.helpers.createDeferred(); + const deferred1 = new this.jiffClient.helpers.Deferred(); + const deferred2 = new this.jiffClient.helpers.Deferred(); Promise.all([deferred1.promise, deferred2.promise]).then(task.deferred.resolve); task.deferred = deferred1; remainingTasks.deferred = deferred2; @@ -19,81 +23,81 @@ module.exports = function (jiffClient) { task.id = remainingTasks.id_list.shift(); task.id_list = null; } - jiffClient.currentPreprocessingTasks.pushHead(remainingTasks); + this.jiffClient.currentPreprocessingTasks.pushHead(remainingTasks); } if (task.id_list != null) { task.id = task.id_list[0]; task.id_list = null; } return task; - }; + } - const checkIfDone = function () { - if (currentBatchLoad === 0 && suspendedTasks === 0) { - const callback = jiffClient.preprocessingCallback; - jiffClient.preprocessingCallback = null; - callback(jiffClient); + checkIfDone() { + if (this.currentBatchLoad === 0 && this.suspendedTasks === 0) { + const callback = this.jiffClient.preprocessingCallback; + this.jiffClient.preprocessingCallback = null; + callback(this.jiffClient); } - }; + } - const buildID = function (task) { + buildID(task) { // Two kinds of operations: one that relies on different sets of senders and receivers, and one that has a set of holders if (task.dependent_op === 'open' || task.dependent_op === 'bits.open') { // TODO: make this part of the description in table const open_parties = task.params['open_parties'] != null ? task.params['open_parties'] : task.receivers_list; - task.id = jiffClient.counters.gen_op_id2_preprocessing(task.dependent_op, open_parties, task.receivers_list); + task.id = this.jiffClient.counters.gen_op_id2_preprocessing(task.dependent_op, open_parties, task.receivers_list); } else { - task.id = jiffClient.counters.gen_op_id_preprocessing(task.dependent_op, task.receivers_list); + task.id = this.jiffClient.counters.gen_op_id_preprocessing(task.dependent_op, task.receivers_list); } - }; + } - const taskIsExecutable = function (task) { + taskIsExecutable(task) { // if the protocol name is in the map, it can be directly executed - const namespace = find_closest_namespace(task.dependent_op, task.params['namespace']); + const namespace = this.find_closest_namespace(task.dependent_op, task.params['namespace']); return namespace == null; - }; + } - const find_closest_namespace = function (op, starting_namespace) { - let namespace_index = jiffClient.extensions.indexOf(starting_namespace); + find_closest_namespace(op, starting_namespace) { + let namespace_index = this.jiffClient.extensions.indexOf(starting_namespace); while (namespace_index >= 0) { - const namespace = jiffClient.extensions[namespace_index]; - if (jiffClient.preprocessing_function_map[namespace] != null && jiffClient.preprocessing_function_map[namespace][op] != null) { + const namespace = this.jiffClient.extensions[parseInt(namespace_index, 10)]; + if (this.jiffClient.preprocessing_function_map[String(namespace)] != null && this.jiffClient.preprocessing_function_map[String(namespace)][String(op)] != null) { return namespace; } namespace_index--; } return null; - }; + } // execute a task and handle it upon completion - const executeTask = function (task) { - currentBatchLoad++; + executeTask(task) { + this.currentBatchLoad++; const _params = Object.assign({}, task.params); _params.output_op_id = task.id; - const protocol = task.protocols[task.dependent_op] || jiffClient.default_preprocessing_protocols[task.dependent_op]; + const protocol = task.protocols[task.dependent_op] || this.jiffClient.default_preprocessing_protocols[task.dependent_op]; const result = protocol(task.threshold, task.receivers_list, task.compute_list, task.Zp, _params, task.protocols); if (result.promise == null || result.promise.then == null) { - taskFinished(task, result); + this.taskFinished(task, result); } else { - result.promise.then(taskFinished.bind(null, task, result)); + result.promise.then(this.taskFinished.bind(this, task, result)); } - }; - const taskFinished = function (task, result) { - currentBatchLoad--; + } + taskFinished(task, result) { + this.currentBatchLoad--; - if (task.receivers_list.indexOf(jiffClient.id) > -1) { - jiffClient.store_preprocessing(task.id, result.share); + if (task.receivers_list.indexOf(this.jiffClient.id) > -1) { + this.jiffClient.preprocess.api.store_preprocessing(task.id, result.share); } task.deferred.resolve(); - jiffClient.preprocessingDaemon(); - }; + this.preprocessingDaemon(); + } // expand task by one level and replace the node in the task list - const expandTask = function (task) { + expandTask(task) { // copy of params const _params = Object.assign({}, task.params); @@ -102,8 +106,8 @@ module.exports = function (jiffClient) { // and pre-process those with the right op_ids. // ID should never be null - const namespace = find_closest_namespace(task.dependent_op, _params['namespace']); - let preprocessing_dependencies = jiffClient.preprocessing_function_map[namespace][task.dependent_op]; + const namespace = this.find_closest_namespace(task.dependent_op, _params['namespace']); + let preprocessing_dependencies = this.jiffClient.preprocessing_function_map[String(namespace)][String(task.dependent_op)]; if (typeof preprocessing_dependencies === 'function') { preprocessing_dependencies = preprocessing_dependencies( @@ -117,7 +121,7 @@ module.exports = function (jiffClient) { task.id, _params, task, - jiffClient + this.jiffClient ); } @@ -134,7 +138,7 @@ module.exports = function (jiffClient) { let extra_params = Object.assign({}, _params, dependency['params']); extra_params['namespace'] = dependency['namespace'] != null ? dependency['namespace'] : 'base'; if (dependency.handler != null) { - extra_params = dependency.handler(task.threshold, task.receivers_list, task.compute_list, task.Zp, task.id, extra_params, task, jiffClient); + extra_params = dependency.handler(task.threshold, task.receivers_list, task.compute_list, task.Zp, task.id, extra_params, task, this.jiffClient); } if (extra_params.ignore === true) { continue; @@ -165,7 +169,7 @@ module.exports = function (jiffClient) { id: null, params: extra_params, protocols: task.protocols, - deferred: jiffClient.helpers.createDeferred() + deferred: new this.jiffClient.helpers.Deferred() }; deferredChain.push(nextTask.deferred.promise); @@ -191,7 +195,7 @@ module.exports = function (jiffClient) { Promise.all(required_ops).then( function (nextTask) { delete nextTask['wait']; - jiffClient.preprocessingDaemon(); + this.preprocessingDaemon(); }.bind(null, nextTask) ); @@ -205,8 +209,8 @@ module.exports = function (jiffClient) { } Promise.all(deferredChain).then(task.deferred.resolve); - jiffClient.currentPreprocessingTasks = newTasks.extend(jiffClient.currentPreprocessingTasks); - }; + this.jiffClient.currentPreprocessingTasks = newTasks.extend(this.jiffClient.currentPreprocessingTasks); + } /** * Preprocessing Daemon that executes all currently scheduled preprocessing tasks (entries in jiffClient.currentPreprocessingTasks array) in order. @@ -214,32 +218,35 @@ module.exports = function (jiffClient) { * @memberof module:jiff-client~JIFFClient * @instance */ - jiffClient.preprocessingDaemon = function () { - while (currentBatchLoad < jiffClient.preprocessingBatchSize) { - let task = jiffClient.currentPreprocessingTasks.popHead(); + + preprocessingDaemon() { + while (this.currentBatchLoad < this.jiffClient.preprocessingBatchSize) { + let task = this.jiffClient.currentPreprocessingTasks.popHead(); if (task == null) { - checkIfDone(); + this.checkIfDone(); return; } if (task.object.wait) { - jiffClient.currentPreprocessingTasks.pushHead(task.object); + this.jiffClient.currentPreprocessingTasks.pushHead(task.object); break; } - task = getFirstTask(task.object); + task = this.getFirstTask(task.object); if (task.id == null) { - buildID(task); + this.buildID(task); } // check if task is executable or no - if (taskIsExecutable(task)) { - executeTask(task); // co-recursively calls preprocessingDaemon() + if (this.taskIsExecutable(task)) { + this.executeTask(task); // co-recursively calls preprocessingDaemon() } else { //expand single task - expandTask(task); + this.expandTask(task); } } - }; -}; + } +} + +module.exports = PreprocessDaemon; diff --git a/lib/client/preprocessing/handlers.js b/lib/client/preprocessing/handlers.js index 2304c4c49..4b4bce924 100644 --- a/lib/client/preprocessing/handlers.js +++ b/lib/client/preprocessing/handlers.js @@ -1,16 +1,16 @@ // internal functions for use in preprocessing function map -module.exports = { - bits_count: function (threshold, receivers_list, compute_list, Zp, op_id, params) { +class PreprocessHandlers { + bits_count(threshold, receivers_list, compute_list, Zp, op_id, params) { let bitLength = params.bitLength; if (bitLength == null) { bitLength = Zp.toString(2).length; } return bitLength; - }, - constant_bits_count: function () { - return module.exports.bits_count.apply(null, arguments) - 1; - }, - dynamic_bits_cmult: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { + } + constant_bits_count() { + return this.bits_count.apply(null, arguments) - 1; + } + dynamic_bits_cmult(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { // constant bit length let constantBits = Zp.toString(2).length; if (params.constantBits != null) { @@ -28,8 +28,8 @@ module.exports = { ops.push({ op: 'bits.sadd', op_id: ':bits.sadd:' + i, params: { bitLengthLeft: accLength, bitLengthRight: bitLength + i } }); } return ops; - }, - dynamic_bits_smult: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { + } + dynamic_bits_smult(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { let bitLength = params.bitLength; if (bitLength == null) { bitLength = Zp.toString(2).length; @@ -51,8 +51,8 @@ module.exports = { ops.push({ op: 'bits.sadd', op_id: ':bits.sadd:' + i, params: { bitLengthLeft: accLength, bitLengthRight: max + i } }); } return ops; - }, - choice_bits_count: function (choice, offset) { + } + choice_bits_count(choice, offset) { if (offset == null) { offset = 0; } @@ -69,11 +69,11 @@ module.exports = { return choice(left, right) + offset; }; - }, - decomposition_ifelse_count: function (threshold, receivers_list, compute_list, Zp, op_id, params) { + } + decomposition_ifelse_count(threshold, receivers_list, compute_list, Zp, op_id, params) { return Zp.toString(2).length; - }, - dynamic_bits_sdiv: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { + } + dynamic_bits_sdiv(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { let bitLength = params.bitLength; if (bitLength == null) { bitLength = Zp.toString(2).length; @@ -94,8 +94,9 @@ module.exports = { } } return ops; - }, - dynamic_bits_cdiv: function (dir) { + } + + dynamic_bits_cdiv(dir) { return function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params) { let constantBits = Zp.toString(2).length; if (params.constantBits != null) { @@ -131,15 +132,15 @@ module.exports = { } return ops; }; - }, + } // rejection sampling - dynamic_rejection_sampling: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { + dynamic_rejection_sampling(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { const previousPreprocessing = jiff.preprocessing_table[task.id]; params.reject_count = params.reject_count == null ? -1 : params.reject_count; if (previousPreprocessing == null || previousPreprocessing === 'RETRY' || (previousPreprocessing[0] != null && previousPreprocessing[0].value === 'RETRY')) { if (!params.defaultBounds && (params.lower_bound == null || params.upper_bound == null)) { - jiff.store_preprocessing(task.id, { ondemand: true }); + jiff.preprocess.api.store_preprocessing(task.id, { ondemand: true }); return []; } @@ -201,9 +202,9 @@ module.exports = { } return []; - }, + } // random quotients for cdiv - dynamic_random_and_quotient: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { + dynamic_random_and_quotient(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { const constantNotProvided = params.constant == null; receivers_list = constantNotProvided ? compute_list : receivers_list; Zp = Zp ? Zp : jiff.Zp; @@ -223,7 +224,7 @@ module.exports = { ]; if (constantNotProvided) { - jiff.store_preprocessing(task_id, { ondemand: true }); + jiff.preprocess.api.store_preprocessing(task_id, { ondemand: true }); return dependent_ops; } @@ -237,9 +238,9 @@ module.exports = { ); return dependent_ops; - }, + } // fast exponentiation - dynamic_fast_exponentiation: function (dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { + dynamic_fast_exponentiation(dependent_op, count, protocols, threshold, receivers_list, compute_list, Zp, task_id, params, task, jiff) { Zp = Zp ? Zp : jiff.Zp; const constantNotProvided = params.constant == null; let constant = params.constant; @@ -275,11 +276,13 @@ module.exports = { } ops.push({ op: 'smult', op_id: ':smult0:' + i }); return ops; - }, + } // for various equality tests, preprocess of cpow(Zp - 1) (Fermat's little theorem) - handler_cpow_Zp_minus_1: function (threshold, receivers_list, compute_list, Zp, op_id, params, task, jiff) { + handler_cpow_Zp_minus_1(threshold, receivers_list, compute_list, Zp, op_id, params, task, jiff) { Zp = Zp ? Zp : jiff.Zp; params.constant = jiff.share_helpers['-'](Zp, 1); return params; } -}; +} + +module.exports = PreprocessHandlers; diff --git a/lib/client/preprocessing/map.js b/lib/client/preprocessing/map.js index a5e4f6266..f1d060a62 100644 --- a/lib/client/preprocessing/map.js +++ b/lib/client/preprocessing/map.js @@ -1,145 +1,157 @@ -module.exports = function (jiffClient) { - const handlers = require('./handlers.js'); +/* eslint-disable */ +const PreprocessHandlers = require('./handlers.js'); +const handlers = new PreprocessHandlers(); - jiffClient.default_preprocessing_protocols = { - generate_beaver: jiffClient.protocols.generate_beaver_bgw, - generate_random_number: jiffClient.protocols.generate_random_number, - sampling: jiffClient.protocols.rejection_sampling, - generate_random_bits: jiffClient.protocols.generate_random_bits, - generate_random_bit: jiffClient.protocols.generate_random_bit_bgw, - generate_zero: jiffClient.protocols.generate_zero, - generate_random_and_quotient: jiffClient.protocols.generate_random_and_quotient - }; +class PreprocessingMap { + constructor(jiffClient) { + this.jiffClient = jiffClient; + this.initMap(); + } - jiffClient.preprocessing_function_map = { - base: { - // arithmetic sharing protocols - smult: [ - { op: 'open', op_id: ':open1' }, - { op: 'generate_beaver', op_id: ':triplet' }, - { op: 'open', op_id: ':open2' } - ], - sxor_bit: [{ op: 'smult', op_id: ':smult1' }], - slt: [ - { op: 'lt_halfprime', op_id: ':halfprime:1' }, - { op: 'lt_halfprime', op_id: ':halfprime:2' }, - { op: 'lt_halfprime', op_id: ':halfprime:3' }, - { op: 'smult', op_id: ':smult1' }, - { op: 'smult', op_id: ':smult2' } - ], - cgt: [ - { op: 'lt_halfprime', op_id: ':halfprime:1' }, - { op: 'lt_halfprime', op_id: ':halfprime:2' }, - { op: 'smult', op_id: ':smult1' } - ], - clt: [ - { op: 'lt_halfprime', op_id: ':halfprime:1' }, - { op: 'lt_halfprime', op_id: ':halfprime:2' }, - { op: 'smult', op_id: ':smult1' } - ], - lt_halfprime: [ - { op: 'rejection_sampling', op_id: ':sampling', params: { defaultBounds: true } }, - { op: 'smult', op_id: ':smult1' }, - { op: 'bits.cgt', op_id: ':bits.cgt' }, - { op: 'sxor_bit', op_id: ':sxor_bit' }, - { op: 'open', op_id: ':open' } - ], - cneq: [{ op: 'cpow', op_id: ':cpow', handler: handlers.handler_cpow_Zp_minus_1 }], - cpow: handlers.dynamic_fast_exponentiation, - cdiv: [ - { op: 'cgt', op_id: ':wrap_cgt' }, - { op: 'cgteq', op_id: ':cor1' }, - { op: 'cgteq', op_id: ':cor2' }, - { op: 'smult', op_id: ':smult' }, - { op: 'clt', op_id: ':zero_check' }, - { op: 'smult', op_id: ':zero_it' }, - { op: 'open', op_id: ':open' }, - { op: 'quotient', op_id: ':quotient' } - ], - sdiv: [ - { op: 'bit_decomposition', op_id: ':decomposition1' }, - { op: 'bit_decomposition', op_id: ':decomposition2' }, - { op: 'bits.sdiv', op_id: ':bits.sdiv' } - ], - if_else: [{ op: 'smult', op_id: ':smult' }], - // bits protocols - bit_decomposition: [ - { op: 'rejection_sampling', op_id: ':sampling', params: { defaultBounds: true } }, - { op: 'bits.csubr', op_id: ':bits.csubr:1' }, - { op: 'bits.csubr', op_id: ':bits.csubr:2' }, - { op: 'if_else', op_id: ':if_else:', count: handlers.decomposition_ifelse_count }, - { op: 'open', op_id: ':open' } - ], - // comparisons - 'bits.cgteq': [{ op: 'smult', op_id: ':smult:', count: handlers.constant_bits_count }], - 'bits.cneq': [{ op: 'sor_bit', op_id: ':sor_bit:', count: handlers.constant_bits_count }], - 'bits.sneq': [ - { op: 'sxor_bit', op_id: ':sxor_bit:initial' }, - { op: 'sxor_bit', op_id: ':sxor_bit:', count: handlers.choice_bits_count(Math.min, -1) }, - { op: 'sor_bit', op_id: ':sor_bit:', count: handlers.choice_bits_count(Math.max, -1) } - ], - 'bits.sgteq': [ - { op: 'smult', op_id: ':smult:initial' }, - { op: 'smult', op_id: ':smult1:', count: handlers.choice_bits_count(Math.max, -1) }, - { op: 'sxor_bit', op_id: ':sxor_bit1:', count: handlers.choice_bits_count(Math.min, -1) }, - { op: 'smult', op_id: ':smult2:', count: handlers.choice_bits_count(Math.min, -1) } - ], - 'bits.sgt': [ - { op: 'bits.sgteq', op_id: ':bits.sgteq' }, - { op: 'bits.sneq', op_id: ':bits.sneq' }, - { op: 'smult', op_id: ':smult' } - ], - // constant arithmetic - 'bits.cadd': [ - { op: 'smult', op_id: ':smult:', count: handlers.constant_bits_count }, - { op: 'sxor_bit', op_id: ':sxor_bit:', count: handlers.constant_bits_count } - ], - 'bits.cmult': handlers.dynamic_bits_cmult, - 'bits.cdivl': handlers.dynamic_bits_cdiv('left'), - 'bits.cdivr': handlers.dynamic_bits_cdiv('right'), - // secret arithmetic - 'bits.sadd': [ - { op: 'sxor_bit', op_id: ':sxor_bit:initial' }, - { op: 'smult', op_id: ':smult:initial' }, - { op: 'smult', op_id: ':smult1:', count: handlers.choice_bits_count(Math.max, -1) }, - { op: 'sxor_bit', op_id: ':sxor_bit1:', count: handlers.choice_bits_count(Math.max, -1) }, - { op: 'smult', op_id: ':smult2:', count: handlers.choice_bits_count(Math.min, -1) }, - { op: 'sxor_bit', op_id: ':sxor_bit2:', count: handlers.choice_bits_count(Math.min, -1) } - ], - 'bits.smult': handlers.dynamic_bits_smult, - 'bits.sdiv': handlers.dynamic_bits_sdiv, - 'bits.open': [{ op: 'open', op_id: ':', count: handlers.bits_count }], - // refresh/open - refresh: [{ op: 'generate_zero', op_id: '' }], - open: [{ op: 'refresh', op_id: ':refresh' }], - // generating a random number and its quotient / constant - quotient: handlers.dynamic_random_and_quotient, - // rejection sampling - rejection_sampling: handlers.dynamic_rejection_sampling - } - }; + initMap() { + const jiffClient = this.jiffClient; - // arithmetic protocols - jiffClient.preprocessing_function_map['base']['sor_bit'] = jiffClient.preprocessing_function_map['base']['sxor_bit']; - jiffClient.preprocessing_function_map['base']['smod'] = jiffClient.preprocessing_function_map['base']['sdiv']; - jiffClient.preprocessing_function_map['base']['slteq'] = jiffClient.preprocessing_function_map['base']['slt']; - jiffClient.preprocessing_function_map['base']['sgteq'] = jiffClient.preprocessing_function_map['base']['slt']; - jiffClient.preprocessing_function_map['base']['sgt'] = jiffClient.preprocessing_function_map['base']['slt']; - jiffClient.preprocessing_function_map['base']['clteq'] = jiffClient.preprocessing_function_map['base']['cgt']; - jiffClient.preprocessing_function_map['base']['cgteq'] = jiffClient.preprocessing_function_map['base']['clt']; - jiffClient.preprocessing_function_map['base']['seq'] = jiffClient.preprocessing_function_map['base']['cneq']; - jiffClient.preprocessing_function_map['base']['sneq'] = jiffClient.preprocessing_function_map['base']['cneq']; - jiffClient.preprocessing_function_map['base']['ceq'] = jiffClient.preprocessing_function_map['base']['cneq']; + jiffClient.default_preprocessing_protocols = { + generate_beaver: jiffClient.protocols.generate_beaver_bgw, + generate_random_number: jiffClient.protocols.generate_random_number, + sampling: jiffClient.protocols.rejection_sampling, + generate_random_bits: jiffClient.protocols.generate_random_bits, + generate_random_bit: jiffClient.protocols.generate_random_bit_bgw, + generate_zero: jiffClient.protocols.generate_zero, + generate_random_and_quotient: jiffClient.protocols.generate_random_and_quotient + }; - // bits protocols - jiffClient.preprocessing_function_map['base']['bits.clt'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; - jiffClient.preprocessing_function_map['base']['bits.clteq'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; - jiffClient.preprocessing_function_map['base']['bits.cgt'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; - jiffClient.preprocessing_function_map['base']['bits.ceq'] = jiffClient.preprocessing_function_map['base']['bits.cneq']; - jiffClient.preprocessing_function_map['base']['bits.slt'] = jiffClient.preprocessing_function_map['base']['bits.sgteq']; - jiffClient.preprocessing_function_map['base']['bits.slteq'] = jiffClient.preprocessing_function_map['base']['bits.sgt']; - jiffClient.preprocessing_function_map['base']['bits.seq'] = jiffClient.preprocessing_function_map['base']['bits.sneq']; - jiffClient.preprocessing_function_map['base']['bits.csubl'] = jiffClient.preprocessing_function_map['base']['bits.cadd']; - jiffClient.preprocessing_function_map['base']['bits.csubr'] = jiffClient.preprocessing_function_map['base']['bits.cadd']; - jiffClient.preprocessing_function_map['base']['bits.ssub'] = jiffClient.preprocessing_function_map['base']['bits.sadd']; -}; + jiffClient.preprocessing_function_map = { + base: { + // arithmetic sharing protocols + smult: [ + { op: 'open', op_id: ':open1' }, + { op: 'generate_beaver', op_id: ':triplet' }, + { op: 'open', op_id: ':open2' } + ], + sxor_bit: [{ op: 'smult', op_id: ':smult1' }], + slt: [ + { op: 'lt_halfprime', op_id: ':halfprime:1' }, + { op: 'lt_halfprime', op_id: ':halfprime:2' }, + { op: 'lt_halfprime', op_id: ':halfprime:3' }, + { op: 'smult', op_id: ':smult1' }, + { op: 'smult', op_id: ':smult2' } + ], + cgt: [ + { op: 'lt_halfprime', op_id: ':halfprime:1' }, + { op: 'lt_halfprime', op_id: ':halfprime:2' }, + { op: 'smult', op_id: ':smult1' } + ], + clt: [ + { op: 'lt_halfprime', op_id: ':halfprime:1' }, + { op: 'lt_halfprime', op_id: ':halfprime:2' }, + { op: 'smult', op_id: ':smult1' } + ], + lt_halfprime: [ + { op: 'rejection_sampling', op_id: ':sampling', params: { defaultBounds: true } }, + { op: 'smult', op_id: ':smult1' }, + { op: 'bits.cgt', op_id: ':bits.cgt' }, + { op: 'sxor_bit', op_id: ':sxor_bit' }, + { op: 'open', op_id: ':open' } + ], + cneq: [{ op: 'cpow', op_id: ':cpow', handler: handlers.handler_cpow_Zp_minus_1 }], + cpow: handlers.dynamic_fast_exponentiation, + cdiv: [ + { op: 'cgt', op_id: ':wrap_cgt' }, + { op: 'cgteq', op_id: ':cor1' }, + { op: 'cgteq', op_id: ':cor2' }, + { op: 'smult', op_id: ':smult' }, + { op: 'clt', op_id: ':zero_check' }, + { op: 'smult', op_id: ':zero_it' }, + { op: 'open', op_id: ':open' }, + { op: 'quotient', op_id: ':quotient' } + ], + sdiv: [ + { op: 'bit_decomposition', op_id: ':decomposition1' }, + { op: 'bit_decomposition', op_id: ':decomposition2' }, + { op: 'bits.sdiv', op_id: ':bits.sdiv' } + ], + if_else: [{ op: 'smult', op_id: ':smult' }], + // bits protocols + bit_decomposition: [ + { op: 'rejection_sampling', op_id: ':sampling', params: { defaultBounds: true } }, + { op: 'bits.csubr', op_id: ':bits.csubr:1' }, + { op: 'bits.csubr', op_id: ':bits.csubr:2' }, + { op: 'if_else', op_id: ':if_else:', count: handlers.decomposition_ifelse_count }, + { op: 'open', op_id: ':open' } + ], + // comparisons + 'bits.cgteq': [{ op: 'smult', op_id: ':smult:', count: handlers.constant_bits_count }], + 'bits.cneq': [{ op: 'sor_bit', op_id: ':sor_bit:', count: handlers.constant_bits_count }], + 'bits.sneq': [ + { op: 'sxor_bit', op_id: ':sxor_bit:initial' }, + { op: 'sxor_bit', op_id: ':sxor_bit:', count: handlers.choice_bits_count(Math.min, -1) }, + { op: 'sor_bit', op_id: ':sor_bit:', count: handlers.choice_bits_count(Math.max, -1) } + ], + 'bits.sgteq': [ + { op: 'smult', op_id: ':smult:initial' }, + { op: 'smult', op_id: ':smult1:', count: handlers.choice_bits_count(Math.max, -1) }, + { op: 'sxor_bit', op_id: ':sxor_bit1:', count: handlers.choice_bits_count(Math.min, -1) }, + { op: 'smult', op_id: ':smult2:', count: handlers.choice_bits_count(Math.min, -1) } + ], + 'bits.sgt': [ + { op: 'bits.sgteq', op_id: ':bits.sgteq' }, + { op: 'bits.sneq', op_id: ':bits.sneq' }, + { op: 'smult', op_id: ':smult' } + ], + // constant arithmetic + 'bits.cadd': [ + { op: 'smult', op_id: ':smult:', count: handlers.constant_bits_count }, + { op: 'sxor_bit', op_id: ':sxor_bit:', count: handlers.constant_bits_count } + ], + 'bits.cmult': handlers.dynamic_bits_cmult, + 'bits.cdivl': handlers.dynamic_bits_cdiv('left'), + 'bits.cdivr': handlers.dynamic_bits_cdiv('right'), + // secret arithmetic + 'bits.sadd': [ + { op: 'sxor_bit', op_id: ':sxor_bit:initial' }, + { op: 'smult', op_id: ':smult:initial' }, + { op: 'smult', op_id: ':smult1:', count: handlers.choice_bits_count(Math.max, -1) }, + { op: 'sxor_bit', op_id: ':sxor_bit1:', count: handlers.choice_bits_count(Math.max, -1) }, + { op: 'smult', op_id: ':smult2:', count: handlers.choice_bits_count(Math.min, -1) }, + { op: 'sxor_bit', op_id: ':sxor_bit2:', count: handlers.choice_bits_count(Math.min, -1) } + ], + 'bits.smult': handlers.dynamic_bits_smult, + 'bits.sdiv': handlers.dynamic_bits_sdiv, + 'bits.open': [{ op: 'open', op_id: ':', count: handlers.bits_count }], + // refresh/open + refresh: [{ op: 'generate_zero', op_id: '' }], + open: [{ op: 'refresh', op_id: ':refresh' }], + // generating a random number and its quotient / constant + quotient: handlers.dynamic_random_and_quotient, + // rejection sampling + rejection_sampling: handlers.dynamic_rejection_sampling + } + }; + + // arithmetic protocols + jiffClient.preprocessing_function_map['base']['sor_bit'] = jiffClient.preprocessing_function_map['base']['sxor_bit']; + jiffClient.preprocessing_function_map['base']['smod'] = jiffClient.preprocessing_function_map['base']['sdiv']; + jiffClient.preprocessing_function_map['base']['slteq'] = jiffClient.preprocessing_function_map['base']['slt']; + jiffClient.preprocessing_function_map['base']['sgteq'] = jiffClient.preprocessing_function_map['base']['slt']; + jiffClient.preprocessing_function_map['base']['sgt'] = jiffClient.preprocessing_function_map['base']['slt']; + jiffClient.preprocessing_function_map['base']['clteq'] = jiffClient.preprocessing_function_map['base']['cgt']; + jiffClient.preprocessing_function_map['base']['cgteq'] = jiffClient.preprocessing_function_map['base']['clt']; + jiffClient.preprocessing_function_map['base']['seq'] = jiffClient.preprocessing_function_map['base']['cneq']; + jiffClient.preprocessing_function_map['base']['sneq'] = jiffClient.preprocessing_function_map['base']['cneq']; + jiffClient.preprocessing_function_map['base']['ceq'] = jiffClient.preprocessing_function_map['base']['cneq']; + + // bits protocols + jiffClient.preprocessing_function_map['base']['bits.clt'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; + jiffClient.preprocessing_function_map['base']['bits.clteq'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; + jiffClient.preprocessing_function_map['base']['bits.cgt'] = jiffClient.preprocessing_function_map['base']['bits.cgteq']; + jiffClient.preprocessing_function_map['base']['bits.ceq'] = jiffClient.preprocessing_function_map['base']['bits.cneq']; + jiffClient.preprocessing_function_map['base']['bits.slt'] = jiffClient.preprocessing_function_map['base']['bits.sgteq']; + jiffClient.preprocessing_function_map['base']['bits.slteq'] = jiffClient.preprocessing_function_map['base']['bits.sgt']; + jiffClient.preprocessing_function_map['base']['bits.seq'] = jiffClient.preprocessing_function_map['base']['bits.sneq']; + jiffClient.preprocessing_function_map['base']['bits.csubl'] = jiffClient.preprocessing_function_map['base']['bits.cadd']; + jiffClient.preprocessing_function_map['base']['bits.csubr'] = jiffClient.preprocessing_function_map['base']['bits.cadd']; + jiffClient.preprocessing_function_map['base']['bits.ssub'] = jiffClient.preprocessing_function_map['base']['bits.sadd']; + } +} +module.exports = PreprocessingMap; diff --git a/lib/client/protocols/bits/protocols.js b/lib/client/protocols/bits/protocols.js index fc9180cdf..7b969fbda 100644 --- a/lib/client/protocols/bits/protocols.js +++ b/lib/client/protocols/bits/protocols.js @@ -30,7 +30,7 @@ class BitProtocols { } // try to get preprocessed samples - const result = jiff.get_preprocessing(op_id); + const result = jiff.preprocess.api.get_preprocessing(op_id); if (result != null && result.ondemand !== true) { return result; } @@ -66,12 +66,12 @@ class BitProtocols { } else { // preprocess on demand delete jiff.preprocessing_table[op_id]; - jiff.preprocessing('rejection_sampling', 1, null, threshold, parties, parties, Zp, [op_id], { + jiff.preprocess.api.preprocessing('rejection_sampling', 1, null, threshold, parties, parties, Zp, [op_id], { lower_bound: lower_bound, upper_bound: upper_bound }); - jiff.executePreprocessing(function () { - jiff.utils.resolve_many_secrets(final_deferreds, jiff.get_preprocessing(op_id)); + jiff.preprocess.api.executePreprocessing(function () { + jiff.utils.resolve_many_secrets(final_deferreds, jiff.preprocess.api.get_preprocessing(op_id)); }); } diff --git a/lib/client/protocols/numbers/arithmetic.js b/lib/client/protocols/numbers/arithmetic.js index f01102fba..1294b36a0 100644 --- a/lib/client/protocols/numbers/arithmetic.js +++ b/lib/client/protocols/numbers/arithmetic.js @@ -220,7 +220,7 @@ module.exports = function (SecretShare) { }; // Get shares of triplets. - const triplet = this.jiff.get_preprocessing(op_id + ':triplet'); + const triplet = this.jiff.preprocess.api.get_preprocessing(op_id + ':triplet'); if (triplet == null) { const promise = this.jiff.from_crypto_provider('triplet', this.holders, Math.max(this.threshold, o.threshold), this.Zp, op_id + ':triplet'); promise.then(function (msg) { @@ -386,7 +386,7 @@ module.exports = function (SecretShare) { }; // Preprocessing cases - const quotient = this.jiff.get_preprocessing(op_id + ':quotient'); + const quotient = this.jiff.preprocess.api.get_preprocessing(op_id + ':quotient'); if (quotient == null) { // case 1: no preprocessing with crypto provider! const promise = this.jiff.from_crypto_provider('quotient', this.holders, this.threshold, this.Zp, op_id + ':quotient', { constant: cst }); @@ -395,9 +395,9 @@ module.exports = function (SecretShare) { }); } else if (quotient.ondemand === true) { // case 2: constant was not available at preprocessing time, must do it now! - this.jiff.preprocessing('quotient', 1, null, this.threshold, this.holders, this.holders, this.Zp, [op_id + ':quotient'], { constant: cst, namespace: 'base' }); - this.jiff.executePreprocessing(function () { - const quotient = self.jiff.get_preprocessing(op_id + ':quotient'); + this.jiff.preprocess.api.preprocessing('quotient', 1, null, this.threshold, this.holders, this.holders, this.Zp, [op_id + ':quotient'], { constant: cst, namespace: 'base' }); + this.jiff.preprocess.api.executePreprocessing(function () { + const quotient = self.jiff.preprocess.api.get_preprocessing(op_id + ':quotient'); ready_quotient(quotient.r, quotient.q); }); } else { diff --git a/lib/client/protocols/numbers/comparison.js b/lib/client/protocols/numbers/comparison.js index 768200e7f..c362e64b9 100644 --- a/lib/client/protocols/numbers/comparison.js +++ b/lib/client/protocols/numbers/comparison.js @@ -428,7 +428,7 @@ module.exports = function (SecretShare) { }; // generate the bits of a random number less than our prime - const bits = this.jiff.get_preprocessing(op_id + ':sampling'); + const bits = this.jiff.preprocess.api.get_preprocessing(op_id + ':sampling'); if (bits == null) { const promise = this.jiff.from_crypto_provider('numbers', this.holders, this.threshold, this.Zp, op_id + ':sampling', { bitLength: bitLength, diff --git a/lib/client/protocols/numbers/protocols.js b/lib/client/protocols/numbers/protocols.js index ff435d03a..9ecdcea9d 100644 --- a/lib/client/protocols/numbers/protocols.js +++ b/lib/client/protocols/numbers/protocols.js @@ -27,7 +27,7 @@ module.exports = function (SecretShare) { }; // get shares of zero - const zero = this.jiff.get_preprocessing(op_id); + const zero = this.jiff.preprocess.api.get_preprocessing(op_id); if (zero == null) { const promise = this.jiff.from_crypto_provider('numbers', this.holders, this.threshold, this.Zp, op_id, { number: 0, @@ -90,7 +90,7 @@ module.exports = function (SecretShare) { }; // generate the bits of a random number less than our prime - const bits = this.jiff.get_preprocessing(op_id + ':sampling'); + const bits = this.jiff.preprocess.api.get_preprocessing(op_id + ':sampling'); if (bits == null) { const promise = this.jiff.from_crypto_provider('numbers', this.holders, this.threshold, this.Zp, op_id + ':sampling', { bitLength: bitLength, diff --git a/lib/jiff-client.js b/lib/jiff-client.js index ded0d791b..cbd1c275c 100644 --- a/lib/jiff-client.js +++ b/lib/jiff-client.js @@ -58,9 +58,9 @@ const share_helpers = require('./client/shareHelpers.js'); const api = require('./client/api.js'); // preprocessing -const preprocessingMap = require('./client/preprocessing/map.js'); -const preprocessingAPI = require('./client/preprocessing/api.js'); -const preprocessingDaemon = require('./client/preprocessing/daemon.js'); +const PreprocessingMap = require('./client/preprocessing/map.js'); +const PreprocessingAPI = require('./client/preprocessing/api.js'); +const PreprocessDaemon = require('./client/preprocessing/daemon.js'); /** * Creates a new jiff client instance. @@ -421,9 +421,9 @@ function JIFFClient(hostname, computation_id, options) { api(this); // Preprocessing - preprocessingMap(this); - preprocessingAPI(this); - preprocessingDaemon(this); + this.preprocess = new PreprocessingMap(this); + this.preprocess.api = new PreprocessingAPI(this); + this.preprocess.daemon = new PreprocessDaemon(this); // set up counters for op_ids counters(this); diff --git a/tests/regr-tests/bit-preprocess.test.ts b/tests/regr-tests/bit-preprocess.test.ts index 835162fd2..d63c7ec85 100644 --- a/tests/regr-tests/bit-preprocess.test.ts +++ b/tests/regr-tests/bit-preprocess.test.ts @@ -47,12 +47,12 @@ describe('JIFF Preprocessing Operations', () => { it('should correctly preprocess bitwise operation and return 3000', async () => { function bit_smult(jiffClient: any, id: number) { - jiffClient.preprocessing('smult', 2, null, null, null, null, null, null, { div: false }); - jiffClient.preprocessing('open', 1); + jiffClient.preprocess.api.preprocessing('smult', 2, null, null, null, null, null, null, { div: false }); + jiffClient.preprocess.api.preprocessing('open', 1); return new Promise((resolve, reject) => { jiffClient.wait_for([1, 2], async () => { try { - await jiffClient.executePreprocessing(async function () { + await jiffClient.preprocess.api.executePreprocessing(async function () { const jiff_bits = jiffClient.protocols.bits; const input = await jiff_bits.share(entries[id]); const sec_ttl = await jiff_bits.smult(input[1], input[2]); diff --git a/tests/regr-tests/preprocess.test.ts b/tests/regr-tests/preprocess.test.ts index c44451ac1..9c23e6e42 100644 --- a/tests/regr-tests/preprocess.test.ts +++ b/tests/regr-tests/preprocess.test.ts @@ -46,13 +46,13 @@ describe('JIFF Preprocessing Operations', () => { it('should correctly preprocess inner product of the input array and return 329.59', async () => { function innerprod(jiffClient: any, id: number) { - jiffClient.preprocessing('smult', entries[id].length, null, null, null, null, null, null, { div: false }); - jiffClient.preprocessing('open', 1); + jiffClient.preprocess.api.preprocessing('smult', entries[id].length, null, null, null, null, null, null, { div: false }); + jiffClient.preprocess.api.preprocessing('open', 1); return new Promise((resolve, reject) => { jiffClient.wait_for([1, 2, 3], async () => { try { let sec_ttl: any = 0; - await jiffClient.executePreprocessing(async function () { + await jiffClient.preprocess.api.executePreprocessing(async function () { const input = await jiffClient.share_array(entries[id], null, 3, [1, 2, 3], [1, 2]); const array1 = input[1]; const array2 = input[2];