/* * 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); } }