// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/ZKProofInit.java
// public class ZKProofInit {
// 
//     @Stringable
//     private BigInteger gRoot;
//     @Stringable
//     private BigInteger hRoot;
//     /**
//      * Generates a zero-knowledge proof which proves that bcParameters.g and bcParameters.h are quadratic residues,
//      * which is implies that they are part of the same cyclic sub group.
//      * @param bcParameters
//      * @param id An id which identifies the proof instance. The result should depend on the proof it is used for to
//      *           prevent replay attacks.
//      * @return
//      */
//     public static ZKProofInit generate(BCParameters bcParameters, String id){
//         ZKProofInit result = new ZKProofInit();
//         result.gRoot = squareRoot(bcParameters.getH(), bcParameters.getP(), bcParameters.getQ());
//         result.hRoot = squareRoot(bcParameters.getG(), bcParameters.getP(), bcParameters.getQ());
//         return result;
//     }
// 
//     /**
//      * Verifies this zk proof for the given bcParameters.
//      * @param bcParameters
//      * @param id
//      */
//     public void verify(BCParameters bcParameters, String id){
//         BigInteger gRootSquared = gRoot.pow(2).mod(bcParameters.getN());
//         BigInteger hRootSquared = hRoot.pow(2).mod(bcParameters.getN());
// 
//         if(! bcParameters.getH().equals(gRootSquared) || ! bcParameters.getG().equals(hRootSquared)){
//             throw new ProtocolException("Verification of ZKProof init with id  " + id + " failed.");
//         }
//     }
// 
//     private static BigInteger squareRoot(BigInteger x, BigInteger p, BigInteger q){
//         BigInteger four = new BigInteger("4");
//         BigInteger rp = x.modPow(p.add(BigInteger.ONE).divide(four), p);
//         BigInteger rq = x.modPow(q.add(BigInteger.ONE).divide(four), q);
// 
//         BigIntEuclidean euclidp = BigIntEuclidean.calculate(p, q);
//         BigIntEuclidean euclidq = BigIntEuclidean.calculate(q, p);
// 
//         BigInteger ep = euclidp.y.multiply(q);
//         BigInteger eq = euclidq.y.multiply(p);
// 
//         BigInteger r = rp.multiply(ep).add(rq.multiply(eq)).mod(p.multiply(q));
// 
//         return r;
//     }
// }
// 
// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/IPairingProtocol.java
// public interface IPairingProtocol {
// 
//     public PairingMessage pair(PairingMessage pairingMessage);
// }
// 
// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/PairingMessage.java
// public class PairingMessage {
//     PaillierKeyPair pkp;
//     byte[] otherPublicKey;
//     BCParameters bcParameters;
//     ZKProofInit zkProofInit;
// 
//     private PairingMessage(){ }
// 
//     public PairingMessage(ECPoint otherPublicKey, PaillierKeyPair pkp, BCParameters bcParameters,
//                           ZKProofInit zkProofInit) {
//         if(pkp.containsPrivateKey()){
//             throw new RuntimeException("Non null private key in PaillierKeyPair. This must not be the case for a pairing message!");
//         }
//         this.pkp = pkp;
//         this.otherPublicKey = otherPublicKey.normalize().getEncoded(true);
//         if(bcParameters.containsPrivateSecrets()){
//             throw new RuntimeException("Non null private key in PaillierKeyPair. This must not be the case for a pairing message!");
//         }
//         this.bcParameters = bcParameters;
//         this.zkProofInit = zkProofInit;
//     }
// 
//     public ECPoint getOtherPublicKey() {
//         return ECKey.CURVE.getCurve().decodePoint(otherPublicKey);
//     }
// 
//     public PaillierKeyPair getPkp() {
//         return pkp;
//     }
// 
//     public BCParameters getBcParameters() {
//         return bcParameters;
//     }
// 
//     public ZKProofInit getZkProofInit() {
//         return zkProofInit;
//     }
// }


import de.uni_bonn.bit.wallet_protocol.ZKProofInit;
import org.bitcoinj.core.ECKey;
import de.uni_bonn.bit.wallet_protocol.IPairingProtocol;
import de.uni_bonn.bit.wallet_protocol.PairingMessage;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.pqc.math.linearalgebra.IntegerFunctions;
import java.math.BigInteger;
/*
* Copyright 2014 Christopher Mann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uni_bonn.bit;



/**
 * This class implements the {@link de.uni_bonn.bit.wallet_protocol.IPairingProtocol}. It contains the desktop's logic
 * for the pairing protocol. This class is used to create an avro server.
 */
public class PairingProtocolImpl implements IPairingProtocol{

    private BigInteger keyShare;
    private String address;
    private PairingProtocolListener listener;
    private KeyShareWalletExtension walletExtension;

    private static final BigInteger nEC = ECKey.CURVE.getN();

    public PairingProtocolImpl(PairingProtocolListener listener, KeyShareWalletExtension walletExtension) {
        this.listener = listener;
        this.keyShare = IntegerFunctions.randomize(nEC.subtract(BigInteger.ONE)).add(BigInteger.ONE);
        this.walletExtension = walletExtension;
    }

