/* * 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 ZpGroupElement = require('./zp-group-element'); var validator = require('./input-validator'); var codec = require('scytl-codec'); var forge = require('node-forge'); module.exports = ZpSubgroup; var BigInteger = forge.jsbn.BigInteger; /** * Encapsulates a Zp subgroup. To instantiate this object, use the method {@link * MathematicalService.newZpSubgroup}. *
* Given a prime p
, the Zp group is defined as the set of all
* Integers (mod p)
. A Zp subgroup is a subset of the Zp group,
* of order q
, defined as a set of Primes (mod p)
.
*
* Both the Zp group and the Zp subgroup are finite cyclic groups, which means
* that all of their elements can be generated by exponentiating a special Zp
* group element called the generator
.
*
* When the modulus p
and the order q
are related
* by the restriction, p = 2q + 1
, then the Zp subgroup can also
* be referred to as a quadratic residue group.
*
* @class ZpSubgroup
* @property {forge.jsbn.BigInteger} p The modulus of the Zp subgroup.
* @property {forge.jsbn.BigInteger} q The order of the Zp subgroup.
* @property {ZpGroupElement} generator The generator element of the Zp
* subgroup.
* @property {ZpGroupElement} identity The identity element of the Zp subgroup.
*/
function ZpSubgroup(p, q, g) {
this.p = p;
this.q = q;
this.generator = new ZpGroupElement(p, q, g);
this.identity = new ZpGroupElement(p, q, BigInteger.ONE);
Object.freeze(this);
}
ZpSubgroup.prototype = {
/**
* Checks whether a Zp group element provided as input is a member of this
* Zp subgroup.
*
* An element is a member of the Zp subgroup if its value satisfies the
* following conditions:
*
0 < value < p
valueq mod p = 1
true
if the element provided as input
* is a member of the subgroup, false otherwise.
* @throws {Error}
* If the input data validation fails.
*/
isGroupMember: function(element) {
checkZpGroupElement(
element, 'Zp group element to check for group membership');
if (element.p.equals(this.p)) {
return element.value.modPow(this.q, this.p).equals(BigInteger.ONE);
} else {
return false;
}
},
/**
* Checks if this Zp subgroup is equal to the Zp subgroup provided as input.
*
* @function equals
* @memberof ZpSubgroup
* @param {ZpSubgroup}
* group The Zp subgroup to compare with this Zp subgroup.
* @returns {boolean} True if the equality holds, false otherwise.
* @throws {Error}
* If the input data validation fails.
*/
equals: function(group) {
validator.checkIsInstanceOf(
group, ZpSubgroup, 'ZpSubgroup',
'Zp subgroup to compare with this Zp subgroup');
if (group.p.equals(this.p) && group.q.equals(this.q) &&
group.generator.equals(this.generator)) {
return true;
} else {
return false;
}
},
/**
* Check whether this Zp subgroup is a quadratic residue group, which is
* defined such that p = 2q + 1
.
*
* @function isQuadraticResidueGroup
* @memberof ZpSubgroup
* @returns {boolean} true
if the given group is a quadratic
* residue group, false
otherwise.
*/
isQuadraticResidueGroup: function() {
return this.p.equals(
new BigInteger('2').multiply(this.q).add(BigInteger.ONE));
},
/**
* Serializes this object into a JSON string representation.
*
* IMPORTANT: This serialization must be exactly the same as the
* corresponding serialization in the library cryptoLib
,
* implemented in Java, since the two libraries are expected to communicate
* with each other via these serializations.
*
* @function toJson
* @memberof ZpSubgroup
* @returns {string} The JSON string representation of this object.
*/
toJson: function() {
return JSON.stringify({
zpSubgroup: {
p: codec.base64Encode(this.p),
q: codec.base64Encode(this.q),
g: codec.base64Encode(this.generator.value)
}
});
}
};
function checkZpGroupElement(element, label) {
validator.checkZpGroupElement(element, label);
validator.checkIsInstanceOf(element, ZpGroupElement, 'ZpGroupElement', label);
}