/*
* Copyright 2018 Scytl Secure Electronic Voting SA
*
* All rights reserved
*
* See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
*/
/* jshint node:true */
'use strict';
var ZeroKnowledgeProof = require('./proof');
var ZeroKnowledgeProofPreComputation = require('./pre-computation');
var SchnorrProofHandler = require('./handlers/schnorr-proof-handler');
var ExponentiationProofHandler =
require('./handlers/exponentiation-proof-handler');
var PlaintextProofHandler = require('./handlers/plaintext-proof-handler');
var SimplePlaintextEqualityProofHandler =
require('./handlers/simple-plaintext-equality-proof-handler');
var PlaintextEqualityProofHandler =
require('./handlers/plaintext-equality-proof-handler');
var PlaintextExponentEqualityProofHandler =
require('./handlers/plaintext-exponent-equality-proof-handler');
var OrProofHandler = require('./handlers/or-proof-handler');
var cryptoPolicy = require('scytl-cryptopolicy');
var messageDigest = require('scytl-messagedigest');
var mathematical = require('scytl-mathematical');
var validator = require('./input-validator');
var codec = require('scytl-codec');
require('./array');
module.exports = ZeroKnowledgeProofService;
/**
* @class ZeroKnowledgeProofService
* @classdesc The zero-knowledge proof service API. To instantiate this object,
* use the method {@link newService}.
* @hideconstructor
* @param {Object}
* [options] An object containing optional arguments.
* @param {Policy}
* [options.policy=Default policy] The cryptographic policy to use.
* @param {MessageDigestService}
* [options.messageDigestService=Created internally] The message
* digest service to use.
* @param {SecureRandomService}
* [options.secureRandomService=Created internally] The secure random
* service to use.
* @param {MathematicalService}
* [options.mathematicalService=Created internally] The mathematical
* service to use.
*/
function ZeroKnowledgeProofService(options) {
options = options || {};
var policy;
if (options.policy) {
policy = options.policy;
} else {
policy = cryptoPolicy.newInstance();
}
var messageDigestService_;
if (options.messageDigestService) {
messageDigestService_ = options.messageDigestService;
} else {
messageDigestService_ = messageDigest.newService({policy: policy});
}
var secureRandomService;
if (options.secureRandomService) {
secureRandomService = options.secureRandomService;
}
var mathService_;
if (options.mathematicalService) {
mathService_ = options.mathematicalService;
} else if (secureRandomService) {
mathService_ =
mathematical.newService({secureRandomService: secureRandomService});
} else {
mathService_ = mathematical.newService();
}
/**
* Creates a new ZeroKnowledgeProof object from a provided zero-knowledge
* proof of knowledge or its components.
*
* @function newProof
* @memberof ZeroKnowledgeProofService
* @param {Exponent}
* hashOrJson The hash of the zero-knowledge proof of knowledge
* OR a JSON string representation of a
* ZeroKnowledgeProof object, compatible with its
* toJson
method. For the latter case, any
* additional input arguments will be ignored.
* @param {Exponent[]}
* values The values of the zero-knowledge proof of knowledge.
* @returns {ZeroKnowledgeProof} The new ZeroKnowledgeProof object.
* @throws {Error}
* If the input data validation fails.
*/
this.newProof = function(hashOrJson, exponents) {
if (typeof hashOrJson !== 'string') {
validator.checkExponent(
hashOrJson, 'Hash to create new ZeroKnowledgeProof object');
validator.checkExponents(
exponents, 'Exponents to create new ZeroKnowledgeProof object');
return new ZeroKnowledgeProof(hashOrJson, exponents);
} else {
return jsonToProof(hashOrJson);
}
};
/**
* Creates a new ZeroKnowledgeProofPreComputation object from a provided
* zero-knowledge proof of knowledge pre-computation or its components.
*
* @function newPreComputation
* @memberof ZeroKnowledgeProofService
* @param {Exponent[]}
* exponentsOrJson The array of randomly generated exponents that
* comprise the pre-computation OR a JSON string
* representation of a ZeroKnowledgeProofPreComputation object,
* compatible with its toJson
method. For the
* latter case, any additional input arguments will be ignored.
* @param {ZpGroupElements[]}
* phiOutputs The array of PHI function output elements that
* comprise the pre-computation.
* @returns {ZeroKnowledgeProofPreComputation} The new
* ZeroKnowledgeProofPreComputation object.
* @throws {Error}
* If the input data validation fails.
*/
this.newPreComputation = function(exponentsOrJson, phiOutputs) {
if (typeof exponentsOrJson !== 'string') {
validator.checkExponents(
exponentsOrJson,
'Exponents to create new ZeroKnowledgeProofPreComputation object');
validator.checkZpGroupElements(
phiOutputs,
'PHI function output elements to create new ZeroKnowledgeProofPreComputation object');
return new ZeroKnowledgeProofPreComputation(exponentsOrJson, phiOutputs);
} else {
return jsonToPreComputation(exponentsOrJson);
}
};
/**
* Creates new SchnorrProofHandler object, for generating, pre-computing and
* verifying Schnorr zero-knowledge proofs of knowledge.
*
* @function newSchnorrProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {SchnorrProofHandler} The SchnorrProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newSchnorrProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for Schnorr proof handler');
return new SchnorrProofHandler(group, messageDigestService_, mathService_);
};
/**
* Creates new ExponentiationProofHandler object, for generating,
* pre-computing and verifying exponentation zero-knowledge proofs of
* knowledge. It must be initialized with base elements before it is used.
*
* @function newExponentiationProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {ExponentiationProofHandler} The ExponentiationProofHandler
* object.
* @throws {Error}
* If the input data validation fails.
*/
this.newExponentiationProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for exponentiation proof handler');
return new ExponentiationProofHandler(
group, messageDigestService_, mathService_);
};
/**
* Creates new PlaintextProofHandler object, for generating, pre-computing
* and verifying plaintext zero-knowledge proofs of knowledge. It must be
* initialized with an ElGamal public key before it is used.
*
* @function newPlaintextProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {PlaintextProofHandler} The PlaintextProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newPlaintextProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for plaintext proof handler');
return new PlaintextProofHandler(
group, messageDigestService_, mathService_);
};
/**
* Creates new SimplePlaintextEqualityProofHandler object, for generating,
* pre-computing and verifying simple plaintext equality zero-knowledge
* proofs of knowledge. It must be initialized with primary and secondary
* ElGamal public keys before it is used.
*
* @function newSimplePlaintextEqualityProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {SimplePlaintextEqualityProofHandler} The
* SimplePlaintextEqualityProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newSimplePlaintextEqualityProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for simple plaintext equality proof handler');
return new SimplePlaintextEqualityProofHandler(
group, messageDigestService_, mathService_);
};
/**
* Creates new PlaintextEqualityProofHandler object, for generating,
* pre-computing and verifying plaintext equality zero-knowledge proofs of
* knowledge. It must be initialized with primary and secondary ElGamal
* public keys before it is used.
*
* @function newPlaintextEqualityProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {PlaintextEqualityProofHandler} The
* PlaintextEqualityProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newPlaintextEqualityProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for plaintext equality proof handler');
return new PlaintextEqualityProofHandler(
group, messageDigestService_, mathService_);
};
/**
* Creates new PlaintextExponentEqualityProofHandler object, for generating,
* pre-computing and verifying plaintext exponent equality zero-knowledge
* proofs of knowledge. It must be initialized with base elements before it
* is used.
*
* @function newPlaintextExponentEqualityProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {PlaintextExponentEqualityProofHandler} The
* PlaintextExponentEqualityProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newPlaintextExponentEqualityProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for plaintext exponent equality proof handler');
return new PlaintextExponentEqualityProofHandler(
group, messageDigestService_, mathService_);
};
/**
* Creates new OrProofHandler object, for generating, pre-computing and
* verifying OR zero-knowledge proofs of knowledge. It must be initialized
* with an ElGamal public key before it is used.
*
* @function newOrProofHandler
* @memberof ZeroKnowledgeProofService
* @param {ZpSubgroup}
* group The Zp subgroup to which all exponents and Zp group
* elements required for the proof generation are associated or
* belong, respectively.
* @returns {OrProofHandler} The OrProofHandler object.
* @throws {Error}
* If the input data validation fails.
*/
this.newOrProofHandler = function(group) {
validator.checkIsObjectWithProperties(
group, 'Zp subgroup for OR proof handler');
return new OrProofHandler(group, messageDigestService_, mathService_);
};
function jsonToProof(json) {
validator.checkIsJsonString(
json, 'JSON to deserialize to ZeroKnowledgeProof object');
var parsed = JSON.parse(json).zkProof;
var q = codec.bytesToBigInteger(codec.base64Decode(parsed.q));
var hash = mathService_.newExponent(
q, codec.bytesToBigInteger(codec.base64Decode(parsed.hash)));
var values = [];
var valuesB64 = parsed.values;
for (var i = 0; i < valuesB64.length; i++) {
values.push(mathService_.newExponent(
q, codec.bytesToBigInteger(codec.base64Decode(valuesB64[i]))));
}
return new ZeroKnowledgeProof(hash, values);
}
function jsonToPreComputation(json) {
validator.checkIsJsonString(
json, 'JSON to deserialize to ZeroKnowledgeProofPreComputation object');
var parsed = JSON.parse(json).preComputed;
var p = codec.bytesToBigInteger(codec.base64Decode(parsed.p));
var q = codec.bytesToBigInteger(codec.base64Decode(parsed.q));
var exponentValues = parsed.exponents;
var exponents = [];
for (var i = 0; i < exponentValues.length; i++) {
exponents.push(mathService_.newExponent(
q, codec.bytesToBigInteger(codec.base64Decode(exponentValues[i]))));
}
var phiOutputValues = parsed.phiOutputs;
var phiOutputs = [];
for (var j = 0; j < phiOutputValues.length; j++) {
phiOutputs.push(mathService_.newZpGroupElement(
p, q,
codec.bytesToBigInteger(codec.base64Decode(phiOutputValues[j]))));
}
return new ZeroKnowledgeProofPreComputation(exponents, phiOutputs);
}
}