    @Override
    public PairingMessage pair(PairingMessage message) {
        message.getZkProofInit().verify(message.getBcParameters(), "Phone Init Proof");
        ECPoint publicKey = ECKey.CURVE.getG().multiply(keyShare).normalize();
        PaillierKeyPair pkp = PaillierKeyPair.generatePaillierKeyPair();
        BCParameters desktopBCParameters = BCParameters.generateBCParameters();
// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/ZKProofInit.java
// public class ZKProofInit {
// 
//     @Stringable
//     private BigInteger gRoot;
//     @Stringable
//     private BigInteger hRoot;
//     /**
//      * Generates a zero-knowledge proof which proves that bcParameters.g and bcParameters.h are quadratic residues,
//      * which is implies that they are part of the same cyclic sub group.
//      * @param bcParameters
//      * @param id An id which identifies the proof instance. The result should depend on the proof it is used for to
//      *           prevent replay attacks.
//      * @return
//      */
//     public static ZKProofInit generate(BCParameters bcParameters, String id){
//         ZKProofInit result = new ZKProofInit();
//         result.gRoot = squareRoot(bcParameters.getH(), bcParameters.getP(), bcParameters.getQ());
//         result.hRoot = squareRoot(bcParameters.getG(), bcParameters.getP(), bcParameters.getQ());
//         return result;
//     }
// 
//     /**
//      * Verifies this zk proof for the given bcParameters.
//      * @param bcParameters
//      * @param id
//      */
//     public void verify(BCParameters bcParameters, String id){
//         BigInteger gRootSquared = gRoot.pow(2).mod(bcParameters.getN());
//         BigInteger hRootSquared = hRoot.pow(2).mod(bcParameters.getN());
// 
//         if(! bcParameters.getH().equals(gRootSquared) || ! bcParameters.getG().equals(hRootSquared)){
//             throw new ProtocolException("Verification of ZKProof init with id  " + id + " failed.");
//         }
//     }
// 
//     private static BigInteger squareRoot(BigInteger x, BigInteger p, BigInteger q){
//         BigInteger four = new BigInteger("4");
//         BigInteger rp = x.modPow(p.add(BigInteger.ONE).divide(four), p);
//         BigInteger rq = x.modPow(q.add(BigInteger.ONE).divide(four), q);
// 
//         BigIntEuclidean euclidp = BigIntEuclidean.calculate(p, q);
//         BigIntEuclidean euclidq = BigIntEuclidean.calculate(q, p);
// 
//         BigInteger ep = euclidp.y.multiply(q);
//         BigInteger eq = euclidq.y.multiply(p);
// 
//         BigInteger r = rp.multiply(ep).add(rq.multiply(eq)).mod(p.multiply(q));
// 
//         return r;
//     }
// }
// 
// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/IPairingProtocol.java
// public interface IPairingProtocol {
// 
//     public PairingMessage pair(PairingMessage pairingMessage);
// }
// 
// Path: wallet_lib/src/main/java/de/uni_bonn/bit/wallet_protocol/PairingMessage.java
// public class PairingMessage {
//     PaillierKeyPair pkp;
//     byte[] otherPublicKey;
//     BCParameters bcParameters;
//     ZKProofInit zkProofInit;
// 
//     private PairingMessage(){ }
// 
//     public PairingMessage(ECPoint otherPublicKey, PaillierKeyPair pkp, BCParameters bcParameters,
//                           ZKProofInit zkProofInit) {
//         if(pkp.containsPrivateKey()){
//             throw new RuntimeException("Non null private key in PaillierKeyPair. This must not be the case for a pairing message!");
//         }
//         this.pkp = pkp;
//         this.otherPublicKey = otherPublicKey.normalize().getEncoded(true);
//         if(bcParameters.containsPrivateSecrets()){
//             throw new RuntimeException("Non null private key in PaillierKeyPair. This must not be the case for a pairing message!");
//         }
//         this.bcParameters = bcParameters;
//         this.zkProofInit = zkProofInit;
//     }
// 
//     public ECPoint getOtherPublicKey() {
//         return ECKey.CURVE.getCurve().decodePoint(otherPublicKey);
//     }
// 
//     public PaillierKeyPair getPkp() {
//         return pkp;
//     }
// 
//     public BCParameters getBcParameters() {
//         return bcParameters;
//     }
// 
//     public ZKProofInit getZkProofInit() {
//         return zkProofInit;
//     }
// }


// Path: desktop_wallet/src/main/java/de/uni_bonn/bit/PairingProtocolImpl.java
import de.uni_bonn.bit.wallet_protocol.ZKProofInit;
import org.bitcoinj.core.ECKey;
import de.uni_bonn.bit.wallet_protocol.IPairingProtocol;
import de.uni_bonn.bit.wallet_protocol.PairingMessage;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.pqc.math.linearalgebra.IntegerFunctions;
import java.math.BigInteger;

/*
* Copyright 2014 Christopher Mann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uni_bonn.bit;



/**
 * This class implements the {@link de.uni_bonn.bit.wallet_protocol.IPairingProtocol}. It contains the desktop's logic
 * for the pairing protocol. This class is used to create an avro server.
 */
public class PairingProtocolImpl implements IPairingProtocol{

    private BigInteger keyShare;
    private String address;
    private PairingProtocolListener listener;
    private KeyShareWalletExtension walletExtension;

    private static final BigInteger nEC = ECKey.CURVE.getN();

    public PairingProtocolImpl(PairingProtocolListener listener, KeyShareWalletExtension walletExtension) {
        this.listener = listener;
        this.keyShare = IntegerFunctions.randomize(nEC.subtract(BigInteger.ONE)).add(BigInteger.ONE);
        this.walletExtension = walletExtension;
    }

    @Override
    public PairingMessage pair(PairingMessage message) {
        message.getZkProofInit().verify(message.getBcParameters(), "Phone Init Proof");
        ECPoint publicKey = ECKey.CURVE.getG().multiply(keyShare).normalize();
        PaillierKeyPair pkp = PaillierKeyPair.generatePaillierKeyPair();
        BCParameters desktopBCParameters = BCParameters.generateBCParameters();
        ZKProofInit myZKProof = ZKProofInit.generate(desktopBCParameters, "Desktop Init Proof");