// Path: src/main/java/edu/stanford/crypto/ECConstants.java
// public final class ECConstants {
//     static {
//         SecP256K1Curve curve = new SecP256K1Curve();
//         BigInteger hash = BigInteger.ZERO;
//         try {
//             MessageDigest sha256 = sha256 = MessageDigest.getInstance("SHA-256");
//             sha256.update("PROVISIONS".getBytes());
//             hash = new BigInteger(sha256.digest());
// 
//         } catch (NoSuchAlgorithmException e) {
//             e.printStackTrace();
//         }
//         ECFieldElement x = new SecP256K1FieldElement(hash.mod(curve.getQ()));
//         ECFieldElement rhs = x.square().multiply(x.add(curve.getA())).add(curve.getB());
//         ECFieldElement y = rhs.sqrt();
// 
// 
//         H = curve.validatePoint(x.toBigInteger(), y.toBigInteger());
// 
// 
//     }
// 
//     public static final ECCurve BITCOIN_CURVE = new SecP256K1Curve();
//     public static final ECPoint INFINITY = BITCOIN_CURVE.getInfinity();
//     public static final int STANDARD_SECURITY = 256;
//     public static final int CHALLENGE_LENGTH = 256;
//     public static final ECPoint G = CustomNamedCurves.getByName("secp256k1").getG();
//     public static final ECPoint H;
//     public static final BigInteger Q = BITCOIN_CURVE.getOrder();
//     public static final BigInteger CHALLENGE_Q = Q.min(BigInteger.ONE.shiftLeft(256));
// 
//     private ECConstants() {
//     }
// }
// 
// Path: src/main/java/edu/stanford/crypto/ProofUtils.java
// public class ProofUtils {
//     private static final ThreadLocal<MessageDigest> SHA256;
//     private static final SecureRandom RNG;
// 
//     public static BigInteger computeChallenge(ECPoint ... points) {
//         for (ECPoint point : points) {
//             SHA256.get().update(point.getEncoded(false));
//         }
//         byte[] hash = SHA256.get().digest();
//         return new BigInteger(hash).mod(ECConstants.CHALLENGE_Q);
//     }
// 
//     public static BigInteger hash(String id, BigInteger salt) {
//         SHA256.get().update(id.getBytes());
//         SHA256.get().update(salt.toByteArray());
//         return new BigInteger(SHA256.get().digest());
//     }
// 
//     public static BigInteger randomNumber(int bits) {
//         return new BigInteger(bits, RNG);
//     }
// 
//     public static BigInteger randomNumber() {
//         return ProofUtils.randomNumber(256);
//     }
// 
//     static {
//         RNG = new SecureRandom();
//         SHA256 = ThreadLocal.withInitial(() -> {
//             try {
//                 return MessageDigest.getInstance("SHA-256");
//             }
//             catch (NoSuchAlgorithmException e) {
//                 e.printStackTrace();
//                 throw new IllegalStateException(e);
//             }
//         }
//         );
//     }
// }
// 
// Path: src/main/java/edu/stanford/crypto/proof/ProofSystem.java
// public interface ProofSystem<P extends Proof, T extends ProofData<P>> {
//     P createProof(T var1);
// }


import edu.stanford.crypto.ECConstants;
import edu.stanford.crypto.ProofUtils;
import edu.stanford.crypto.proof.ProofSystem;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.util.Optional;
/*
 * Decompiled with CFR 0_110.
 */
package edu.stanford.crypto.proof.assets;



/**
 * Zero knowledge proof for public key y with balance b of the statement:<br>
 * "Either I know the private key x such that xG=y and p is a commitment to b or p is a commitment to 0."
 */
