Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

[Testing] Make test generated keys deterministic w/in block generator #1657

Merged
merged 2 commits into from
Jul 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@
*/
public class SECP256K1 {

private static final String ALGORITHM = "ECDSA";
private static final String CURVE_NAME = "secp256k1";
private static final String PROVIDER = "BC";
public static final String ALGORITHM = "ECDSA";
public static final String CURVE_NAME = "secp256k1";
public static final String PROVIDER = "BC";

public static final ECDomainParameters CURVE;
public static final BigInteger HALF_CURVE_ORDER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive;

import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SecureRandomProvider;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.uint.UInt256;

import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
Expand All @@ -36,17 +42,46 @@
import java.util.Set;
import java.util.stream.IntStream;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class BlockDataGenerator {

static {
Security.addProvider(new BouncyCastleProvider());
}

private final Random random;
private final KeyPairGenerator keyPairGenerator;

public BlockDataGenerator(final int seed) {
this.random = new Random(seed);
keyPairGenerator = createKeyPairGenerator(seed);
}

public BlockDataGenerator() {
this(1);
}

private KeyPairGenerator createKeyPairGenerator(final long seed) {
final KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator = KeyPairGenerator.getInstance(SECP256K1.ALGORITHM, SECP256K1.PROVIDER);
} catch (final Exception e) {
throw new RuntimeException(e);
}
final ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SECP256K1.CURVE_NAME);
try {
final SecureRandom secureRandom = SecureRandomProvider.createSecureRandom();
secureRandom.setSeed(seed);
keyPairGenerator.initialize(ecGenParameterSpec, secureRandom);
} catch (final InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
return keyPairGenerator;
}

/**
* Generates a sequence of blocks with some accounts and account storage pre-populated with random
* data.
Expand Down Expand Up @@ -254,7 +289,7 @@ public Transaction transaction(final BytesValue payload) {
.value(Wei.wrap(bytes32()))
.payload(payload)
.chainId(BigInteger.ONE)
.signAndBuild(SECP256K1.KeyPair.generate());
.signAndBuild(generateKeyPair());
}

public Transaction transaction() {
Expand All @@ -266,7 +301,7 @@ public Transaction transaction() {
.value(Wei.wrap(bytes32()))
.payload(bytes32())
.chainId(BigInteger.ONE)
.signAndBuild(SECP256K1.KeyPair.generate());
.signAndBuild(generateKeyPair());
}

public Set<Transaction> transactions(final int n) {
Expand All @@ -276,7 +311,7 @@ public Set<Transaction> transactions(final int n) {
Wei value = Wei.wrap(bytes32());
int chainId = 1;
Bytes32 payload = bytes32();
SECP256K1.Signature signature = SECP256K1.sign(payload, SECP256K1.KeyPair.generate());
final SECP256K1.Signature signature = SECP256K1.sign(payload, generateKeyPair());

final Set<Transaction> txs =
IntStream.range(0, n)
Expand Down Expand Up @@ -402,6 +437,24 @@ private byte[] bytes(final int size, final int zerofill) {
return bytes;
}

private SECP256K1.KeyPair generateKeyPair() {
final java.security.KeyPair rawKeyPair = keyPairGenerator.generateKeyPair();
final BCECPrivateKey privateKey = (BCECPrivateKey) rawKeyPair.getPrivate();
final BCECPublicKey publicKey = (BCECPublicKey) rawKeyPair.getPublic();

final BigInteger privateKeyValue = privateKey.getD();

// Ethereum does not use encoded public keys like bitcoin - see
// https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm for details
// Additionally, as the first bit is a constant prefix (0x04) we ignore this value
final byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);
final BigInteger publicKeyValue =
new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.length));

return new SECP256K1.KeyPair(
SECP256K1.PrivateKey.create(privateKeyValue), SECP256K1.PublicKey.create(publicKeyValue));
}

public static class BlockOptions {
private OptionalLong blockNumber = OptionalLong.empty();
private Optional<Hash> parentHash = Optional.empty();
Expand Down