private PairSequenceWithProofs(ECCurve curve, ASN1Sequence sequence) { ASN1Sequence s = ASN1Sequence.getInstance(sequence.getObjectAt(0)); ecPairs = new ECPair[s.size()]; for (int i = 0; i != ecPairs.length; i++) { ecPairs[i] = Pair.getInstance(curve, s.getObjectAt(i)).getECPair(); } s = ASN1Sequence.getInstance(sequence.getObjectAt(1)); ecProofs = new ECDecryptionProof[s.size()]; for (int i = 0; i != ecPairs.length; i++) { ASN1Sequence proof = ASN1Sequence.getInstance(s.getObjectAt(i)); ecProofs[i] = new ECDecryptionProof(curve.decodePoint(ASN1OctetString.getInstance(proof.getObjectAt(0)).getOctets()), curve.decodePoint(ASN1OctetString.getInstance(proof.getObjectAt(1)).getOctets()), ASN1Integer.getInstance(proof.getObjectAt(2)).getValue()); } }
public static Pair getInstance(ECCurve curve, Object o) { if (o instanceof Pair) { return (Pair)o; } if (o != null) { ASN1Sequence s = ASN1Sequence.getInstance(o); byte[] encX = ASN1OctetString.getInstance(s.getObjectAt(0)).getOctets(); byte[] encY = ASN1OctetString.getInstance(s.getObjectAt(1)).getOctets(); return new Pair(new ECPair(curve.decodePoint(encX), curve.decodePoint(encY))); } return null; }
private BigInteger computeChallenge(ECPoint a, ECPoint b, ECPoint c, ECPair partial, ECPoint g) { SHA256Digest sha256 = new SHA256Digest(); addIn(sha256, a); addIn(sha256, b); addIn(sha256, c); addIn(sha256, partial.getX()); addIn(sha256, g); addIn(sha256, q); byte[] res = new byte[sha256.getDigestSize()]; sha256.doFinal(res, 0); return new BigInteger(1, res); }
public byte[] transform(byte[] message) { ECPair[] pairs = PairSequence.getInstance(parameters.getParameters().getCurve(), message).getECPairs(); for (int i = 0; i != pairs.length; i++) { pairs[i] = transform.transform(pairs[i]); } try { return new PairSequence(pairs).getEncoded(); } catch (IOException e) { // TODO: log an error, or maybe throw an exception return message; } }
private ECPoint[] reassemblePoints(ECDomainParameters domainParams, List<byte[]>[] partialDecrypts, BigInteger[] weights, int baseIndex, BigInteger baseWeight, int messageIndex) throws ServiceConnectionException { List<byte[]> baseMessageBlock = partialDecrypts[baseIndex]; PairSequenceWithProofs ps = PairSequenceWithProofs.getInstance(domainParams.getCurve(), baseMessageBlock.get(messageIndex)); ECPoint[] weightedDecryptions = new ECPoint[ps.size()]; ECPoint[] fulls = new ECPoint[ps.size()]; ECPair[] partials = ps.getECPairs(); for (int i = 0; i != weightedDecryptions.length; i++) { weightedDecryptions[i] = partials[i].getX().multiply(baseWeight); } for (int wIndex = baseIndex + 1; wIndex < weights.length; wIndex++) { if (weights[wIndex] != null) { PairSequenceWithProofs pairSequenceWithProofs = PairSequenceWithProofs.getInstance(domainParams.getCurve(), partialDecrypts[wIndex].get(messageIndex)); ECPair[] nPartials = pairSequenceWithProofs.getECPairs(); for (int i = 0; i != weightedDecryptions.length; i++) { weightedDecryptions[i] = weightedDecryptions[i].add(nPartials[i].getX().multiply(weights[wIndex])); } } } for (int i = 0; i != weightedDecryptions.length; i++) { fulls[i] = partials[i].getY().add(weightedDecryptions[i].negate()); } return fulls; }
private ECPoint[] reassemblePoints(ECPoint[][] partialDecrypts, ECPair[] encMessage, BigInteger[] weights, int baseIndex, BigInteger baseWeight) { ECPoint[] weightedDecryptions = new ECPoint[partialDecrypts[0].length]; ECPoint[] fulls = new ECPoint[partialDecrypts[0].length]; ECPair[] partials = new ECPair[partialDecrypts[baseIndex].length]; for (int i = 0; i != partials.length; i++) { partials[i] = new ECPair(partialDecrypts[baseIndex][i], encMessage[i].getY()); } for (int i = 0; i != weightedDecryptions.length; i++) { weightedDecryptions[i] = partials[i].getX().multiply(baseWeight); } for (int wIndex = baseIndex + 1; wIndex < weights.length; wIndex++) { if (weights[wIndex] != null) { for (int i = 0; i != weightedDecryptions.length; i++) { weightedDecryptions[i] = weightedDecryptions[i].add(partialDecrypts[wIndex][i].multiply(weights[wIndex])); } } } for (int i = 0; i != weightedDecryptions.length; i++) { fulls[i] = partials[i].getY().add(weightedDecryptions[i].negate()); } return fulls; }
private PairSequence(ECCurve curve, ASN1Sequence s) { ecPairs = new ECPair[s.size()]; for (int i = 0; i != ecPairs.length; i++) { ecPairs[i] = Pair.getInstance(curve, s.getObjectAt(i)).getECPair(); } }
/** * <pre> * PairSequence ::= SEQUENCE OF Pair * </pre> * * @return an encoding of an ASN.1 sequence */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); for (ECPair pair : ecPairs) { v.add(new Pair(pair)); } return new DERSequence(v); }
/** * <pre> * PairSequence ::= SEQUENCE OF Pair * </pre> * * @return an encoding of an ASN.1 sequence */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector tot = new ASN1EncodableVector(); ASN1EncodableVector v = new ASN1EncodableVector(); for (ECPair pair : ecPairs) { v.add(new Pair(pair)); } tot.add(new DERSequence(v)); v = new ASN1EncodableVector(); for (ECDecryptionProof proof : ecProofs) { ASN1EncodableVector proofV = new ASN1EncodableVector(); proofV.add(new DEROctetString(proof.getA().getEncoded(true))); proofV.add(new DEROctetString(proof.getB().getEncoded(true))); proofV.add(new ASN1Integer(proof.getR())); v.add(new DERSequence(proofV)); } tot.add(new DERSequence(v)); return new DERSequence(tot); }
ECDecryptionProof computeProof(ECPoint c, ECPair partial) { BigInteger s = generateS(); ECPoint a = domainParameters.getG().multiply(s).normalize(); ECPoint b = c.multiply(s).normalize(); BigInteger challenge = computeChallenge(a, b, c, partial, domainParameters.getG()); BigInteger f = s.add(operator.transform(challenge)).mod(domainParameters.getN()); return new ECDecryptionProof(a, b, f); }
private void doTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) { ECPoint data = priKey.getParameters().getG().multiply(value); ECEncryptor encryptor = new ECElGamalEncryptor(); encryptor.init(pRandom); ECPair pair = encryptor.encrypt(data); ECDecryptor decryptor = new ECElGamalDecryptor(); decryptor.init(priKey); ECPoint result = decryptor.decrypt(pair); if (!data.equals(result)) { fail("point pair failed to decrypt back to original"); } }
private static void generateBallots(File ballotDir, File candidateDir, String baseName, Random rand, int ballotSize, ECElGamalEncryptor encryptor, ECDomainParameters ecParams, SecureRandom pointRandom) throws IOException { File ballotFile = new File(ballotDir, baseName + ".blt"); File candidateFile = new File(candidateDir, baseName + "." + "candidates.cid"); int numberOfCandidates = 4 + rand.nextInt(10); List<ECPoint> candidateNumbers = new ArrayList<>(numberOfCandidates); for (int candidateNo = 0; candidateNo != numberOfCandidates; candidateNo++) { candidateNumbers.add(generatePoint(ecParams, pointRandom)); } int numberOfBallots = ballotSize + rand.nextInt(ballotSize / 10); ECPair[][] ballots = new ECPair[numberOfBallots][]; for (int ballotNo = 0; ballotNo != numberOfBallots; ballotNo++) { Collections.shuffle(candidateNumbers, rand); ECPair[] ballot = new ECPair[numberOfCandidates]; for (int i = 0; i != ballot.length; i++) { ballot[i] = encryptor.encrypt(candidateNumbers.get(i)); } ballots[ballotNo] = ballot; } OutputStream fOut = new BufferedOutputStream(new FileOutputStream(ballotFile)); for (int j = 0; j != ballots.length; j++) { fOut.write(new PairSequence(ballots[j]).getEncoded()); } fOut.close(); createCandidateList(baseName, candidateFile, "ATL", candidateNumbers); }
private List<byte[]> verifyPoints(ECPair[] cipherText, ECDomainParameters domainParams, String[] nodeNames, AsymmetricKeyParameter[] pubKeys, List<byte[]>[] partialDecrypts, BigInteger[] weights, int messageIndex) throws ServiceConnectionException { List<byte[]> proofList = new ArrayList<>(); for (int wIndex = 0; wIndex < weights.length; wIndex++) { if (weights[wIndex] != null) { ECPublicKeyParameters nodeKey = (ECPublicKeyParameters)pubKeys[wIndex]; PairSequenceWithProofs pairSequenceWithProofs = PairSequenceWithProofs.getInstance(domainParams.getCurve(), partialDecrypts[wIndex].get(messageIndex)); ECDecryptionProof[] proofs = pairSequenceWithProofs.getECProofs(); ECPair[] partials = pairSequenceWithProofs.getECPairs(); if (proofs.length != partials.length) { eventNotifier.notify(EventNotifier.Level.ERROR, "Partial decrypts and proofs differ in length from node " + nodeNames[wIndex]); throw new ServiceConnectionException("Partial decrypts and proofs differ in length"); } ECPoint[] decrypts = new ECPoint[partials.length]; for (int i = 0; i != partials.length; i++) { decrypts[i] = partials[i].getX(); } boolean hasPassed = true; for (int i = 0; i != partials.length; i++) { if (!proofs[i].isVerified(nodeKey, cipherText[i].getX(), partials[i].getX())) { hasPassed = false; } } try { proofList.add(new ChallengeLogMessage(messageIndex, wIndex, hasPassed, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(nodeKey), decrypts, proofs).getEncoded()); if (hasPassed) { eventNotifier.notify(EventNotifier.Level.INFO, "Proof for message " + messageIndex + " for node " + nodeNames[wIndex] + " passed."); } else { eventNotifier.notify(EventNotifier.Level.ERROR, "Proof for message " + messageIndex + " for node " + nodeNames[wIndex] + " failed!"); } } catch (Exception e) { eventNotifier.notify(EventNotifier.Level.ERROR, "Partial decrypts failed to encode from " + nodeNames[wIndex] + ": " + e.getMessage(), e); throw new ServiceConnectionException("Partial decrypts failed to encode from " + nodeNames[wIndex] + ": " + e.getMessage(), e); } } } return proofList; }
Pair(ECPair ecPair) { this.ecPair = ecPair; }
public ECPair getECPair() { return ecPair; }
public MessageReply handle(Message message) { switch (((CommandMessage)message).getType()) { case PARTIAL_DECRYPT: DecryptDataMessage decMessage = DecryptDataMessage.getInstance(message.getPayload()); List<byte[]> messages = decMessage.getMessages(); PostedMessageDataBlock.Builder partialDecryptsBuilder = new PostedMessageDataBlock.Builder(messages.size()); PrivateKeyOperator operator = nodeContext.getPrivateKeyOperator(decMessage.getKeyID()); if (!(operator instanceof ECPrivateKeyOperator)) { return new MessageReply(MessageReply.Type.ERROR, new DERUTF8String("Inappropriate key type")); } ECPrivateKeyOperator ecOperator = (ECPrivateKeyOperator)operator; ECDomainParameters domainParameters = ecOperator.getDomainParameters(); ProofGenerator pGen = new ProofGenerator(ecOperator, new SecureRandom()); // TODO: randomness for (int i = 0; i != messages.size(); i++) { PairSequence ps = PairSequence.getInstance(domainParameters.getCurve(), messages.get(i)); ECPair[] pairs = ps.getECPairs(); ECDecryptionProof[] proofs = new ECDecryptionProof[pairs.length]; for (int j = 0; j != pairs.length; j++) { ECPoint c = pairs[j].getX(); pairs[j] = new ECPair(ecOperator.transform(pairs[j].getX()), pairs[j].getY()); proofs[j] = pGen.computeProof(c, pairs[j]); } try { partialDecryptsBuilder.add(new PairSequenceWithProofs(pairs, proofs).getEncoded()); } catch (IOException e) { nodeContext.getEventNotifier().notify(EventNotifier.Level.ERROR, "Error encoding decrypt: " + e.getMessage(), e); return new MessageReply(MessageReply.Type.ERROR, new DERUTF8String("Error encoding decrypt: " + e.getMessage())); } } return new MessageReply(MessageReply.Type.OKAY, new ShareMessage(operator.getSequenceNo(), partialDecryptsBuilder.build())); default: nodeContext.getEventNotifier().notify(EventNotifier.Level.ERROR, "Unknown command: " + message.getType()); return new MessageReply(MessageReply.Type.ERROR, new DERUTF8String("Unknown command: " + message.getType())); } }
private void doTest(ECDomainParameters domainParams, AsymmetricCipherKeyPair[] kps, int threshold, boolean shouldPass, int... missing) { int numberOfPeers = kps.length; // create the splitter for the peers/threshold over the order of the curve. ShamirSecretSplitter secretSplitter = new ShamirSecretSplitter(numberOfPeers, threshold, domainParams.getN(), new SecureRandom()); // Having created a private key the server creates shares of that // private key. It would keep one share for itself and sends the others // shares to the other servers. BigInteger[][] privateKeyShares = new BigInteger[numberOfPeers][]; BigInteger[] finalPrivateKeyShares = new BigInteger[numberOfPeers]; for (int i = 0; i < numberOfPeers; i++) { privateKeyShares[i] = secretSplitter.split(((ECPrivateKeyParameters)kps[i].getPrivate()).getD()).getShares(); } // Simulates distributing shares and combining them for (int i = 0; i < numberOfPeers; i++) { finalPrivateKeyShares[i] = privateKeyShares[0][i]; for (int j = 1; j < numberOfPeers; j++) { finalPrivateKeyShares[i] = finalPrivateKeyShares[i].add(privateKeyShares[j][i]); } } ECPoint pubPoint = ((ECPublicKeyParameters)kps[0].getPublic()).getQ(); for (int i = 1; i < numberOfPeers; i++) { pubPoint = pubPoint.add(((ECPublicKeyParameters)kps[i].getPublic()).getQ()); } ECPublicKeyParameters jointPub = new ECPublicKeyParameters(pubPoint, domainParams); // Create a random plaintext ECPoint plaintext = generatePoint(domainParams, new SecureRandom()); // Encrypt it using the joint public key ECEncryptor enc = new ECElGamalEncryptor(); enc.init(new ParametersWithRandom(jointPub, new SecureRandom())); ECPair cipherText = enc.encrypt(plaintext); // do partial decrypts ECPoint[] partialDecs = new ECPoint[numberOfPeers]; for (int i = 0; i < numberOfPeers; i++) { partialDecs[i] = cipherText.getX().multiply(finalPrivateKeyShares[i]); } // simulate missing peers for (int i = 0; i != missing.length; i++) { partialDecs[missing[i]] = null; } // decryption step LagrangeWeightCalculator lagrangeWeightCalculator = new LagrangeWeightCalculator(numberOfPeers, domainParams.getN()); BigInteger[] weights = lagrangeWeightCalculator.computeWeights(partialDecs); // weighting ECPoint weightedDecryption = partialDecs[0].multiply(weights[0]); for (int i = 1; i < weights.length; i++) { if (partialDecs[i] != null) { weightedDecryption = weightedDecryption.add(partialDecs[i].multiply(weights[i])); } } // Do final decryption to recover plaintext ECPoint ECPoint decrypted = cipherText.getY().add(weightedDecryption.negate()); Assert.assertEquals(shouldPass, plaintext.equals(decrypted)); }
private void doSameKeyTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) { ECPoint data = priKey.getParameters().getG().multiply(value); ECEncryptor encryptor = new ECElGamalEncryptor(); encryptor.init(pRandom); ECPair pair = encryptor.encrypt(data); ECPairTransform ecr = new ECNewRandomnessTransform(); ecr.init(pRandom); ECPair srcPair = pair; // re-encrypt the message portion pair = ecr.transform(srcPair); ECDecryptor decryptor = new ECElGamalDecryptor(); decryptor.init(priKey); // decrypt the fully transformed point. ECPoint result = decryptor.decrypt(pair); if (!data.equals(result)) { fail("point pair failed to decrypt back to original"); } }
private void doTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) { ECPoint data = priKey.getParameters().getG().multiply(value); ECEncryptor encryptor = new ECElGamalEncryptor(); encryptor.init(pRandom); ECPair pair = encryptor.encrypt(data); ECKeyPairGenerator ecGen = new ECKeyPairGenerator(); ecGen.init(new ECKeyGenerationParameters(priKey.getParameters(), new SecureRandom())); AsymmetricCipherKeyPair reEncKP = ecGen.generateKeyPair(); ECPairTransform ecr = new ECNewPublicKeyTransform(); ecr.init(reEncKP.getPublic()); ECPair srcPair = pair; // re-encrypt the message portion pair = ecr.transform(srcPair); ECDecryptor decryptor = new ECElGamalDecryptor(); decryptor.init(priKey); // decrypt out the original private key ECPoint p = decryptor.decrypt(new ECPair(srcPair.getX(), pair.getY())); decryptor.init(reEncKP.getPrivate()); // decrypt the fully transformed point. ECPoint result = decryptor.decrypt(new ECPair(pair.getX(), p)); if (!data.equals(result)) { fail("point pair failed to decrypt back to original"); } }
/** * Create a sequence from a single pair. * * @param ecPair the pair to include */ public PairSequence(ECPair ecPair) { this.ecPairs = new ECPair[] { ecPair }; }
/** * Create a sequence from a collection of pairs. * * @param ecPairs the pairs to include. */ public PairSequence(ECPair... ecPairs) { this.ecPairs = ecPairs.clone(); }
/** * Return the EC pairs held in this sequence. * * @return an array of EC pairs. */ public ECPair[] getECPairs() { return ecPairs.clone(); }
/** * Create a sequence from a collection of pairs representing partial decrypts. * * @param ecPairs the pairs to include. * @param ecProofs proofs of decryption associated with each pair */ public PairSequenceWithProofs(ECPair[] ecPairs, ECDecryptionProof[] ecProofs) { this.ecPairs = ecPairs.clone(); this.ecProofs = ecProofs.clone(); }
/** * Return the EC partial decrypts held in this object. * * @return an array of EC pairs. */ public ECPair[] getECPairs() { return ecPairs; }