* verify auth nonce less than 2**64-1 during auth processing

* auth to zero address deletes delegation
* auth to precompile returns empty code
* auth nonce < 2**8
* increase auth base cost to 12500

Signed-off-by: Daniel Lehrner <daniel.lehrner@consensys.net>
pull/7754/head
Daniel Lehrner 1 month ago
parent 1269cc1a98
commit d7e5686fe7
  1. 2
      crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/AbstractSECP256.java
  2. 9
      crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/CodeDelegationSignature.java
  3. 2
      crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/SignatureAlgorithm.java
  4. 27
      crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/CodeDelegationSignatureTest.java
  5. 2
      datatypes/src/main/java/org/hyperledger/besu/datatypes/CodeDelegation.java
  6. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java
  7. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  8. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionDecoder.java
  9. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoder.java
  10. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
  11. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CodeDelegationProcessor.java
  12. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  13. 8
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/CodeDelegationTransactionEncoderTest.java
  14. 14
      evm/src/main/java/org/hyperledger/besu/evm/worldstate/DelegatedCodeService.java

@ -214,7 +214,7 @@ public abstract class AbstractSECP256 implements SignatureAlgorithm {
@Override
public CodeDelegationSignature createCodeDelegationSignature(
final BigInteger r, final BigInteger s, final BigInteger yParity) {
final BigInteger r, final BigInteger s, final byte yParity) {
return CodeDelegationSignature.create(r, s, yParity);
}

@ -42,7 +42,7 @@ public class CodeDelegationSignature extends SECPSignature {
* @return the new CodeDelegationSignature
*/
public static CodeDelegationSignature create(
final BigInteger r, final BigInteger s, final BigInteger yParity) {
final BigInteger r, final BigInteger s, final byte yParity) {
checkNotNull(r);
checkNotNull(s);
@ -56,11 +56,6 @@ public class CodeDelegationSignature extends SECPSignature {
"Invalid 's' value, should be < 2^256 but got " + s.toString(16));
}
if (yParity.compareTo(TWO_POW_256) >= 0) {
throw new IllegalArgumentException(
"Invalid 'yParity' value, should be < 2^256 but got " + yParity.toString(16));
}
return new CodeDelegationSignature(r, s, yParity.byteValue());
return new CodeDelegationSignature(r, s, yParity);
}
}

