package happy.research.pgp;
import happy.coding.math.Randoms;
import happy.research.pgp.PGPNode.SignerType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MaxIterationsExceededException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.analysis.integration.SimpsonIntegrator;
import org.apache.log4j.Logger;
public abstract class AbstractPGP
{
protected static Logger logger = Logger.getLogger(AbstractPGP.class);
protected static int numNodes = 0;
protected static int COMPLETES_NEEDED = 0;
protected static int MARGINALS_NEEDED = 0;
protected static double CONFIDENCE_THRESHOLD = 0.0;
protected static double SIMILARITY_THRESHOLD = 0.0;
protected static double CANDIDATE_VECTOR_RATIO = 0.0;
protected static double COMPLETE_TRUST_THRESHOLD = 0.0;
protected static double MARGINAL_TRUST_THRESHOLD = 0.0;
protected static int runTimes = 0;
protected static double CHAIN_TRUSTVALUE_THRESHOLD = 0.0;
protected static String TRADITIONAL_PGP = "Traditional PGP";
protected static String MODIFIED_PGP = "Modified PGP";
protected static String OURMETHOD_PGP = "Our Method PGP";
protected static String TRUSTCHAIN_PGP = "Trust Chain PGP";
protected static String TRUSTCHAINWTHRESHOLD_PGP = "Trust Chain with threshold PGP";
protected static String TRADITIONAL_CHAIN_PGP = "Tranditional with chain of trust PGP";
protected static String OURMETHOD_CHAIN_PGP = "Our Method with chain of trust PGP";
private static double MAX_DISTANCE = Math.abs(CertificateType.VALID.getInherentValue()
- CertificateType.INVALID.getInherentValue());
private static double ACCURACY_PERCENT = 0.2;
protected static double ACCURACY_THRESHOLD = MAX_DISTANCE * ACCURACY_PERCENT;
public static List<PGPNode> generateTestData() throws Exception
{
// load configuration files
EnvironmentParams params = EnvironmentParams.createInstance();
params.loadConfigFile("pgp.config.properties");
numNodes = params.numNodes;
MARGINALS_NEEDED = params.marginalsNeeded;
COMPLETES_NEEDED = params.completesNeeded;
CONFIDENCE_THRESHOLD = params.confidence_threshold;
SIMILARITY_THRESHOLD = params.similarity_threshold;
CANDIDATE_VECTOR_RATIO = params.ratCandidateVector;
COMPLETE_TRUST_THRESHOLD = params.complete_trust_threshold;
MARGINAL_TRUST_THRESHOLD = params.marginal_trust_threshold;
runTimes = params.runTimes;
CHAIN_TRUSTVALUE_THRESHOLD = params.chain_trust_value_threshold;
// generate initial nodes
List<PGPNode> nodes = generateNodes(params);
// signing
int[] xpSignerIndexArray = xpSign(nodes, params);
int[] mdSignerIndexArray = mdSign(nodes, params, xpSignerIndexArray);
int[] exceptions = new int[xpSignerIndexArray.length + mdSignerIndexArray.length];
for (int i = 0; i < exceptions.length; i++)
{
if (i < xpSignerIndexArray.length)
exceptions[i] = xpSignerIndexArray[i];
else
exceptions[i] = mdSignerIndexArray[i - xpSignerIndexArray.length];
}
Arrays.sort(exceptions);
@SuppressWarnings("unused")
int[] nbSignerIndexArray = nbSign(nodes, params, exceptions);
// print out test data
for (PGPNode node : nodes)
logger.debug(node);
return nodes;
}
protected abstract Performance firePerformanceTest(final List<PGPNode> nodes);
protected double evaluatePearsonSimilarity(double rx, double ry, int[] rxs, int[] rys, int dimention)
{
double denominator_x = 0.0, denominator_y = 0.0, numerator = 0.0;
double tx = 0.0, ty = 0.0;
for (int i = 0; i < dimention; i++)
{
tx = rxs[i] - rx;
ty = rys[i] - ry;
numerator += tx * ty;
denominator_x += tx * tx;
denominator_y += ty * ty;
}
if (denominator_x == 0 && denominator_y == 0 && rx == ry)
{
return 1.0;
} else if (denominator_x == 0 && denominator_y == 0 && (rx + ry == 0))
{
return 0.0;
}
return numerator / Math.sqrt(denominator_x * denominator_y);
}
protected double evaluateCosineSimilarity(int[] rxs, int[] rys, int dimension)
{
double denominator_x = 0.0, denominator_y = 0.0, numerator = 0.0;
for (int i = 0; i < dimension; i++)
{
numerator += rxs[i] * rys[i];
denominator_x += rxs[i] * rxs[i];
denominator_y += rys[i] * rys[i];
}
return numerator / (Math.sqrt(denominator_x) * Math.sqrt(denominator_y));
}
protected double calculateCertainty(final double r, final double s) throws MaxIterationsExceededException,
FunctionEvaluationException, IllegalArgumentException
{
SimpsonIntegrator integrator = new SimpsonIntegrator();
final double denominator = calculateDenominator(r, s);
UnivariateRealFunction f = new UnivariateRealFunction() {
public double value(double x) throws FunctionEvaluationException
{
double result = Math.pow(x, r) * Math.pow(1 - x, s) / denominator - 1;
return Math.abs(result);
}
};
return integrator.integrate(f, 0.0, 1.0);
}
private double calculateDenominator(final double r, final double s) throws MaxIterationsExceededException,
FunctionEvaluationException, IllegalArgumentException
{
SimpsonIntegrator integrator = new SimpsonIntegrator();
UnivariateRealFunction f = new UnivariateRealFunction() {
public double value(double x) throws FunctionEvaluationException
{
return Math.pow(x, r) * Math.pow(1 - x, s);
}
};
return integrator.integrate(f, 0.0, 1.0);
}
protected Performance calculatePerformance(String methodId, int[] coversCount, double[] coverages,
double[] distances, double[] accuracies)
{
// overall performance
Performance p = new Performance(methodId);
// coverage
double coverage_sum = 0.0;
for (int i = 0; i < coverages.length; i++)
coverage_sum += coverages[i];
p.setCoverage(coverage_sum / coverages.length);
// distance
double distance_sum = 0.0;
int count = 0;
for (int i = 0; i < distances.length; i++)
if (coversCount[i] > 0)
{
count++;
distance_sum += distances[i];
}
p.setDistance(distance_sum / count);
// accuracy
double accuracy_sum = 0.0;
for (double accuracy : accuracies)
accuracy_sum += accuracy;
p.setAccuracy(accuracy_sum / accuracies.length);
return p;
}
private static List<PGPNode> generateNodes(EnvironmentParams params)
throws Exception
{
List<PGPNode> nodes = new ArrayList<>(numNodes * 2);
int numInvNodes = (int) (numNodes * params.ratInvalidCerts + 0.5);
int numHonestIntros = (int) (numNodes * params.ratHonestIntros + 0.5);
int numNeutralIntros = (int) (numNodes * params.ratNeutralIntros + 0.5);
// generate random index of the invalid certificates
int[] invalidIndexArray = Randoms.nextIntArray(numInvNodes, numNodes);
// set introducer type
int[] honestIndexArray = Randoms.nextIntArray(numHonestIntros, numNodes, null);
int[] neutralIndexArray = Randoms.nextIntArray(numNeutralIntros, numNodes, honestIndexArray);
int numLittleMistakeSigner = (int) (numNodes
* params.ratLittleMistakeSigner + 0.5D);
int numNeutralMistakeSigner = (int) (numNodes
* params.ratNeutralMistakeSigner + 0.5D);
int[] littleMistakeIndexArray = Randoms.nextIntArray(
numLittleMistakeSigner, numNodes, null);
int[] neutralMistakeIndexArray = Randoms.nextIntArray(
numNeutralMistakeSigner, numNodes, littleMistakeIndexArray);
// generate all the PGP nodes
for (int i = 0; i < numNodes; i++)
{
PGPNode node;
if (Arrays.binarySearch(invalidIndexArray, i) >= 0)
node = new PGPNode(i, CertificateType.INVALID);
else
node = new PGPNode(i, CertificateType.VALID);
if (Arrays.binarySearch(honestIndexArray, i) >= 0)
node.setHonestType(PGPNode.HonestType.Honest);
else if (Arrays.binarySearch(neutralIndexArray, i) >= 0)
node.setHonestType(PGPNode.HonestType.Neutral);
else {
node.setHonestType(PGPNode.HonestType.Dishonest);
}
if (Arrays.binarySearch(littleMistakeIndexArray, i) >= 0)
node.setMistakeType(PGPNode.MistakeSingerType.Little);
else if (Arrays.binarySearch(neutralMistakeIndexArray, i) >= 0)
node.setMistakeType(PGPNode.MistakeSingerType.Neutral);
else
node.setMistakeType(PGPNode.MistakeSingerType.Many);
nodes.add(node);
}
return nodes;
}
private static int[] xpSign(List<PGPNode> nodes, EnvironmentParams params) throws Exception
{
int numSigners = (int) (numNodes * params.ratExperiencedSigner + 0.5);
int[] signerIndexArray = Randoms.nextIntArray(numSigners, numNodes, null);
for (int i = 0; i < signerIndexArray.length; i++)
{
// signer
int signerIndex = signerIndexArray[i];
PGPNode signer = nodes.get(signerIndex);
signer.setSignerType(SignerType.ExperiencedSigner);
/* part 1: directly signing */
// targets: for different signer, the number of targets varies
int numTargets = (int) (numNodes
* Randoms.uniform(params.ratMinManySigning, params.ratMaxManySigning) + 0.5);
int[] targetsIndexArray = Randoms.nextIntArray(numTargets, numNodes, new int[] { signerIndex });
// specifies which nodes will be signed correctly
int numHonestSigning;
int[] honestIndexArray = null;
switch (signer.getHonestType())
{
case Honest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinHonestSigning, params.ratMaxHonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Neutral:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinNeutralSigning, params.ratMaxNeutralSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Dishonest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinDishonestSigning, params.ratMaxDishonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
default:
break;
}
int numMistakeTargets = 0;
int[] mistakeIndexArray = (int[]) null;
switch (signer.getMistakeType()) {
case Little:
numMistakeTargets = (int) (numTargets
* Randoms
.uniform(
params.ratMinLittleMistakeHappen,
params.ratMaxLittleMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Neutral:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(
params.ratMinNeutralMistakeHappen,
params.ratMaxNeutralMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Many:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(params.ratMinManyMistakeHappen,
params.ratMaxManyMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
}
// sign targets
for (int j = 0; j < numTargets; j++)
{
PGPNode target = nodes.get(targetsIndexArray[j]);
sign(signer, target, honestIndexArray, mistakeIndexArray, j);
}
/* part 2: specify trusted neighbours */
int numSpecifiedTargets = (int) (numTargets
* Randoms.uniform(params.ratMinDirectlySpecified, params.ratMaxDirectlySpecified) + 0.5);
if (numSpecifiedTargets <= 0)
continue;
/**
* rule out: 1) already singed targets 2) the current target itself
*/
int[] expts = new int[targetsIndexArray.length + 1];
for (int k = 0; k < expts.length; k++) {
if (k == expts.length - 1) {
expts[k] = signerIndex;
} else {
if (k >= targetsIndexArray.length)
continue;
expts[k] = targetsIndexArray[k];
}
}
Arrays.sort(expts);
int[] specifiedTargetsIndexArray = Randoms.nextIntArray(
numSpecifiedTargets, numNodes, expts);
for (int k = 0; k < specifiedTargetsIndexArray.length; k++) {
PGPNode target = nodes.get(specifiedTargetsIndexArray[k]);
int t = Randoms.uniform(numNodes);
TrustType trustness = t % 2 == 0 ? TrustType.MARGINALLY_TRUST
: TrustType.COMPLETED_TRUST;
signer.addSpecifiedTarget(target, trustness);
}
}
return signerIndexArray;
}
private static void sign(PGPNode signer, PGPNode target,
int[] honestIndexArray, int[] mistakeIndexArray, int index)
{
CertificateType ct;
TrustType tt = TrustType.UNKNOWN_TRUST;
if (Arrays.binarySearch(honestIndexArray, index) >= 0)
ct = target.getCertificate() == CertificateType.VALID ? CertificateType.VALID : CertificateType.INVALID;
else
ct = target.getCertificate() == CertificateType.VALID ? CertificateType.INVALID : CertificateType.VALID;
if (ct == CertificateType.INVALID) {
signer.signTarget(target, ct, TrustType.UNKNOWN_TRUST);
return;
}
if (Arrays.binarySearch(mistakeIndexArray, index) >= 0) {
switch (target.getHonestType()) {
case Honest:
tt = TrustType.MARGINALLY_TRUST;
break;
case Neutral:
tt = Randoms.uniform(10) % 2 == 0 ? TrustType.COMPLETED_TRUST
: TrustType.UNKNOWN_TRUST;
break;
case Dishonest:
tt = TrustType.MARGINALLY_TRUST;
break;
default:
break;
}
} else {
switch (target.getHonestType()) {
case Honest:
tt = TrustType.COMPLETED_TRUST;
break;
case Neutral:
tt = TrustType.MARGINALLY_TRUST;
break;
case Dishonest:
tt = TrustType.UNKNOWN_TRUST;
break;
}
}
signer.signTarget(target, ct, tt);
}
private static int[] mdSign(List<PGPNode> nodes, EnvironmentParams params, int[] exceptions)
throws Exception
{
int numSigners = (int) (numNodes * params.ratMediumSigner + 0.5);
int[] signerIndexArray = Randoms.nextIntArray(numSigners, numNodes, exceptions);
int[] exceptionArray = new int[numNodes];
for (int i = 0; i < exceptions.length; i++)
exceptionArray[i] = exceptions[i];
for (int i = 0; i < signerIndexArray.length; i++)
{
// signer
int signerIndex = signerIndexArray[i];
PGPNode signer = nodes.get(signerIndex);
signer.setSignerType(SignerType.MediumSigner);
// targets: for different signer, the number of targets varies
int numTargets = (int) (numNodes
* Randoms.uniform(params.ratMinNormalSigning, params.ratMaxNormalSigning) + 0.5);
exceptionArray[exceptions.length] = signerIndex;
int[] targetsIndexArray = Randoms.nextIntArray(numTargets, numNodes, exceptionArray);
// specifies which nodes will be signed correctly
int numHonestSigning;
int[] honestIndexArray = null;
switch (signer.getHonestType())
{
case Honest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinHonestSigning, params.ratMaxHonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Neutral:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinNeutralSigning, params.ratMaxNeutralSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Dishonest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinDishonestSigning, params.ratMaxDishonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
default:
break;
}
int numMistakeTargets = 0;
int[] mistakeIndexArray = null;
switch (signer.getMistakeType()) {
case Little:
numMistakeTargets = (int) (numTargets
* Randoms
.uniform(
params.ratMinLittleMistakeHappen,
params.ratMaxLittleMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Neutral:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(
params.ratMinNeutralMistakeHappen,
params.ratMaxNeutralMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Many:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(params.ratMinManyMistakeHappen,
params.ratMaxManyMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
}
// sign targets
for (int j = 0; j < numTargets; j++) {
PGPNode target = nodes.get(targetsIndexArray[j]);
sign(signer, target, honestIndexArray, mistakeIndexArray, j);
}
/* part 2: specify trusted neighbours */
int numSpecifiedTargets = (int) (numTargets
* Randoms.uniform(params.ratMinDirectlySpecified, params.ratMaxDirectlySpecified) + 0.5);
if (numSpecifiedTargets <= 0)
continue;
/**
* rule out:
*
* 1) already singed targets, including xpSinged and mdSigned 2)
* targets with invalid certificate 3) the current target itself
*/
int[] expts = new int[exceptions.length + targetsIndexArray.length
+ 1];
for (int k = 0; k < expts.length; k++) {
if (k < exceptions.length)
expts[k] = exceptions[k];
else if (k < expts.length - 1)
expts[k] = targetsIndexArray[k - exceptions.length];
else {
if (k != expts.length - 1)
continue;
expts[k] = signerIndex;
}
}
Arrays.sort(expts);
int[] specifiedTargetsIndexArray = Randoms.nextIntArray(
numSpecifiedTargets, numNodes, expts);
for (int k = 0; k < specifiedTargetsIndexArray.length; k++)
{
PGPNode target = nodes.get(specifiedTargetsIndexArray[k]);
int t = Randoms.uniform(numNodes);
TrustType trustness = t % 2 == 0 ? TrustType.MARGINALLY_TRUST
: TrustType.COMPLETED_TRUST;
signer.addSpecifiedTarget(target, trustness);
}
/* end of part 2 */
}
return signerIndexArray;
}
private static int[] nbSign(List<PGPNode> nodes, EnvironmentParams params, int[] exceptions)
throws Exception
{
int numSigners = (int) (numNodes * params.ratNewbieSigner + 0.5);
int[] signerIndexArray = Randoms.nextIntArray(numSigners, numNodes, exceptions);
int[] exceptionsArray = new int[exceptions.length + 1];
for (int i = 0; i < exceptions.length; i++)
exceptionsArray[i] = exceptions[i];
for (int i = 0; i < signerIndexArray.length; i++)
{
// signer
int signerIndex = signerIndexArray[i];
PGPNode signer = nodes.get(signerIndex);
signer.setSignerType(SignerType.NewbieSigner);
// targets: for different signer, the number of targets varies
int numTargets = (int) (numNodes
* Randoms.uniform(params.ratMinLittleSigning, params.ratMaxLittleSigning) + 0.5);
// avoid signing itself
exceptionsArray[exceptions.length] = signerIndex;
int[] targetsIndexArray = Randoms.nextIntArray(numTargets, numNodes, exceptionsArray);
// specifies which nodes will be signed correctly
int numHonestSigning;
int[] honestIndexArray = null;
switch (signer.getHonestType())
{
case Honest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinHonestSigning, params.ratMaxHonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Neutral:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinNeutralSigning, params.ratMaxNeutralSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
case Dishonest:
numHonestSigning = (int) (numTargets
* Randoms.uniform(params.ratMinDishonestSigning, params.ratMaxDishonestSigning) + 0.5);
honestIndexArray = Randoms.nextIntArray(numHonestSigning, numTargets, null);
break;
default:
break;
}
int numMistakeTargets = 0;
int[] mistakeIndexArray = (int[]) null;
switch (signer.getMistakeType()) {
case Little:
numMistakeTargets = (int) (numTargets
* Randoms
.uniform(
params.ratMinLittleMistakeHappen,
params.ratMaxLittleMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Neutral:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(
params.ratMinNeutralMistakeHappen,
params.ratMaxNeutralMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
case Many:
numMistakeTargets = (int) (numTargets
* Randoms.uniform(params.ratMinManyMistakeHappen,
params.ratMaxManyMistakeHappen) + 0.5);
mistakeIndexArray = Randoms.nextIntArray(
numMistakeTargets, numTargets, null);
break;
}
// sign targets
for (int j = 0; j < numTargets; j++)
{
PGPNode target = nodes.get(targetsIndexArray[j]);
sign(signer, target, honestIndexArray, mistakeIndexArray, j);
}
/* part 2: specify trusted neighbours */
int numSpecifiedTargets = (int) (numTargets
* Randoms.uniform(params.ratMinDirectlySpecified, params.ratMaxDirectlySpecified) + 0.5);
if (numSpecifiedTargets > 0)
{
int[] expts = new int[exceptions.length + targetsIndexArray.length + 1];
for (int k = 0; k < expts.length; k++)
{
if (k < exceptions.length)
expts[k] = exceptions[k];
else if (k < expts.length - 1)
expts[k] = targetsIndexArray[k - exceptions.length];
else {
if (k != expts.length - 1)
continue;
expts[k] = signerIndex;
}
}
Arrays.sort(expts);
int[] specifiedTargetsIndexArray = Randoms
.nextIntArray(numSpecifiedTargets, numNodes, expts);
for (int k = 0; k < specifiedTargetsIndexArray.length; k++)
{
PGPNode target = nodes.get(specifiedTargetsIndexArray[k]);
int t = Randoms.uniform(numNodes);
TrustType trustness = t % 2 == 0 ? TrustType.MARGINALLY_TRUST : TrustType.COMPLETED_TRUST;
signer.addSpecifiedTarget(target, trustness);
}
}
/* end of part 2 */
}
return signerIndexArray;
}
}