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.
This commit is contained in:
Steven Barclay 2021-11-21 17:10:40 +00:00 committed by Christoph Atteneder
parent 2cb238318f
commit b3f7cb5c76
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B
2 changed files with 0 additions and 237 deletions

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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<byte[], byte[], Boolean> isChallengeValid = Arrays::equals;
private static final BiFunction<BigInteger, BigInteger, Boolean> isTargetValid = BigInteger::equals;
public static CompletableFuture<ProofOfWork> 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<byte[], byte[], Boolean> challengeValidation,
BiFunction<BigInteger, BigInteger, Boolean> 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<ProofOfWork> mint(byte[] payload,
byte[] challenge,
BigInteger target,
BiFunction<byte[], BigInteger, Boolean> 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<byte[], BigInteger, Boolean> testTarget) {
return verify(proofOfWork,
controlChallenge,
controlTarget,
ProofOfWorkService.isChallengeValid,
ProofOfWorkService.isTargetValid,
testTarget);
}
static boolean verify(ProofOfWork proofOfWork,
byte[] controlChallenge,
BigInteger controlTarget,
BiFunction<byte[], byte[], Boolean> challengeValidation,
BiFunction<BigInteger, BigInteger, Boolean> targetValidation,
BiFunction<byte[], BigInteger, Boolean> testTarget) {
return challengeValidation.apply(proofOfWork.getChallenge(), controlChallenge) &&
targetValidation.apply(proofOfWork.getTarget(), controlTarget) &&
verify(proofOfWork, testTarget);
}
private static boolean verify(ProofOfWork proofOfWork, BiFunction<byte[], BigInteger, Boolean> 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);
}
}

View file

@ -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<ProofOfWork> 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.");
}
}