From b3f7cb5c76ded0c0e335252f2e00ce5b34937bfa Mon Sep 17 00:00:00 2001 From: Steven Barclay Date: Sun, 21 Nov 2021 17:10:40 +0000 Subject: [PATCH] Code cleanup: remove unused PoW class & test Remove (possible draft) 'ProofOfWorkService(Test)', which is a near duplicate of the class 'HashCashService' but is currently unused. --- .../common/crypto/ProofOfWorkService.java | 156 ------------------ .../common/crypto/ProofOfWorkServiceTest.java | 81 --------- 2 files changed, 237 deletions(-) delete mode 100644 common/src/main/java/bisq/common/crypto/ProofOfWorkService.java delete mode 100644 common/src/test/java/bisq/common/crypto/ProofOfWorkServiceTest.java diff --git a/common/src/main/java/bisq/common/crypto/ProofOfWorkService.java b/common/src/main/java/bisq/common/crypto/ProofOfWorkService.java deleted file mode 100644 index c94e4e5c1f..0000000000 --- a/common/src/main/java/bisq/common/crypto/ProofOfWorkService.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.common.crypto; - -import com.google.common.primitives.Longs; - -import java.math.BigInteger; - -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; - -import lombok.extern.slf4j.Slf4j; - -/** - * Bitcoin-like proof of work implementation. Differs from original hashcash by using BigInteger for comparing - * the hash result with the target difficulty to gain more fine grained control for difficulty adjustment. - * This class provides a convenience method getDifficultyAsBigInteger(numLeadingZeros) to get values which are - * equivalent to the hashcash difficulty values. - * - * See https://en.wikipedia.org/wiki/Hashcash" - * "Unlike hashcash, Bitcoin's difficulty target does not specify a minimum number of leading zeros in the hash. - * Instead, the hash is interpreted as a (very large) integer, and this integer must be less than the target integer." - */ -@Slf4j -public class ProofOfWorkService { - // Default validations. Custom implementations might use tolerance. - private static final BiFunction isChallengeValid = Arrays::equals; - private static final BiFunction isTargetValid = BigInteger::equals; - - public static CompletableFuture mint(byte[] payload, - byte[] challenge, - BigInteger target) { - return mint(payload, - challenge, - target, - ProofOfWorkService::testTarget); - } - - public static boolean verify(ProofOfWork proofOfWork) { - return verify(proofOfWork, - proofOfWork.getChallenge(), - proofOfWork.getTarget()); - } - - public static boolean verify(ProofOfWork proofOfWork, - byte[] controlChallenge, - BigInteger controlTarget) { - return verify(proofOfWork, - controlChallenge, - controlTarget, - ProofOfWorkService::testTarget); - } - - public static boolean verify(ProofOfWork proofOfWork, - byte[] controlChallenge, - BigInteger controlTarget, - BiFunction challengeValidation, - BiFunction targetValidation) { - return verify(proofOfWork, - controlChallenge, - controlTarget, - challengeValidation, - targetValidation, - ProofOfWorkService::testTarget); - - } - - public static BigInteger getTarget(int numLeadingZeros) { - return BigInteger.TWO.pow(255 - numLeadingZeros).subtract(BigInteger.ONE); - } - - private static boolean testTarget(byte[] result, BigInteger target) { - return getUnsignedBigInteger(result).compareTo(target) < 0; - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Generic - /////////////////////////////////////////////////////////////////////////////////////////// - - static CompletableFuture mint(byte[] payload, - byte[] challenge, - BigInteger target, - BiFunction testTarget) { - return CompletableFuture.supplyAsync(() -> { - long ts = System.currentTimeMillis(); - byte[] result; - long counter = 0; - do { - result = toSha256Hash(payload, challenge, ++counter); - } - while (!testTarget.apply(result, target)); - return new ProofOfWork(payload, counter, challenge, target, System.currentTimeMillis() - ts); - }); - } - - static boolean verify(ProofOfWork proofOfWork, - byte[] controlChallenge, - BigInteger controlTarget, - BiFunction testTarget) { - return verify(proofOfWork, - controlChallenge, - controlTarget, - ProofOfWorkService.isChallengeValid, - ProofOfWorkService.isTargetValid, - testTarget); - } - - static boolean verify(ProofOfWork proofOfWork, - byte[] controlChallenge, - BigInteger controlTarget, - BiFunction challengeValidation, - BiFunction targetValidation, - BiFunction testTarget) { - return challengeValidation.apply(proofOfWork.getChallenge(), controlChallenge) && - targetValidation.apply(proofOfWork.getTarget(), controlTarget) && - verify(proofOfWork, testTarget); - } - - private static boolean verify(ProofOfWork proofOfWork, BiFunction testTarget) { - byte[] hash = toSha256Hash(proofOfWork.getPayload(), proofOfWork.getChallenge(), proofOfWork.getCounter()); - return testTarget.apply(hash, proofOfWork.getTarget()); - } - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Utils - /////////////////////////////////////////////////////////////////////////////////////////// - - private static BigInteger getUnsignedBigInteger(byte[] result) { - return new BigInteger(1, result); - } - - private static byte[] toSha256Hash(byte[] payload, byte[] challenge, long counter) { - byte[] preImage = org.bouncycastle.util.Arrays.concatenate(payload, - challenge, - Longs.toByteArray(counter)); - return Hash.getSha256Hash(preImage); - } -} diff --git a/common/src/test/java/bisq/common/crypto/ProofOfWorkServiceTest.java b/common/src/test/java/bisq/common/crypto/ProofOfWorkServiceTest.java deleted file mode 100644 index a4bab784b9..0000000000 --- a/common/src/test/java/bisq/common/crypto/ProofOfWorkServiceTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package bisq.common.crypto; - -import org.apache.commons.lang3.RandomStringUtils; - -import java.nio.charset.StandardCharsets; - -import java.math.BigInteger; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ExecutionException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -public class ProofOfWorkServiceTest { - private final static Logger log = LoggerFactory.getLogger(ProofOfWorkServiceTest.class); - - // @Ignore - @Test - public void testDiffIncrease() throws ExecutionException, InterruptedException { - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < 12; i++) { - run(i, stringBuilder); - } - log.info(stringBuilder.toString()); - - //Test result on a 4 GHz Intel Core i7: - //Minting 1000 tokens with 0 leading zeros took 0.279 ms per token and 2 iterations in average. Verification took 0.025 ms per token. - //Minting 1000 tokens with 1 leading zeros took 0.063 ms per token and 4 iterations in average. Verification took 0.007 ms per token. - //Minting 1000 tokens with 2 leading zeros took 0.074 ms per token and 8 iterations in average. Verification took 0.004 ms per token. - //Minting 1000 tokens with 3 leading zeros took 0.117 ms per token and 16 iterations in average. Verification took 0.003 ms per token. - //Minting 1000 tokens with 4 leading zeros took 0.116 ms per token and 33 iterations in average. Verification took 0.003 ms per token. - //Minting 1000 tokens with 5 leading zeros took 0.204 ms per token and 65 iterations in average. Verification took 0.003 ms per token. - //Minting 1000 tokens with 6 leading zeros took 0.23 ms per token and 131 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 7 leading zeros took 0.445 ms per token and 270 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 8 leading zeros took 0.856 ms per token and 530 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 9 leading zeros took 1.629 ms per token and 988 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 10 leading zeros took 3.291 ms per token and 2103 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 11 leading zeros took 6.259 ms per token and 4009 iterations in average. Verification took 0.001 ms per token. - //Minting 1000 tokens with 12 leading zeros took 13.845 ms per token and 8254 iterations in average. Verification took 0.002 ms per token. - //Minting 1000 tokens with 13 leading zeros took 26.052 ms per token and 16645 iterations in average. Verification took 0.002 ms per token. - - //Minting 100 tokens with 14 leading zeros took 69.14 ms per token and 40917 iterations in average. Verification took 0.06 ms per token. - //Minting 100 tokens with 15 leading zeros took 102.14 ms per token and 65735 iterations in average. Verification took 0.01 ms per token. - //Minting 100 tokens with 16 leading zeros took 209.44 ms per token and 135137 iterations in average. Verification took 0.01 ms per token. - //Minting 100 tokens with 17 leading zeros took 409.46 ms per token and 263751 iterations in average. Verification took 0.01 ms per token. - //Minting 100 tokens with 18 leading zeros took 864.21 ms per token and 555671 iterations in average. Verification took 0.0 ms per token. - //Minting 100 tokens with 19 leading zeros took 1851.33 ms per token and 1097760 iterations in average. Verification took 0.0 ms per token. - } - - private void run(int numLeadingZeros, StringBuilder stringBuilder) throws ExecutionException, InterruptedException { - int numTokens = 1000; - BigInteger target = ProofOfWorkService.getTarget(numLeadingZeros); - byte[] payload = RandomStringUtils.random(50, true, true).getBytes(StandardCharsets.UTF_8); - long ts = System.currentTimeMillis(); - List tokens = new ArrayList<>(); - for (int i = 0; i < numTokens; i++) { - byte[] challenge = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8); - tokens.add(ProofOfWorkService.mint(payload, challenge, target).get()); - } - double size = tokens.size(); - long ts2 = System.currentTimeMillis(); - long averageCounter = Math.round(tokens.stream().mapToLong(ProofOfWork::getCounter).average().orElse(0)); - boolean allValid = tokens.stream().allMatch(ProofOfWorkService::verify); - assertTrue(allValid); - double time1 = (System.currentTimeMillis() - ts) / size; - double time2 = (System.currentTimeMillis() - ts2) / size; - stringBuilder.append("\nMinting ").append(numTokens) - .append(" tokens with ").append(numLeadingZeros) - .append(" leading zeros took ").append(time1) - .append(" ms per token and ").append(averageCounter) - .append(" iterations in average. Verification took ").append(time2) - .append(" ms per token."); - } -}