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

Commit

Permalink
PrivacyMarkerTransaction to be signed with a randomly generated key (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
rain-on authored Aug 16, 2019
1 parent 623f750 commit 7de86d4
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public void startNode(final PantheonNode node) {
params.add(node.getPrivacyParameters().getEnclavePublicKeyFile().getAbsolutePath());
params.add("--privacy-precompiled-address");
params.add(String.valueOf(node.getPrivacyParameters().getPrivacyAddress()));
params.add("--privacy-marker-transaction-signing-key-file");
params.add(node.homeDirectory().resolve("key").toString());
}

params.add("--bootnodes");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.storage.StorageProvider;
Expand All @@ -30,6 +31,7 @@
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.util.Optional;

import com.google.common.io.Files;

Expand All @@ -42,7 +44,7 @@ public class PrivacyParameters {
private URI enclaveUri;
private String enclavePublicKey;
private File enclavePublicKeyFile;
private SECP256K1.KeyPair signingKeyPair;
private Optional<SECP256K1.KeyPair> signingKeyPair = Optional.empty();
private WorldStateArchive privateWorldStateArchive;
private StorageProvider privateStorageProvider;

Expand Down Expand Up @@ -89,12 +91,12 @@ public void setEnclavePublicKeyFile(final File enclavePublicKeyFile) {
this.enclavePublicKeyFile = enclavePublicKeyFile;
}

public SECP256K1.KeyPair getSigningKeyPair() {
public Optional<SECP256K1.KeyPair> getSigningKeyPair() {
return signingKeyPair;
}

public void setSigningKeyPair(final SECP256K1.KeyPair signingKeyPair) {
this.signingKeyPair = signingKeyPair;
this.signingKeyPair = Optional.ofNullable(signingKeyPair);
}

public WorldStateArchive getPrivateWorldStateArchive() {
Expand Down Expand Up @@ -145,6 +147,7 @@ public static class Builder {
private Path dataDir;
private File enclavePublicKeyFile;
private String enclavePublicKey;
private Path privateKeyPath;

public Builder setPrivacyAddress(final Integer privacyAddress) {
this.privacyAddress = privacyAddress;
Expand All @@ -171,6 +174,11 @@ public Builder setDataDir(final Path dataDir) {
return this;
}

public Builder setPrivateKeyPath(final Path privateKeyPath) {
this.privateKeyPath = privateKeyPath;
return this;
}

public PrivacyParameters build() throws IOException {
PrivacyParameters config = new PrivacyParameters();
if (enabled) {
Expand Down Expand Up @@ -200,6 +208,9 @@ public PrivacyParameters build() throws IOException {
config.setPrivateStorageProvider(privateStorageProvider);
config.setPrivateTransactionStorage(privateTransactionStorage);
config.setPrivateStateStorage(privateStateStorage);
if (privateKeyPath != null) {
config.setSigningKeyPair(KeyPair.load(privateKeyPath.toFile()));
}
}
config.setEnabled(enabled);
config.setEnclaveUri(enclaveUrl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
package tech.pegasys.pantheon.ethereum.privacy;

import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.enclave.Enclave;
import tech.pegasys.pantheon.enclave.types.ReceiveRequest;
import tech.pegasys.pantheon.enclave.types.ReceiveResponse;
Expand All @@ -24,9 +23,9 @@
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.util.bytes.BytesValues;
Expand All @@ -44,42 +43,38 @@ public class PrivateTransactionHandler {
private static final Logger LOG = LogManager.getLogger();

private final Enclave enclave;
private final Address privacyPrecompileAddress;
private final SECP256K1.KeyPair nodeKeyPair;
private final Address signerAddress;
private final String enclavePublicKey;
private final PrivateStateStorage privateStateStorage;
private final WorldStateArchive privateWorldStateArchive;
private final PrivateTransactionValidator privateTransactionValidator;
private final PrivateMarkerTransactionFactory privateMarkerTransactionFactory;

public PrivateTransactionHandler(
final PrivacyParameters privacyParameters, final Optional<BigInteger> chainId) {
final PrivacyParameters privacyParameters,
final Optional<BigInteger> chainId,
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) {
this(
new Enclave(privacyParameters.getEnclaveUri()),
Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()),
privacyParameters.getSigningKeyPair(),
privacyParameters.getEnclavePublicKey(),
privacyParameters.getPrivateStateStorage(),
privacyParameters.getPrivateWorldStateArchive(),
new PrivateTransactionValidator(chainId));
new PrivateTransactionValidator(chainId),
privateMarkerTransactionFactory);
}

public PrivateTransactionHandler(
final Enclave enclave,
final Address privacyPrecompileAddress,
final SECP256K1.KeyPair nodeKeyPair,
final String enclavePublicKey,
final PrivateStateStorage privateStateStorage,
final WorldStateArchive privateWorldStateArchive,
final PrivateTransactionValidator privateTransactionValidator) {
final PrivateTransactionValidator privateTransactionValidator,
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) {
this.enclave = enclave;
this.privacyPrecompileAddress = privacyPrecompileAddress;
this.nodeKeyPair = nodeKeyPair;
this.signerAddress = Util.publicKeyToAddress(nodeKeyPair.getPublicKey());
this.enclavePublicKey = enclavePublicKey;
this.privateStateStorage = privateStateStorage;
this.privateWorldStateArchive = privateWorldStateArchive;
this.privateTransactionValidator = privateTransactionValidator;
this.privateMarkerTransactionFactory = privateMarkerTransactionFactory;
}

public String sendToOrion(final PrivateTransaction privateTransaction) throws Exception {
Expand Down Expand Up @@ -117,19 +112,8 @@ public String getPrivacyGroup(final String key, final PrivateTransaction private
}

public Transaction createPrivacyMarkerTransaction(
final String transactionEnclaveKey,
final PrivateTransaction privateTransaction,
final Long nonce) {

return Transaction.builder()
.nonce(nonce)
.gasPrice(privateTransaction.getGasPrice())
.gasLimit(privateTransaction.getGasLimit())
.to(privacyPrecompileAddress)
.value(privateTransaction.getValue())
.payload(BytesValues.fromBase64(transactionEnclaveKey))
.sender(signerAddress)
.signAndBuild(nodeKeyPair);
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
return privateMarkerTransactionFactory.create(transactionEnclaveKey, privateTransaction);
}

public ValidationResult<TransactionInvalidReason> validatePrivateTransaction(
Expand Down Expand Up @@ -187,12 +171,4 @@ public long getSenderNonce(final Address sender, final String privacyGroupId) {
// private state does not exist
Account.DEFAULT_NONCE);
}

public Address getSignerAddress() {
return signerAddress;
}

public String getEnclaveKey() {
return enclavePublicKey;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.privacy.markertransaction;

import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.ethereum.util.NonceProvider;

public class FixedKeySigningPrivateMarkerTransactionFactory
extends PrivateMarkerTransactionFactory {

private final NonceProvider nonceProvider;
private final KeyPair signingKey;
private final Address sender;

public FixedKeySigningPrivateMarkerTransactionFactory(
final Address privacyPrecompileAddress,
final NonceProvider nonceProvider,
final KeyPair signingKey) {
super(privacyPrecompileAddress);
this.nonceProvider = nonceProvider;
this.signingKey = signingKey;
this.sender = Util.publicKeyToAddress(signingKey.getPublicKey());
}

@Override
public Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
return create(
transactionEnclaveKey, privateTransaction, nonceProvider.getNonce(sender), signingKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.privacy.markertransaction;

import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.util.bytes.BytesValues;

public abstract class PrivateMarkerTransactionFactory {

private final Address privacyPrecompileAddress;

public PrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) {
this.privacyPrecompileAddress = privacyPrecompileAddress;
}

private Address getPrivacyPrecompileAddress() {
return privacyPrecompileAddress;
}

public abstract Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction);

protected Transaction create(
final String transactionEnclaveKey,
final PrivateTransaction privateTransaction,
final long nonce,
final KeyPair signingKey) {
return Transaction.builder()
.nonce(nonce)
.gasPrice(privateTransaction.getGasPrice())
.gasLimit(privateTransaction.getGasLimit())
.to(getPrivacyPrecompileAddress())
.value(privateTransaction.getValue())
.payload(BytesValues.fromBase64(transactionEnclaveKey))
.signAndBuild(signingKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.privacy.markertransaction;

import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;

public class RandomSigningPrivateMarkerTransactionFactory extends PrivateMarkerTransactionFactory {

public RandomSigningPrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) {
super(privacyPrecompileAddress);
}

@Override
public Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
final KeyPair signingKey = KeyPair.generate();
return create(transactionEnclaveKey, privateTransaction, 0, signingKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.util;

import tech.pegasys.pantheon.ethereum.core.Address;

@FunctionalInterface
public interface NonceProvider {

long getNonce(final Address address);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues;
Expand Down Expand Up @@ -114,21 +115,21 @@ public void setUp() throws Exception {
privateTransactionHandler =
new PrivateTransactionHandler(
mockEnclave(),
Address.DEFAULT_PRIVACY,
KEY_PAIR,
OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage,
worldStateArchive,
privateTransactionValidator);
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
brokenPrivateTransactionHandler =
new PrivateTransactionHandler(
brokenMockEnclave(),
Address.DEFAULT_PRIVACY,
KEY_PAIR,
OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage,
worldStateArchive,
privateTransactionValidator);
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
}

@Test
Expand All @@ -145,7 +146,7 @@ public void validLegacyTransactionThroughHandler() throws Exception {
privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId);

final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction, 0L);
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);

assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
Expand All @@ -167,7 +168,7 @@ public void validPantheonTransactionThroughHandler() throws Exception {
transaction, transaction.getPrivacyGroupId().get().toString());

final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction, 0L);
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);

assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
Expand Down
Loading

0 comments on commit 7de86d4

Please sign in to comment.