public class AddressProofSystem implements ProofSystem<AddressProof, AddressProofData> {
    @Override
    public AddressProof createProof(AddressProofData data) {
        BigInteger u1 = ProofUtils.randomNumber();
        BigInteger u2 = ProofUtils.randomNumber();
        BigInteger u3 = ProofUtils.randomNumber();
        BigInteger u4 = ProofUtils.randomNumber();
        ECPoint g = data.getG();
        ECPoint h = data.getH();
        ECPoint y = data.getPublicKey();
        ECPoint b = data.getG().multiply(data.getBalance());
        ECPoint a1 = b.multiply(u1).add(h.multiply(u2));
        ECPoint a2 = y.multiply(u1).add(h.multiply(u3));
        ECPoint a3 = g.multiply(u4).add(h.multiply(u3));
        Optional<BigInteger> privateKey = data.getPrivateKey();
        BigInteger v = data.getBalanceRandomness();
        BigInteger t = data.getKeyKnownRandomness();
        BigInteger s = privateKey.isPresent() ? BigInteger.ONE : BigInteger.ZERO;
        ECPoint p = b.multiply(s).add(h.multiply(v));
        ECPoint l = y.multiply(s).add(h.multiply(t));

        //Binary proof
// Path: src/main/java/edu/stanford/crypto/ECConstants.java
// public final class ECConstants {
//     static {
//         SecP256K1Curve curve = new SecP256K1Curve();
//         BigInteger hash = BigInteger.ZERO;
//         try {
//             MessageDigest sha256 = sha256 = MessageDigest.getInstance("SHA-256");
//             sha256.update("PROVISIONS".getBytes());
//             hash = new BigInteger(sha256.digest());
// 
//         } catch (NoSuchAlgorithmException e) {
//             e.printStackTrace();
//         }
//         ECFieldElement x = new SecP256K1FieldElement(hash.mod(curve.getQ()));
//         ECFieldElement rhs = x.square().multiply(x.add(curve.getA())).add(curve.getB());
//         ECFieldElement y = rhs.sqrt();
// 
// 
//         H = curve.validatePoint(x.toBigInteger(), y.toBigInteger());
// 
// 
//     }
// 
//     public static final ECCurve BITCOIN_CURVE = new SecP256K1Curve();
//     public static final ECPoint INFINITY = BITCOIN_CURVE.getInfinity();
//     public static final int STANDARD_SECURITY = 256;
//     public static final int CHALLENGE_LENGTH = 256;
//     public static final ECPoint G = CustomNamedCurves.getByName("secp256k1").getG();
//     public static final ECPoint H;
//     public static final BigInteger Q = BITCOIN_CURVE.getOrder();
//     public static final BigInteger CHALLENGE_Q = Q.min(BigInteger.ONE.shiftLeft(256));
// 
//     private ECConstants() {
//     }
// }
// 
// Path: src/main/java/edu/stanford/crypto/ProofUtils.java
// public class ProofUtils {
//     private static final ThreadLocal<MessageDigest> SHA256;
//     private static final SecureRandom RNG;
// 
//     public static BigInteger computeChallenge(ECPoint ... points) {
//         for (ECPoint point : points) {
//             SHA256.get().update(point.getEncoded(false));
//         }
//         byte[] hash = SHA256.get().digest();
//         return new BigInteger(hash).mod(ECConstants.CHALLENGE_Q);
//     }
// 
//     public static BigInteger hash(String id, BigInteger salt) {
//         SHA256.get().update(id.getBytes());
//         SHA256.get().update(salt.toByteArray());
//         return new BigInteger(SHA256.get().digest());
//     }
// 
//     public static BigInteger randomNumber(int bits) {
//         return new BigInteger(bits, RNG);
//     }
// 
//     public static BigInteger randomNumber() {
//         return ProofUtils.randomNumber(256);
//     }
// 
//     static {
//         RNG = new SecureRandom();
//         SHA256 = ThreadLocal.withInitial(() -> {
//             try {
//                 return MessageDigest.getInstance("SHA-256");
//             }
//             catch (NoSuchAlgorithmException e) {
//                 e.printStackTrace();
//                 throw new IllegalStateException(e);
//             }
//         }
//         );
//     }
// }
// 
// Path: src/main/java/edu/stanford/crypto/proof/ProofSystem.java
// public interface ProofSystem<P extends Proof, T extends ProofData<P>> {
//     P createProof(T var1);
// }


// Path: src/main/java/edu/stanford/crypto/proof/assets/AddressProofSystem.java
import edu.stanford.crypto.ECConstants;
import edu.stanford.crypto.ProofUtils;
import edu.stanford.crypto.proof.ProofSystem;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.util.Optional;

/*
 * Decompiled with CFR 0_110.
 */
package edu.stanford.crypto.proof.assets;



/**
 * Zero knowledge proof for public key y with balance b of the statement:<br>
 * "Either I know the private key x such that xG=y and p is a commitment to b or p is a commitment to 0."
 */
public class AddressProofSystem implements ProofSystem<AddressProof, AddressProofData> {
    @Override
    public AddressProof createProof(AddressProofData data) {
        BigInteger u1 = ProofUtils.randomNumber();
        BigInteger u2 = ProofUtils.randomNumber();
        BigInteger u3 = ProofUtils.randomNumber();
        BigInteger u4 = ProofUtils.randomNumber();
        ECPoint g = data.getG();
        ECPoint h = data.getH();
        ECPoint y = data.getPublicKey();
        ECPoint b = data.getG().multiply(data.getBalance());
        ECPoint a1 = b.multiply(u1).add(h.multiply(u2));
        ECPoint a2 = y.multiply(u1).add(h.multiply(u3));
        ECPoint a3 = g.multiply(u4).add(h.multiply(u3));
        Optional<BigInteger> privateKey = data.getPrivateKey();
        BigInteger v = data.getBalanceRandomness();
        BigInteger t = data.getKeyKnownRandomness();
        BigInteger s = privateKey.isPresent() ? BigInteger.ONE : BigInteger.ZERO;
        ECPoint p = b.multiply(s).add(h.multiply(v));
        ECPoint l = y.multiply(s).add(h.multiply(t));

        //Binary proof
        BigInteger uZero = ProofUtils.randomNumber();