@ -224,7 +224,7 @@ public interface SignatureAlgorithm {
* @return the code delegation signature
*/
CodeDelegationSignature createCodeDelegationSignature(
final BigInteger r, final BigInteger s, final BigInteger yParity);
final BigInteger r, final BigInteger s, final byte yParity);
/**
* Decode secp signature.

@ -29,19 +29,19 @@ class CodeDelegationSignatureTest {
void testValidInputs() {
BigInteger r = BigInteger.ONE;
BigInteger s = BigInteger.TEN;
BigInteger yParity = BigInteger.ONE;
byte yParity = (byte) 1;
CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity);
assertThat(r).isEqualTo(result.getR());
assertThat(s).isEqualTo(result.getS());
assertThat(yParity.byteValue()).isEqualTo(result.getRecId());
assertThat(yParity).isEqualTo(result.getRecId());
}
@Test
void testNullRValue() {
BigInteger s = BigInteger.TEN;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> CodeDelegationSignature.create(null, s, yParity));
@ -50,7 +50,7 @@ class CodeDelegationSignatureTest {
@Test
void testNullSValue() {
BigInteger r = BigInteger.ONE;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, null, yParity));
@ -60,7 +60,7 @@ class CodeDelegationSignatureTest {
void testRValueExceedsTwoPow256() {
BigInteger r = TWO_POW_256;
BigInteger s = BigInteger.TEN;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
@ -71,34 +71,23 @@ class CodeDelegationSignatureTest {
void testSValueExceedsTwoPow256() {
BigInteger r = BigInteger.ONE;
BigInteger s = TWO_POW_256;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
.withMessageContainingAll("Invalid 's' value, should be < 2^256");
}
@Test
void testYParityExceedsTwoPow256() {
BigInteger r = BigInteger.ONE;
BigInteger s = BigInteger.TWO;
BigInteger yParity = TWO_POW_256;
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CodeDelegationSignature.create(r, s, yParity))
.withMessageContainingAll("Invalid 'yParity' value, should be < 2^256");
}
@Test
void testValidYParityZero() {
BigInteger r = BigInteger.ONE;
BigInteger s = BigInteger.TEN;
BigInteger yParity = BigInteger.ZERO;
byte yParity = (byte) 0;
CodeDelegationSignature result = CodeDelegationSignature.create(r, s, yParity);
assertThat(r).isEqualTo(result.getR());
assertThat(s).isEqualTo(result.getS());
assertThat(yParity.byteValue()).isEqualTo(result.getRecId());
assertThat(yParity).isEqualTo(result.getRecId());
}
}

@ -25,7 +25,7 @@ import java.util.Optional;
*/
public interface CodeDelegation {
/** The cost of delegating code on an existing account. */
long PER_AUTH_BASE_COST = 2_500L;
long PER_AUTH_BASE_COST = 12_500L;
/**
* Return the chain id.

@ -20,7 +20,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
@ -140,7 +140,7 @@ public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelega
private Optional<Address> computeAuthority() {
BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
CodeDelegationEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
CodeDelegationTransactionEncoder.encodeSingleCodeDelegationWithoutSignature(this, rlpOutput);
final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded()));

@ -38,7 +38,7 @@ import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
@ -937,7 +937,8 @@ public class Transaction
chainId,
accessList,
rlpOutput);
CodeDelegationEncoder.encodeCodeDelegationInner(authorizationList, rlpOutput);
CodeDelegationTransactionEncoder.encodeCodeDelegationInner(
authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.DELEGATE_CODE.getSerializedType()), encoded);

@ -81,7 +81,7 @@ public class CodeDelegationTransactionDecoder {
final Address address = Address.wrap(input.readBytes());
final long nonce = input.readLongScalar();
final BigInteger yParity = input.readUInt256Scalar().toUnsignedBigInteger();
final byte yParity = (byte) input.readUnsignedByteScalar();
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();

@ -25,9 +25,9 @@ import java.util.List;
import org.apache.tuweni.bytes.Bytes;
public class CodeDelegationEncoder {
public class CodeDelegationTransactionEncoder {
private CodeDelegationEncoder() {
private CodeDelegationTransactionEncoder() {
// private constructor
}
@ -49,7 +49,7 @@ public class CodeDelegationEncoder {
final CodeDelegation payload, final RLPOutput rlpOutput) {
rlpOutput.startList();
encodeAuthorizationDetails(payload, rlpOutput);
rlpOutput.writeIntScalar(payload.signature().getRecId());
rlpOutput.writeUnsignedByte(payload.signature().getRecId());
rlpOutput.writeBigIntegerScalar(payload.signature().getR());
rlpOutput.writeBigIntegerScalar(payload.signature().getS());
rlpOutput.endList();

@ -41,7 +41,7 @@ public class TransactionEncoder {
TransactionType.BLOB,
BlobTransactionEncoder::encode,
TransactionType.DELEGATE_CODE,
CodeDelegationEncoder::encode);
CodeDelegationTransactionEncoder::encode);
private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.CodeDelegation;
import org.hyperledger.besu.ethereum.core.Transaction;
@ -89,6 +91,11 @@ public class CodeDelegationProcessor {
return;
}
if (codeDelegation.nonce() == MAX_NONCE) {
LOG.trace("Nonce of code delegation must be less than 2^64-1");
return;
}
final Optional<Address> authorizer = codeDelegation.authorizer();
if (authorizer.isEmpty()) {
LOG.trace("Invalid signature for code delegation");
@ -128,7 +135,9 @@ public class CodeDelegationProcessor {
result.incremenentAlreadyExistingDelegators();
}
evmWorldUpdater.authorizedCodeService().addDelegatedCode(authority, codeDelegation.address());
evmWorldUpdater
.authorizedCodeService()
.processDelegatedCodeAuthorization(authority, codeDelegation.address());
authority.incrementNonce();
}
}

@ -177,12 +177,6 @@ public class MainnetTransactionValidator implements TransactionValidator {
"Invalid signature for code delegation. S value must be less or equal than the half curve order.");
}
if (codeDelegation.nonce() == MAX_NONCE) {
return ValidationResult.invalid(
TransactionInvalidReason.NONCE_OVERFLOW,
"Nonce of code delegation must be less than 2^64-1");
}
if (codeDelegation.signature().getRecId() != 0
&& codeDelegation.signature().getRecId() != 1) {
return ValidationResult.invalid(

@ -30,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CodeDelegationEncoderTest {
class CodeDelegationTransactionEncoderTest {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@ -59,7 +59,7 @@ class CodeDelegationEncoderTest {
"3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99", 16),
(byte) 0));
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
@ -85,7 +85,7 @@ class CodeDelegationEncoderTest {
"25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031", 16),
(byte) 1));
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(
@ -111,7 +111,7 @@ class CodeDelegationEncoderTest {
"3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df", 16),
(byte) 1));
CodeDelegationEncoder.encodeSingleCodeDelegation(authorization, output);
CodeDelegationTransactionEncoder.encodeSingleCodeDelegation(authorization, output);
assertThat(output.encoded())
.isEqualTo(

@ -40,12 +40,20 @@ public class DelegatedCodeService {
}
/**
* Add the delegated code to the given account.
* Process the delegated code authorization. It will set the code to 0x ef0100 + delegated code
* address. If the address is 0, it will set the code to empty.
*
* @param account the account to which the delegated code is added.
* @param delegatedCodeAddress the address of the delegated code.
* @param delegatedCodeAddress the address of the target of the authorization.
*/
public void addDelegatedCode(final MutableAccount account, final Address delegatedCodeAddress) {
public void processDelegatedCodeAuthorization(
final MutableAccount account, final Address delegatedCodeAddress) {
// authorization to zero address removes any delegated code
if (delegatedCodeAddress.equals(Address.ZERO)) {
account.setCode(Bytes.EMPTY);
return;
}
account.setCode(Bytes.concatenate(DELEGATED_CODE_PREFIX, delegatedCodeAddress));
}

Loading…
Cancel
Save