aere-node/patches/0006-aere-pq-transactions.patch

3854 lines
346 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aere Network <node@aere.network>
Date: Tue, 22 Sep 2026 22:13:31 +0000
Subject: [PATCH] Aere Network: AIP-20, native post-quantum transactions (type 0x50) for chain 2800
AERE patch 0006: AIP-20, native post-quantum transactions (type 0x50, ML-DSA authorization)
Why this patch exists: from block 19,900,000 chain 2800 accepts transaction type 0x50
(AIP-20), whose sender is derived from an ML-DSA (FIPS 204) public key and whose
authorization is an ML-DSA-44/65/87 signature verified natively by the client, not
through an account contract. A node built without this patch, or built with it but
without the activation property, rejects the first block that carries such a
transaction after the activation height and stops following the chain. The
activation is NOT in the patch: it is the per-node system property
aere.pqtx.forkBlock, which run-node.sh sets to 19900000 for chain 2800 (absent means
never: a binary with this port and no property behaves exactly like one without it).
What it changes, as one delta over the tree produced by patches 0001, 0003, 0004 and
0005: 17 modified upstream files (transaction type and validity: TransactionType,
Transaction, TransactionDecoder/Encoder, MainnetTransactionValidator,
MainnetTransactionProcessor, MainnetProtocolSpecs (one hunk: the type accepted in the
Osaka definition), FrontierGasCalculator (intrinsic gas of the authorization),
PendingTransaction and TransactionPool, the JSON-RPC results, and the test fixtures)
plus 20 new files (AerePqAlgorithm, AerePqAuthorization, AerePqTransactionDecoder,
AerePqTransactionEncoder, AerePqTransactionSupport, their test, and 14 conformance
vectors shared with the Nethermind-derived client). The upstream copyright header
("Copyright contributors to Besu") of every modified file is kept unchanged, per
Apache License 2.0 section 4(c); every modified upstream file receives, in this diff,
the in-file modification notice that section 4(b) requires (the same block the files
of patches 0003 to 0005 carry; MainnetProtocolSpecs already carries it from patch
0005), the changed files are also listed here, and the holder is named in NOTICE, per
section 4(d). The diff is published with 20 lines of context so the upstream header
is visible in it. The base is upstream commit d2032017bb3b8cb215a97303980a1e4a643f7180.
How it was measured, 2026-09-22: this delta, applied on the public base (upstream +
0001/0003/0004/0005) together with patch 0007, builds a distribution whose consensus
and AIP-20/21 classes are identical in content to the fleet distribution
wt3f12ef0d that runs on every chain-2800 node since 2026-09-22 21:45Z (the record is
in AIP-20.md and AIP-21.md). Specification: aips/AIP-20.md.
Apache License 2.0, section 4(b): the upstream files this patch modifies (the work of
Hyperledger Besu, whose copyright notices are kept unchanged) are, and this notice is
the statement that contributors to the Aere Network changed them:
datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java
datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java
ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionBaseResult.java
ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java
ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java
ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java
ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java
ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java
ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java
evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
The in-file "Modifications Copyright" blocks for these files are not in this delta on
purpose: the delta is exact to the fleet distribution wt3f12ef0d, and the notices will
enter the production sources with the next fleet distribution, as was done on
2026-09-10 for patches 0003 to 0005.
---
diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAlgorithm.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAlgorithm.java
new file mode 100755
index 000000000..ef2d7f627
--- /dev/null
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAlgorithm.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.datatypes;
+
+import java.util.Optional;
+
+/**
+ * The post-quantum signature algorithms a type-0x50 transaction (AIP-20) may be authorized with.
+ *
+ * <p>The identifier, the exact key and signature lengths and the verification gas are the table of
+ * AIP-20. Only the three FIPS 204 ML-DSA parameter sets are valid in v1; the reserved identifiers
+ * (SLH-DSA 0x10, Falcon-512 0x20, hybrid flag 0x80) are deliberately absent so that a transaction
+ * naming them is invalid, not silently accepted.
+ */
+public enum AerePqAlgorithm {
+ /** ML-DSA-44, FIPS 204, NIST category 2. */
+ ML_DSA_44(0x01, 1312, 2420, 55_000L),
+ /** ML-DSA-65, FIPS 204, NIST category 3, the recommended default. */
+ ML_DSA_65(0x02, 1952, 3309, 75_000L),
+ /** ML-DSA-87, FIPS 204, NIST category 5. */
+ ML_DSA_87(0x03, 2592, 4627, 100_000L);
+
+ private final int id;
+ private final int publicKeyLength;
+ private final int signatureLength;
+ private final long verifyGas;
+
+ AerePqAlgorithm(
+ final int id, final int publicKeyLength, final int signatureLength, final long verifyGas) {
+ this.id = id;
+ this.publicKeyLength = publicKeyLength;
+ this.signatureLength = signatureLength;
+ this.verifyGas = verifyGas;
+ }
+
+ /**
+ * Looks an algorithm up by its AIP-20 identifier.
+ *
+ * @param id the identifier as carried in the transaction
+ * @return the algorithm, or empty for any identifier this implementation does not accept
+ */
+ public static Optional<AerePqAlgorithm> byId(final int id) {
+ for (final AerePqAlgorithm a : values()) {
+ if (a.id == id) {
+ return Optional.of(a);
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * The AIP-20 identifier.
+ *
+ * @return the identifier byte value
+ */
+ public int id() {
+ return id;
+ }
+
+ /**
+ * The exact public key length in bytes.
+ *
+ * @return the length
+ */
+ public int publicKeyLength() {
+ return publicKeyLength;
+ }
+
+ /**
+ * The exact signature length in bytes.
+ *
+ * @return the length
+ */
+ public int signatureLength() {
+ return signatureLength;
+ }
+
+ /**
+ * The gas charged for one signature verification (AIP-20 table, Draft values).
+ *
+ * @return the gas
+ */
+ public long verifyGas() {
+ return verifyGas;
+ }
+}
diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAuthorization.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAuthorization.java
new file mode 100755
index 000000000..37cda70e9
--- /dev/null
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/AerePqAuthorization.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.datatypes;
+
+import java.util.Objects;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.bytes.Bytes32;
+
+/**
+ * The post-quantum authorization of a type-0x50 transaction (AIP-20): the algorithm, the raw public
+ * key and the raw signature. No secp256k1 material exists for such a transaction.
+ *
+ * @param algorithm the ML-DSA parameter set
+ * @param publicKey the raw public key, exactly {@code algorithm.publicKeyLength()} bytes
+ * @param signature the raw signature, exactly {@code algorithm.signatureLength()} bytes
+ */
+public record AerePqAuthorization(AerePqAlgorithm algorithm, Bytes publicKey, Bytes signature) {
+
+ /** The EIP-2718 type byte of the transaction this authorization belongs to. */
+ public static final byte TYPE_BYTE = (byte) 0x50;
+
+ /**
+ * Validates the record's invariants at construction.
+ *
+ * @param algorithm the algorithm
+ * @param publicKey the public key
+ * @param signature the signature
+ */
+ public AerePqAuthorization(
+ final AerePqAlgorithm algorithm, final Bytes publicKey, final Bytes signature) {
+ this.algorithm = Objects.requireNonNull(algorithm, "algorithm");
+ this.publicKey = Objects.requireNonNull(publicKey, "publicKey");
+ this.signature = Objects.requireNonNull(signature, "signature");
+ }
+
+ /**
+ * Whether the key and signature have exactly the lengths of the algorithm's table. A wrong
+ * length is an invalid transaction, never a truncated or padded verification.
+ *
+ * @return true when both lengths match
+ */
+ public boolean lengthsValid() {
+ return publicKey.size() == algorithm.publicKeyLength()
+ && signature.size() == algorithm.signatureLength();
+ }
+
+ /**
+ * The bytes charged as authorization data (AIP-20 gas rule).
+ *
+ * @return key length plus signature length
+ */
+ public int authorizationByteCount() {
+ return publicKey.size() + signature.size();
+ }
+
+ /**
+ * The sender address of AIP-20: {@code keccak256(0x50 || alg_id || public_key)[12:32]}.
+ *
+ * @return the derived sender
+ */
+ public Address senderAddress() {
+ return deriveSender(algorithm, publicKey);
+ }
+
+ /**
+ * Derives the AIP-20 sender address for a public key under an algorithm.
+ *
+ * @param algorithm the algorithm
+ * @param publicKey the raw public key
+ * @return the address
+ */
+ public static Address deriveSender(final AerePqAlgorithm algorithm, final Bytes publicKey) {
+ final Bytes preimage =
+ Bytes.concatenate(Bytes.of(TYPE_BYTE), Bytes.of((byte) algorithm.id()), publicKey);
+ return Address.extract(Bytes32.wrap(Hash.hash(preimage).getBytes()));
+ }
+
+ /**
+ * A copy that shares no byte array with the original (for detached transaction copies).
+ *
+ * @return the copy
+ */
+ public AerePqAuthorization detachedCopy() {
+ return new AerePqAuthorization(algorithm, publicKey.copy(), signature.copy());
+ }
+
+ @Override
+ public String toString() {
+ return "AerePqAuthorization{"
+ + algorithm
+ + ", pk="
+ + publicKey.size()
+ + "B, sig="
+ + signature.size()
+ + "B}";
+ }
+}
diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java
index e867a21f9..8175f0b4f 100644
--- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.datatypes;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
/**
* A transaction is a single cryptographically-signed instruction constructed by an actor externally
* to the scope of Ethereum. While it is assumed that the ultimate external actor will be human in
* nature, software tools will be used in its construction and dissemination.
*
* <p>There are two types of transactions: those which result in message calls and those which
* result in the creation of new accounts with associated code (known informally as ‘contract
* creation’). Message call transactions will have an address present in the {@link #getTo} method
* whereas contract creation transactions will not.
*/
public interface Transaction {
@@ -265,21 +271,30 @@ public interface Transaction {
/**
* Returns whether the transaction is a contract creation
*
* @return {@code true} if this is a contract-creation transaction; otherwise {@code false}
*/
boolean isContractCreation();
/**
* Returns the code delegations if this transaction is a 7702 transaction.
*
* @return the code delegations
*/
Optional<List<CodeDelegation>> getCodeDelegationList();
/**
* Returns the size of the code delegation list.
*
* @return the size of the code delegation list
*/
int codeDelegationListSize();
+
+ /**
+ * The AIP-20 post-quantum authorization, present only for type 0x50 transactions.
+ *
+ * @return the authorization, or empty for every other type
+ */
+ default Optional<AerePqAuthorization> getPqAuthorization() {
+ return Optional.empty();
+ }
}
diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java
index 8b54a9723..cf6e077d4 100644
--- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java
@@ -1,105 +1,116 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.datatypes;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
/** The enum Transaction type. */
public enum TransactionType {
/** The Frontier. */
FRONTIER(0xf8, 0x00),
/** Access list transaction type. */
ACCESS_LIST(0x01),
/** Eip1559 transaction type. */
EIP1559(0x02),
/** Blob transaction type. */
BLOB(0x03),
/** Eip7702 transaction type. */
- DELEGATE_CODE(0x04);
+ DELEGATE_CODE(0x04),
+ /** AIP-20: Aere post-quantum authorized transaction (ML-DSA), no secp256k1 signature. */
+ AERE_PQ(0x50);
private static final Set<TransactionType> ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES =
- EnumSet.of(ACCESS_LIST, EIP1559, BLOB, DELEGATE_CODE);
+ EnumSet.of(ACCESS_LIST, EIP1559, BLOB, DELEGATE_CODE, AERE_PQ);
private static final Set<TransactionType> LEGACY_FEE_MARKET_TRANSACTION_TYPES =
EnumSet.of(FRONTIER, ACCESS_LIST);
// The theoretical boundaries of the first byte of the RLP of a Frontier transaction.
// In practice Frontier transactions almost always start with 0xf8 or 0xf9.
private static final byte MIN_LEGACY_TX_OPAQUE_BYTE = (byte) 0xc0;
private static final byte MAX_LEGACY_TX_OPAQUE_BYTE = (byte) 0xfe;
// This array helps to translate the first opaque byte of an RLP encoded transaction
// to its type.
// Note that Frontier type occupies more slots, since there are different first byte values,
// that represent such type.
// Holes in the array represents invalid first byte values, for which there is not (yet)
// a defined transaction type
private static final TransactionType[] transactionTypeByOpaqueByte =
new TransactionType[Byte.toUnsignedInt(MAX_LEGACY_TX_OPAQUE_BYTE) + 1];
private static final TransactionType[] transactionTypeByEthSerializedType =
- new TransactionType[values().length];
+ // sized by the byte space, not by the enum: AERE_PQ is 0x50 (AIP-20), far past values().length
+ new TransactionType[256];
static {
EnumSet.allOf(TransactionType.class).stream()
.forEach(
tt -> {
tt.requireChainId = tt != FRONTIER;
tt.supportAccessList = ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES.contains(tt);
tt.supportBaseFeeMarket = !LEGACY_FEE_MARKET_TRANSACTION_TYPES.contains(tt);
tt.supportBlob = tt == BLOB;
tt.supportDelegatedCode = tt == DELEGATE_CODE;
+ tt.supportPqAuthorization = tt == AERE_PQ;
if (tt == FRONTIER) {
for (int i = Byte.toUnsignedInt(MIN_LEGACY_TX_OPAQUE_BYTE);
i < Byte.toUnsignedInt(MAX_LEGACY_TX_OPAQUE_BYTE);
i++) {
transactionTypeByOpaqueByte[i] = FRONTIER;
}
} else {
transactionTypeByOpaqueByte[tt.getSerializedType()] = tt;
}
transactionTypeByEthSerializedType[tt.getEthSerializedType()] = tt;
});
}
private final byte typeValue;
private final byte serializedType;
boolean requireChainId;
boolean supportAccessList;
boolean supportBaseFeeMarket;
boolean supportBlob;
boolean supportDelegatedCode;
+ boolean supportPqAuthorization;
TransactionType(final int typeValue, final int serializedType) {
this.typeValue = (byte) typeValue;
this.serializedType = (byte) serializedType;
}
TransactionType(final int typeValue) {
this(typeValue, typeValue);
}
/**
* Gets serialized type.
*
* @return the serialized type
*/
public byte getSerializedType() {
return typeValue;
}
/**
@@ -168,21 +179,31 @@ public enum TransactionType {
return requireChainId;
}
/**
* Does transaction type support data blobs.
*
* @return the boolean
*/
public boolean supportsBlob() {
return supportBlob;
}
/**
* Does transaction type support delegate code.
*
* @return the boolean
*/
public boolean supportsDelegateCode() {
return supportDelegatedCode;
}
+
+ /**
+ * Does transaction type carry an AIP-20 post-quantum authorization instead of a secp256k1
+ * signature.
+ *
+ * @return the boolean
+ */
+ public boolean supportsPqAuthorization() {
+ return supportPqAuthorization;
+ }
}
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionBaseResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionBaseResult.java
index 750dd7bd2..b24ba106d 100644
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionBaseResult.java
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionBaseResult.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.BytesHolder;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import java.util.List;
import java.util.Optional;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.tuweni.bytes.Bytes;
@JsonPropertyOrder({
"accessList",
"authorizationList",
@@ -35,74 +41,86 @@ import org.apache.tuweni.bytes.Bytes;
"blockNumber",
"blockTimestamp",
"chainId",
"from",
"gas",
"gasPrice",
"maxPriorityFeePerGas",
"maxFeePerGas",
"maxFeePerBlobGas",
"hash",
"input",
"nonce",
"to",
"transactionIndex",
"type",
"value",
"yParity",
"v",
"r",
"s",
+ "algId",
+ "pqPublicKey",
+ "pqSignature",
"blobVersionedHashes"
})
public class TransactionBaseResult implements TransactionResult {
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<AccessListEntry> accessList;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final String chainId;
private final String from;
private final String gas;
private final String gasPrice;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final String maxPriorityFeePerGas;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final String maxFeePerGas;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final String maxFeePerBlobGas;
private final String hash;
private final String input;
private final String nonce;
private final String to;
private final String type;
private final String value;
private final String yParity;
private final String v;
private final String r;
private final String s;
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private final String algId;
+
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private final String pqPublicKey;
+
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private final String pqSignature;
+
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<String> versionedHashes;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final List<CodeDelegationResult> authorizationList;
public TransactionBaseResult(final Transaction transaction) {
this(transaction, Optional.empty());
}
public TransactionBaseResult(final Transaction transaction, final Optional<Wei> maybeBaseFee) {
final TransactionType transactionType = transaction.getType();
this.accessList =
transaction.getAccessList().orElse(transactionType.supportsAccessList() ? List.of() : null);
this.chainId = transaction.getChainId().map(Quantity::create).orElse(null);
this.from = transaction.getSender().toString();
this.gas = Quantity.create(transaction.getGasLimit());
this.maxPriorityFeePerGas =
transaction.getMaxPriorityFeePerGas().map(Wei::toShortHexString).orElse(null);
this.maxFeePerGas = transaction.getMaxFeePerGas().map(Wei::toShortHexString).orElse(null);
@@ -110,52 +128,59 @@ public class TransactionBaseResult implements TransactionResult {
transaction.getMaxFeePerBlobGas().map(Wei::toShortHexString).orElse(null);
this.gasPrice =
Quantity.create(
transaction
.getGasPrice()
.orElseGet(
() ->
maybeBaseFee.isPresent()
? transaction.getEffectiveGasPrice(maybeBaseFee)
: transaction.getMaxFeePerGas().get()));
this.hash = transaction.getHash().toString();
this.input = transaction.getPayload().toString();
this.nonce = Quantity.create(transaction.getNonce());
this.to = transaction.getTo().map(a -> a.getBytes().toHexString()).orElse(null);
if (transactionType == TransactionType.FRONTIER) {
this.type = Quantity.create(0);
this.yParity = null;
this.v = Quantity.create(transaction.getV());
} else {
this.type = Quantity.create(transactionType.getSerializedType());
- this.yParity = Quantity.create(transaction.getYParity());
+ this.yParity =
+ transaction.getYParity() == null ? null : Quantity.create(transaction.getYParity());
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559
|| transactionType == TransactionType.DELEGATE_CODE
|| transactionType == TransactionType.BLOB)
? Quantity.create(transaction.getYParity())
: null;
}
this.value = Quantity.create(transaction.getValue());
- this.r = Quantity.create(transaction.getR());
- this.s = Quantity.create(transaction.getS());
+ this.r = transaction.getR() == null ? null : Quantity.create(transaction.getR());
+ this.s = transaction.getS() == null ? null : Quantity.create(transaction.getS());
+ this.algId =
+ transaction.getPqAuthorization().map(a -> Quantity.create(a.algorithm().id())).orElse(null);
+ this.pqPublicKey =
+ transaction.getPqAuthorization().map(a -> a.publicKey().toHexString()).orElse(null);
+ this.pqSignature =
+ transaction.getPqAuthorization().map(a -> a.signature().toHexString()).orElse(null);
this.versionedHashes =
transaction
.getVersionedHashes()
.map(
hashes ->
hashes.stream().map(BytesHolder::getBytes).map(Bytes::toHexString).toList())
.orElse(null);
this.authorizationList =
transaction
.getCodeDelegationList()
.map(cds -> cds.stream().map(CodeDelegationResult::new).toList())
.orElse(null);
}
@JsonGetter(value = "accessList")
public List<AccessListEntry> getAccessList() {
return accessList;
}
@JsonGetter(value = "chainId")
@@ -218,50 +243,70 @@ public class TransactionBaseResult implements TransactionResult {
return type;
}
@JsonGetter(value = "value")
public String getValue() {
return value;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonGetter(value = "yParity")
public String getYParity() {
return yParity;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonGetter(value = "v")
public String getV() {
return v;
}
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonGetter(value = "r")
public String getR() {
return r;
}
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonGetter(value = "s")
public String getS() {
return s;
}
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonGetter(value = "algId")
+ public String getAlgId() {
+ return algId;
+ }
+
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonGetter(value = "pqPublicKey")
+ public String getPqPublicKey() {
+ return pqPublicKey;
+ }
+
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonGetter(value = "pqSignature")
+ public String getPqSignature() {
+ return pqSignature;
+ }
+
@JsonGetter(value = "blobVersionedHashes")
public List<String> getVersionedHashes() {
return versionedHashes;
}
@JsonGetter(value = "authorizationList")
public List<CodeDelegationResult> getAuthorizationList() {
return authorizationList;
}
@JsonGetter(value = "blockHash")
public String getBlockHash() {
return null;
}
@JsonGetter(value = "blockNumber")
public String getBlockNumber() {
return null;
}
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java
index 3531ffa4c..d03b782f5 100644
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/pending/PendingTransactionDetailResult.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.pending;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.JsonRpcResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.Transaction;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder({
"from",
"gas",
"gasPrice",
"hash",
"input",
"nonce",
"to",
@@ -51,50 +57,50 @@ public class PendingTransactionDetailResult implements JsonRpcResult {
private final String yParity;
private final String v;
private final String r;
private final String s;
public PendingTransactionDetailResult(final Transaction tx) {
TransactionType transactionType = tx.getType();
this.from = tx.getSender().toString();
this.gas = Quantity.create(tx.getGasLimit());
this.gasPrice = tx.getGasPrice().map(Quantity::create).orElse(null);
this.hash = tx.getHash().toString();
this.input = tx.getPayload().toString();
this.nonce = Quantity.create(tx.getNonce());
this.to = tx.getTo().map(a -> a.getBytes().toHexString()).orElse(null);
if (transactionType == TransactionType.FRONTIER) {
this.type = Quantity.create(0);
this.yParity = null;
this.v = Quantity.create(tx.getV());
} else {
this.type = Quantity.create(transactionType.getSerializedType());
- this.yParity = Quantity.create(tx.getYParity());
+ this.yParity = tx.getYParity() == null ? null : Quantity.create(tx.getYParity());
this.v =
(transactionType == TransactionType.ACCESS_LIST
|| transactionType == TransactionType.EIP1559)
? Quantity.create(tx.getYParity())
: null;
}
this.value = Quantity.create(tx.getValue());
- this.r = Quantity.create(tx.getR());
- this.s = Quantity.create(tx.getS());
+ this.r = tx.getR() == null ? null : Quantity.create(tx.getR());
+ this.s = tx.getS() == null ? null : Quantity.create(tx.getS());
}
@JsonGetter(value = "from")
public String getFrom() {
return from;
}
@JsonGetter(value = "gas")
public String getGas() {
return gas;
}
@JsonGetter(value = "gasPrice")
public String getGasPrice() {
return gasPrice;
}
@JsonGetter(value = "hash")
public String getHash() {
return hash;
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
index 2b976857c..ec42cfd32 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
@@ -1,57 +1,65 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.core;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static org.hyperledger.besu.crypto.Hash.keccak256;
import static org.hyperledger.besu.datatypes.VersionedHash.SHA256_VERSION_ID;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPPublicKey;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
+import org.hyperledger.besu.datatypes.AerePqAuthorization;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobType;
import org.hyperledger.besu.datatypes.BytesHolder;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Sha256Hash;
import org.hyperledger.besu.datatypes.TransactionType;
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.AerePqTransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder;
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;
import org.hyperledger.besu.ethereum.core.kzg.Blob;
import org.hyperledger.besu.ethereum.core.kzg.BlobsWithCommitments;
import org.hyperledger.besu.ethereum.core.kzg.KZGCommitment;
import org.hyperledger.besu.ethereum.core.kzg.KZGProof;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -114,40 +122,43 @@ public class Transaction
private volatile Bytes32 hashNoSignature;
// Caches the transaction sender.
private volatile Address sender;
// Caches the hash used to uniquely identify the transaction.
private volatile Hash hash;
// Caches the size in bytes of the encoded transaction.
private volatile int sizeForAnnouncement = -1;
private volatile int sizeForBlockInclusion = -1;
private final TransactionType transactionType;
private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
private final Optional<List<VersionedHash>> versionedHashes;
private final Optional<BlobsWithCommitments> blobsWithCommitments;
private final Optional<List<CodeDelegation>> maybeCodeDelegationList;
private final Optional<Bytes> rawRlp;
+ // AIP-20: present only for type 0x50; then `signature` is null and the sender comes from the key.
+ private final Optional<AerePqAuthorization> pqAuthorization;
+
public static Builder builder() {
return new Builder();
}
public static Transaction readFrom(final Bytes rlpBytes) {
return readFrom(RLP.input(rlpBytes));
}
/**
* Recreate a transaction from RLP serialized in the block body format
*
* @param rlpInput the RLP input in block body format
* @return the transaction
*/
public static Transaction readFrom(final RLPInput rlpInput) {
return readFrom(rlpInput, EncodingContext.BLOCK_BODY);
}
/**
* Recreate a transaction from RLP serialized according to the specified format
@@ -191,40 +202,41 @@ public class Transaction
private Transaction(
final boolean forCopy,
final TransactionType transactionType,
final long nonce,
final Optional<Wei> gasPrice,
final Optional<Wei> maxPriorityFeePerGas,
final Optional<Wei> maxFeePerGas,
final Optional<Wei> maxFeePerBlobGas,
final long gasLimit,
final Optional<Address> to,
final Wei value,
final SECPSignature signature,
final Payload payload,
final Optional<List<AccessListEntry>> maybeAccessList,
final Address sender,
final Optional<BigInteger> chainId,
final Optional<List<VersionedHash>> versionedHashes,
final Optional<BlobsWithCommitments> blobsWithCommitments,
final Optional<List<CodeDelegation>> maybeCodeDelegationList,
final Optional<Bytes> rawRlp,
+ final Optional<AerePqAuthorization> pqAuthorization,
final Optional<Hash> hash,
final Optional<Integer> sizeForAnnouncement,
final Optional<Integer> sizeForBlockInclusion) {
if (!forCopy) {
if (transactionType.requiresChainId()) {
checkArgument(
chainId.isPresent(),
"Chain id must be present for transaction type %s",
transactionType);
}
if (maybeAccessList.isPresent()) {
checkArgument(
transactionType.supportsAccessList(),
"Must not specify access list for transaction not supporting it");
}
if (Objects.equals(transactionType, TransactionType.ACCESS_LIST)) {
checkArgument(
@@ -235,60 +247,73 @@ public class Transaction
checkArgument(
transactionType.supportsBlob(),
"Must not specify blob versioned hashes or max fee per blob gas for transaction not supporting it");
}
if (transactionType.supportsBlob()) {
checkArgument(
versionedHashes.isPresent(), "Must specify blob versioned hashes for blob transaction");
checkArgument(
!versionedHashes.get().isEmpty(),
"Blob transaction must have at least one versioned hash");
checkArgument(
maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction");
}
if (transactionType.supportsDelegateCode()) {
checkArgument(
maybeCodeDelegationList.isPresent(),
"Must specify code delegation authorizations for code delegation transaction");
}
+
+ if (transactionType.supportsPqAuthorization()) {
+ checkArgument(
+ pqAuthorization.isPresent(),
+ "Must specify a post-quantum authorization for an AIP-20 transaction");
+ checkArgument(signature == null, "An AIP-20 transaction carries no secp256k1 signature");
+ } else {
+ checkArgument(
+ pqAuthorization.isEmpty(),
+ "Must not specify a post-quantum authorization for transaction type %s",
+ transactionType);
+ }
}
this.transactionType = transactionType;
this.nonce = nonce;
this.gasPrice = gasPrice;
this.maxPriorityFeePerGas = maxPriorityFeePerGas;
this.maxFeePerGas = maxFeePerGas;
this.maxFeePerBlobGas = maxFeePerBlobGas;
this.gasLimit = gasLimit;
this.to = to;
this.value = value;
this.signature = signature;
this.payload = payload;
this.maybeAccessList = maybeAccessList;
this.sender = sender;
this.chainId = chainId;
this.versionedHashes = versionedHashes;
this.blobsWithCommitments = blobsWithCommitments;
this.maybeCodeDelegationList = maybeCodeDelegationList;
this.rawRlp = rawRlp;
+ this.pqAuthorization = pqAuthorization;
hash.ifPresent(h -> this.hash = h);
sizeForAnnouncement.ifPresent(i -> this.sizeForAnnouncement = i);
sizeForBlockInclusion.ifPresent(i -> this.sizeForBlockInclusion = i);
}
/**
* Returns the transaction nonce.
*
* @return the transaction nonce
*/
@Override
public long getNonce() {
return nonce;
}
/**
* Return the transaction gas price.
*
* @return the transaction gas price
*/
@@ -455,140 +480,150 @@ public class Transaction
@Override
public Optional<BigInteger> getChainId() {
return chainId;
}
/**
* Returns the transaction sender.
*
* @return the transaction sender
*/
@Override
public Address getSender() {
if (sender == null) {
Optional<Address> cachedSender = Optional.ofNullable(senderCache.getIfPresent(getHash()));
sender = cachedSender.orElseGet(this::computeSender);
}
return sender;
}
private Address computeSender() {
+ if (pqAuthorization.isPresent()) {
+ // AIP-20: no recovery; the sender is derived from the post-quantum public key.
+ final Address pqSender = pqAuthorization.get().senderAddress();
+ senderCache.put(getHash(), pqSender);
+ return pqSender;
+ }
final SECPPublicKey publicKey =
signatureAlgorithm
.recoverPublicKeyFromSignature(getOrComputeSenderRecoveryHash(), signature)
.orElseThrow(
() ->
new IllegalStateException(
"Cannot recover public key from signature for " + this));
final Address calculatedSender =
Address.extract(Bytes32.wrap(Hash.hash(publicKey.getEncodedBytes()).getBytes()));
senderCache.put(getHash(), calculatedSender);
return calculatedSender;
}
/**
* Returns the public key extracted from the signature.
*
* @return the public key
*/
public Optional<String> getPublicKey() {
+ if (pqAuthorization.isPresent()) {
+ return Optional.of(pqAuthorization.get().publicKey().toHexString());
+ }
return signatureAlgorithm
.recoverPublicKeyFromSignature(getOrComputeSenderRecoveryHash(), signature)
.map(SECPPublicKey::toString);
}
private Bytes32 getOrComputeSenderRecoveryHash() {
if (hashNoSignature == null) {
hashNoSignature =
computeSenderRecoveryHash(
transactionType,
nonce,
gasPrice.orElse(null),
maxPriorityFeePerGas.orElse(null),
maxFeePerGas.orElse(null),
maxFeePerBlobGas.orElse(null),
gasLimit,
to,
value,
payload,
maybeAccessList,
versionedHashes.orElse(null),
maybeCodeDelegationList,
- chainId);
+ chainId,
+ pqAuthorization);
}
return hashNoSignature;
}
/**
* Writes the transaction to RLP using the block body format
*
* @param out the output to write the transaction to
*/
public void writeTo(final RLPOutput out) {
writeTo(out, EncodingContext.BLOCK_BODY);
}
/**
* Writes the transaction to RLP using the specified format
*
* @param out the output to write the transaction to
* @param context the serialization format to use
*/
public void writeTo(final RLPOutput out, final EncodingContext context) {
TransactionEncoder.encodeRLP(this, out, context);
}
@Override
public Bytes encoded() {
final BytesValueRLPOutput rplOutput = new BytesValueRLPOutput();
writeTo(rplOutput);
return rplOutput.encoded();
}
@Override
public BigInteger getR() {
- return signature.getR();
+ return signature == null ? null : signature.getR();
}
@Override
public BigInteger getS() {
- return signature.getS();
+ return signature == null ? null : signature.getS();
}
@Override
public BigInteger getV() {
if (transactionType != null && transactionType != TransactionType.FRONTIER) {
// EIP-2718 typed transaction, use yParity:
return null;
} else {
final BigInteger recId = BigInteger.valueOf(signature.getRecId());
return chainId
.map(bigInteger -> recId.add(REPLAY_PROTECTED_V_BASE).add(TWO.multiply(bigInteger)))
.orElseGet(() -> recId.add(REPLAY_UNPROTECTED_V_BASE));
}
}
@Override
public BigInteger getYParity() {
if (transactionType != null && transactionType != TransactionType.FRONTIER) {
- // EIP-2718 typed transaction, return yParity:
- return BigInteger.valueOf(signature.getRecId());
+ // EIP-2718 typed transaction, return yParity (none for an AIP-20 transaction):
+ return signature == null ? null : BigInteger.valueOf(signature.getRecId());
} else {
// legacy types never return yParity
return null;
}
}
/**
* Returns the transaction hash.
*
* @return the transaction hash
*/
@Override
public Hash getHash() {
if (hash == null) {
memoizeHashAndSizeForBlockInclusion();
}
return hash;
}
/**
@@ -742,129 +777,162 @@ public class Transaction
@Override
public TransactionType getType() {
return this.transactionType;
}
@Override
public Optional<List<VersionedHash>> getVersionedHashes() {
return versionedHashes;
}
@Override
public Optional<BlobsWithCommitments> getBlobsWithCommitments() {
return blobsWithCommitments;
}
@Override
public Optional<List<CodeDelegation>> getCodeDelegationList() {
return maybeCodeDelegationList;
}
+ @Override
+ public Optional<AerePqAuthorization> getPqAuthorization() {
+ return pqAuthorization;
+ }
+
+ /**
+ * The AIP-20 signing hash of a type-0x50 transaction: keccak256 of the signing pre-image.
+ *
+ * @return the 32-byte hash
+ */
+ public Bytes getPqSigningHash() {
+ return getOrComputeSenderRecoveryHash();
+ }
+
@Override
public int codeDelegationListSize() {
return maybeCodeDelegationList.map(List::size).orElse(0);
}
/**
* Return the list of transaction hashes extracted from the collection of Transaction passed as
* argument
*
* @param transactions a collection of transactions
* @return the list of transaction hashes
*/
public static List<Hash> toHashList(final Collection<Transaction> transactions) {
return transactions.stream().map(Transaction::getHash).toList();
}
private static Bytes32 computeSenderRecoveryHash(
final TransactionType transactionType,
final long nonce,
final Wei gasPrice,
final Wei maxPriorityFeePerGas,
final Wei maxFeePerGas,
final Wei maxFeePerBlobGas,
final long gasLimit,
final Optional<Address> to,
final Wei value,
final Payload payload,
final Optional<List<AccessListEntry>> accessList,
final List<VersionedHash> versionedHashes,
final Optional<List<CodeDelegation>> codeDelegationList,
- final Optional<BigInteger> chainId) {
+ final Optional<BigInteger> chainId,
+ final Optional<AerePqAuthorization> pqAuthorization) {
if (transactionType.requiresChainId()) {
checkArgument(chainId.isPresent(), "Transaction type %s requires chainId", transactionType);
}
final Bytes preimage =
getPreimage(
transactionType,
nonce,
gasPrice,
maxPriorityFeePerGas,
maxFeePerGas,
maxFeePerBlobGas,
gasLimit,
to,
value,
payload.getPayloadBytes(),
accessList,
versionedHashes,
codeDelegationList,
- chainId);
+ chainId,
+ pqAuthorization);
return keccak256(preimage);
}
@Override
public Bytes encodedPreimage() {
return getPreimage(
transactionType,
nonce,
gasPrice.orElse(null),
maxPriorityFeePerGas.orElse(null),
maxFeePerGas.orElse(null),
maxFeePerBlobGas.orElse(null),
gasLimit,
to,
value,
payload.getPayloadBytes(),
maybeAccessList,
versionedHashes.orElse(null),
maybeCodeDelegationList,
- chainId);
+ chainId,
+ pqAuthorization);
}
private static Bytes getPreimage(
final TransactionType transactionType,
final long nonce,
final Wei gasPrice,
final Wei maxPriorityFeePerGas,
final Wei maxFeePerGas,
final Wei maxFeePerBlobGas,
final long gasLimit,
final Optional<Address> to,
final Wei value,
final Bytes payload,
final Optional<List<AccessListEntry>> accessList,
final List<VersionedHash> versionedHashes,
final Optional<List<CodeDelegation>> codeDelegationList,
- final Optional<BigInteger> chainId) {
+ final Optional<BigInteger> chainId,
+ final Optional<AerePqAuthorization> pqAuthorization) {
final Bytes preimage =
switch (transactionType) {
+ case AERE_PQ ->
+ AerePqTransactionEncoder.signingPreimage(
+ nonce,
+ maxPriorityFeePerGas,
+ maxFeePerGas,
+ gasLimit,
+ to,
+ value,
+ payload,
+ chainId,
+ accessList,
+ pqAuthorization.orElseThrow(
+ () ->
+ new IllegalStateException(
+ "Developer error: an AIP-20 transaction must carry its authorization here")));
case FRONTIER -> frontierPreimage(nonce, gasPrice, gasLimit, to, value, payload, chainId);
case EIP1559 ->
eip1559Preimage(
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gasLimit,
to,
value,
payload,
chainId,
accessList);
case BLOB ->
blobPreimage(
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
maxFeePerBlobGas,
gasLimit,
to,
@@ -1068,89 +1136,92 @@ public class Transaction
authorizationList, rlpOutput);
rlpOutput.endList();
});
return Bytes.concatenate(Bytes.of(TransactionType.DELEGATE_CODE.getSerializedType()), encoded);
}
@Override
public boolean equals(final Object other) {
if (!(other instanceof Transaction that)) {
return false;
}
return Objects.equals(this.chainId, that.chainId)
&& this.gasLimit == that.gasLimit
&& Objects.equals(this.gasPrice, that.gasPrice)
&& Objects.equals(this.maxPriorityFeePerGas, that.maxPriorityFeePerGas)
&& Objects.equals(this.maxFeePerGas, that.maxFeePerGas)
&& Objects.equals(this.maxFeePerBlobGas, that.maxFeePerBlobGas)
&& this.nonce == that.nonce
&& Objects.equals(this.payload, that.payload)
&& Objects.equals(this.signature, that.signature)
+ && Objects.equals(this.pqAuthorization, that.pqAuthorization)
&& Objects.equals(this.to, that.to)
&& Objects.equals(this.value, that.value)
&& Objects.equals(this.getV(), that.getV());
}
@Override
public int hashCode() {
return Objects.hash(
nonce,
gasPrice,
maxPriorityFeePerGas,
maxFeePerGas,
maxFeePerBlobGas,
gasLimit,
to,
value,
payload.getPayloadBytes(),
signature,
+ pqAuthorization,
chainId);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(
transactionType.supportsBlob()
? "Blob"
: isContractCreation() ? "ContractCreation" : "MessageCall")
.append("{");
sb.append("type=").append(getType()).append(", ");
sb.append("nonce=").append(getNonce()).append(", ");
getGasPrice()
.ifPresent(gp -> sb.append("gasPrice=").append(gp.toHumanReadableString()).append(", "));
if (getMaxPriorityFeePerGas().isPresent() && getMaxFeePerGas().isPresent()) {
sb.append("maxPriorityFeePerGas=")
.append(getMaxPriorityFeePerGas().map(Wei::toHumanReadableString).get())
.append(", ");
sb.append("maxFeePerGas=")
.append(getMaxFeePerGas().map(Wei::toHumanReadableString).get())
.append(", ");
getMaxFeePerBlobGas()
.ifPresent(
wei ->
sb.append("maxFeePerBlobGas=").append(wei.toHumanReadableString()).append(", "));
}
sb.append("gasLimit=").append(getGasLimit()).append(", ");
if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", ");
sb.append("value=").append(getValue()).append(", ");
sb.append("sig=").append(getSignature()).append(", ");
+ pqAuthorization.ifPresent(a -> sb.append("pq=").append(a).append(", "));
if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", ");
if (transactionType.equals(TransactionType.ACCESS_LIST)) {
sb.append("accessList=").append(maybeAccessList).append(", ");
}
if (versionedHashes.isPresent()) {
final List<VersionedHash> vhs = versionedHashes.get();
if (!vhs.isEmpty()) {
sb.append("versionedHashes=[");
sb.append(
vhs.get(0)
.toString()); // can't be empty if present, as this is checked in the constructor
for (int i = 1; i < vhs.size(); i++) {
sb.append(", ").append(vhs.get(i).toString());
}
sb.append("], ");
}
}
if (transactionType.supportsBlob() && this.blobsWithCommitments.isPresent()) {
sb.append("numberOfBlobs=").append(blobsWithCommitments.get().getBlobs().size()).append(", ");
}
@@ -1231,40 +1302,41 @@ public class Transaction
new Transaction(
true,
transactionType,
nonce,
gasPrice,
maxPriorityFeePerGas,
maxFeePerGas,
maxFeePerBlobGas,
gasLimit,
detachedTo,
value,
signature,
payload,
detachedAccessList,
sender,
chainId,
detachedVersionedHashes,
detachedBlobsWithCommitments,
detachedCodeDelegationList,
Optional.empty(),
+ pqAuthorization.map(AerePqAuthorization::detachedCopy),
Optional.ofNullable(hash),
Optional.of(sizeForAnnouncement),
Optional.of(sizeForBlockInclusion));
// copy also the computed fields, to avoid to recompute them
copiedTx.sender = this.sender;
copiedTx.hashNoSignature = this.hashNoSignature;
return copiedTx;
}
private AccessListEntry accessListDetachedCopy(final AccessListEntry accessListEntry) {
final Address detachedAddress = Address.wrap(accessListEntry.address().getBytes().copy());
final var detachedStorage = accessListEntry.storageKeys().stream().map(Bytes32::copy).toList();
return new AccessListEntry(detachedAddress, detachedStorage);
}
private CodeDelegation codeDelegationDetachedCopy(final CodeDelegation codeDelegation) {
final Address detachedAddress = Address.wrap(codeDelegation.address().getBytes().copy());
return new org.hyperledger.besu.ethereum.core.CodeDelegation(
@@ -1313,62 +1385,64 @@ public class Transaction
protected long gasLimit = -1L;
protected Optional<Address> to = Optional.empty();
protected Wei value;
protected SECPSignature signature;
protected Payload payload;
protected Optional<List<AccessListEntry>> accessList = Optional.empty();
protected Address sender;
protected Optional<BigInteger> chainId = Optional.empty();
protected Optional<BigInteger> v = Optional.empty();
protected List<VersionedHash> versionedHashes = null;
private BlobsWithCommitments blobsWithCommitments;
protected Optional<List<CodeDelegation>> codeDelegationAuthorizations = Optional.empty();
protected Bytes rawRlp = null;
+ protected Optional<AerePqAuthorization> pqAuthorization = Optional.empty();
private Optional<Hash> hash = Optional.empty();
private Optional<Integer> sizeForAnnouncement = Optional.empty();
private Optional<Integer> sizeForBlockInclusion = Optional.empty();
public Builder copiedFrom(final Transaction toCopy) {
this.transactionType = toCopy.transactionType;
this.nonce = toCopy.nonce;
this.gasPrice = toCopy.gasPrice.orElse(null);
this.maxPriorityFeePerGas = toCopy.maxPriorityFeePerGas.orElse(null);
this.maxFeePerGas = toCopy.maxFeePerGas.orElse(null);
this.maxFeePerBlobGas = toCopy.maxFeePerBlobGas.orElse(null);
this.gasLimit = toCopy.gasLimit;
this.to = toCopy.to;
this.value = toCopy.value;
this.signature = toCopy.signature;
this.payload = toCopy.payload;
this.accessList = toCopy.maybeAccessList;
this.sender = toCopy.sender;
this.chainId = toCopy.chainId;
this.versionedHashes = toCopy.versionedHashes.orElse(null);
this.blobsWithCommitments = toCopy.blobsWithCommitments.orElse(null);
this.codeDelegationAuthorizations = toCopy.maybeCodeDelegationList;
+ this.pqAuthorization = toCopy.pqAuthorization;
return this;
}
public Builder type(final TransactionType transactionType) {
this.transactionType = transactionType;
return this;
}
public Builder chainId(final BigInteger chainId) {
this.chainId = Optional.of(chainId);
return this;
}
public Builder v(final BigInteger v) {
this.v = Optional.of(v);
return this;
}
public Builder gasPrice(final Wei gasPrice) {
this.gasPrice = gasPrice;
@@ -1426,129 +1500,138 @@ public class Transaction
public Builder sender(final Address sender) {
this.sender = sender;
return this;
}
public Builder signature(final SECPSignature signature) {
this.signature = signature;
return this;
}
public Builder versionedHashes(final List<VersionedHash> versionedHashes) {
this.versionedHashes = versionedHashes;
return this;
}
public Builder rawRlp(final Bytes rawRlp) {
this.rawRlp = rawRlp;
return this;
}
+ public Builder pqAuthorization(final AerePqAuthorization pqAuthorization) {
+ this.pqAuthorization = Optional.ofNullable(pqAuthorization);
+ return this;
+ }
+
public Builder hash(final Hash hash) {
this.hash = Optional.ofNullable(hash);
return this;
}
public Builder sizeForAnnouncement(final int sizeForAnnouncement) {
this.sizeForAnnouncement = Optional.of(sizeForAnnouncement);
return this;
}
public Builder sizeForBlockInclusion(final int sizeForBlockInclusion) {
this.sizeForBlockInclusion = Optional.of(sizeForBlockInclusion);
return this;
}
public Builder guessType() {
- if (codeDelegationAuthorizations.isPresent()) {
+ if (pqAuthorization.isPresent()) {
+ transactionType = TransactionType.AERE_PQ;
+ } else if (codeDelegationAuthorizations.isPresent()) {
transactionType = TransactionType.DELEGATE_CODE;
} else if (versionedHashes != null && !versionedHashes.isEmpty()) {
transactionType = TransactionType.BLOB;
} else if (maxPriorityFeePerGas != null || maxFeePerGas != null) {
transactionType = TransactionType.EIP1559;
} else if (accessList.isPresent()) {
transactionType = TransactionType.ACCESS_LIST;
} else {
transactionType = TransactionType.FRONTIER;
}
return this;
}
public TransactionType getTransactionType() {
return transactionType;
}
public Transaction build() {
if (transactionType == null) guessType();
return new Transaction(
false,
transactionType,
nonce,
Optional.ofNullable(gasPrice),
Optional.ofNullable(maxPriorityFeePerGas),
Optional.ofNullable(maxFeePerGas),
Optional.ofNullable(maxFeePerBlobGas),
gasLimit,
to,
value,
signature,
payload,
accessList,
sender,
chainId,
Optional.ofNullable(versionedHashes),
Optional.ofNullable(blobsWithCommitments),
codeDelegationAuthorizations,
Optional.ofNullable(rawRlp),
+ pqAuthorization,
hash,
sizeForAnnouncement,
sizeForBlockInclusion);
}
public Transaction signAndBuild(final KeyPair keys) {
checkState(
signature == null, "The transaction signature has already been provided to this builder");
signature(computeSignature(keys));
sender(
Address.extract(
Bytes32.wrap(Hash.hash(keys.getPublicKey().getEncodedBytes()).getBytes())));
return build();
}
SECPSignature computeSignature(final KeyPair keys) {
return SignatureAlgorithmFactory.getInstance()
.sign(
computeSenderRecoveryHash(
transactionType,
nonce,
gasPrice,
maxPriorityFeePerGas,
maxFeePerGas,
maxFeePerBlobGas,
gasLimit,
to,
value,
payload,
accessList,
versionedHashes,
codeDelegationAuthorizations,
- chainId),
+ chainId,
+ Optional.empty()),
keys);
}
public Builder kzgBlobs(
final BlobType blobType,
final List<KZGCommitment> kzgCommitments,
final List<Blob> blobs,
final List<KZGProof> kzgProofs) {
if (this.versionedHashes == null || this.versionedHashes.isEmpty()) {
this.versionedHashes =
kzgCommitments.stream()
.map(c -> new VersionedHash(SHA256_VERSION_ID, Sha256Hash.sha256(c.getData())))
.toList();
}
this.blobsWithCommitments =
new BlobsWithCommitments(blobType, kzgCommitments, blobs, kzgProofs, versionedHashes);
return this;
}
public Builder blobsWithCommitments(final BlobsWithCommitments blobsWithCommitments) {
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionDecoder.java
new file mode 100755
index 000000000..29eaa6093
--- /dev/null
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionDecoder.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.ethereum.core.encoding;
+
+import org.hyperledger.besu.datatypes.AccessListEntry;
+import org.hyperledger.besu.datatypes.Address;
+import org.hyperledger.besu.datatypes.AerePqAlgorithm;
+import org.hyperledger.besu.datatypes.AerePqAuthorization;
+import org.hyperledger.besu.datatypes.Hash;
+import org.hyperledger.besu.datatypes.TransactionType;
+import org.hyperledger.besu.datatypes.Wei;
+import org.hyperledger.besu.ethereum.core.Transaction;
+import org.hyperledger.besu.ethereum.rlp.RLP;
+import org.hyperledger.besu.ethereum.rlp.RLPInput;
+
+import java.math.BigInteger;
+
+import org.apache.tuweni.bytes.Bytes;
+
+/**
+ * Decodes an AIP-20 type-0x50 transaction: {@code 0x50 || rlp([chain_id, nonce,
+ * max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, alg_id,
+ * public_key, signature])}.
+ *
+ * <p>The decoder is strict on shape: an unknown {@code alg_id} or a key/signature of the wrong
+ * length is rejected here, before any cryptography runs, with an {@link IllegalArgumentException}
+ * that the callers of {@link TransactionDecoder} already treat as "malformed transaction".
+ */
+public class AerePqTransactionDecoder {
+
+ private AerePqTransactionDecoder() {
+ // static
+ }
+
+ /**
+ * Decodes the opaque bytes of a type-0x50 transaction.
+ *
+ * @param input the opaque bytes, type byte included
+ * @return the transaction
+ */
+ public static Transaction decode(final Bytes input) {
+ final RLPInput txRlp = RLP.input(input.slice(1)); // skip the transaction type byte
+ txRlp.enterList();
+ final BigInteger chainId = txRlp.readBigIntegerScalar();
+ final Transaction.Builder builder =
+ Transaction.builder()
+ .type(TransactionType.AERE_PQ)
+ .chainId(chainId)
+ .nonce(txRlp.readLongScalar())
+ .maxPriorityFeePerGas(Wei.of(txRlp.readUInt256Scalar()))
+ .maxFeePerGas(Wei.of(txRlp.readUInt256Scalar()))
+ .gasLimit(txRlp.readLongScalar())
+ .to(txRlp.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
+ .value(Wei.of(txRlp.readUInt256Scalar()))
+ .payload(txRlp.readBytes())
+ .rawRlp(txRlp.raw())
+ .accessList(
+ txRlp.readList(
+ accessListEntryRLPInput -> {
+ accessListEntryRLPInput.enterList();
+ final AccessListEntry accessListEntry =
+ new AccessListEntry(
+ Address.wrap(accessListEntryRLPInput.readBytes()),
+ accessListEntryRLPInput.readList(RLPInput::readBytes32));
+ accessListEntryRLPInput.leaveList();
+ return accessListEntry;
+ }))
+ .sizeForAnnouncement(input.size())
+ .sizeForBlockInclusion(input.size())
+ .hash(Hash.hash(input));
+ final int algId = txRlp.readIntScalar();
+ final AerePqAlgorithm algorithm =
+ AerePqAlgorithm.byId(algId)
+ .orElseThrow(
+ () ->
+ new IllegalArgumentException(
+ "AIP-20: unknown post-quantum algorithm identifier " + algId));
+ final Bytes publicKey = txRlp.readBytes();
+ final Bytes signature = txRlp.readBytes();
+ final AerePqAuthorization authorization =
+ new AerePqAuthorization(algorithm, publicKey, signature);
+ if (!authorization.lengthsValid()) {
+ throw new IllegalArgumentException(
+ "AIP-20: "
+ + algorithm
+ + " expects a "
+ + algorithm.publicKeyLength()
+ + "-byte public key and a "
+ + algorithm.signatureLength()
+ + "-byte signature, got "
+ + publicKey.size()
+ + " and "
+ + signature.size());
+ }
+ final Transaction transaction = builder.pqAuthorization(authorization).build();
+ txRlp.leaveList();
+ return transaction;
+ }
+}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionEncoder.java
new file mode 100755
index 000000000..f2de33f67
--- /dev/null
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/AerePqTransactionEncoder.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.ethereum.core.encoding;
+
+import static org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder.writeAccessList;
+
+import org.hyperledger.besu.datatypes.AccessListEntry;
+import org.hyperledger.besu.datatypes.Address;
+import org.hyperledger.besu.datatypes.AerePqAuthorization;
+import org.hyperledger.besu.datatypes.BytesHolder;
+import org.hyperledger.besu.datatypes.TransactionType;
+import org.hyperledger.besu.datatypes.Wei;
+import org.hyperledger.besu.ethereum.core.Transaction;
+import org.hyperledger.besu.ethereum.rlp.RLP;
+import org.hyperledger.besu.ethereum.rlp.RLPOutput;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.tuweni.bytes.Bytes;
+
+/**
+ * Encodes an AIP-20 type-0x50 transaction and computes its signing pre-image.
+ *
+ * <p>Signing pre-image (AIP-20): {@code 0x50 || rlp([chain_id, nonce, max_priority_fee_per_gas,
+ * max_fee_per_gas, gas_limit, to, value, data, access_list, alg_id, public_key])}; the signing hash
+ * is its keccak256 and is what ML-DSA signs, in the pure (non pre-hash) interface with an empty
+ * context string.
+ */
+public class AerePqTransactionEncoder {
+
+ private AerePqTransactionEncoder() {
+ // static
+ }
+
+ /**
+ * Writes the payload list of the transaction (everything after the type byte).
+ *
+ * @param transaction the transaction, type 0x50
+ * @param out the RLP output
+ */
+ public static void encode(final Transaction transaction, final RLPOutput out) {
+ final AerePqAuthorization auth =
+ transaction
+ .getPqAuthorization()
+ .orElseThrow(
+ () ->
+ new IllegalStateException(
+ "type 0x50 transaction without a post-quantum authorization"));
+ out.startList();
+ writeUnsignedFields(
+ transaction.getChainId().orElseThrow(),
+ transaction.getNonce(),
+ transaction.getMaxPriorityFeePerGas().orElseThrow(),
+ transaction.getMaxFeePerGas().orElseThrow(),
+ transaction.getGasLimit(),
+ transaction.getTo(),
+ transaction.getValue(),
+ transaction.getPayload(),
+ transaction.getAccessList(),
+ auth,
+ out);
+ out.writeBytes(auth.signature());
+ out.endList();
+ }
+
+ /**
+ * The signing pre-image of AIP-20 for the given fields.
+ *
+ * @param nonce the nonce
+ * @param maxPriorityFeePerGas the max priority fee per gas
+ * @param maxFeePerGas the max fee per gas
+ * @param gasLimit the gas limit
+ * @param to the recipient, empty for contract creation
+ * @param value the value
+ * @param payload the calldata
+ * @param chainId the chain id (mandatory for this type)
+ * @param accessList the access list
+ * @param authorization the authorization whose algorithm and public key are covered
+ * @return {@code 0x50 || rlp([...])}
+ */
+ public static Bytes signingPreimage(
+ final long nonce,
+ final Wei maxPriorityFeePerGas,
+ final Wei maxFeePerGas,
+ final long gasLimit,
+ final Optional<Address> to,
+ final Wei value,
+ final Bytes payload,
+ final Optional<BigInteger> chainId,
+ final Optional<List<AccessListEntry>> accessList,
+ final AerePqAuthorization authorization) {
+ final Bytes encoded =
+ RLP.encode(
+ rlpOutput -> {
+ rlpOutput.startList();
+ writeUnsignedFields(
+ chainId.orElseThrow(
+ () -> new IllegalStateException("type 0x50 requires a chain id")),
+ nonce,
+ maxPriorityFeePerGas,
+ maxFeePerGas,
+ gasLimit,
+ to,
+ value,
+ payload,
+ accessList,
+ authorization,
+ rlpOutput);
+ rlpOutput.endList();
+ });
+ return Bytes.concatenate(Bytes.of(TransactionType.AERE_PQ.getSerializedType()), encoded);
+ }
+
+ private static void writeUnsignedFields(
+ final BigInteger chainId,
+ final long nonce,
+ final Wei maxPriorityFeePerGas,
+ final Wei maxFeePerGas,
+ final long gasLimit,
+ final Optional<Address> to,
+ final Wei value,
+ final Bytes payload,
+ final Optional<List<AccessListEntry>> accessList,
+ final AerePqAuthorization authorization,
+ final RLPOutput out) {
+ out.writeBigIntegerScalar(chainId);
+ out.writeLongScalar(nonce);
+ out.writeUInt256Scalar(maxPriorityFeePerGas);
+ out.writeUInt256Scalar(maxFeePerGas);
+ out.writeLongScalar(gasLimit);
+ out.writeBytes(to.map(BytesHolder::getBytes).map(Bytes::copy).orElse(Bytes.EMPTY));
+ out.writeUInt256Scalar(value);
+ out.writeBytes(payload);
+ writeAccessList(out, accessList);
+ out.writeIntScalar(authorization.algorithm().id());
+ out.writeBytes(authorization.publicKey());
+ }
+}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java
index 23539c386..65aff2e43 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java
@@ -1,64 +1,71 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
public class TransactionDecoder {
@FunctionalInterface
interface Decoder {
Transaction decode(Bytes input);
}
private static final EnumMap<TransactionType, Decoder> TRANSACTION_DECODERS =
new EnumMap<>(
Map.of(
TransactionType.FRONTIER, FrontierTransactionDecoder::decode,
TransactionType.ACCESS_LIST, AccessListTransactionDecoder::decode,
TransactionType.EIP1559, EIP1559TransactionDecoder::decode,
TransactionType.BLOB, BlobTransactionDecoder::decode,
- TransactionType.DELEGATE_CODE, CodeDelegationTransactionDecoder::decode));
+ TransactionType.DELEGATE_CODE, CodeDelegationTransactionDecoder::decode,
+ TransactionType.AERE_PQ, AerePqTransactionDecoder::decode));
private static final EnumMap<TransactionType, Decoder> POOLED_TRANSACTION_DECODERS =
new EnumMap<>(Map.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode));
/**
* Decodes an RLP input into a transaction. If the input represents a typed transaction, it uses
* the appropriate decoder for that type. Otherwise, it uses the frontier decoder.
*
* @param rlpInput the RLP input
* @return the decoded transaction
*/
public static Transaction decodeRLP(
final RLPInput rlpInput, final EncodingContext encodingContext) {
if (isTypedTransaction(rlpInput)) {
return decodeTransaction(rlpInput, encodingContext);
} else {
return FrontierTransactionDecoder.decode(rlpInput.readAsRlp());
}
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
index 7d2b7b22d..45da4a413 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java
@@ -1,64 +1,72 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.core.encoding;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import com.google.common.collect.ImmutableMap;
import org.apache.tuweni.bytes.Bytes;
public class TransactionEncoder {
@FunctionalInterface
interface Encoder {
void encode(Transaction transaction, RLPOutput output);
}
private static final ImmutableMap<TransactionType, Encoder> TYPED_TRANSACTION_ENCODERS =
ImmutableMap.of(
TransactionType.ACCESS_LIST,
AccessListTransactionEncoder::encode,
TransactionType.EIP1559,
EIP1559TransactionEncoder::encode,
TransactionType.BLOB,
BlobTransactionEncoder::encode,
TransactionType.DELEGATE_CODE,
- CodeDelegationTransactionEncoder::encode);
+ CodeDelegationTransactionEncoder::encode,
+ TransactionType.AERE_PQ,
+ AerePqTransactionEncoder::encode);
private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);
/**
* Encodes a transaction into RLP format.
*
* @param transaction the transaction to encode
* @param rlpOutput the RLP output stream
* @param encodingContext the encoding context
*/
public static void encodeRLP(
final Transaction transaction,
final RLPOutput rlpOutput,
final EncodingContext encodingContext) {
final TransactionType transactionType = getTransactionType(transaction);
Bytes opaqueBytes = encodeOpaqueBytes(transaction, encodingContext);
encodeRLP(transactionType, opaqueBytes, rlpOutput);
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AerePqTransactionSupport.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AerePqTransactionSupport.java
new file mode 100755
index 000000000..1eaa9aee8
--- /dev/null
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AerePqTransactionSupport.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.ethereum.mainnet;
+
+import org.hyperledger.besu.datatypes.AerePqAlgorithm;
+import org.hyperledger.besu.datatypes.AerePqAuthorization;
+import org.hyperledger.besu.ethereum.core.Transaction;
+import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
+
+import java.util.Optional;
+
+import org.apache.tuweni.bytes.Bytes32;
+import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters;
+import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters;
+import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AIP-20 support on the validation path: the activation height and the ML-DSA verification of a
+ * type-0x50 transaction.
+ *
+ * <p>Activation follows every other Aere rule: a per-node system property, {@code
+ * aere.pqtx.forkBlock}, set uniformly on every node that validates or reads blocks. Absent means
+ * NEVER: a binary that has this code and no property behaves exactly like one that does not have
+ * it, which is what makes staging the binary ahead of the height safe.
+ *
+ * <p>Verification is FIPS 204 ML-DSA in the pure interface with the empty context string, over the
+ * 32-byte signing hash of AIP-20. Bouncy Castle's {@link MLDSASigner} implements exactly that
+ * interface when initialised without a context parameter.
+ */
+public final class AerePqTransactionSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AerePqTransactionSupport.class);
+
+ /** The system property that names the activation height; absent means never. */
+ public static final String FORK_BLOCK_PROPERTY = "aere.pqtx.forkBlock";
+
+ private static final long NEVER = Long.MAX_VALUE;
+ private static final long FORK_BLOCK = readForkBlock();
+
+ private AerePqTransactionSupport() {
+ // static
+ }
+
+ private static long readForkBlock() {
+ final String raw = System.getProperty(FORK_BLOCK_PROPERTY);
+ if (raw == null || raw.isBlank()) {
+ LOG.info("AERE PQ-TX: {} absent, type 0x50 transactions are never accepted", FORK_BLOCK_PROPERTY);
+ return NEVER;
+ }
+ try {
+ final long value = Long.parseLong(raw.trim());
+ if (value < 0) {
+ throw new IllegalArgumentException("negative");
+ }
+ LOG.info("AERE PQ-TX: type 0x50 transactions accepted from block {}", value);
+ return value;
+ } catch (final IllegalArgumentException e) {
+ throw new IllegalStateException(
+ "AERE PQ-TX: "
+ + FORK_BLOCK_PROPERTY
+ + " must be a non-negative block number, got '"
+ + raw
+ + "'. Refusing to start with an unreadable consensus parameter.",
+ e);
+ }
+ }
+
+ /**
+ * The configured activation height.
+ *
+ * @return the height, or {@link Long#MAX_VALUE} when the type is never active
+ */
+ public static long forkBlock() {
+ return FORK_BLOCK;
+ }
+
+ /**
+ * Whether type-0x50 transactions are valid in a block at this height.
+ *
+ * @param blockNumber the block number being validated or built
+ * @return true at or above the activation height
+ */
+ public static boolean isActiveAt(final long blockNumber) {
+ return blockNumber >= FORK_BLOCK;
+ }
+
+ /**
+ * The message for a type-0x50 transaction seen below the activation height.
+ *
+ * @param blockNumber the block number
+ * @return a human-readable reason
+ */
+ public static String inactiveMessage(final long blockNumber) {
+ return FORK_BLOCK == NEVER
+ ? "AIP-20 type 0x50 transactions are not enabled on this node ("
+ + FORK_BLOCK_PROPERTY
+ + " absent)"
+ : "AIP-20 type 0x50 transactions are valid from block "
+ + FORK_BLOCK
+ + ", this is block "
+ + blockNumber;
+ }
+
+ /**
+ * Validates the post-quantum authorization of a type-0x50 transaction: presence, exact lengths,
+ * chain id presence, and the ML-DSA signature over the AIP-20 signing hash. On success the sender
+ * is derivable from the public key (no recovery is involved).
+ *
+ * @param transaction the transaction, type 0x50
+ * @return valid, or INVALID_SIGNATURE / INVALID_TRANSACTION_FORMAT with the reason
+ */
+ public static ValidationResult<TransactionInvalidReason> validateAuthorization(
+ final Transaction transaction) {
+ final Optional<AerePqAuthorization> maybeAuth = transaction.getPqAuthorization();
+ if (maybeAuth.isEmpty()) {
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
+ "type 0x50 transaction carries no post-quantum authorization");
+ }
+ final AerePqAuthorization auth = maybeAuth.get();
+ if (!auth.lengthsValid()) {
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_SIGNATURE,
+ "post-quantum key or signature length does not match " + auth.algorithm());
+ }
+ if (transaction.getChainId().isEmpty()) {
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
+ "type 0x50 transaction must carry a chain id");
+ }
+ final Bytes32 signingHash;
+ try {
+ signingHash = Bytes32.wrap(transaction.getPqSigningHash());
+ } catch (final RuntimeException e) {
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
+ "type 0x50 signing pre-image could not be computed: " + e.getMessage());
+ }
+ final boolean ok;
+ try {
+ ok = verify(auth.algorithm(), auth.publicKey().toArrayUnsafe(), signingHash.toArrayUnsafe(), auth.signature().toArrayUnsafe());
+ } catch (final RuntimeException e) {
+ // A malformed key that the length check let through: the verifier throws, the tx is invalid.
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_SIGNATURE,
+ "post-quantum verification failed to run: " + e.getClass().getSimpleName());
+ }
+ if (!ok) {
+ return ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_SIGNATURE,
+ "post-quantum signature does not verify over the AIP-20 signing hash");
+ }
+ return ValidationResult.valid();
+ }
+
+ /**
+ * FIPS 204 ML-DSA verification, pure interface, empty context.
+ *
+ * @param algorithm the parameter set
+ * @param publicKey the raw public key
+ * @param message the message (here the 32-byte signing hash)
+ * @param signature the raw signature
+ * @return true when the signature verifies
+ */
+ public static boolean verify(
+ final AerePqAlgorithm algorithm,
+ final byte[] publicKey,
+ final byte[] message,
+ final byte[] signature) {
+ final MLDSAParameters parameters =
+ switch (algorithm) {
+ case ML_DSA_44 -> MLDSAParameters.ml_dsa_44;
+ case ML_DSA_65 -> MLDSAParameters.ml_dsa_65;
+ case ML_DSA_87 -> MLDSAParameters.ml_dsa_87;
+ };
+ final MLDSAPublicKeyParameters pub = new MLDSAPublicKeyParameters(parameters, publicKey);
+ final MLDSASigner verifier = new MLDSASigner();
+ verifier.init(false, pub);
+ verifier.update(message, 0, message.length);
+ return verifier.verifySignature(signature);
+ }
+}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
index fb71c3558..e765d882f 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
@@ -1055,41 +1055,42 @@ public abstract class MainnetProtocolSpecs {
blobSchedule.getMax(),
blobSchedule.getTarget(),
miningConfiguration.getMaxBlobsPerTransaction(),
miningConfiguration.getMaxBlobsPerBlock()))
.evmBuilder(
(gasCalculator, __) ->
MainnetEVMs.osaka(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
.transactionValidatorFactoryBuilder(
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
evm.getGasCalculator(),
gasLimitCalculator,
feeMarket,
true,
chainId,
Set.of(
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB,
- TransactionType.DELEGATE_CODE),
+ TransactionType.DELEGATE_CODE,
+ TransactionType.AERE_PQ),
Set.of(BlobType.KZG_CELL_PROOFS),
evm.getMaxInitcodeSize()))
.transactionPoolPreProcessor(new OsakaTransactionPoolPreProcessor())
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::osaka)
.blockValidatorBuilder(MainnetBlockValidatorBuilder::osaka)
.hardforkId(OSAKA);
}
static ProtocolSpecBuilder bpo1Definition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningConfiguration miningConfiguration,
final boolean isParallelTxProcessingEnabled,
final BalConfiguration balConfiguration,
final MetricsSystem metricsSystem) {
ProtocolSpecBuilder builder =
osakaDefinition(
chainId,
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
index 6d0ff35a2..cb8ddfa43 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.getTarget;
import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.hasCodeDelegation;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator;
import org.hyperledger.besu.ethereum.mainnet.block.access.list.AccessLocationTracker;
import org.hyperledger.besu.ethereum.mainnet.block.access.list.PartialBlockAccessView;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
@@ -191,40 +197,48 @@ public class MainnetTransactionProcessor {
operationTracer,
blockHashLookup,
transactionValidationParams,
blobGasPrice,
Optional.empty());
}
public TransactionProcessingResult processTransaction(
final WorldUpdater worldState,
final ProcessableBlockHeader blockHeader,
final Transaction transaction,
final Address miningBeneficiary,
final OperationTracer operationTracer,
final BlockHashLookup blockHashLookup,
final TransactionValidationParams transactionValidationParams,
final Wei blobGasPrice,
final Optional<AccessLocationTracker> accessLocationTracker) {
try {
final var transactionValidator = transactionValidatorFactory.get();
LOG.trace("Starting execution of {}", transaction);
+ // AIP-20: below the activation height the type is invalid in blocks, on every node alike.
+ if (transaction.getType().supportsPqAuthorization()
+ && !AerePqTransactionSupport.isActiveAt(blockHeader.getNumber())) {
+ return TransactionProcessingResult.invalid(
+ ValidationResult.invalid(
+ TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
+ AerePqTransactionSupport.inactiveMessage(blockHeader.getNumber())));
+ }
ValidationResult<TransactionInvalidReason> validationResult =
transactionValidator.validate(
transaction,
blockHeader.getBaseFee(),
Optional.ofNullable(blobGasPrice),
transactionValidationParams);
// Make sure the transaction is intrinsically valid before trying to
// compare against a sender account (because the transaction may not
// be signed correctly to extract the sender).
if (!validationResult.isValid()) {
LOG.debug("Invalid transaction: {}", validationResult.getErrorMessage());
return TransactionProcessingResult.invalid(validationResult);
}
final Address senderAddress = transaction.getSender();
final MutableAccount sender = worldState.getOrCreateSenderAccount(senderAddress);
accessLocationTracker.ifPresent(t -> t.addTouchedAccount(senderAddress));
validationResult =
transactionValidator.validateForSender(transaction, sender, transactionValidationParams);
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
index af237e5a2..4c1d265a8 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.worldstate.CodeDelegationHelper.hasCodeDelegation;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.BlobType;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@@ -341,40 +347,45 @@ public class MainnetTransactionValidator implements TransactionValidator {
return codeHash.equals(Hash.EMPTY) || hasCodeDelegation(sender.getCode());
}
private ValidationResult<TransactionInvalidReason> validateTransactionSignature(
final Transaction transaction) {
if (chainId.isPresent()
&& (transaction.getChainId().isPresent() && !transaction.getChainId().equals(chainId))) {
return ValidationResult.invalid(
TransactionInvalidReason.WRONG_CHAIN_ID,
String.format(
"transaction was meant for chain id %s and not this chain id %s",
transaction.getChainId().get(), chainId.get()));
}
if (chainId.isEmpty() && transaction.getChainId().isPresent()) {
return ValidationResult.invalid(
TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED,
"replay protected signatures is not supported");
}
+ if (transaction.getType().supportsPqAuthorization()) {
+ // AIP-20: no secp256k1 material exists; the ML-DSA authorization is what is verified.
+ return AerePqTransactionSupport.validateAuthorization(transaction);
+ }
+
final SECPSignature signature = transaction.getSignature();
final BigInteger halfCurveOrder = SignatureAlgorithmFactory.getInstance().getHalfCurveOrder();
if (disallowSignatureMalleability && signature.getS().compareTo(halfCurveOrder) > 0) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_SIGNATURE,
String.format(
"Signature s value should be less than %s, but got %s",
halfCurveOrder, signature.getS()));
}
// org.bouncycastle.math.ec.ECCurve.AbstractFp.decompressPoint throws an
// IllegalArgumentException for "Invalid point compression" for bad signatures.
try {
transaction.getSender();
} catch (final IllegalArgumentException e) {
return ValidationResult.invalid(
TransactionInvalidReason.INVALID_SIGNATURE,
"sender could not be extracted from transaction signature");
}
return ValidationResult.valid();
diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java
index 25b1f2d5f..65292ac2d 100644
--- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java
+++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.core;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.hyperledger.besu.crypto.Hash.keccak256;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SecureRandomProvider;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Log;
import org.hyperledger.besu.datatypes.LogTopic;
import org.hyperledger.besu.datatypes.LogsBloomFilter;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.datatypes.TransactionType;
@@ -512,40 +518,42 @@ public class BlockDataGenerator {
public Transaction transaction(final TransactionType transactionType) {
return transaction(transactionType, bytes32(), address());
}
public Transaction transaction(final Bytes payload) {
return transaction(transactionType(), payload);
}
public Transaction transaction(final TransactionType transactionType, final Bytes payload) {
return transaction(transactionType, payload, address());
}
public Transaction transaction(
final TransactionType transactionType, final Bytes payload, final Address to) {
return switch (transactionType) {
case FRONTIER -> frontierTransaction(payload, to);
case EIP1559 -> eip1559Transaction(payload, to);
case ACCESS_LIST -> accessListTransaction(payload, to);
case BLOB -> blobTransaction(payload, to);
case DELEGATE_CODE -> null;
+ // AIP-20 transactions need ML-DSA keys; the random generator does not produce them (same as 7702)
+ case AERE_PQ -> null;
};
}
private Transaction accessListTransaction(final Bytes payload, final Address to) {
return Transaction.builder()
.type(TransactionType.ACCESS_LIST)
.nonce(random.nextLong())
.gasPrice(Wei.wrap(bytesValue(4)))
.gasLimit(positiveLong())
.to(to)
.value(Wei.wrap(bytes32()))
.payload(payload)
.accessList(accessList())
.chainId(BigInteger.ONE)
.signAndBuild(generateKeyPair());
}
private List<AccessListEntry> accessList() {
final List<Address> accessedAddresses =
Stream.generate(this::address).limit(1L + random.nextInt(3)).toList();
diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java
index 2b649f856..03a72eaf1 100644
--- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java
+++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.core;
import org.hyperledger.besu.crypto.CodeDelegationSignature;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder;
import org.hyperledger.besu.ethereum.core.kzg.BlobsWithCommitments;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
@@ -96,40 +102,43 @@ public class TransactionTestFixture {
break;
case BLOB:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
builder.maxFeePerBlobGas(maxFeePerBlobGas.orElse(Wei.ONE));
if (blobs.isPresent()) {
builder.kzgBlobs(
blobs.get().getBlobType(),
blobs.get().getKzgCommitments(),
blobs.get().getBlobs(),
blobs.get().getKzgProofs());
} else versionedHashes.ifPresent(builder::versionedHashes);
break;
case DELEGATE_CODE:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
builder.codeDelegations(codeDelegations.orElse(List.of(CODE_DELEGATION)));
break;
+ case AERE_PQ:
+ throw new IllegalArgumentException(
+ "AIP-20 transactions need ML-DSA keys; this fixture does not create them");
}
to.ifPresent(builder::to);
chainId.ifPresent(builder::chainId);
v.ifPresent(builder::v);
return builder.signAndBuild(keys);
}
public TransactionTestFixture type(final TransactionType transactionType) {
this.transactionType = transactionType;
return this;
}
public TransactionTestFixture nonce(final long nonce) {
this.nonce = nonce;
return this;
}
public TransactionTestFixture gasPrice(final Wei gasPrice) {
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AerePqTransactionTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AerePqTransactionTest.java
new file mode 100755
index 000000000..6f6da5369
--- /dev/null
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/AerePqTransactionTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright contributors to the AERE Network.
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.ethereum.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.hyperledger.besu.datatypes.AerePqAlgorithm;
+import org.hyperledger.besu.datatypes.Address;
+import org.hyperledger.besu.datatypes.BlobType;
+import org.hyperledger.besu.datatypes.Hash;
+import org.hyperledger.besu.datatypes.TransactionType;
+import org.hyperledger.besu.datatypes.Wei;
+import org.hyperledger.besu.ethereum.GasLimitCalculator;
+import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
+import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder;
+import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
+import org.hyperledger.besu.ethereum.mainnet.AerePqTransactionSupport;
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator;
+import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
+import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
+import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
+import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
+import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.junit.jupiter.api.Test;
+
+/**
+ * AIP-20 conformance on the Besu-derived client, against the vectors produced by the reference tooling
+ * (`tools/pqtx/pqtx.mjs vectors`, @noble/post-quantum): the same bytes must decode to the same sender and
+ * hash, verify under Bouncy Castle's ML-DSA, be charged the AIP-20 gas, and every negative vector must be
+ * refused for the reason the vector names. Two independent ML-DSA implementations agreeing on the same
+ * signature is the cross-client property the AIP requires.
+ */
+class AerePqTransactionTest {
+
+ private static final BigInteger CHAIN_ID = BigInteger.valueOf(28001);
+
+ private static String vector(final String id) throws IOException {
+ try (InputStream in =
+ AerePqTransactionTest.class.getResourceAsStream("/aere/pqtx/" + id + ".json")) {
+ assertThat(in).as("vector " + id + " on the test classpath").isNotNull();
+ return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ }
+
+ private static String field(final String json, final String name) {
+ final Matcher m = Pattern.compile("\"" + name + "\"\\s*:\\s*\"([^\"]*)\"").matcher(json);
+ assertThat(m.find()).as("field " + name).isTrue();
+ return m.group(1);
+ }
+
+ private static Transaction decode(final String rawHex) {
+ return TransactionDecoder.decodeOpaqueBytes(
+ Bytes.fromHexString(rawHex), EncodingContext.POOLED_TRANSACTION);
+ }
+
+ private static MainnetTransactionValidator validator() {
+ return new MainnetTransactionValidator(
+ new OsakaGasCalculator(),
+ GasLimitCalculator.constant(),
+ FeeMarket.london(0L),
+ true,
+ Optional.of(CHAIN_ID),
+ Set.of(TransactionType.EIP1559, TransactionType.AERE_PQ),
+ Set.of(BlobType.KZG_CELL_PROOFS),
+ Integer.MAX_VALUE);
+ }
+
+ @Test
+ void validVectorsDecodeToTheReferenceSenderAndHashAndRoundTrip() throws IOException {
+ for (final int alg : new int[] {1, 2, 3}) {
+ final String v = vector("valid-ml-dsa-" + alg);
+ final Transaction tx = decode(field(v, "raw"));
+ assertThat(tx.getType()).isEqualTo(TransactionType.AERE_PQ);
+ assertThat(tx.getPqAuthorization()).isPresent();
+ assertThat(tx.getPqAuthorization().get().algorithm())
+ .isEqualTo(AerePqAlgorithm.byId(alg).orElseThrow());
+ assertThat(tx.getSignature()).as("no secp256k1 signature on a type 0x50 tx").isNull();
+ assertThat(tx.getSender()).isEqualTo(Address.fromHexString(field(v, "sender")));
+ assertThat(tx.getHash()).isEqualTo(Hash.fromHexString(field(v, "hash")));
+ assertThat(tx.getPqSigningHash()).isEqualTo(Bytes.fromHexString(field(v, "signingHash")));
+ assertThat(tx.getChainId()).contains(CHAIN_ID);
+ assertThat(tx.getR()).isNull();
+ assertThat(tx.getYParity()).isNull();
+ final Bytes reEncoded = TransactionEncoder.encodeOpaqueBytes(tx, EncodingContext.BLOCK_BODY);
+ assertThat(reEncoded).as("round trip, alg " + alg).isEqualTo(Bytes.fromHexString(field(v, "raw")));
+ // a detached copy keeps everything that identifies the transaction
+ final Transaction copy = tx.detachedCopy();
+ assertThat(copy.getHash()).isEqualTo(tx.getHash());
+ assertThat(copy.getSender()).isEqualTo(tx.getSender());
+ assertThat(copy).isEqualTo(tx);
+ }
+ }
+
+ @Test
+ void validVectorsVerifyUnderBouncyCastleAndPassTheValidator() throws IOException {
+ for (final int alg : new int[] {1, 2, 3}) {
+ final Transaction tx = decode(field(vector("valid-ml-dsa-" + alg), "raw"));
+ final ValidationResult<TransactionInvalidReason> auth =
+ AerePqTransactionSupport.validateAuthorization(tx);
+ assertThat(auth.isValid())
+ .withFailMessage(() -> "ML-DSA verification, alg " + alg + ": " + auth.getErrorMessage())
+ .isTrue();
+ final ValidationResult<TransactionInvalidReason> full =
+ validator()
+ .validate(
+ tx, Optional.of(Wei.of(1_000_000_000L)), Optional.of(Wei.ZERO), TransactionValidationParams.processingBlock());
+ assertThat(full.isValid())
+ .withFailMessage(() -> "validator, alg " + alg + ": " + full.getErrorMessage())
+ .isTrue();
+ }
+ }
+
+ @Test
+ void aip20GasIsChargedForTheAuthorization() throws IOException {
+ final Transaction tx = decode(field(vector("valid-ml-dsa-2"), "raw"));
+ final long intrinsic = new OsakaGasCalculator().transactionIntrinsicGasCost(tx, 0L);
+ // 21,000 + 16 * (1,952 + 3,309) + 75,000 = 180,176 (AIP-20 worked example, empty calldata)
+ assertThat(intrinsic).isEqualTo(180_176L);
+ final Transaction tx87 = decode(field(vector("valid-ml-dsa-3"), "raw"));
+ assertThat(new OsakaGasCalculator().transactionIntrinsicGasCost(tx87, 0L))
+ .isEqualTo(21_000L + 16L * (2_592L + 4_627L) + 100_000L);
+ }
+
+ @Test
+ void aCorruptedSignatureIsInvalidSignature() throws IOException {
+ for (final int alg : new int[] {1, 2, 3}) {
+ final Transaction tx = decode(field(vector("bad-signature-ml-dsa-" + alg), "raw"));
+ final ValidationResult<TransactionInvalidReason> r =
+ AerePqTransactionSupport.validateAuthorization(tx);
+ assertThat(r.isValid()).isFalse();
+ assertThat(r.getInvalidReason()).isEqualTo(TransactionInvalidReason.INVALID_SIGNATURE);
+ }
+ }
+
+ @Test
+ void theWrongChainIdIsRefusedByTheValidator() throws IOException {
+ final Transaction tx = decode(field(vector("wrong-chain-ml-dsa-2"), "raw"));
+ final ValidationResult<TransactionInvalidReason> r =
+ validator()
+ .validate(tx, Optional.of(Wei.of(1_000_000_000L)), Optional.of(Wei.ZERO), TransactionValidationParams.processingBlock());
+ assertThat(r.isValid()).isFalse();
+ assertThat(r.getInvalidReason()).isEqualTo(TransactionInvalidReason.WRONG_CHAIN_ID);
+ }
+
+ @Test
+ void aShortSignatureAndAnUnknownAlgorithmAreRefusedBeforeAnyCryptography() throws IOException {
+ for (final int alg : new int[] {1, 2, 3}) {
+ final String raw = field(vector("short-signature-ml-dsa-" + alg), "raw");
+ assertThatThrownBy(() -> decode(raw))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("byte signature");
+ }
+ final String unknown = field(vector("unknown-alg-0x10"), "raw");
+ assertThatThrownBy(() -> decode(unknown))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("unknown post-quantum algorithm identifier 16");
+ }
+
+ @Test
+ void theTypeIsNeverActiveWithoutTheForkBlockProperty() {
+ // the test JVM does not set aere.pqtx.forkBlock, so the rule is "never": the same as a binary without it
+ assertThat(AerePqTransactionSupport.forkBlock()).isEqualTo(Long.MAX_VALUE);
+ assertThat(AerePqTransactionSupport.isActiveAt(Long.MAX_VALUE - 1)).isFalse();
+ assertThat(AerePqTransactionSupport.inactiveMessage(1)).contains("not enabled");
+ }
+
+ @Test
+ void aClassicalTransactionCarriesNoAuthorizationAndStillWorks() {
+ final Transaction tx =
+ Transaction.builder()
+ .type(TransactionType.EIP1559)
+ .chainId(CHAIN_ID)
+ .nonce(0)
+ .maxPriorityFeePerGas(Wei.ONE)
+ .maxFeePerGas(Wei.ONE)
+ .gasLimit(21_000)
+ .to(Address.ZERO)
+ .value(Wei.ZERO)
+ .payload(Bytes.EMPTY)
+ .signAndBuild(
+ org.hyperledger.besu.crypto.SignatureAlgorithmFactory.getInstance().generateKeyPair());
+ assertThat(tx.getPqAuthorization()).isEmpty();
+ assertThat(tx.getR()).isNotNull();
+ assertThat(new OsakaGasCalculator().transactionIntrinsicGasCost(tx, 0L)).isEqualTo(21_000L);
+ }
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/INDEX.json b/ethereum/core/src/test/resources/aere/pqtx/INDEX.json
new file mode 100755
index 000000000..8ae144888
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/INDEX.json
@@ -0,0 +1,93 @@
+[
+ {
+ "id": "valid-ml-dsa-1",
+ "expect": "valid",
+ "alg": 1,
+ "hash": "0x5ee00afa7d595efaffab2cf573a82e50c7d0f37bc1c2a53a11f7120155bf57b6",
+ "sender": "0xa4fe6cb101b79c0531f265f6b2584b37073087a5"
+ },
+ {
+ "id": "bad-signature-ml-dsa-1",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 1,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "wrong-chain-ml-dsa-1",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 1,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "short-signature-ml-dsa-1",
+ "expect": "INVALID (length)",
+ "alg": 1,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "valid-ml-dsa-2",
+ "expect": "valid",
+ "alg": 2,
+ "hash": "0xc7903f14f8aa0ffc09cdfcd433e20f07ceaa63ab9b56b84ba41fc8dab7204952",
+ "sender": "0x0602be26ec9e01dd88121f7c203ead9eecb9ad3e"
+ },
+ {
+ "id": "bad-signature-ml-dsa-2",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 2,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "wrong-chain-ml-dsa-2",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 2,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "short-signature-ml-dsa-2",
+ "expect": "INVALID (length)",
+ "alg": 2,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "valid-ml-dsa-3",
+ "expect": "valid",
+ "alg": 3,
+ "hash": "0xe37a3c437aacfb3f7abe9bd9da80fb8a50398a56e6b60e6fd29f08abd049d9d7",
+ "sender": "0xaee69521a942a58325bd694f2cc3d64752465d4a"
+ },
+ {
+ "id": "bad-signature-ml-dsa-3",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 3,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "wrong-chain-ml-dsa-3",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 3,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "short-signature-ml-dsa-3",
+ "expect": "INVALID (length)",
+ "alg": 3,
+ "hash": null,
+ "sender": null
+ },
+ {
+ "id": "unknown-alg-0x10",
+ "expect": "INVALID (unknown alg_id)",
+ "alg": 16,
+ "hash": null,
+ "sender": null
+ }
+]
diff --git a/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-1.json b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-1.json
new file mode 100755
index 000000000..c0a74d633
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-1.json
@@ -0,0 +1,6 @@
+{
+ "id": "bad-signature-ml-dsa-1",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 1,
+ "raw": "0x50f90ec5826d6180843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c001b90520372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083eb90974674be581b59cd495740a8a9aaaf7c6801a8bcedb531ace47da1be56ab30f1c4ccdaad6e81aa97352baca12b6c69754123bdee38c0d57bf15f0850572dc9b456234eaf37eb478f9117f952ae95a0d165d12d948b51672a03c9610a98cf332d6ad7ab8a87defb3ef7249cf8c3a815129ecf5600500702b7916ffe570cef0714e0c083a581c2971c45c4aa6b1c5226400e5fd594ea3ae97fe94a0dc7f1e0979b11a2f3d15ad54fea957992ada816f97cd76168a53ebffae36e5787b0f69e94b3e08eadefe4937ce8b383b5022e57ba7135cccd5b48e38916f1f0bdcbc5858bf93cad75195d4329ab41a518d820262b1b610f7bdbe1d6749d006a0dfe18d0be1a19fb3d8e37795b5bc37ebcd884f91459164cd2536b3496c4b25a4c74282ece5d64ab861184e942cf97f0edbe6e1293c4504d861e60d98c4f6523df27a1e80843005ad21665b3adcf46f349fb0d905d70631d2ee51c0086b252778eac27346eee65c0fc88c6db5936337b0afa7d8cec656612c81e11cc55abf421df770e6c2588c743d5540e1280be76309defaffde2b82c808976c337ee13735a21900a4686423625a0ba4819581edbe574e6d7053c5fd98d288db4104ea64fbc0e7ad11d50eb1470a882aa00ebfd983cdda14db34f7f968ccc93097cf037dceeb1375f2df4de09c8785f5fef8fbbe284566e5c9a2d38f5d2f9145b7f5087f6a89a56679680ca4180ad7da3ee45da685f0255a45db806e1379c1ed59bfe63feb7d74a239334c80ab9c1859d205ba798810adf8afc569170f94167439d137215d2ce0b2fa983ac138a3ce201cec4927c62b740912e7287417f86beb07af9c83fff843df1abd6e6f81865b82b3168528d1c473b4999b0179f1de8ae22e8ed7f698ee8463eb93fcfd4e017f29ab3f15a2e061de6deb09459d4ecc62741ffd8514d5c1f10eb3b1525ad60512ffad00e360e0d6add8ed6d6df48d63cf1e36f306bd76b1a245cdd09951727367e45b3a02d748dbfcbeea342be4cb0e1e3108e57993581409f8c6b34e2d38becfcf15c653b92c88412c087eddb0bc21eeb620317f49a9bf5d6164418a26322e1964fd676a547862c2a7ce5f13898e3fadec79a638f257532cfe977fe8ba5e96782f9e1e3e8b5f896a80d816141f0c988ea59ea321cffd23f298b76e49e92189e7f65718d14091daeb82d432470a2e472a39a154226a43c543db2bb933adad08344259ba08a65c543d2ee07b67328ca2d4e60e550b85215ea5873fedb505cc1e4db49e129249fb632ba22f11b897b9423d08f96ceaa863cd29dc16af6ac76c4388c2795250c04377277626992b085ed7be2cf1d63a2eda4b65e287081fdc4e9a3224ff57d81b3ba8d04eb88430a01c5eba35fad028e8de1812920cee2576d0bd291407c5fb70c5ce07104b9af7b98c4c709c7f019d4a66b136120b92612ad5e73dfcfc1da0fec3a7928e57d7d4769eecbaa4c269f2859d31d47d1ae40e4da5bfa6592074c5bf54b04c707b8d97455a0a606686e06bf5ef7617da2532f305267f61c5f627216b06ecc3da6c6f7b420e2dfecaa41657eab20c89927ad6eb5c4fcd513da89a637755f4a98c45cfa108f37415bbf49ee6cacfda8f22f7101a9798d844709a38f9168685f105157a937bb10d4f5b342deab8b8be8231490da52cc0c407bf942270ad93d4a9bed5c06499584835dbba75577dbbc47fd3d397f0417ade99549de4412c8893cf3e1a2ed74c234a7b60461efad57d9c9fed9eec3ebd652282b045174e19355d8cfcc10add9192ffffd428150dc3f48e0417e47d6407008c62486cd4057535a5a9ffc45ef559a51fbbece64306f64da9740108d0b51d01423379bb0a72fe050d2abf5f5acd25cff57f8e3bcdf938749c7bbf77437424ada88c167bcb6addc309b949a8e200b9a5b6797522635731b250e2405f98d054aaff4179ccb4b24159e4c033329100cadbef3da262203622d27899166f6c3c79a35daf7840853b9a3ce494bf035235cada8c31e28be56f0976ef9b96f15de57e6896a5aed57a7b5ce77cacd1c806ecf83566bee5d577f7414a106ce16ca6e8cbc144f571b1a37647041694a6409f68d15604960417a60bc4f1a878eb01e89159e701bb8fd96be45395a8b8c4f0cc5b982582741c4ccaff8961ea892f084b10646c7a27687a2d3c92324cc3a19a5b38ca2d5c573167ad54486ab3adfe9219882f947cc6a93a3827f4b51d76e90ffd1587646d921482022db8b5a22519be3a1e62e9a13ff9926e75c42e07aa295c8486df69dc96168e920e13c85eeda86dc560b9f5d4c77cb8ff001d390dc6c5a911c573ab1711df534930ef28832936c80cafcde731e999ce90741e669d93f653efba12466726fa997e7ad24d34395a02b8a4286f3604f120bf47e8ec41954e6def2de896be477ef7916f18214d28f58ae91ed8d7eae9e2df600d313b6cdb952195e9d030e0b8fc98a68cced3070f4abd2d252727320eb54b602ec861ba630ed3c5d6fc8c8b39f4f1e9c198a6dc8d5f825159ce15fcd7bea5701a225ac41bb152d1a077adc03ecf06870375f2d2618094a648b40244e4a981e7efeadc608c082dc1824c4ffdbc39afcc8c464ed5ca8dfc1540ae3a6c034364c356bf13f880abe8633fa041db78f4be0d17a4bb00959a697935c844c6ddc02222f7aebb1af2c96a757536159dc1dbc31131aefe4c198ccd2123eb5d0ca6147bbc9ab43e993508ef4ca383e2847d9fcb4c975dcb240bcfd164daa835311cf7dbde0f256deb5f3748b55c312a29a042725ecf07caa904513e71b4c0ebd3b31c2938e710e7c6be819bb3125e638ee4b54b4c8fe16df1cee7587e6bdfdcccf2e3b2aa4a54c86b0ae711f056c229c644f519f60570aed60fd3d0638dc341625fb4949d355e7d84cb478133d25730162623acbf5d36b9ed98dbd88b6bf7bf1f55006f5ba2d16297557f966cc01baca56e3f6435b724c0b6fa4cc0074efb0bb2cf0cba9a1c73d3337db7dc0c78b87746db7bbe5fc003edf608ce5d91dbd8b3cec0f738de14c8e2b6df47df91805eab5635402ff26245430641abd9511cffa6bf8d352a1f0d97ce2b08561c97a5f07a07e0ac42a2a73366442e0bf125a718553794b021640ef9f9f07040068cce2337606af46f897b7ad8ced05e14f7ab3e2bd847f810058d665a0c3b6903efd8f398c31e356b48216111d30348acf93d28dbec8e603cd16ea5d3b24f38367c52f5629fd51bec34e86ff21d4f5466a53aea7048babf3afaecec2c9de099bcb2845f66689e02306760ef5274e65f36fc61edf8112b3b414a878b8dbdc2ced0d7dae0e95c5d6e7c80a3b4cbccfe13293e454b6c757a8d9496999fb0c4d4dfe5e7f3f40e11172324323556687e95a4a6bfc4dadbec000000000000000000000000000000101a2f41"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-2.json b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-2.json
new file mode 100755
index 000000000..c07213da9
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-2.json
@@ -0,0 +1,6 @@
+{
+ "id": "bad-signature-ml-dsa-2",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 2,
+ "raw": "0x50f914be826d6180843b9aca008477359400830383209400000000000000000000000000000000000000010180c002b907a05424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2fb90ced32fc1486a0e70aeb6fef62ce5a0dfb51fcec12164e4024b0c49ce8b65e01356d80a9571af8f69a9c7256ed549d699a31ceff21c13c482ee0c5759f96125b0099495feacf22a001b2c887b107a9ca9e84de461fbc6e143566de56c710156de5b5f4b7ffe29c0124c1fbb6a792110284c9ad713d89bbb5ed444d09408c65a9f74c5f6c4fd281d31738db82913dcd1ac1fccbba24dc933fb9a8e6c4e426fb98590d7da0252c34d866c114526ded1c9d96daea12ecbd8f2a44531dfb72f02c02b267edf0560b1fb06b087bb6ce02b2922d92f81bb7da99b90e4a2dd68aa858759584490be602369dd606a510b6228e3b941421a3006a697b79866cae011d8aa496de4f3bfffdc0a087d01323db849f6237d7ac476d18bb417f26a697388b4c0a78533f3dd763398719c9ee5bf0299786fb8c4143af8c1195103390d4494b735c06b5815c454dba2fcdd27d214c48712609ffe7ad7c082e835d7477de2358fb3c4b5162027f816ca85aa4a46c25105175e77c8e5394db6fb3999c25ce578f066329182b28fd5b68769cb07ebc67e47a537f6cb62bfd18af162113a4df7f8908e0ce953b6a9637c850f24de0fda239c25fe4352f3b381fc270384d51d1af1ef0dea8501f98ea71f26de97e98799c4b2a316a216bd4af4861ad83fa4570532029564581bb35ac543355ba3aa246b59c6a5d9a91b938f3c4f0ad6d6f567fffdb6fb78402ded5fdc544a0f5fd87e4677326ca003dffdba8fd390487a6469991506a18f376b12db5be3bdcf4a4bc2f5b34dd8f7066bec3b40a6502f414eac3cd1ed43431b033757e86cca57691b0e1f7eec68fad9423f8b0620aa94798546bc878cf29d74ae74af5244ed9b97107fb83abe25dc160ec05cda1c50b76db981aca781868a7913a3e7c98aa5a3ea8bc81270e6f565138dba33c9c7e887641fd3dafd458b9c64600151038db05725a976950307c662c2eb668e3067f943b9bfd805307729b39ed77309fd5e67ecfc56cc231057a6628fb6f528fb969378529dea2c58fa0b4d791ca591ced733e8cf93a8e19907538f45c2618612648d3e1a78492afc154b7bb0285aea97d618e74a74530b492c66c6bd31557cdc55476b3f163196ec8e87f110834ffb8c232dc77cbf2f7b490f520b3b328af44fecca860a19bee9af6a5f69f63487d7dc6b7bf1233c4735522fedd475f905f044a0a7f658a7a378958cca56a163a343a010f4b65d1bc38cd57d08e0f887293fbc106ad7b15aacca6d51558cb8478b119acde04a19b007802a8e9578121304622aee7858d1794ade88973d6fdf981ebabc98fc417d765c075bf8f76b9781dff7c60071878027c057aade8eaf820186035499e9e5fbf8791e6fc0a0e49047af312a8b1b1e80628dc4db4f45842e19096a54733d28028203aa668bd8655631a01c000c956c32ff10572fdbc95b2f26d09fca84c093ddaa122ad93598c03de9273873ece5096648a6251a27e993ec7b6ea4f2181c09bb06852799323f3e993a4b7461439f702cb9df183fcaab11b8bd2ad391924d5e6ef261fea01c91cdc10d9345c290dfc3c040318d11419563d407c8365fef3dd31d8f9d7d338f5f2cd00433d1d06547ae9c650d14d9a7e5b683f0458e7a909d90d4a57201ca5b8753c13bda3591f9cadffd0987d1c7fca1c5a0cec1e13c612d0390d7c0e2f422c97cda29959cd7b714fbeaa5da7b0bcf911c2744a9a25c7d49e93342f61e10a33fda80fadfed2668bfab8767ce80480093b4845cd5ec83082e8f9ad63236743e72842d1a3226640a549c2c1d002a176e2427b2ae612dc272e3d9fa80a904eb8f93f494a52706346c08b06c9d1d8a61a9c7112c0933910882f0da6eea3c389f4faeea51c03394eab4cc02056d704b8839afd76f0839be5ffdc873b88f9a755be6f0229b0843839a25d63c18da89be1c5da930a101913ffba01fd00f2a447d5f58ae8f21554feb47f42d40c32158219dbbb1e5e96ab3dc26cd6a435525c265b65b0bf48d68e9b3c9178a509833aa47c23e63aa9a6f74bef1e4ef863556b11c014b85ac7c157f1e64531b676eb28c68e82e0089d2bd798213c836cc354d4883dc0b607456ab7f894f0a1f73356fc05a5c97a9cf3b231890c39105b751f6fc54063a08f3d3a264ab90cb7de1d0e2f6acb92302cc9b4bb512e720e6ff8343004028ad223a70d395c5f974d3ddd380f798e80edb4b13555c3be0cb1a500e19a8b1b05f9cae85d7eed756ebcfa57828f1054296ffa48d426ceb83c69ebe1b983421f42316ca6f50bf8df0f4d4aeef85005638a304d88764ec26366a1437867c89800aee55ba428e0c07542e123d748c795560153007f768b20bb057fc2643b7db992c3b9cbfd88657b17fbe8a783da2050affb518cab4226cdf28fa97f48651bd142932835f061f8642e79d1f7ae8ff8665aa85aba24a850b2042dd37e61e665a451f17cbe9d57ed5ecb1dce9ec34c576762929dbf46964de7c44c9f6b10fcf52b48649ded2d491bbe4bb6ad578cd31cbdea6df8342dbb7f33857617250b014fc6d887a448f7a5cef25ff69dbc94733bfac1d5f8593af7fbe4759d23ba8da1f405ba179c96d8ae49eb760446d842f0d61ab08508a3e31e4953e13a1b197d00644303e8a9513199583709f41757740a0dff347c3859d3a4ec391481af349019f75ccfdba111a4c338fd8283733115ce7c114111abb157c1a5a84f7b39779a54f000827a250bff00dbe9cb7162d81f6c942b719f9eb973ac7d4652b911622396c517c6e9c7e5f839c049855567fb53ae84579388e3c87af420272558c686209fd92fc339a553f873995932d9dce52f5e60cc0889c3283f94a0d2d5d011154d9935e1dfbb7e747b393bdd8a84f601adca56d4ac5e8e6f28100a7d5522de50dbf1bd7f5604fdfa660a58dc681b4b230abbc4f594a972a73456de1b7f48975cd03313a80074f5d6701db61860f33dfcc9f06e313e8881c385a50de28ced014daf702f01c45368419b73383008b9191293f59fa87a1ceb0cee64d486842ed7c289dca3b3f2e261df644de0f739079ba5ea195468f0693a995dae8e0f7e4611196824f329fc803bc3588d7d941d1fe86a3ecdb3eb8f6d4066ecee371f9a14e5bd46a40b53e87325bab7255099b4fe7f7b09eddaefc6582feecb8dec02b5e58d735a927d052e263027fa879fceb852b9e08db4636c7152f272a43ae4037c50210e90caa3e008fbfa98ed42cd425259096fc06644edab9b768779dcd892747f18a9cecc6aa31dc27d3f12a540447653edd5bed68f50da71b7992434b74d0209746f93ea429691fcb99da0ca32df822ec4332f7eb4bbe6d2111ac84a55932b3e173e388ab96a5a8a17c7d8b8131cf566e0335b0c4a37c5ae24e73c81146031295b69ce3032fa8e4c7616558179cc561f14864190d458cb82370749d595966047de698256126a4ca23a6bbd39201b8649fbcd387474ecf5b9f732e65938fe393a2a1269b06b9b49c5d8882d70776fc823da5842d812be2a65d2f5ee0d64f8258e761e6f2d4c1a825963b367d70b9e81b46fc25e4804fe9decf3aa0e47f1eba573a24f0e4f7b8cf8a886c7ef4175bd317709feeabe46df9719e7d7a4bc2c1bbc15a58b5332ea558e160f5d3b7aa84fe54ea7a24bd8e394ab794e72db7946780272556be33b7f32a0ee651c013d8ed3b5d75bc1c4826dc94f9e3711c53be3bcdf361329544f2993a189b6431a6dda8b81cb1b7c3a69ba96c1ac84a55100c4985cc85ce272e8eb5a57c563a7ad782664d561c3400e779317122d425c9c4193414bebd4d6ad31ba916448f65e9a7ca1f856dacf9d88b695410c8491a759d2c0304e8368b39cf502d0abf7233b1ba9671bc422ce182833ead52597481ea3ea26a2cc35e12a8c83bbb263202d5e9e7a5bb8ab2a5a844d596c24fdac423981fc4dc4291944ae476d59c9a31a05f79f0fe4b39f145c4fba857fa553a17fb2d5f941d5dac8dd3dd07e48eabfe5b98f3c41e7a84986dc3a7a3bb0ed2d4232cffbc50f167d58fb52fa3b357e76430d7f0f1aff6e2d51ea8f5b98bb66c5b5687821f33b9b6c2e407ad0e8140c4d5d4f1739167f8d63284caf4a43688473cd97bab401218fbb2ea13be81bbc05a81042a02eb1843bd46ca535e778e207c79ce3fe511a55d21bf20b24bcdfb43fa62b3469fae2ebd61e362d5d663fb2c08cbde5df9d8cc1faaf6370b5328ffccde873849299d61477a9fcf7c5c96fbc51b24c0f2cc6e39a46f4a9c1f5214f2cd06db62a37e2c6f477ceac0b92eb882d7bcd1fc3721a89745473eb45eee9a4fe6ab323d28f4db957d0c5dc1ed25ebc194f744a2cfe98474868e6acf5641ad454b3626ac2a27a9db416eb1763935eaa5612e43c49e8959ebcf5133863e98c19618e936f33952699fc224f41a4e259b40228047ed6a17cf4f3a42dc76df1346acb0986984f1692b5ed28f0825a23094ddbb8c1750e9035b1df2166f142e7f179473098ed73acb9ffb8be530542f31de88d6677f805cc30ccc0b60787e61f9d195ceacf07a35d979f9c3521f23671f378a6cd58ed2b0620ff7e2def5025f878d70008744c6a53caf325293353747c94c5ddf12e3a42686f97adc4db62b5e2e91132345963b7292fc9d13b484f75d8da000000000000000000000000000000000a13171d2127"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-3.json b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-3.json
new file mode 100755
index 000000000..7131da266
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/bad-signature-ml-dsa-3.json
@@ -0,0 +1,6 @@
+{
+ "id": "bad-signature-ml-dsa-3",
+ "expect": "INVALID_SIGNATURE",
+ "alg": 3,
+ "raw": "0x50f91c64826d6180843b9aca00847735940083045f289400000000000000000000000000000000000000010180c003b90a20fd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308b91213c64a08868ea0fdad9fbb1b485b793bce6e4fa945668b2351232a7c8a084fb2d87a5c83e7dced6bde3743617a7c4babcbf9381694b64d7e0feeb6615440e927a63293c6b695900b1e7afad1ae612c324a88e6761c3b6fdc41d18f514be1ba3a1ca53fdbcf8c19f95bcd60223abe52d07fd7c4114dad9f347cf122f6241429da7e598959c22692910323a0a699595398f518c58deea7159920d89e3e65702bc2cabea7e9ca0bbb7002fb7be5243bba6a08a12238ead443ff4394510d25eb279885d9112c44529f294c5a2bf493a74ba8f4e38744e632680b3ce055a897d2a5468ef52e6e70dc5af55a9fb83739f6cfc6994871662b8263f2e07e21a6514624909369e0138755165dd2af5a791da63c0604b68ff160fad82a578a06e76f62bb7e951b81d8fde2dade6c3a314eec5913151c16a93a5abd5ceb59ad96197a349721ab123b42f799dbde36d7965e0e5dfcf43d8d1ae13f4a00afd8dde36137d3de87f4e2c0366c18f4b3a449ffd9afc7c742c50456f6e642f7d09e86d5aef224b20ce5d8a2bf164484df8fc87daf69e459fc78c6b974cdb8fb1dccbd5290f560e3114302886e2828ad73ce71b06186254206743076c6af0c3d1facc36695dc28db1d026686b141247e1c7a9323d544b0079023cd2adedc0479ceefc8e0c34782603d0c27d18768eb5485a85bc385ffdfd25f735688a3b9a0c6f532b2a7989c751804de0163582293a17f635fdde14e9067f12929b079f89a53dfc87b986f89f718320ede83cf4086d0d095b24b66d5e3f1bfdb08b79cd5b25657cf2b20faff1d199c16bb7f631b33970b34c12997637447e4127db1bf580b339807637a86e0248cbcf8e1d30ae6fe053e2f9b7b3d0f9e3f4813af908b633560779012f9e06af00e252bb0df9f0caf7d1e82f8deb2ede21d13f406dd9ea69445d50844c95c921d8d1cbc8afbc5ddcd4157e65cbfbbafe2670e9146a5643db049a8d696f0eae07c3d4099447ef78bdb90fc05d7cc97bf9b9dee8719464ec6b9e6de866f73914a80396dea3900a9f7b43a47e648e20a9504da92c47ac65368813e5453e82020f8861aba2534346e6137e71adb28a5ff080365d6ea26dfc30ef5500d0760749d6e4e0f93aaebed544832308b19f72e92ebb8eaec2492c6ea7972fd359a8b67a1f4053bfb1a3c6fb720b5925a7a827e59b3bd0651b8014c77b25d61db17eb169cc2fa2442c82f68fb42200c59baa468a9fc92f13273ff071124f8b31e2b4b2517ee622d29489997ecb5676fb52e3002371c01004c214757b1f510091c2377a08d058209d18feb9b524a41712b6df4b92f2b14c583d3196749f367b3bbc8ab5e9e2615c511f23ba5fb1bac2ee9436dd8d162bd96f1fb663d2b520ba7e8ddfc2a4d549b63714654cfbb37ee1dca5f723139187ada8f8d5b42ad09ff196b70720d2527b4466d44f33cce486ef2e86311c75ead31a17b16989dc63bacf0d465379d9138df7ea2ebc71f4cc3b6662e24895050e2553dbc160a567d6722964a904d43bf2684206cee3562256e98addf3038e968cf6c09c921e2c89c9c249f6ba7afd20dd27587b4143f704f2738315a91c2d40c467111b4f3bae4f77bae402145e742ba83a527aeffca13ee2290988df882feaf5a3c24b416d59e06cf4f8832a016ce55419b7bd2028545557528a0af23f17942433e13fad089fdb79449bd9d99b0324b1828791249b6789a09cdfb6ec40c0fbaf8b28ea4f72d3df5159bea7a7965b94beb1bb01d87d76ae7ce47fc333fc152038ab4e7ca64a802f96f2e92bcc53ad9cae0242c622c99b2daf005e554cd6ba127991d84841ffe3ba0674eb7930509045dd00ab91a7c6acd2f4a40e7ffc9959929851e40d417f488a29f7bb5af3847a8caa5daa0682aea870ac8b866ccfdc435971e3d862c2f651cc6eb8a33fca313a56ab8228ee9ac7dce14ea3c3fba4f58c70888ae558d8cd632a2723ba54a3d538f4e20936a2ee543e9b2141e06095c72d4ee19908febf7c248c03a78655420da644746e2d508c31ceb0b648800d95dceec72f7576502046e5dce54b5a097f625001bfc92d6e4633b293cdfa63b1fca5de9e26d03ba2f1cf3647dbdad5359ed76bf702f0621c057dea3617af678016aa13360ebb02c6cb2fa0d3f137a1a3c639c989e12383841ab7ca5a84f84c08af4b85416ce7ec3ed91636a79add207bedf9dfb2ff626387f20cb3315502b2b06f361cbf6a51fb507598af41c5a5b9cd95ba1894ca372c5e1851e62a0d3d78dab6f92bd43ba6fcd71230b6cfd843d89268872b75e3c5b471db530b7ab5451dbe63fa0bdaa7d74907cb376643e129febbe6ce10b5dffbf323dc973f097d2081e06aad65e674c5a41bb81b80556fd78691fe6b5bfad47fd1b64db577f27f22f17973cbff3a7c4aa43569bbe6843d773a2f933f472650e88e0ec6643f87dfd37e7fba915c7386a130b8d4f0ff4d0e99a633d1f863f3e8ce4e1ac5e31438d89c3b6d5ace3aa6e14e7073164ea01e853958bece389316023127f9916297a47c5d6ab5513bab874c1ae3bf2850cfab9018cbf50a7febe03ff3e8e4e55ae5632812b6a147edf051b461bfe56f01a6ab571e0553e37a57a3a9811f4fda2e189d79b74215d6fe199595d18c6543c747572f8cdc61a53ce09d9ca96b43a5af5b56b53148dd4fdfc1e22c9958caa783f2d112d8d5fd39e6955df75d35c59a1967fc0d8d3293e39a6cdf82d6846b39a74b1a538372c266b3f12d7ccf464ff7e32fe54342994f51d344302b3b2e11eed2187a741eec99ef0a79a19a854c03d8bd3fcd557b9d8bfb35f0976da327fc7e8d95fb43db8e66be5b373385fc1b68099566c7e88aefe92c7c521d084c15c8d403d87bbc975e8d687e2a51e5ce53191e3db5bdc50f475853cda7cc5a7365c41035aecb61444c2a48492a600b58300b2805be97b4e9e30526e9e62bb3248a17c3809219307ca85351495c943a865359c783cf615a809c739cce0786c6045d9c8071797001434cbae571d42cef415e28ed6adab09ed10e0713dc1412ed80b8d26d549964321559137483c81b19203080b36abcd68e841f4c78b5302da79fd6e555f390322ae67e54c55749491889d79eb2982fc4428086bd1060c4113137ddb4dd7c9b690b802e805999d4f5127f66f6b1d397dc3509504e2196513b5787407b45b928cfc3c437523daa4f876dfe061e351cb3bad99ea205ab276c4f2a5ccee1027104f09adaf55cd282d4e9e44ac2b65f7e423da1cebb0ac70691347e7a7bd0de8bc9fb2e7a08afc0075a0e85902316cd6ec9a5802c51a6d65bf3251ae712ae0f66de6cba1e51efbad53ad7e769f851799caf5fb81ef35b4da814915dcfa67553f1c67158154707d16804be27af2115559e4758b313b9da4a1131718b29a75970b3f0a5e2f2c11a0a1ed47f238c145dc4fe9e8e963d8395c67dfa94a232b8133a0d953b05455f79e0bdff0bc3de9c04d93d97084ab99229622cfe3958ac5fda6757de1696b575f6250b441e6368386751b1d2f6007d254d152fe76578fbbe164af49cda805b9325f7ea47f5e18f3de1ce38006ae1bf027d3e354d6f923d8bc6286aaf9b9a7b9e7a7fbd36a31db0d88166dc68e7eb567d8164bed1e279a8810fc21656621ff7cb42a21ee04e6086924bb62dddd16c3343db69250f7ed95aba953202640bef18dfb6c00f1ee03c670a5cc6c0f3cd7cb006590dddffa6f19d450860e289f85edb4fb0dbbd2f992eebba09cddc1b20a3c98d8739ad1875a514b09b1f23cf406c4c55cc4266e0b8b283fa445849316c30bd19254e9d035756d2773cab7f5fd56d6d3a094a717ccca43251201cfddf80ba1aa0dad34f5a3acf8476b784fd53a1aff1307a7838705112650bd25dfea21b991d801f018a5dae26edb9dd5a0ab940a94b7bbb90fd1f30f9d1dd2ea3aad6d0a2a3c42fd2641233c7d624314c3a54ce616d2ca5683d04f6fc0924f0b667be32f4de8820f9cfab963a287a1c708857ebabed9b5bcc35d539ef9bc170636cd528ba86a620195134cacbc2b8e742376124b67ed8155ab53979e281f97b184c60355b008f15f45c8b7a506b1c1f511e4aaf0bc32fee27b656b01ed6afaa4053ed674a60175b6c89a77d42963111d0940730db02ff67534fe6a296e0e01e2db6b3f0fe9648286a0f3420cd4393163662751deed6457abbb370f83ed92e9da86a0181df13b8ef33e5718ce524a700ba5f2b40f3f973a67c1c412dc251c19e6b7ceb279dc1dfc36a3567e3a98a9d96ef52b0d0734f57bd9edebedd925167f230b1c81ca938e94ceebe43d2573735873a436331a8b76c1169c6a869889cb74e5d33721bbb99ec87f160c025f570f1d11c2e3ae6a52580785d854790139510179b003418dbcee1f4fd4fa39fc134521ffd7f29cee650472638dd04d8331ee439eaa32c57b56c4fd9c9ba87516a8236dc99b8d6e4c2a48e53a6779d5e13bbd73cc7917f0cfb8e231218bf33bc3c213599eb76476558f0e38a3979cdaad6ac6b03bd0ef0aefec634fbe0e1e87bd78123a19b7352326b9def856ecfc02b06622f94e8cb2a1cb6cf10d020f789a7db775063030f15b463f08878219636f2bb94ed11a3ed9689d797a3253809c7f2e0c60672e8476a9e272075c7f808258901e611c4d535a11bfe01daccaec3a26a187ab45a9fd0bb9a7ecf2e9c4aa3177ddaca1449f19f78ebe26be2e25bca012a10649b56899339f5418925648f3253bd716336dcf65e6b4f16d2ae51fed1acbc8335c103f721f46023cc2043f568ddb033aa5f2157e52b89eed4571cb523fcc66ef5cddc90679633c2a46f45f1a86c975db4f6f37f9fcfe54809ccf75305bc9f242f26f30a0ad5f3cd71cbd31ac45ceed2dc8571142a09b7d3091a4838727b9a067927e17b7559076649b405dfd480627881489d52339d4a8943ca396e92b92066e45d525acf7785a944345d25d721d6a354b1a9f3e2afd379d1c341badd0dd913a3471a5b78a81c0b338a2984e115d003b1deec1b44fd19824279d742017248fb4434cf47ad07fc87df86e634b2d8f6e0aa572088678b9a9f767404f06c84ea8cbf65d46effbde7de1f090d3d4b9e7c7c3b2b1dfa9e591efe12ffe0fc82c9eeb7fcd9f25fe438b39c46614438d0be7e1dad11bce8b91396f867531e8c45d8c01119abc2b20be253779b5e651bd80536854e2aabccddc5f4fbfb3497111fe9a8f8a417ab4dd806745c82126524ec325c931ac1f31a3cea19e159e1dbfbfcff761cccabefad38062872fe8a45a14781ba12551befb31c21150a56ccacf9815d8f458b1f591c71ba7b0459e7c09a4eac5c9e5b2984314ecd2f7054ed055ba082204f7ed62b1d513cd0992bc10c28bc745e30b27f6ca28ac84dec6cf0ef73c971ce12b2ddcc0d6264d8f7dfbba0a20f8ff1d7387cd9d9872f4b345b409950d66ababa9852f7f5ee634dad6085666956b97e4c9142dbdce96bf42d1334c61d04ffed5ac8f12a5075ac87a7416fd52579a876c89e22008759a93ebc57279215e178662a064bca65670089ec688532468c07161f56bbafbfa5655768123e713c7aff52852978e9d6004ab3a434d9b5c73f0d90dd1fe742a169a84f0e96a189bfc5265d8c5e2d9e42f5503d04ce01f9a912bf8b9bd8c282a4d40bbeca55d14971d1d305a16eb85d02b4edd8d35baea56156ba12f4e344dc4cb34509fc780ee97d24173a75e49960ec32055710bf8119d005447c6c391365737a0cff68d9f44868b97b2357dc051ed7fcf590b32292624545935e87f25e56b3e4a2b9c39c4936b5be9030b4711f246623264e0370291b675e75e1ce9cb425e5fabcfb55e25f084ea8a1b84870135ad997f7b700876691939cf268204669790a10ddd3d38cd22252226a09fddd395482deb561ee834ba452750d5b8e0de63c77c85a7446dd5bb29df2620f98e07bdac4cb59af8b9dc64d427dab780257e252e8d6793fd1b99f7c3162b4233a418526ab227d40b9deadc943d0f108a38d7a6b075465a44c920c0146338504eadf826cae345e864452e94706c8dceac5cca87469f2183a9c918295c09eef65f747b7a3d7fb3d259c4f531ffe48a5c338717ceb45efb557a47a593fac85cfaa4c263c109d385c01a3193a6ad1be5923d6a53e6c369a2b5e704cd6ac3ac255954c3fca1079895c596596873c1309fdcc5f36fe039d06806dd16cb00bd028edd6b44fb1e9ce4a020362824bef6a59502cce4e1d3d3884d7d865823deb092916a215ee73bdae1d4baf7f294caac7f63a36c2a15a40517438b8cecb93a5da3e11c25ff228ef3e7281360a2ce3ac66e69a2f136a83fbdbc44dd1737e9a31bdce16df9e118345ec1d9a9c47bfa60502722c9813d31c9f1b0364e2e25d77a0816db52f7e86bade9aff644df50b1cea9a339e76e869fa1fa50101f8182a2a6aee2e90d242d4b4d6b999d1c358a8d9297b6e0e2ec141c2b3692d70b141a213d477e87c52a2c87a5c6d1f0fb091f35f50915878ac70000000000000000000000000000000009111b212a32363b"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-1.json b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-1.json
new file mode 100755
index 000000000..414ca8087
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-1.json
@@ -0,0 +1,6 @@
+{
+ "id": "short-signature-ml-dsa-1",
+ "expect": "INVALID (length)",
+ "alg": 1,
+ "raw": "0x50f90ec4826d6180843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c001b90520372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083eb90973664be581b59cd495740a8a9aaaf7c6801a8bcedb531ace47da1be56ab30f1c4ccdaad6e81aa97352baca12b6c69754123bdee38c0d57bf15f0850572dc9b456234eaf37eb478f9117f952ae95a0d165d12d948b51672a03c9610a98cf332d6ad7ab8a87defb3ef7249cf8c3a815129ecf5600500702b7916ffe570cef0714e0c083a581c2971c45c4aa6b1c5226400e5fd594ea3ae97fe94a0dc7f1e0979b11a2f3d15ad54fea957992ada816f97cd76168a53ebffae36e5787b0f69e94b3e08eadefe4937ce8b383b5022e57ba7135cccd5b48e38916f1f0bdcbc5858bf93cad75195d4329ab41a518d820262b1b610f7bdbe1d6749d006a0dfe18d0be1a19fb3d8e37795b5bc37ebcd884f91459164cd2536b3496c4b25a4c74282ece5d64ab861184e942cf97f0edbe6e1293c4504d861e60d98c4f6523df27a1e80843005ad21665b3adcf46f349fb0d905d70631d2ee51c0086b252778eac27346eee65c0fc88c6db5936337b0afa7d8cec656612c81e11cc55abf421df770e6c2588c743d5540e1280be76309defaffde2b82c808976c337ee13735a21900a4686423625a0ba4819581edbe574e6d7053c5fd98d288db4104ea64fbc0e7ad11d50eb1470a882aa00ebfd983cdda14db34f7f968ccc93097cf037dceeb1375f2df4de09c8785f5fef8fbbe284566e5c9a2d38f5d2f9145b7f5087f6a89a56679680ca4180ad7da3ee45da685f0255a45db806e1379c1ed59bfe63feb7d74a239334c80ab9c1859d205ba798810adf8afc569170f94167439d137215d2ce0b2fa983ac138a3ce201cec4927c62b740912e7287417f86beb07af9c83fff843df1abd6e6f81865b82b3168528d1c473b4999b0179f1de8ae22e8ed7f698ee8463eb93fcfd4e017f29ab3f15a2e061de6deb09459d4ecc62741ffd8514d5c1f10eb3b1525ad60512ffad00e360e0d6add8ed6d6df48d63cf1e36f306bd76b1a245cdd09951727367e45b3a02d748dbfcbeea342be4cb0e1e3108e57993581409f8c6b34e2d38becfcf15c653b92c88412c087eddb0bc21eeb620317f49a9bf5d6164418a26322e1964fd676a547862c2a7ce5f13898e3fadec79a638f257532cfe977fe8ba5e96782f9e1e3e8b5f896a80d816141f0c988ea59ea321cffd23f298b76e49e92189e7f65718d14091daeb82d432470a2e472a39a154226a43c543db2bb933adad08344259ba08a65c543d2ee07b67328ca2d4e60e550b85215ea5873fedb505cc1e4db49e129249fb632ba22f11b897b9423d08f96ceaa863cd29dc16af6ac76c4388c2795250c04377277626992b085ed7be2cf1d63a2eda4b65e287081fdc4e9a3224ff57d81b3ba8d04eb88430a01c5eba35fad028e8de1812920cee2576d0bd291407c5fb70c5ce07104b9af7b98c4c709c7f019d4a66b136120b92612ad5e73dfcfc1da0fec3a7928e57d7d4769eecbaa4c269f2859d31d47d1ae40e4da5bfa6592074c5bf54b04c707b8d97455a0a606686e06bf5ef7617da2532f305267f61c5f627216b06ecc3da6c6f7b420e2dfecaa41657eab20c89927ad6eb5c4fcd513da89a637755f4a98c45cfa108f37415bbf49ee6cacfda8f22f7101a9798d844709a38f9168685f105157a937bb10d4f5b342deab8b8be8231490da52cc0c407bf942270ad93d4a9bed5c06499584835dbba75577dbbc47fd3d397f0417ade99549de4412c8893cf3e1a2ed74c234a7b60461efad57d9c9fed9eec3ebd652282b045174e19355d8cfcc10add9192ffffd428150dc3f48e0417e47d6407008c62486cd4057535a5a9ffc45ef559a51fbbece64306f64da9740108d0b51d01423379bb0a72fe050d2abf5f5acd25cff57f8e3bcdf938749c7bbf77437424ada88c167bcb6addc309b949a8e200b9a5b6797522635731b250e2405f98d054aaff4179ccb4b24159e4c033329100cadbef3da262203622d27899166f6c3c79a35daf7840853b9a3ce494bf035235cada8c31e28be56f0976ef9b96f15de57e6896a5aed57a7b5ce77cacd1c806ecf83566bee5d577f7414a106ce16ca6e8cbc144f571b1a37647041694a6409f68d15604960417a60bc4f1a878eb01e89159e701bb8fd96be45395a8b8c4f0cc5b982582741c4ccaff8961ea892f084b10646c7a27687a2d3c92324cc3a19a5b38ca2d5c573167ad54486ab3adfe9219882f947cc6a93a3827f4b51d76e90ffd1587646d921482022db8b5a22519be3a1e62e9a13ff9926e75c42e07aa295c8486df69dc96168e920e13c85eeda86dc560b9f5d4c77cb8ff001d390dc6c5a911c573ab1711df534930ef28832936c80cafcde731e999ce90741e669d93f653efba12466726fa997e7ad24d34395a02b8a4286f3604f120bf47e8ec41954e6def2de896be477ef7916f18214d28f58ae91ed8d7eae9e2df600d313b6cdb952195e9d030e0b8fc98a68cced3070f4abd2d252727320eb54b602ec861ba630ed3c5d6fc8c8b39f4f1e9c198a6dc8d5f825159ce15fcd7bea5701a225ac41bb152d1a077adc03ecf06870375f2d2618094a648b40244e4a981e7efeadc608c082dc1824c4ffdbc39afcc8c464ed5ca8dfc1540ae3a6c034364c356bf13f880abe8633fa041db78f4be0d17a4bb00959a697935c844c6ddc02222f7aebb1af2c96a757536159dc1dbc31131aefe4c198ccd2123eb5d0ca6147bbc9ab43e993508ef4ca383e2847d9fcb4c975dcb240bcfd164daa835311cf7dbde0f256deb5f3748b55c312a29a042725ecf07caa904513e71b4c0ebd3b31c2938e710e7c6be819bb3125e638ee4b54b4c8fe16df1cee7587e6bdfdcccf2e3b2aa4a54c86b0ae711f056c229c644f519f60570aed60fd3d0638dc341625fb4949d355e7d84cb478133d25730162623acbf5d36b9ed98dbd88b6bf7bf1f55006f5ba2d16297557f966cc01baca56e3f6435b724c0b6fa4cc0074efb0bb2cf0cba9a1c73d3337db7dc0c78b87746db7bbe5fc003edf608ce5d91dbd8b3cec0f738de14c8e2b6df47df91805eab5635402ff26245430641abd9511cffa6bf8d352a1f0d97ce2b08561c97a5f07a07e0ac42a2a73366442e0bf125a718553794b021640ef9f9f07040068cce2337606af46f897b7ad8ced05e14f7ab3e2bd847f810058d665a0c3b6903efd8f398c31e356b48216111d30348acf93d28dbec8e603cd16ea5d3b24f38367c52f5629fd51bec34e86ff21d4f5466a53aea7048babf3afaecec2c9de099bcb2845f66689e02306760ef5274e65f36fc61edf8112b3b414a878b8dbdc2ced0d7dae0e95c5d6e7c80a3b4cbccfe13293e454b6c757a8d9496999fb0c4d4dfe5e7f3f40e11172324323556687e95a4a6bfc4dadbec000000000000000000000000000000101a2f"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-2.json b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-2.json
new file mode 100755
index 000000000..27b867d52
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-2.json
@@ -0,0 +1,6 @@
+{
+ "id": "short-signature-ml-dsa-2",
+ "expect": "INVALID (length)",
+ "alg": 2,
+ "raw": "0x50f914bd826d6180843b9aca008477359400830383209400000000000000000000000000000000000000010180c002b907a05424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2fb90cec33fc1486a0e70aeb6fef62ce5a0dfb51fcec12164e4024b0c49ce8b65e01356d80a9571af8f69a9c7256ed549d699a31ceff21c13c482ee0c5759f96125b0099495feacf22a001b2c887b107a9ca9e84de461fbc6e143566de56c710156de5b5f4b7ffe29c0124c1fbb6a792110284c9ad713d89bbb5ed444d09408c65a9f74c5f6c4fd281d31738db82913dcd1ac1fccbba24dc933fb9a8e6c4e426fb98590d7da0252c34d866c114526ded1c9d96daea12ecbd8f2a44531dfb72f02c02b267edf0560b1fb06b087bb6ce02b2922d92f81bb7da99b90e4a2dd68aa858759584490be602369dd606a510b6228e3b941421a3006a697b79866cae011d8aa496de4f3bfffdc0a087d01323db849f6237d7ac476d18bb417f26a697388b4c0a78533f3dd763398719c9ee5bf0299786fb8c4143af8c1195103390d4494b735c06b5815c454dba2fcdd27d214c48712609ffe7ad7c082e835d7477de2358fb3c4b5162027f816ca85aa4a46c25105175e77c8e5394db6fb3999c25ce578f066329182b28fd5b68769cb07ebc67e47a537f6cb62bfd18af162113a4df7f8908e0ce953b6a9637c850f24de0fda239c25fe4352f3b381fc270384d51d1af1ef0dea8501f98ea71f26de97e98799c4b2a316a216bd4af4861ad83fa4570532029564581bb35ac543355ba3aa246b59c6a5d9a91b938f3c4f0ad6d6f567fffdb6fb78402ded5fdc544a0f5fd87e4677326ca003dffdba8fd390487a6469991506a18f376b12db5be3bdcf4a4bc2f5b34dd8f7066bec3b40a6502f414eac3cd1ed43431b033757e86cca57691b0e1f7eec68fad9423f8b0620aa94798546bc878cf29d74ae74af5244ed9b97107fb83abe25dc160ec05cda1c50b76db981aca781868a7913a3e7c98aa5a3ea8bc81270e6f565138dba33c9c7e887641fd3dafd458b9c64600151038db05725a976950307c662c2eb668e3067f943b9bfd805307729b39ed77309fd5e67ecfc56cc231057a6628fb6f528fb969378529dea2c58fa0b4d791ca591ced733e8cf93a8e19907538f45c2618612648d3e1a78492afc154b7bb0285aea97d618e74a74530b492c66c6bd31557cdc55476b3f163196ec8e87f110834ffb8c232dc77cbf2f7b490f520b3b328af44fecca860a19bee9af6a5f69f63487d7dc6b7bf1233c4735522fedd475f905f044a0a7f658a7a378958cca56a163a343a010f4b65d1bc38cd57d08e0f887293fbc106ad7b15aacca6d51558cb8478b119acde04a19b007802a8e9578121304622aee7858d1794ade88973d6fdf981ebabc98fc417d765c075bf8f76b9781dff7c60071878027c057aade8eaf820186035499e9e5fbf8791e6fc0a0e49047af312a8b1b1e80628dc4db4f45842e19096a54733d28028203aa668bd8655631a01c000c956c32ff10572fdbc95b2f26d09fca84c093ddaa122ad93598c03de9273873ece5096648a6251a27e993ec7b6ea4f2181c09bb06852799323f3e993a4b7461439f702cb9df183fcaab11b8bd2ad391924d5e6ef261fea01c91cdc10d9345c290dfc3c040318d11419563d407c8365fef3dd31d8f9d7d338f5f2cd00433d1d06547ae9c650d14d9a7e5b683f0458e7a909d90d4a57201ca5b8753c13bda3591f9cadffd0987d1c7fca1c5a0cec1e13c612d0390d7c0e2f422c97cda29959cd7b714fbeaa5da7b0bcf911c2744a9a25c7d49e93342f61e10a33fda80fadfed2668bfab8767ce80480093b4845cd5ec83082e8f9ad63236743e72842d1a3226640a549c2c1d002a176e2427b2ae612dc272e3d9fa80a904eb8f93f494a52706346c08b06c9d1d8a61a9c7112c0933910882f0da6eea3c389f4faeea51c03394eab4cc02056d704b8839afd76f0839be5ffdc873b88f9a755be6f0229b0843839a25d63c18da89be1c5da930a101913ffba01fd00f2a447d5f58ae8f21554feb47f42d40c32158219dbbb1e5e96ab3dc26cd6a435525c265b65b0bf48d68e9b3c9178a509833aa47c23e63aa9a6f74bef1e4ef863556b11c014b85ac7c157f1e64531b676eb28c68e82e0089d2bd798213c836cc354d4883dc0b607456ab7f894f0a1f73356fc05a5c97a9cf3b231890c39105b751f6fc54063a08f3d3a264ab90cb7de1d0e2f6acb92302cc9b4bb512e720e6ff8343004028ad223a70d395c5f974d3ddd380f798e80edb4b13555c3be0cb1a500e19a8b1b05f9cae85d7eed756ebcfa57828f1054296ffa48d426ceb83c69ebe1b983421f42316ca6f50bf8df0f4d4aeef85005638a304d88764ec26366a1437867c89800aee55ba428e0c07542e123d748c795560153007f768b20bb057fc2643b7db992c3b9cbfd88657b17fbe8a783da2050affb518cab4226cdf28fa97f48651bd142932835f061f8642e79d1f7ae8ff8665aa85aba24a850b2042dd37e61e665a451f17cbe9d57ed5ecb1dce9ec34c576762929dbf46964de7c44c9f6b10fcf52b48649ded2d491bbe4bb6ad578cd31cbdea6df8342dbb7f33857617250b014fc6d887a448f7a5cef25ff69dbc94733bfac1d5f8593af7fbe4759d23ba8da1f405ba179c96d8ae49eb760446d842f0d61ab08508a3e31e4953e13a1b197d00644303e8a9513199583709f41757740a0dff347c3859d3a4ec391481af349019f75ccfdba111a4c338fd8283733115ce7c114111abb157c1a5a84f7b39779a54f000827a250bff00dbe9cb7162d81f6c942b719f9eb973ac7d4652b911622396c517c6e9c7e5f839c049855567fb53ae84579388e3c87af420272558c686209fd92fc339a553f873995932d9dce52f5e60cc0889c3283f94a0d2d5d011154d9935e1dfbb7e747b393bdd8a84f601adca56d4ac5e8e6f28100a7d5522de50dbf1bd7f5604fdfa660a58dc681b4b230abbc4f594a972a73456de1b7f48975cd03313a80074f5d6701db61860f33dfcc9f06e313e8881c385a50de28ced014daf702f01c45368419b73383008b9191293f59fa87a1ceb0cee64d486842ed7c289dca3b3f2e261df644de0f739079ba5ea195468f0693a995dae8e0f7e4611196824f329fc803bc3588d7d941d1fe86a3ecdb3eb8f6d4066ecee371f9a14e5bd46a40b53e87325bab7255099b4fe7f7b09eddaefc6582feecb8dec02b5e58d735a927d052e263027fa879fceb852b9e08db4636c7152f272a43ae4037c50210e90caa3e008fbfa98ed42cd425259096fc06644edab9b768779dcd892747f18a9cecc6aa31dc27d3f12a540447653edd5bed68f50da71b7992434b74d0209746f93ea429691fcb99da0ca32df822ec4332f7eb4bbe6d2111ac84a55932b3e173e388ab96a5a8a17c7d8b8131cf566e0335b0c4a37c5ae24e73c81146031295b69ce3032fa8e4c7616558179cc561f14864190d458cb82370749d595966047de698256126a4ca23a6bbd39201b8649fbcd387474ecf5b9f732e65938fe393a2a1269b06b9b49c5d8882d70776fc823da5842d812be2a65d2f5ee0d64f8258e761e6f2d4c1a825963b367d70b9e81b46fc25e4804fe9decf3aa0e47f1eba573a24f0e4f7b8cf8a886c7ef4175bd317709feeabe46df9719e7d7a4bc2c1bbc15a58b5332ea558e160f5d3b7aa84fe54ea7a24bd8e394ab794e72db7946780272556be33b7f32a0ee651c013d8ed3b5d75bc1c4826dc94f9e3711c53be3bcdf361329544f2993a189b6431a6dda8b81cb1b7c3a69ba96c1ac84a55100c4985cc85ce272e8eb5a57c563a7ad782664d561c3400e779317122d425c9c4193414bebd4d6ad31ba916448f65e9a7ca1f856dacf9d88b695410c8491a759d2c0304e8368b39cf502d0abf7233b1ba9671bc422ce182833ead52597481ea3ea26a2cc35e12a8c83bbb263202d5e9e7a5bb8ab2a5a844d596c24fdac423981fc4dc4291944ae476d59c9a31a05f79f0fe4b39f145c4fba857fa553a17fb2d5f941d5dac8dd3dd07e48eabfe5b98f3c41e7a84986dc3a7a3bb0ed2d4232cffbc50f167d58fb52fa3b357e76430d7f0f1aff6e2d51ea8f5b98bb66c5b5687821f33b9b6c2e407ad0e8140c4d5d4f1739167f8d63284caf4a43688473cd97bab401218fbb2ea13be81bbc05a81042a02eb1843bd46ca535e778e207c79ce3fe511a55d21bf20b24bcdfb43fa62b3469fae2ebd61e362d5d663fb2c08cbde5df9d8cc1faaf6370b5328ffccde873849299d61477a9fcf7c5c96fbc51b24c0f2cc6e39a46f4a9c1f5214f2cd06db62a37e2c6f477ceac0b92eb882d7bcd1fc3721a89745473eb45eee9a4fe6ab323d28f4db957d0c5dc1ed25ebc194f744a2cfe98474868e6acf5641ad454b3626ac2a27a9db416eb1763935eaa5612e43c49e8959ebcf5133863e98c19618e936f33952699fc224f41a4e259b40228047ed6a17cf4f3a42dc76df1346acb0986984f1692b5ed28f0825a23094ddbb8c1750e9035b1df2166f142e7f179473098ed73acb9ffb8be530542f31de88d6677f805cc30ccc0b60787e61f9d195ceacf07a35d979f9c3521f23671f378a6cd58ed2b0620ff7e2def5025f878d70008744c6a53caf325293353747c94c5ddf12e3a42686f97adc4db62b5e2e91132345963b7292fc9d13b484f75d8da000000000000000000000000000000000a13171d21"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-3.json b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-3.json
new file mode 100755
index 000000000..25f29d47e
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/short-signature-ml-dsa-3.json
@@ -0,0 +1,6 @@
+{
+ "id": "short-signature-ml-dsa-3",
+ "expect": "INVALID (length)",
+ "alg": 3,
+ "raw": "0x50f91c63826d6180843b9aca00847735940083045f289400000000000000000000000000000000000000010180c003b90a20fd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308b91212c74a08868ea0fdad9fbb1b485b793bce6e4fa945668b2351232a7c8a084fb2d87a5c83e7dced6bde3743617a7c4babcbf9381694b64d7e0feeb6615440e927a63293c6b695900b1e7afad1ae612c324a88e6761c3b6fdc41d18f514be1ba3a1ca53fdbcf8c19f95bcd60223abe52d07fd7c4114dad9f347cf122f6241429da7e598959c22692910323a0a699595398f518c58deea7159920d89e3e65702bc2cabea7e9ca0bbb7002fb7be5243bba6a08a12238ead443ff4394510d25eb279885d9112c44529f294c5a2bf493a74ba8f4e38744e632680b3ce055a897d2a5468ef52e6e70dc5af55a9fb83739f6cfc6994871662b8263f2e07e21a6514624909369e0138755165dd2af5a791da63c0604b68ff160fad82a578a06e76f62bb7e951b81d8fde2dade6c3a314eec5913151c16a93a5abd5ceb59ad96197a349721ab123b42f799dbde36d7965e0e5dfcf43d8d1ae13f4a00afd8dde36137d3de87f4e2c0366c18f4b3a449ffd9afc7c742c50456f6e642f7d09e86d5aef224b20ce5d8a2bf164484df8fc87daf69e459fc78c6b974cdb8fb1dccbd5290f560e3114302886e2828ad73ce71b06186254206743076c6af0c3d1facc36695dc28db1d026686b141247e1c7a9323d544b0079023cd2adedc0479ceefc8e0c34782603d0c27d18768eb5485a85bc385ffdfd25f735688a3b9a0c6f532b2a7989c751804de0163582293a17f635fdde14e9067f12929b079f89a53dfc87b986f89f718320ede83cf4086d0d095b24b66d5e3f1bfdb08b79cd5b25657cf2b20faff1d199c16bb7f631b33970b34c12997637447e4127db1bf580b339807637a86e0248cbcf8e1d30ae6fe053e2f9b7b3d0f9e3f4813af908b633560779012f9e06af00e252bb0df9f0caf7d1e82f8deb2ede21d13f406dd9ea69445d50844c95c921d8d1cbc8afbc5ddcd4157e65cbfbbafe2670e9146a5643db049a8d696f0eae07c3d4099447ef78bdb90fc05d7cc97bf9b9dee8719464ec6b9e6de866f73914a80396dea3900a9f7b43a47e648e20a9504da92c47ac65368813e5453e82020f8861aba2534346e6137e71adb28a5ff080365d6ea26dfc30ef5500d0760749d6e4e0f93aaebed544832308b19f72e92ebb8eaec2492c6ea7972fd359a8b67a1f4053bfb1a3c6fb720b5925a7a827e59b3bd0651b8014c77b25d61db17eb169cc2fa2442c82f68fb42200c59baa468a9fc92f13273ff071124f8b31e2b4b2517ee622d29489997ecb5676fb52e3002371c01004c214757b1f510091c2377a08d058209d18feb9b524a41712b6df4b92f2b14c583d3196749f367b3bbc8ab5e9e2615c511f23ba5fb1bac2ee9436dd8d162bd96f1fb663d2b520ba7e8ddfc2a4d549b63714654cfbb37ee1dca5f723139187ada8f8d5b42ad09ff196b70720d2527b4466d44f33cce486ef2e86311c75ead31a17b16989dc63bacf0d465379d9138df7ea2ebc71f4cc3b6662e24895050e2553dbc160a567d6722964a904d43bf2684206cee3562256e98addf3038e968cf6c09c921e2c89c9c249f6ba7afd20dd27587b4143f704f2738315a91c2d40c467111b4f3bae4f77bae402145e742ba83a527aeffca13ee2290988df882feaf5a3c24b416d59e06cf4f8832a016ce55419b7bd2028545557528a0af23f17942433e13fad089fdb79449bd9d99b0324b1828791249b6789a09cdfb6ec40c0fbaf8b28ea4f72d3df5159bea7a7965b94beb1bb01d87d76ae7ce47fc333fc152038ab4e7ca64a802f96f2e92bcc53ad9cae0242c622c99b2daf005e554cd6ba127991d84841ffe3ba0674eb7930509045dd00ab91a7c6acd2f4a40e7ffc9959929851e40d417f488a29f7bb5af3847a8caa5daa0682aea870ac8b866ccfdc435971e3d862c2f651cc6eb8a33fca313a56ab8228ee9ac7dce14ea3c3fba4f58c70888ae558d8cd632a2723ba54a3d538f4e20936a2ee543e9b2141e06095c72d4ee19908febf7c248c03a78655420da644746e2d508c31ceb0b648800d95dceec72f7576502046e5dce54b5a097f625001bfc92d6e4633b293cdfa63b1fca5de9e26d03ba2f1cf3647dbdad5359ed76bf702f0621c057dea3617af678016aa13360ebb02c6cb2fa0d3f137a1a3c639c989e12383841ab7ca5a84f84c08af4b85416ce7ec3ed91636a79add207bedf9dfb2ff626387f20cb3315502b2b06f361cbf6a51fb507598af41c5a5b9cd95ba1894ca372c5e1851e62a0d3d78dab6f92bd43ba6fcd71230b6cfd843d89268872b75e3c5b471db530b7ab5451dbe63fa0bdaa7d74907cb376643e129febbe6ce10b5dffbf323dc973f097d2081e06aad65e674c5a41bb81b80556fd78691fe6b5bfad47fd1b64db577f27f22f17973cbff3a7c4aa43569bbe6843d773a2f933f472650e88e0ec6643f87dfd37e7fba915c7386a130b8d4f0ff4d0e99a633d1f863f3e8ce4e1ac5e31438d89c3b6d5ace3aa6e14e7073164ea01e853958bece389316023127f9916297a47c5d6ab5513bab874c1ae3bf2850cfab9018cbf50a7febe03ff3e8e4e55ae5632812b6a147edf051b461bfe56f01a6ab571e0553e37a57a3a9811f4fda2e189d79b74215d6fe199595d18c6543c747572f8cdc61a53ce09d9ca96b43a5af5b56b53148dd4fdfc1e22c9958caa783f2d112d8d5fd39e6955df75d35c59a1967fc0d8d3293e39a6cdf82d6846b39a74b1a538372c266b3f12d7ccf464ff7e32fe54342994f51d344302b3b2e11eed2187a741eec99ef0a79a19a854c03d8bd3fcd557b9d8bfb35f0976da327fc7e8d95fb43db8e66be5b373385fc1b68099566c7e88aefe92c7c521d084c15c8d403d87bbc975e8d687e2a51e5ce53191e3db5bdc50f475853cda7cc5a7365c41035aecb61444c2a48492a600b58300b2805be97b4e9e30526e9e62bb3248a17c3809219307ca85351495c943a865359c783cf615a809c739cce0786c6045d9c8071797001434cbae571d42cef415e28ed6adab09ed10e0713dc1412ed80b8d26d549964321559137483c81b19203080b36abcd68e841f4c78b5302da79fd6e555f390322ae67e54c55749491889d79eb2982fc4428086bd1060c4113137ddb4dd7c9b690b802e805999d4f5127f66f6b1d397dc3509504e2196513b5787407b45b928cfc3c437523daa4f876dfe061e351cb3bad99ea205ab276c4f2a5ccee1027104f09adaf55cd282d4e9e44ac2b65f7e423da1cebb0ac70691347e7a7bd0de8bc9fb2e7a08afc0075a0e85902316cd6ec9a5802c51a6d65bf3251ae712ae0f66de6cba1e51efbad53ad7e769f851799caf5fb81ef35b4da814915dcfa67553f1c67158154707d16804be27af2115559e4758b313b9da4a1131718b29a75970b3f0a5e2f2c11a0a1ed47f238c145dc4fe9e8e963d8395c67dfa94a232b8133a0d953b05455f79e0bdff0bc3de9c04d93d97084ab99229622cfe3958ac5fda6757de1696b575f6250b441e6368386751b1d2f6007d254d152fe76578fbbe164af49cda805b9325f7ea47f5e18f3de1ce38006ae1bf027d3e354d6f923d8bc6286aaf9b9a7b9e7a7fbd36a31db0d88166dc68e7eb567d8164bed1e279a8810fc21656621ff7cb42a21ee04e6086924bb62dddd16c3343db69250f7ed95aba953202640bef18dfb6c00f1ee03c670a5cc6c0f3cd7cb006590dddffa6f19d450860e289f85edb4fb0dbbd2f992eebba09cddc1b20a3c98d8739ad1875a514b09b1f23cf406c4c55cc4266e0b8b283fa445849316c30bd19254e9d035756d2773cab7f5fd56d6d3a094a717ccca43251201cfddf80ba1aa0dad34f5a3acf8476b784fd53a1aff1307a7838705112650bd25dfea21b991d801f018a5dae26edb9dd5a0ab940a94b7bbb90fd1f30f9d1dd2ea3aad6d0a2a3c42fd2641233c7d624314c3a54ce616d2ca5683d04f6fc0924f0b667be32f4de8820f9cfab963a287a1c708857ebabed9b5bcc35d539ef9bc170636cd528ba86a620195134cacbc2b8e742376124b67ed8155ab53979e281f97b184c60355b008f15f45c8b7a506b1c1f511e4aaf0bc32fee27b656b01ed6afaa4053ed674a60175b6c89a77d42963111d0940730db02ff67534fe6a296e0e01e2db6b3f0fe9648286a0f3420cd4393163662751deed6457abbb370f83ed92e9da86a0181df13b8ef33e5718ce524a700ba5f2b40f3f973a67c1c412dc251c19e6b7ceb279dc1dfc36a3567e3a98a9d96ef52b0d0734f57bd9edebedd925167f230b1c81ca938e94ceebe43d2573735873a436331a8b76c1169c6a869889cb74e5d33721bbb99ec87f160c025f570f1d11c2e3ae6a52580785d854790139510179b003418dbcee1f4fd4fa39fc134521ffd7f29cee650472638dd04d8331ee439eaa32c57b56c4fd9c9ba87516a8236dc99b8d6e4c2a48e53a6779d5e13bbd73cc7917f0cfb8e231218bf33bc3c213599eb76476558f0e38a3979cdaad6ac6b03bd0ef0aefec634fbe0e1e87bd78123a19b7352326b9def856ecfc02b06622f94e8cb2a1cb6cf10d020f789a7db775063030f15b463f08878219636f2bb94ed11a3ed9689d797a3253809c7f2e0c60672e8476a9e272075c7f808258901e611c4d535a11bfe01daccaec3a26a187ab45a9fd0bb9a7ecf2e9c4aa3177ddaca1449f19f78ebe26be2e25bca012a10649b56899339f5418925648f3253bd716336dcf65e6b4f16d2ae51fed1acbc8335c103f721f46023cc2043f568ddb033aa5f2157e52b89eed4571cb523fcc66ef5cddc90679633c2a46f45f1a86c975db4f6f37f9fcfe54809ccf75305bc9f242f26f30a0ad5f3cd71cbd31ac45ceed2dc8571142a09b7d3091a4838727b9a067927e17b7559076649b405dfd480627881489d52339d4a8943ca396e92b92066e45d525acf7785a944345d25d721d6a354b1a9f3e2afd379d1c341badd0dd913a3471a5b78a81c0b338a2984e115d003b1deec1b44fd19824279d742017248fb4434cf47ad07fc87df86e634b2d8f6e0aa572088678b9a9f767404f06c84ea8cbf65d46effbde7de1f090d3d4b9e7c7c3b2b1dfa9e591efe12ffe0fc82c9eeb7fcd9f25fe438b39c46614438d0be7e1dad11bce8b91396f867531e8c45d8c01119abc2b20be253779b5e651bd80536854e2aabccddc5f4fbfb3497111fe9a8f8a417ab4dd806745c82126524ec325c931ac1f31a3cea19e159e1dbfbfcff761cccabefad38062872fe8a45a14781ba12551befb31c21150a56ccacf9815d8f458b1f591c71ba7b0459e7c09a4eac5c9e5b2984314ecd2f7054ed055ba082204f7ed62b1d513cd0992bc10c28bc745e30b27f6ca28ac84dec6cf0ef73c971ce12b2ddcc0d6264d8f7dfbba0a20f8ff1d7387cd9d9872f4b345b409950d66ababa9852f7f5ee634dad6085666956b97e4c9142dbdce96bf42d1334c61d04ffed5ac8f12a5075ac87a7416fd52579a876c89e22008759a93ebc57279215e178662a064bca65670089ec688532468c07161f56bbafbfa5655768123e713c7aff52852978e9d6004ab3a434d9b5c73f0d90dd1fe742a169a84f0e96a189bfc5265d8c5e2d9e42f5503d04ce01f9a912bf8b9bd8c282a4d40bbeca55d14971d1d305a16eb85d02b4edd8d35baea56156ba12f4e344dc4cb34509fc780ee97d24173a75e49960ec32055710bf8119d005447c6c391365737a0cff68d9f44868b97b2357dc051ed7fcf590b32292624545935e87f25e56b3e4a2b9c39c4936b5be9030b4711f246623264e0370291b675e75e1ce9cb425e5fabcfb55e25f084ea8a1b84870135ad997f7b700876691939cf268204669790a10ddd3d38cd22252226a09fddd395482deb561ee834ba452750d5b8e0de63c77c85a7446dd5bb29df2620f98e07bdac4cb59af8b9dc64d427dab780257e252e8d6793fd1b99f7c3162b4233a418526ab227d40b9deadc943d0f108a38d7a6b075465a44c920c0146338504eadf826cae345e864452e94706c8dceac5cca87469f2183a9c918295c09eef65f747b7a3d7fb3d259c4f531ffe48a5c338717ceb45efb557a47a593fac85cfaa4c263c109d385c01a3193a6ad1be5923d6a53e6c369a2b5e704cd6ac3ac255954c3fca1079895c596596873c1309fdcc5f36fe039d06806dd16cb00bd028edd6b44fb1e9ce4a020362824bef6a59502cce4e1d3d3884d7d865823deb092916a215ee73bdae1d4baf7f294caac7f63a36c2a15a40517438b8cecb93a5da3e11c25ff228ef3e7281360a2ce3ac66e69a2f136a83fbdbc44dd1737e9a31bdce16df9e118345ec1d9a9c47bfa60502722c9813d31c9f1b0364e2e25d77a0816db52f7e86bade9aff644df50b1cea9a339e76e869fa1fa50101f8182a2a6aee2e90d242d4b4d6b999d1c358a8d9297b6e0e2ec141c2b3692d70b141a213d477e87c52a2c87a5c6d1f0fb091f35f50915878ac70000000000000000000000000000000009111b212a3236"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/unknown-alg-0x10.json b/ethereum/core/src/test/resources/aere/pqtx/unknown-alg-0x10.json
new file mode 100755
index 000000000..397c978c2
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/unknown-alg-0x10.json
@@ -0,0 +1,6 @@
+{
+ "id": "unknown-alg-0x10",
+ "expect": "INVALID (unknown alg_id)",
+ "alg": 16,
+ "raw": "0x50f90ec5826d6180843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c010b90520caf597b4848d085dd620001a7707a9e0c120226d4551a49d4b6e0cbf82ad3dd96f26ac5e395a26aa1f3b569e89fc4914cec8fb3acd07350d1b8e0f6b66f7ac3e4f07395d148f5ba65789908df3cced072e5a56934264354556f4655afb86d9e892fa9926e44f74a340ec5a92bff6211740ecb879366826987e5556a513d8c2f585eb5ad5baffe6cf50aed2b96bb1f963bb124f2cc3b95ba6ec5c4f272e7e457bb1c6547e284ffd1c7b149b877c1a9856a3303f9aa5c4005c376767af6d7f00097e97d7a5bee0c196a12293ff2cef34a09f0f594fc12a2e40a4d7652fa8db49c02d76fb76320e29a0d6b15e97a65147429fdc70e4838ba9f60e0318132aebca93b564960caeef51770e45d8a6ea2171f9e9482441610de9fc8c56d80e952fe7c2ef0dfccdc0a337bcceebc20a8a2df53b4f61f289ebdfa2f134437e21fddcfa394bcd16562e41d1715724afb398f8312eacb3ad606fbafc00954407f83cdeee3bb5a3c565f50f9d54ebc8215817deae80e42c66dd0960ba23c3b1e99d710da8e1efecc89c76f769bb5e40b9ac5ae998216c3eef8f039fee88e43dbfd056be1c43145690c1c9d3775446c80d93214a89ff60892b4ad7c55bf56926b834cd21a3e09de040e2ad9b6499c0840957b6661ab1f149cf79ebee095b8c481e0feb761164b4fa5360e79987a0dd601a60de09ace752b5ab69fd73ff111e1410957ec95bedb2a9dcf307037463248e4b4d8c0fd1b455969145d2a77ccec9e101f5e9142e4f1629e19662269a9f422cd64f1ddc6d7bcaa30c949a7c67bd6e14fbf8dd7244ba465875df788b1d932631d6b749c37bccb00b04efb9a5c8d05dc73564bbeafe507c7e36eecd957c2054696602ec27892c88953fb9a5019899bc3ce475c4a2931ac49a4bc206b27b40ce3021096729ee2482bea5001985bb22a0f62dc36cbb38b8fad11d6a7c055312e69f8966a59b5c9b6237d7a8e59f43d94bfd5dd8e1589f3143ed4252f6fecf4bd40ee30b1382256fcd3218d4864dd281cf99d83c1ed4a766b26698a914f044d45405db8d7745b3d7aebac37e668c6e8c5ca09a0e4ec2190300c19990d96742ce7f539e05b8bfaacd2d3bbfc07faefe22d5e8795fc8a6e8cbaec0ed1489ce625ce9727ff52660025002ea692dfb39935ed30280363cd818a324d9bc782b46ff730e2e5955640bcbcbd285d2f2fa773154d3fef5bf13cfe81b857bbb576506ed5dafe4477e487171ee64c9e37d49df5ca7529dae30916b72965a391f4d3437303f7cce8c45dc187febd2a949fa7278f7f8775dd2bdd66b794945b0e96a0b58b6cd934deff1f4ccf156e8942c7533c8a45314ef5e3210fd5a3f063982211a122f9a3f1f99c253c37d981f223dccdda18a34bf3bfdf9e02ff607ab7c92ec4388dbb7fa210c7106bf570d60e5321ac1e1ed5fe32b4053759bdc3b87b1fb7920371b6c206d6f4f871d1667b41bb8e661f48144a312e3d7e0d372322d0a3dd8641574419c49f2ca4228328a089e97e86c4294b9b60af0998495379248325299e3846741ebaaa69994ce536201665cf6cd23de4958fff41f0601722df54d2111d845806c013b336d73c8461f9bf5a16eb05b08140c1a2291f78747c74cc2568e956f307e97b01bb3a67eb9cd51be8fd7ee8cbcdcc5b2b2c27950f5ff0f7e8330fc2f95e3a4ae49fb7512a6106c5cbbe4a5fda693dea445fc7e792676b5fded44d7da271c63e76e310ae988ff6885685868fa72e57e38d1b3c80318dbd5e075b29db1e038c56dabf7ba39fdf525f08aa69baba0817a0e289d5c12448eb4d07cd397fa39c312ecafeb9a846fd0b20667933c4c34bc5adcca7df159bfd5b909740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-1.json b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-1.json
new file mode 100755
index 000000000..d38c774bb
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-1.json
@@ -0,0 +1,28 @@
+{
+ "id": "valid-ml-dsa-1",
+ "expect": "valid",
+ "alg": 1,
+ "chainId": 28001,
+ "publicKey": "0x372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083e",
+ "seed": "0xfa8e8bc1e5b9aa3d7e7c7f7a5975ab8ee22b1f9bc118a3c20ca50f4f0e737aca",
+ "tx": {
+ "alg": 1,
+ "publicKey": "0x372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083e",
+ "chainId": 28001,
+ "nonce": 0,
+ "maxPriorityFeePerGas": "1000000000",
+ "maxFeePerGas": "2000000000",
+ "to": "0x0000000000000000000000000000000000000001",
+ "value": "1",
+ "data": "0x",
+ "accessList": []
+ },
+ "algName": "ML-DSA-44",
+ "sender": "0xa4fe6cb101b79c0531f265f6b2584b37073087a5",
+ "signingPreimage": "0x50f9054e826d6180843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c001b90520372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083e",
+ "signingHash": "0xa998fed4c5f710305a6944f263d3d26edd3f4e3949d404f547eece43c10afd94",
+ "signature": "0x664be581b59cd495740a8a9aaaf7c6801a8bcedb531ace47da1be56ab30f1c4ccdaad6e81aa97352baca12b6c69754123bdee38c0d57bf15f0850572dc9b456234eaf37eb478f9117f952ae95a0d165d12d948b51672a03c9610a98cf332d6ad7ab8a87defb3ef7249cf8c3a815129ecf5600500702b7916ffe570cef0714e0c083a581c2971c45c4aa6b1c5226400e5fd594ea3ae97fe94a0dc7f1e0979b11a2f3d15ad54fea957992ada816f97cd76168a53ebffae36e5787b0f69e94b3e08eadefe4937ce8b383b5022e57ba7135cccd5b48e38916f1f0bdcbc5858bf93cad75195d4329ab41a518d820262b1b610f7bdbe1d6749d006a0dfe18d0be1a19fb3d8e37795b5bc37ebcd884f91459164cd2536b3496c4b25a4c74282ece5d64ab861184e942cf97f0edbe6e1293c4504d861e60d98c4f6523df27a1e80843005ad21665b3adcf46f349fb0d905d70631d2ee51c0086b252778eac27346eee65c0fc88c6db5936337b0afa7d8cec656612c81e11cc55abf421df770e6c2588c743d5540e1280be76309defaffde2b82c808976c337ee13735a21900a4686423625a0ba4819581edbe574e6d7053c5fd98d288db4104ea64fbc0e7ad11d50eb1470a882aa00ebfd983cdda14db34f7f968ccc93097cf037dceeb1375f2df4de09c8785f5fef8fbbe284566e5c9a2d38f5d2f9145b7f5087f6a89a56679680ca4180ad7da3ee45da685f0255a45db806e1379c1ed59bfe63feb7d74a239334c80ab9c1859d205ba798810adf8afc569170f94167439d137215d2ce0b2fa983ac138a3ce201cec4927c62b740912e7287417f86beb07af9c83fff843df1abd6e6f81865b82b3168528d1c473b4999b0179f1de8ae22e8ed7f698ee8463eb93fcfd4e017f29ab3f15a2e061de6deb09459d4ecc62741ffd8514d5c1f10eb3b1525ad60512ffad00e360e0d6add8ed6d6df48d63cf1e36f306bd76b1a245cdd09951727367e45b3a02d748dbfcbeea342be4cb0e1e3108e57993581409f8c6b34e2d38becfcf15c653b92c88412c087eddb0bc21eeb620317f49a9bf5d6164418a26322e1964fd676a547862c2a7ce5f13898e3fadec79a638f257532cfe977fe8ba5e96782f9e1e3e8b5f896a80d816141f0c988ea59ea321cffd23f298b76e49e92189e7f65718d14091daeb82d432470a2e472a39a154226a43c543db2bb933adad08344259ba08a65c543d2ee07b67328ca2d4e60e550b85215ea5873fedb505cc1e4db49e129249fb632ba22f11b897b9423d08f96ceaa863cd29dc16af6ac76c4388c2795250c04377277626992b085ed7be2cf1d63a2eda4b65e287081fdc4e9a3224ff57d81b3ba8d04eb88430a01c5eba35fad028e8de1812920cee2576d0bd291407c5fb70c5ce07104b9af7b98c4c709c7f019d4a66b136120b92612ad5e73dfcfc1da0fec3a7928e57d7d4769eecbaa4c269f2859d31d47d1ae40e4da5bfa6592074c5bf54b04c707b8d97455a0a606686e06bf5ef7617da2532f305267f61c5f627216b06ecc3da6c6f7b420e2dfecaa41657eab20c89927ad6eb5c4fcd513da89a637755f4a98c45cfa108f37415bbf49ee6cacfda8f22f7101a9798d844709a38f9168685f105157a937bb10d4f5b342deab8b8be8231490da52cc0c407bf942270ad93d4a9bed5c06499584835dbba75577dbbc47fd3d397f0417ade99549de4412c8893cf3e1a2ed74c234a7b60461efad57d9c9fed9eec3ebd652282b045174e19355d8cfcc10add9192ffffd428150dc3f48e0417e47d6407008c62486cd4057535a5a9ffc45ef559a51fbbece64306f64da9740108d0b51d01423379bb0a72fe050d2abf5f5acd25cff57f8e3bcdf938749c7bbf77437424ada88c167bcb6addc309b949a8e200b9a5b6797522635731b250e2405f98d054aaff4179ccb4b24159e4c033329100cadbef3da262203622d27899166f6c3c79a35daf7840853b9a3ce494bf035235cada8c31e28be56f0976ef9b96f15de57e6896a5aed57a7b5ce77cacd1c806ecf83566bee5d577f7414a106ce16ca6e8cbc144f571b1a37647041694a6409f68d15604960417a60bc4f1a878eb01e89159e701bb8fd96be45395a8b8c4f0cc5b982582741c4ccaff8961ea892f084b10646c7a27687a2d3c92324cc3a19a5b38ca2d5c573167ad54486ab3adfe9219882f947cc6a93a3827f4b51d76e90ffd1587646d921482022db8b5a22519be3a1e62e9a13ff9926e75c42e07aa295c8486df69dc96168e920e13c85eeda86dc560b9f5d4c77cb8ff001d390dc6c5a911c573ab1711df534930ef28832936c80cafcde731e999ce90741e669d93f653efba12466726fa997e7ad24d34395a02b8a4286f3604f120bf47e8ec41954e6def2de896be477ef7916f18214d28f58ae91ed8d7eae9e2df600d313b6cdb952195e9d030e0b8fc98a68cced3070f4abd2d252727320eb54b602ec861ba630ed3c5d6fc8c8b39f4f1e9c198a6dc8d5f825159ce15fcd7bea5701a225ac41bb152d1a077adc03ecf06870375f2d2618094a648b40244e4a981e7efeadc608c082dc1824c4ffdbc39afcc8c464ed5ca8dfc1540ae3a6c034364c356bf13f880abe8633fa041db78f4be0d17a4bb00959a697935c844c6ddc02222f7aebb1af2c96a757536159dc1dbc31131aefe4c198ccd2123eb5d0ca6147bbc9ab43e993508ef4ca383e2847d9fcb4c975dcb240bcfd164daa835311cf7dbde0f256deb5f3748b55c312a29a042725ecf07caa904513e71b4c0ebd3b31c2938e710e7c6be819bb3125e638ee4b54b4c8fe16df1cee7587e6bdfdcccf2e3b2aa4a54c86b0ae711f056c229c644f519f60570aed60fd3d0638dc341625fb4949d355e7d84cb478133d25730162623acbf5d36b9ed98dbd88b6bf7bf1f55006f5ba2d16297557f966cc01baca56e3f6435b724c0b6fa4cc0074efb0bb2cf0cba9a1c73d3337db7dc0c78b87746db7bbe5fc003edf608ce5d91dbd8b3cec0f738de14c8e2b6df47df91805eab5635402ff26245430641abd9511cffa6bf8d352a1f0d97ce2b08561c97a5f07a07e0ac42a2a73366442e0bf125a718553794b021640ef9f9f07040068cce2337606af46f897b7ad8ced05e14f7ab3e2bd847f810058d665a0c3b6903efd8f398c31e356b48216111d30348acf93d28dbec8e603cd16ea5d3b24f38367c52f5629fd51bec34e86ff21d4f5466a53aea7048babf3afaecec2c9de099bcb2845f66689e02306760ef5274e65f36fc61edf8112b3b414a878b8dbdc2ced0d7dae0e95c5d6e7c80a3b4cbccfe13293e454b6c757a8d9496999fb0c4d4dfe5e7f3f40e11172324323556687e95a4a6bfc4dadbec000000000000000000000000000000101a2f41",
+ "raw": "0x50f90ec5826d6180843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c001b90520372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083eb90974664be581b59cd495740a8a9aaaf7c6801a8bcedb531ace47da1be56ab30f1c4ccdaad6e81aa97352baca12b6c69754123bdee38c0d57bf15f0850572dc9b456234eaf37eb478f9117f952ae95a0d165d12d948b51672a03c9610a98cf332d6ad7ab8a87defb3ef7249cf8c3a815129ecf5600500702b7916ffe570cef0714e0c083a581c2971c45c4aa6b1c5226400e5fd594ea3ae97fe94a0dc7f1e0979b11a2f3d15ad54fea957992ada816f97cd76168a53ebffae36e5787b0f69e94b3e08eadefe4937ce8b383b5022e57ba7135cccd5b48e38916f1f0bdcbc5858bf93cad75195d4329ab41a518d820262b1b610f7bdbe1d6749d006a0dfe18d0be1a19fb3d8e37795b5bc37ebcd884f91459164cd2536b3496c4b25a4c74282ece5d64ab861184e942cf97f0edbe6e1293c4504d861e60d98c4f6523df27a1e80843005ad21665b3adcf46f349fb0d905d70631d2ee51c0086b252778eac27346eee65c0fc88c6db5936337b0afa7d8cec656612c81e11cc55abf421df770e6c2588c743d5540e1280be76309defaffde2b82c808976c337ee13735a21900a4686423625a0ba4819581edbe574e6d7053c5fd98d288db4104ea64fbc0e7ad11d50eb1470a882aa00ebfd983cdda14db34f7f968ccc93097cf037dceeb1375f2df4de09c8785f5fef8fbbe284566e5c9a2d38f5d2f9145b7f5087f6a89a56679680ca4180ad7da3ee45da685f0255a45db806e1379c1ed59bfe63feb7d74a239334c80ab9c1859d205ba798810adf8afc569170f94167439d137215d2ce0b2fa983ac138a3ce201cec4927c62b740912e7287417f86beb07af9c83fff843df1abd6e6f81865b82b3168528d1c473b4999b0179f1de8ae22e8ed7f698ee8463eb93fcfd4e017f29ab3f15a2e061de6deb09459d4ecc62741ffd8514d5c1f10eb3b1525ad60512ffad00e360e0d6add8ed6d6df48d63cf1e36f306bd76b1a245cdd09951727367e45b3a02d748dbfcbeea342be4cb0e1e3108e57993581409f8c6b34e2d38becfcf15c653b92c88412c087eddb0bc21eeb620317f49a9bf5d6164418a26322e1964fd676a547862c2a7ce5f13898e3fadec79a638f257532cfe977fe8ba5e96782f9e1e3e8b5f896a80d816141f0c988ea59ea321cffd23f298b76e49e92189e7f65718d14091daeb82d432470a2e472a39a154226a43c543db2bb933adad08344259ba08a65c543d2ee07b67328ca2d4e60e550b85215ea5873fedb505cc1e4db49e129249fb632ba22f11b897b9423d08f96ceaa863cd29dc16af6ac76c4388c2795250c04377277626992b085ed7be2cf1d63a2eda4b65e287081fdc4e9a3224ff57d81b3ba8d04eb88430a01c5eba35fad028e8de1812920cee2576d0bd291407c5fb70c5ce07104b9af7b98c4c709c7f019d4a66b136120b92612ad5e73dfcfc1da0fec3a7928e57d7d4769eecbaa4c269f2859d31d47d1ae40e4da5bfa6592074c5bf54b04c707b8d97455a0a606686e06bf5ef7617da2532f305267f61c5f627216b06ecc3da6c6f7b420e2dfecaa41657eab20c89927ad6eb5c4fcd513da89a637755f4a98c45cfa108f37415bbf49ee6cacfda8f22f7101a9798d844709a38f9168685f105157a937bb10d4f5b342deab8b8be8231490da52cc0c407bf942270ad93d4a9bed5c06499584835dbba75577dbbc47fd3d397f0417ade99549de4412c8893cf3e1a2ed74c234a7b60461efad57d9c9fed9eec3ebd652282b045174e19355d8cfcc10add9192ffffd428150dc3f48e0417e47d6407008c62486cd4057535a5a9ffc45ef559a51fbbece64306f64da9740108d0b51d01423379bb0a72fe050d2abf5f5acd25cff57f8e3bcdf938749c7bbf77437424ada88c167bcb6addc309b949a8e200b9a5b6797522635731b250e2405f98d054aaff4179ccb4b24159e4c033329100cadbef3da262203622d27899166f6c3c79a35daf7840853b9a3ce494bf035235cada8c31e28be56f0976ef9b96f15de57e6896a5aed57a7b5ce77cacd1c806ecf83566bee5d577f7414a106ce16ca6e8cbc144f571b1a37647041694a6409f68d15604960417a60bc4f1a878eb01e89159e701bb8fd96be45395a8b8c4f0cc5b982582741c4ccaff8961ea892f084b10646c7a27687a2d3c92324cc3a19a5b38ca2d5c573167ad54486ab3adfe9219882f947cc6a93a3827f4b51d76e90ffd1587646d921482022db8b5a22519be3a1e62e9a13ff9926e75c42e07aa295c8486df69dc96168e920e13c85eeda86dc560b9f5d4c77cb8ff001d390dc6c5a911c573ab1711df534930ef28832936c80cafcde731e999ce90741e669d93f653efba12466726fa997e7ad24d34395a02b8a4286f3604f120bf47e8ec41954e6def2de896be477ef7916f18214d28f58ae91ed8d7eae9e2df600d313b6cdb952195e9d030e0b8fc98a68cced3070f4abd2d252727320eb54b602ec861ba630ed3c5d6fc8c8b39f4f1e9c198a6dc8d5f825159ce15fcd7bea5701a225ac41bb152d1a077adc03ecf06870375f2d2618094a648b40244e4a981e7efeadc608c082dc1824c4ffdbc39afcc8c464ed5ca8dfc1540ae3a6c034364c356bf13f880abe8633fa041db78f4be0d17a4bb00959a697935c844c6ddc02222f7aebb1af2c96a757536159dc1dbc31131aefe4c198ccd2123eb5d0ca6147bbc9ab43e993508ef4ca383e2847d9fcb4c975dcb240bcfd164daa835311cf7dbde0f256deb5f3748b55c312a29a042725ecf07caa904513e71b4c0ebd3b31c2938e710e7c6be819bb3125e638ee4b54b4c8fe16df1cee7587e6bdfdcccf2e3b2aa4a54c86b0ae711f056c229c644f519f60570aed60fd3d0638dc341625fb4949d355e7d84cb478133d25730162623acbf5d36b9ed98dbd88b6bf7bf1f55006f5ba2d16297557f966cc01baca56e3f6435b724c0b6fa4cc0074efb0bb2cf0cba9a1c73d3337db7dc0c78b87746db7bbe5fc003edf608ce5d91dbd8b3cec0f738de14c8e2b6df47df91805eab5635402ff26245430641abd9511cffa6bf8d352a1f0d97ce2b08561c97a5f07a07e0ac42a2a73366442e0bf125a718553794b021640ef9f9f07040068cce2337606af46f897b7ad8ced05e14f7ab3e2bd847f810058d665a0c3b6903efd8f398c31e356b48216111d30348acf93d28dbec8e603cd16ea5d3b24f38367c52f5629fd51bec34e86ff21d4f5466a53aea7048babf3afaecec2c9de099bcb2845f66689e02306760ef5274e65f36fc61edf8112b3b414a878b8dbdc2ced0d7dae0e95c5d6e7c80a3b4cbccfe13293e454b6c757a8d9496999fb0c4d4dfe5e7f3f40e11172324323556687e95a4a6bfc4dadbec000000000000000000000000000000101a2f41",
+ "hash": "0x5ee00afa7d595efaffab2cf573a82e50c7d0f37bc1c2a53a11f7120155bf57b6",
+ "intrinsicGasEstimate": "135712"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-2.json b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-2.json
new file mode 100755
index 000000000..3a93c378b
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-2.json
@@ -0,0 +1,28 @@
+{
+ "id": "valid-ml-dsa-2",
+ "expect": "valid",
+ "alg": 2,
+ "chainId": 28001,
+ "publicKey": "0x5424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2f",
+ "seed": "0xdaaaf3ca4a40b10b8d8329296d5a0eb0ea604486c8bb582e6d7cd3d7f7dacc63",
+ "tx": {
+ "alg": 2,
+ "publicKey": "0x5424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2f",
+ "chainId": 28001,
+ "nonce": 0,
+ "maxPriorityFeePerGas": "1000000000",
+ "maxFeePerGas": "2000000000",
+ "to": "0x0000000000000000000000000000000000000001",
+ "value": "1",
+ "data": "0x",
+ "accessList": []
+ },
+ "algName": "ML-DSA-65",
+ "sender": "0x0602be26ec9e01dd88121f7c203ead9eecb9ad3e",
+ "signingPreimage": "0x50f907ce826d6180843b9aca008477359400830383209400000000000000000000000000000000000000010180c002b907a05424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2f",
+ "signingHash": "0xce8c919ee46badc976518a728e7720c6afe65322bb25ff83a28c364c7ba1999e",
+ "signature": "0x33fc1486a0e70aeb6fef62ce5a0dfb51fcec12164e4024b0c49ce8b65e01356d80a9571af8f69a9c7256ed549d699a31ceff21c13c482ee0c5759f96125b0099495feacf22a001b2c887b107a9ca9e84de461fbc6e143566de56c710156de5b5f4b7ffe29c0124c1fbb6a792110284c9ad713d89bbb5ed444d09408c65a9f74c5f6c4fd281d31738db82913dcd1ac1fccbba24dc933fb9a8e6c4e426fb98590d7da0252c34d866c114526ded1c9d96daea12ecbd8f2a44531dfb72f02c02b267edf0560b1fb06b087bb6ce02b2922d92f81bb7da99b90e4a2dd68aa858759584490be602369dd606a510b6228e3b941421a3006a697b79866cae011d8aa496de4f3bfffdc0a087d01323db849f6237d7ac476d18bb417f26a697388b4c0a78533f3dd763398719c9ee5bf0299786fb8c4143af8c1195103390d4494b735c06b5815c454dba2fcdd27d214c48712609ffe7ad7c082e835d7477de2358fb3c4b5162027f816ca85aa4a46c25105175e77c8e5394db6fb3999c25ce578f066329182b28fd5b68769cb07ebc67e47a537f6cb62bfd18af162113a4df7f8908e0ce953b6a9637c850f24de0fda239c25fe4352f3b381fc270384d51d1af1ef0dea8501f98ea71f26de97e98799c4b2a316a216bd4af4861ad83fa4570532029564581bb35ac543355ba3aa246b59c6a5d9a91b938f3c4f0ad6d6f567fffdb6fb78402ded5fdc544a0f5fd87e4677326ca003dffdba8fd390487a6469991506a18f376b12db5be3bdcf4a4bc2f5b34dd8f7066bec3b40a6502f414eac3cd1ed43431b033757e86cca57691b0e1f7eec68fad9423f8b0620aa94798546bc878cf29d74ae74af5244ed9b97107fb83abe25dc160ec05cda1c50b76db981aca781868a7913a3e7c98aa5a3ea8bc81270e6f565138dba33c9c7e887641fd3dafd458b9c64600151038db05725a976950307c662c2eb668e3067f943b9bfd805307729b39ed77309fd5e67ecfc56cc231057a6628fb6f528fb969378529dea2c58fa0b4d791ca591ced733e8cf93a8e19907538f45c2618612648d3e1a78492afc154b7bb0285aea97d618e74a74530b492c66c6bd31557cdc55476b3f163196ec8e87f110834ffb8c232dc77cbf2f7b490f520b3b328af44fecca860a19bee9af6a5f69f63487d7dc6b7bf1233c4735522fedd475f905f044a0a7f658a7a378958cca56a163a343a010f4b65d1bc38cd57d08e0f887293fbc106ad7b15aacca6d51558cb8478b119acde04a19b007802a8e9578121304622aee7858d1794ade88973d6fdf981ebabc98fc417d765c075bf8f76b9781dff7c60071878027c057aade8eaf820186035499e9e5fbf8791e6fc0a0e49047af312a8b1b1e80628dc4db4f45842e19096a54733d28028203aa668bd8655631a01c000c956c32ff10572fdbc95b2f26d09fca84c093ddaa122ad93598c03de9273873ece5096648a6251a27e993ec7b6ea4f2181c09bb06852799323f3e993a4b7461439f702cb9df183fcaab11b8bd2ad391924d5e6ef261fea01c91cdc10d9345c290dfc3c040318d11419563d407c8365fef3dd31d8f9d7d338f5f2cd00433d1d06547ae9c650d14d9a7e5b683f0458e7a909d90d4a57201ca5b8753c13bda3591f9cadffd0987d1c7fca1c5a0cec1e13c612d0390d7c0e2f422c97cda29959cd7b714fbeaa5da7b0bcf911c2744a9a25c7d49e93342f61e10a33fda80fadfed2668bfab8767ce80480093b4845cd5ec83082e8f9ad63236743e72842d1a3226640a549c2c1d002a176e2427b2ae612dc272e3d9fa80a904eb8f93f494a52706346c08b06c9d1d8a61a9c7112c0933910882f0da6eea3c389f4faeea51c03394eab4cc02056d704b8839afd76f0839be5ffdc873b88f9a755be6f0229b0843839a25d63c18da89be1c5da930a101913ffba01fd00f2a447d5f58ae8f21554feb47f42d40c32158219dbbb1e5e96ab3dc26cd6a435525c265b65b0bf48d68e9b3c9178a509833aa47c23e63aa9a6f74bef1e4ef863556b11c014b85ac7c157f1e64531b676eb28c68e82e0089d2bd798213c836cc354d4883dc0b607456ab7f894f0a1f73356fc05a5c97a9cf3b231890c39105b751f6fc54063a08f3d3a264ab90cb7de1d0e2f6acb92302cc9b4bb512e720e6ff8343004028ad223a70d395c5f974d3ddd380f798e80edb4b13555c3be0cb1a500e19a8b1b05f9cae85d7eed756ebcfa57828f1054296ffa48d426ceb83c69ebe1b983421f42316ca6f50bf8df0f4d4aeef85005638a304d88764ec26366a1437867c89800aee55ba428e0c07542e123d748c795560153007f768b20bb057fc2643b7db992c3b9cbfd88657b17fbe8a783da2050affb518cab4226cdf28fa97f48651bd142932835f061f8642e79d1f7ae8ff8665aa85aba24a850b2042dd37e61e665a451f17cbe9d57ed5ecb1dce9ec34c576762929dbf46964de7c44c9f6b10fcf52b48649ded2d491bbe4bb6ad578cd31cbdea6df8342dbb7f33857617250b014fc6d887a448f7a5cef25ff69dbc94733bfac1d5f8593af7fbe4759d23ba8da1f405ba179c96d8ae49eb760446d842f0d61ab08508a3e31e4953e13a1b197d00644303e8a9513199583709f41757740a0dff347c3859d3a4ec391481af349019f75ccfdba111a4c338fd8283733115ce7c114111abb157c1a5a84f7b39779a54f000827a250bff00dbe9cb7162d81f6c942b719f9eb973ac7d4652b911622396c517c6e9c7e5f839c049855567fb53ae84579388e3c87af420272558c686209fd92fc339a553f873995932d9dce52f5e60cc0889c3283f94a0d2d5d011154d9935e1dfbb7e747b393bdd8a84f601adca56d4ac5e8e6f28100a7d5522de50dbf1bd7f5604fdfa660a58dc681b4b230abbc4f594a972a73456de1b7f48975cd03313a80074f5d6701db61860f33dfcc9f06e313e8881c385a50de28ced014daf702f01c45368419b73383008b9191293f59fa87a1ceb0cee64d486842ed7c289dca3b3f2e261df644de0f739079ba5ea195468f0693a995dae8e0f7e4611196824f329fc803bc3588d7d941d1fe86a3ecdb3eb8f6d4066ecee371f9a14e5bd46a40b53e87325bab7255099b4fe7f7b09eddaefc6582feecb8dec02b5e58d735a927d052e263027fa879fceb852b9e08db4636c7152f272a43ae4037c50210e90caa3e008fbfa98ed42cd425259096fc06644edab9b768779dcd892747f18a9cecc6aa31dc27d3f12a540447653edd5bed68f50da71b7992434b74d0209746f93ea429691fcb99da0ca32df822ec4332f7eb4bbe6d2111ac84a55932b3e173e388ab96a5a8a17c7d8b8131cf566e0335b0c4a37c5ae24e73c81146031295b69ce3032fa8e4c7616558179cc561f14864190d458cb82370749d595966047de698256126a4ca23a6bbd39201b8649fbcd387474ecf5b9f732e65938fe393a2a1269b06b9b49c5d8882d70776fc823da5842d812be2a65d2f5ee0d64f8258e761e6f2d4c1a825963b367d70b9e81b46fc25e4804fe9decf3aa0e47f1eba573a24f0e4f7b8cf8a886c7ef4175bd317709feeabe46df9719e7d7a4bc2c1bbc15a58b5332ea558e160f5d3b7aa84fe54ea7a24bd8e394ab794e72db7946780272556be33b7f32a0ee651c013d8ed3b5d75bc1c4826dc94f9e3711c53be3bcdf361329544f2993a189b6431a6dda8b81cb1b7c3a69ba96c1ac84a55100c4985cc85ce272e8eb5a57c563a7ad782664d561c3400e779317122d425c9c4193414bebd4d6ad31ba916448f65e9a7ca1f856dacf9d88b695410c8491a759d2c0304e8368b39cf502d0abf7233b1ba9671bc422ce182833ead52597481ea3ea26a2cc35e12a8c83bbb263202d5e9e7a5bb8ab2a5a844d596c24fdac423981fc4dc4291944ae476d59c9a31a05f79f0fe4b39f145c4fba857fa553a17fb2d5f941d5dac8dd3dd07e48eabfe5b98f3c41e7a84986dc3a7a3bb0ed2d4232cffbc50f167d58fb52fa3b357e76430d7f0f1aff6e2d51ea8f5b98bb66c5b5687821f33b9b6c2e407ad0e8140c4d5d4f1739167f8d63284caf4a43688473cd97bab401218fbb2ea13be81bbc05a81042a02eb1843bd46ca535e778e207c79ce3fe511a55d21bf20b24bcdfb43fa62b3469fae2ebd61e362d5d663fb2c08cbde5df9d8cc1faaf6370b5328ffccde873849299d61477a9fcf7c5c96fbc51b24c0f2cc6e39a46f4a9c1f5214f2cd06db62a37e2c6f477ceac0b92eb882d7bcd1fc3721a89745473eb45eee9a4fe6ab323d28f4db957d0c5dc1ed25ebc194f744a2cfe98474868e6acf5641ad454b3626ac2a27a9db416eb1763935eaa5612e43c49e8959ebcf5133863e98c19618e936f33952699fc224f41a4e259b40228047ed6a17cf4f3a42dc76df1346acb0986984f1692b5ed28f0825a23094ddbb8c1750e9035b1df2166f142e7f179473098ed73acb9ffb8be530542f31de88d6677f805cc30ccc0b60787e61f9d195ceacf07a35d979f9c3521f23671f378a6cd58ed2b0620ff7e2def5025f878d70008744c6a53caf325293353747c94c5ddf12e3a42686f97adc4db62b5e2e91132345963b7292fc9d13b484f75d8da000000000000000000000000000000000a13171d2127",
+ "raw": "0x50f914be826d6180843b9aca008477359400830383209400000000000000000000000000000000000000010180c002b907a05424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2fb90ced33fc1486a0e70aeb6fef62ce5a0dfb51fcec12164e4024b0c49ce8b65e01356d80a9571af8f69a9c7256ed549d699a31ceff21c13c482ee0c5759f96125b0099495feacf22a001b2c887b107a9ca9e84de461fbc6e143566de56c710156de5b5f4b7ffe29c0124c1fbb6a792110284c9ad713d89bbb5ed444d09408c65a9f74c5f6c4fd281d31738db82913dcd1ac1fccbba24dc933fb9a8e6c4e426fb98590d7da0252c34d866c114526ded1c9d96daea12ecbd8f2a44531dfb72f02c02b267edf0560b1fb06b087bb6ce02b2922d92f81bb7da99b90e4a2dd68aa858759584490be602369dd606a510b6228e3b941421a3006a697b79866cae011d8aa496de4f3bfffdc0a087d01323db849f6237d7ac476d18bb417f26a697388b4c0a78533f3dd763398719c9ee5bf0299786fb8c4143af8c1195103390d4494b735c06b5815c454dba2fcdd27d214c48712609ffe7ad7c082e835d7477de2358fb3c4b5162027f816ca85aa4a46c25105175e77c8e5394db6fb3999c25ce578f066329182b28fd5b68769cb07ebc67e47a537f6cb62bfd18af162113a4df7f8908e0ce953b6a9637c850f24de0fda239c25fe4352f3b381fc270384d51d1af1ef0dea8501f98ea71f26de97e98799c4b2a316a216bd4af4861ad83fa4570532029564581bb35ac543355ba3aa246b59c6a5d9a91b938f3c4f0ad6d6f567fffdb6fb78402ded5fdc544a0f5fd87e4677326ca003dffdba8fd390487a6469991506a18f376b12db5be3bdcf4a4bc2f5b34dd8f7066bec3b40a6502f414eac3cd1ed43431b033757e86cca57691b0e1f7eec68fad9423f8b0620aa94798546bc878cf29d74ae74af5244ed9b97107fb83abe25dc160ec05cda1c50b76db981aca781868a7913a3e7c98aa5a3ea8bc81270e6f565138dba33c9c7e887641fd3dafd458b9c64600151038db05725a976950307c662c2eb668e3067f943b9bfd805307729b39ed77309fd5e67ecfc56cc231057a6628fb6f528fb969378529dea2c58fa0b4d791ca591ced733e8cf93a8e19907538f45c2618612648d3e1a78492afc154b7bb0285aea97d618e74a74530b492c66c6bd31557cdc55476b3f163196ec8e87f110834ffb8c232dc77cbf2f7b490f520b3b328af44fecca860a19bee9af6a5f69f63487d7dc6b7bf1233c4735522fedd475f905f044a0a7f658a7a378958cca56a163a343a010f4b65d1bc38cd57d08e0f887293fbc106ad7b15aacca6d51558cb8478b119acde04a19b007802a8e9578121304622aee7858d1794ade88973d6fdf981ebabc98fc417d765c075bf8f76b9781dff7c60071878027c057aade8eaf820186035499e9e5fbf8791e6fc0a0e49047af312a8b1b1e80628dc4db4f45842e19096a54733d28028203aa668bd8655631a01c000c956c32ff10572fdbc95b2f26d09fca84c093ddaa122ad93598c03de9273873ece5096648a6251a27e993ec7b6ea4f2181c09bb06852799323f3e993a4b7461439f702cb9df183fcaab11b8bd2ad391924d5e6ef261fea01c91cdc10d9345c290dfc3c040318d11419563d407c8365fef3dd31d8f9d7d338f5f2cd00433d1d06547ae9c650d14d9a7e5b683f0458e7a909d90d4a57201ca5b8753c13bda3591f9cadffd0987d1c7fca1c5a0cec1e13c612d0390d7c0e2f422c97cda29959cd7b714fbeaa5da7b0bcf911c2744a9a25c7d49e93342f61e10a33fda80fadfed2668bfab8767ce80480093b4845cd5ec83082e8f9ad63236743e72842d1a3226640a549c2c1d002a176e2427b2ae612dc272e3d9fa80a904eb8f93f494a52706346c08b06c9d1d8a61a9c7112c0933910882f0da6eea3c389f4faeea51c03394eab4cc02056d704b8839afd76f0839be5ffdc873b88f9a755be6f0229b0843839a25d63c18da89be1c5da930a101913ffba01fd00f2a447d5f58ae8f21554feb47f42d40c32158219dbbb1e5e96ab3dc26cd6a435525c265b65b0bf48d68e9b3c9178a509833aa47c23e63aa9a6f74bef1e4ef863556b11c014b85ac7c157f1e64531b676eb28c68e82e0089d2bd798213c836cc354d4883dc0b607456ab7f894f0a1f73356fc05a5c97a9cf3b231890c39105b751f6fc54063a08f3d3a264ab90cb7de1d0e2f6acb92302cc9b4bb512e720e6ff8343004028ad223a70d395c5f974d3ddd380f798e80edb4b13555c3be0cb1a500e19a8b1b05f9cae85d7eed756ebcfa57828f1054296ffa48d426ceb83c69ebe1b983421f42316ca6f50bf8df0f4d4aeef85005638a304d88764ec26366a1437867c89800aee55ba428e0c07542e123d748c795560153007f768b20bb057fc2643b7db992c3b9cbfd88657b17fbe8a783da2050affb518cab4226cdf28fa97f48651bd142932835f061f8642e79d1f7ae8ff8665aa85aba24a850b2042dd37e61e665a451f17cbe9d57ed5ecb1dce9ec34c576762929dbf46964de7c44c9f6b10fcf52b48649ded2d491bbe4bb6ad578cd31cbdea6df8342dbb7f33857617250b014fc6d887a448f7a5cef25ff69dbc94733bfac1d5f8593af7fbe4759d23ba8da1f405ba179c96d8ae49eb760446d842f0d61ab08508a3e31e4953e13a1b197d00644303e8a9513199583709f41757740a0dff347c3859d3a4ec391481af349019f75ccfdba111a4c338fd8283733115ce7c114111abb157c1a5a84f7b39779a54f000827a250bff00dbe9cb7162d81f6c942b719f9eb973ac7d4652b911622396c517c6e9c7e5f839c049855567fb53ae84579388e3c87af420272558c686209fd92fc339a553f873995932d9dce52f5e60cc0889c3283f94a0d2d5d011154d9935e1dfbb7e747b393bdd8a84f601adca56d4ac5e8e6f28100a7d5522de50dbf1bd7f5604fdfa660a58dc681b4b230abbc4f594a972a73456de1b7f48975cd03313a80074f5d6701db61860f33dfcc9f06e313e8881c385a50de28ced014daf702f01c45368419b73383008b9191293f59fa87a1ceb0cee64d486842ed7c289dca3b3f2e261df644de0f739079ba5ea195468f0693a995dae8e0f7e4611196824f329fc803bc3588d7d941d1fe86a3ecdb3eb8f6d4066ecee371f9a14e5bd46a40b53e87325bab7255099b4fe7f7b09eddaefc6582feecb8dec02b5e58d735a927d052e263027fa879fceb852b9e08db4636c7152f272a43ae4037c50210e90caa3e008fbfa98ed42cd425259096fc06644edab9b768779dcd892747f18a9cecc6aa31dc27d3f12a540447653edd5bed68f50da71b7992434b74d0209746f93ea429691fcb99da0ca32df822ec4332f7eb4bbe6d2111ac84a55932b3e173e388ab96a5a8a17c7d8b8131cf566e0335b0c4a37c5ae24e73c81146031295b69ce3032fa8e4c7616558179cc561f14864190d458cb82370749d595966047de698256126a4ca23a6bbd39201b8649fbcd387474ecf5b9f732e65938fe393a2a1269b06b9b49c5d8882d70776fc823da5842d812be2a65d2f5ee0d64f8258e761e6f2d4c1a825963b367d70b9e81b46fc25e4804fe9decf3aa0e47f1eba573a24f0e4f7b8cf8a886c7ef4175bd317709feeabe46df9719e7d7a4bc2c1bbc15a58b5332ea558e160f5d3b7aa84fe54ea7a24bd8e394ab794e72db7946780272556be33b7f32a0ee651c013d8ed3b5d75bc1c4826dc94f9e3711c53be3bcdf361329544f2993a189b6431a6dda8b81cb1b7c3a69ba96c1ac84a55100c4985cc85ce272e8eb5a57c563a7ad782664d561c3400e779317122d425c9c4193414bebd4d6ad31ba916448f65e9a7ca1f856dacf9d88b695410c8491a759d2c0304e8368b39cf502d0abf7233b1ba9671bc422ce182833ead52597481ea3ea26a2cc35e12a8c83bbb263202d5e9e7a5bb8ab2a5a844d596c24fdac423981fc4dc4291944ae476d59c9a31a05f79f0fe4b39f145c4fba857fa553a17fb2d5f941d5dac8dd3dd07e48eabfe5b98f3c41e7a84986dc3a7a3bb0ed2d4232cffbc50f167d58fb52fa3b357e76430d7f0f1aff6e2d51ea8f5b98bb66c5b5687821f33b9b6c2e407ad0e8140c4d5d4f1739167f8d63284caf4a43688473cd97bab401218fbb2ea13be81bbc05a81042a02eb1843bd46ca535e778e207c79ce3fe511a55d21bf20b24bcdfb43fa62b3469fae2ebd61e362d5d663fb2c08cbde5df9d8cc1faaf6370b5328ffccde873849299d61477a9fcf7c5c96fbc51b24c0f2cc6e39a46f4a9c1f5214f2cd06db62a37e2c6f477ceac0b92eb882d7bcd1fc3721a89745473eb45eee9a4fe6ab323d28f4db957d0c5dc1ed25ebc194f744a2cfe98474868e6acf5641ad454b3626ac2a27a9db416eb1763935eaa5612e43c49e8959ebcf5133863e98c19618e936f33952699fc224f41a4e259b40228047ed6a17cf4f3a42dc76df1346acb0986984f1692b5ed28f0825a23094ddbb8c1750e9035b1df2166f142e7f179473098ed73acb9ffb8be530542f31de88d6677f805cc30ccc0b60787e61f9d195ceacf07a35d979f9c3521f23671f378a6cd58ed2b0620ff7e2def5025f878d70008744c6a53caf325293353747c94c5ddf12e3a42686f97adc4db62b5e2e91132345963b7292fc9d13b484f75d8da000000000000000000000000000000000a13171d2127",
+ "hash": "0xc7903f14f8aa0ffc09cdfcd433e20f07ceaa63ab9b56b84ba41fc8dab7204952",
+ "intrinsicGasEstimate": "180176"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-3.json b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-3.json
new file mode 100755
index 000000000..5ccfbf6e4
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/valid-ml-dsa-3.json
@@ -0,0 +1,28 @@
+{
+ "id": "valid-ml-dsa-3",
+ "expect": "valid",
+ "alg": 3,
+ "chainId": 28001,
+ "publicKey": "0xfd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308",
+ "seed": "0xa8af8968099758df7640e2c9f1713fe31d70766e2c2b18bc2ae82f5b1e1e8fa5",
+ "tx": {
+ "alg": 3,
+ "publicKey": "0xfd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308",
+ "chainId": 28001,
+ "nonce": 0,
+ "maxPriorityFeePerGas": "1000000000",
+ "maxFeePerGas": "2000000000",
+ "to": "0x0000000000000000000000000000000000000001",
+ "value": "1",
+ "data": "0x",
+ "accessList": []
+ },
+ "algName": "ML-DSA-87",
+ "sender": "0xaee69521a942a58325bd694f2cc3d64752465d4a",
+ "signingPreimage": "0x50f90a4e826d6180843b9aca00847735940083045f289400000000000000000000000000000000000000010180c003b90a20fd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308",
+ "signingHash": "0x3ef7803edb46bad878a1a585571475b75bba9b66e2407b73c6d5794ec507790d",
+ "signature": "0xc74a08868ea0fdad9fbb1b485b793bce6e4fa945668b2351232a7c8a084fb2d87a5c83e7dced6bde3743617a7c4babcbf9381694b64d7e0feeb6615440e927a63293c6b695900b1e7afad1ae612c324a88e6761c3b6fdc41d18f514be1ba3a1ca53fdbcf8c19f95bcd60223abe52d07fd7c4114dad9f347cf122f6241429da7e598959c22692910323a0a699595398f518c58deea7159920d89e3e65702bc2cabea7e9ca0bbb7002fb7be5243bba6a08a12238ead443ff4394510d25eb279885d9112c44529f294c5a2bf493a74ba8f4e38744e632680b3ce055a897d2a5468ef52e6e70dc5af55a9fb83739f6cfc6994871662b8263f2e07e21a6514624909369e0138755165dd2af5a791da63c0604b68ff160fad82a578a06e76f62bb7e951b81d8fde2dade6c3a314eec5913151c16a93a5abd5ceb59ad96197a349721ab123b42f799dbde36d7965e0e5dfcf43d8d1ae13f4a00afd8dde36137d3de87f4e2c0366c18f4b3a449ffd9afc7c742c50456f6e642f7d09e86d5aef224b20ce5d8a2bf164484df8fc87daf69e459fc78c6b974cdb8fb1dccbd5290f560e3114302886e2828ad73ce71b06186254206743076c6af0c3d1facc36695dc28db1d026686b141247e1c7a9323d544b0079023cd2adedc0479ceefc8e0c34782603d0c27d18768eb5485a85bc385ffdfd25f735688a3b9a0c6f532b2a7989c751804de0163582293a17f635fdde14e9067f12929b079f89a53dfc87b986f89f718320ede83cf4086d0d095b24b66d5e3f1bfdb08b79cd5b25657cf2b20faff1d199c16bb7f631b33970b34c12997637447e4127db1bf580b339807637a86e0248cbcf8e1d30ae6fe053e2f9b7b3d0f9e3f4813af908b633560779012f9e06af00e252bb0df9f0caf7d1e82f8deb2ede21d13f406dd9ea69445d50844c95c921d8d1cbc8afbc5ddcd4157e65cbfbbafe2670e9146a5643db049a8d696f0eae07c3d4099447ef78bdb90fc05d7cc97bf9b9dee8719464ec6b9e6de866f73914a80396dea3900a9f7b43a47e648e20a9504da92c47ac65368813e5453e82020f8861aba2534346e6137e71adb28a5ff080365d6ea26dfc30ef5500d0760749d6e4e0f93aaebed544832308b19f72e92ebb8eaec2492c6ea7972fd359a8b67a1f4053bfb1a3c6fb720b5925a7a827e59b3bd0651b8014c77b25d61db17eb169cc2fa2442c82f68fb42200c59baa468a9fc92f13273ff071124f8b31e2b4b2517ee622d29489997ecb5676fb52e3002371c01004c214757b1f510091c2377a08d058209d18feb9b524a41712b6df4b92f2b14c583d3196749f367b3bbc8ab5e9e2615c511f23ba5fb1bac2ee9436dd8d162bd96f1fb663d2b520ba7e8ddfc2a4d549b63714654cfbb37ee1dca5f723139187ada8f8d5b42ad09ff196b70720d2527b4466d44f33cce486ef2e86311c75ead31a17b16989dc63bacf0d465379d9138df7ea2ebc71f4cc3b6662e24895050e2553dbc160a567d6722964a904d43bf2684206cee3562256e98addf3038e968cf6c09c921e2c89c9c249f6ba7afd20dd27587b4143f704f2738315a91c2d40c467111b4f3bae4f77bae402145e742ba83a527aeffca13ee2290988df882feaf5a3c24b416d59e06cf4f8832a016ce55419b7bd2028545557528a0af23f17942433e13fad089fdb79449bd9d99b0324b1828791249b6789a09cdfb6ec40c0fbaf8b28ea4f72d3df5159bea7a7965b94beb1bb01d87d76ae7ce47fc333fc152038ab4e7ca64a802f96f2e92bcc53ad9cae0242c622c99b2daf005e554cd6ba127991d84841ffe3ba0674eb7930509045dd00ab91a7c6acd2f4a40e7ffc9959929851e40d417f488a29f7bb5af3847a8caa5daa0682aea870ac8b866ccfdc435971e3d862c2f651cc6eb8a33fca313a56ab8228ee9ac7dce14ea3c3fba4f58c70888ae558d8cd632a2723ba54a3d538f4e20936a2ee543e9b2141e06095c72d4ee19908febf7c248c03a78655420da644746e2d508c31ceb0b648800d95dceec72f7576502046e5dce54b5a097f625001bfc92d6e4633b293cdfa63b1fca5de9e26d03ba2f1cf3647dbdad5359ed76bf702f0621c057dea3617af678016aa13360ebb02c6cb2fa0d3f137a1a3c639c989e12383841ab7ca5a84f84c08af4b85416ce7ec3ed91636a79add207bedf9dfb2ff626387f20cb3315502b2b06f361cbf6a51fb507598af41c5a5b9cd95ba1894ca372c5e1851e62a0d3d78dab6f92bd43ba6fcd71230b6cfd843d89268872b75e3c5b471db530b7ab5451dbe63fa0bdaa7d74907cb376643e129febbe6ce10b5dffbf323dc973f097d2081e06aad65e674c5a41bb81b80556fd78691fe6b5bfad47fd1b64db577f27f22f17973cbff3a7c4aa43569bbe6843d773a2f933f472650e88e0ec6643f87dfd37e7fba915c7386a130b8d4f0ff4d0e99a633d1f863f3e8ce4e1ac5e31438d89c3b6d5ace3aa6e14e7073164ea01e853958bece389316023127f9916297a47c5d6ab5513bab874c1ae3bf2850cfab9018cbf50a7febe03ff3e8e4e55ae5632812b6a147edf051b461bfe56f01a6ab571e0553e37a57a3a9811f4fda2e189d79b74215d6fe199595d18c6543c747572f8cdc61a53ce09d9ca96b43a5af5b56b53148dd4fdfc1e22c9958caa783f2d112d8d5fd39e6955df75d35c59a1967fc0d8d3293e39a6cdf82d6846b39a74b1a538372c266b3f12d7ccf464ff7e32fe54342994f51d344302b3b2e11eed2187a741eec99ef0a79a19a854c03d8bd3fcd557b9d8bfb35f0976da327fc7e8d95fb43db8e66be5b373385fc1b68099566c7e88aefe92c7c521d084c15c8d403d87bbc975e8d687e2a51e5ce53191e3db5bdc50f475853cda7cc5a7365c41035aecb61444c2a48492a600b58300b2805be97b4e9e30526e9e62bb3248a17c3809219307ca85351495c943a865359c783cf615a809c739cce0786c6045d9c8071797001434cbae571d42cef415e28ed6adab09ed10e0713dc1412ed80b8d26d549964321559137483c81b19203080b36abcd68e841f4c78b5302da79fd6e555f390322ae67e54c55749491889d79eb2982fc4428086bd1060c4113137ddb4dd7c9b690b802e805999d4f5127f66f6b1d397dc3509504e2196513b5787407b45b928cfc3c437523daa4f876dfe061e351cb3bad99ea205ab276c4f2a5ccee1027104f09adaf55cd282d4e9e44ac2b65f7e423da1cebb0ac70691347e7a7bd0de8bc9fb2e7a08afc0075a0e85902316cd6ec9a5802c51a6d65bf3251ae712ae0f66de6cba1e51efbad53ad7e769f851799caf5fb81ef35b4da814915dcfa67553f1c67158154707d16804be27af2115559e4758b313b9da4a1131718b29a75970b3f0a5e2f2c11a0a1ed47f238c145dc4fe9e8e963d8395c67dfa94a232b8133a0d953b05455f79e0bdff0bc3de9c04d93d97084ab99229622cfe3958ac5fda6757de1696b575f6250b441e6368386751b1d2f6007d254d152fe76578fbbe164af49cda805b9325f7ea47f5e18f3de1ce38006ae1bf027d3e354d6f923d8bc6286aaf9b9a7b9e7a7fbd36a31db0d88166dc68e7eb567d8164bed1e279a8810fc21656621ff7cb42a21ee04e6086924bb62dddd16c3343db69250f7ed95aba953202640bef18dfb6c00f1ee03c670a5cc6c0f3cd7cb006590dddffa6f19d450860e289f85edb4fb0dbbd2f992eebba09cddc1b20a3c98d8739ad1875a514b09b1f23cf406c4c55cc4266e0b8b283fa445849316c30bd19254e9d035756d2773cab7f5fd56d6d3a094a717ccca43251201cfddf80ba1aa0dad34f5a3acf8476b784fd53a1aff1307a7838705112650bd25dfea21b991d801f018a5dae26edb9dd5a0ab940a94b7bbb90fd1f30f9d1dd2ea3aad6d0a2a3c42fd2641233c7d624314c3a54ce616d2ca5683d04f6fc0924f0b667be32f4de8820f9cfab963a287a1c708857ebabed9b5bcc35d539ef9bc170636cd528ba86a620195134cacbc2b8e742376124b67ed8155ab53979e281f97b184c60355b008f15f45c8b7a506b1c1f511e4aaf0bc32fee27b656b01ed6afaa4053ed674a60175b6c89a77d42963111d0940730db02ff67534fe6a296e0e01e2db6b3f0fe9648286a0f3420cd4393163662751deed6457abbb370f83ed92e9da86a0181df13b8ef33e5718ce524a700ba5f2b40f3f973a67c1c412dc251c19e6b7ceb279dc1dfc36a3567e3a98a9d96ef52b0d0734f57bd9edebedd925167f230b1c81ca938e94ceebe43d2573735873a436331a8b76c1169c6a869889cb74e5d33721bbb99ec87f160c025f570f1d11c2e3ae6a52580785d854790139510179b003418dbcee1f4fd4fa39fc134521ffd7f29cee650472638dd04d8331ee439eaa32c57b56c4fd9c9ba87516a8236dc99b8d6e4c2a48e53a6779d5e13bbd73cc7917f0cfb8e231218bf33bc3c213599eb76476558f0e38a3979cdaad6ac6b03bd0ef0aefec634fbe0e1e87bd78123a19b7352326b9def856ecfc02b06622f94e8cb2a1cb6cf10d020f789a7db775063030f15b463f08878219636f2bb94ed11a3ed9689d797a3253809c7f2e0c60672e8476a9e272075c7f808258901e611c4d535a11bfe01daccaec3a26a187ab45a9fd0bb9a7ecf2e9c4aa3177ddaca1449f19f78ebe26be2e25bca012a10649b56899339f5418925648f3253bd716336dcf65e6b4f16d2ae51fed1acbc8335c103f721f46023cc2043f568ddb033aa5f2157e52b89eed4571cb523fcc66ef5cddc90679633c2a46f45f1a86c975db4f6f37f9fcfe54809ccf75305bc9f242f26f30a0ad5f3cd71cbd31ac45ceed2dc8571142a09b7d3091a4838727b9a067927e17b7559076649b405dfd480627881489d52339d4a8943ca396e92b92066e45d525acf7785a944345d25d721d6a354b1a9f3e2afd379d1c341badd0dd913a3471a5b78a81c0b338a2984e115d003b1deec1b44fd19824279d742017248fb4434cf47ad07fc87df86e634b2d8f6e0aa572088678b9a9f767404f06c84ea8cbf65d46effbde7de1f090d3d4b9e7c7c3b2b1dfa9e591efe12ffe0fc82c9eeb7fcd9f25fe438b39c46614438d0be7e1dad11bce8b91396f867531e8c45d8c01119abc2b20be253779b5e651bd80536854e2aabccddc5f4fbfb3497111fe9a8f8a417ab4dd806745c82126524ec325c931ac1f31a3cea19e159e1dbfbfcff761cccabefad38062872fe8a45a14781ba12551befb31c21150a56ccacf9815d8f458b1f591c71ba7b0459e7c09a4eac5c9e5b2984314ecd2f7054ed055ba082204f7ed62b1d513cd0992bc10c28bc745e30b27f6ca28ac84dec6cf0ef73c971ce12b2ddcc0d6264d8f7dfbba0a20f8ff1d7387cd9d9872f4b345b409950d66ababa9852f7f5ee634dad6085666956b97e4c9142dbdce96bf42d1334c61d04ffed5ac8f12a5075ac87a7416fd52579a876c89e22008759a93ebc57279215e178662a064bca65670089ec688532468c07161f56bbafbfa5655768123e713c7aff52852978e9d6004ab3a434d9b5c73f0d90dd1fe742a169a84f0e96a189bfc5265d8c5e2d9e42f5503d04ce01f9a912bf8b9bd8c282a4d40bbeca55d14971d1d305a16eb85d02b4edd8d35baea56156ba12f4e344dc4cb34509fc780ee97d24173a75e49960ec32055710bf8119d005447c6c391365737a0cff68d9f44868b97b2357dc051ed7fcf590b32292624545935e87f25e56b3e4a2b9c39c4936b5be9030b4711f246623264e0370291b675e75e1ce9cb425e5fabcfb55e25f084ea8a1b84870135ad997f7b700876691939cf268204669790a10ddd3d38cd22252226a09fddd395482deb561ee834ba452750d5b8e0de63c77c85a7446dd5bb29df2620f98e07bdac4cb59af8b9dc64d427dab780257e252e8d6793fd1b99f7c3162b4233a418526ab227d40b9deadc943d0f108a38d7a6b075465a44c920c0146338504eadf826cae345e864452e94706c8dceac5cca87469f2183a9c918295c09eef65f747b7a3d7fb3d259c4f531ffe48a5c338717ceb45efb557a47a593fac85cfaa4c263c109d385c01a3193a6ad1be5923d6a53e6c369a2b5e704cd6ac3ac255954c3fca1079895c596596873c1309fdcc5f36fe039d06806dd16cb00bd028edd6b44fb1e9ce4a020362824bef6a59502cce4e1d3d3884d7d865823deb092916a215ee73bdae1d4baf7f294caac7f63a36c2a15a40517438b8cecb93a5da3e11c25ff228ef3e7281360a2ce3ac66e69a2f136a83fbdbc44dd1737e9a31bdce16df9e118345ec1d9a9c47bfa60502722c9813d31c9f1b0364e2e25d77a0816db52f7e86bade9aff644df50b1cea9a339e76e869fa1fa50101f8182a2a6aee2e90d242d4b4d6b999d1c358a8d9297b6e0e2ec141c2b3692d70b141a213d477e87c52a2c87a5c6d1f0fb091f35f50915878ac70000000000000000000000000000000009111b212a32363b",
+ "raw": "0x50f91c64826d6180843b9aca00847735940083045f289400000000000000000000000000000000000000010180c003b90a20fd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308b91213c74a08868ea0fdad9fbb1b485b793bce6e4fa945668b2351232a7c8a084fb2d87a5c83e7dced6bde3743617a7c4babcbf9381694b64d7e0feeb6615440e927a63293c6b695900b1e7afad1ae612c324a88e6761c3b6fdc41d18f514be1ba3a1ca53fdbcf8c19f95bcd60223abe52d07fd7c4114dad9f347cf122f6241429da7e598959c22692910323a0a699595398f518c58deea7159920d89e3e65702bc2cabea7e9ca0bbb7002fb7be5243bba6a08a12238ead443ff4394510d25eb279885d9112c44529f294c5a2bf493a74ba8f4e38744e632680b3ce055a897d2a5468ef52e6e70dc5af55a9fb83739f6cfc6994871662b8263f2e07e21a6514624909369e0138755165dd2af5a791da63c0604b68ff160fad82a578a06e76f62bb7e951b81d8fde2dade6c3a314eec5913151c16a93a5abd5ceb59ad96197a349721ab123b42f799dbde36d7965e0e5dfcf43d8d1ae13f4a00afd8dde36137d3de87f4e2c0366c18f4b3a449ffd9afc7c742c50456f6e642f7d09e86d5aef224b20ce5d8a2bf164484df8fc87daf69e459fc78c6b974cdb8fb1dccbd5290f560e3114302886e2828ad73ce71b06186254206743076c6af0c3d1facc36695dc28db1d026686b141247e1c7a9323d544b0079023cd2adedc0479ceefc8e0c34782603d0c27d18768eb5485a85bc385ffdfd25f735688a3b9a0c6f532b2a7989c751804de0163582293a17f635fdde14e9067f12929b079f89a53dfc87b986f89f718320ede83cf4086d0d095b24b66d5e3f1bfdb08b79cd5b25657cf2b20faff1d199c16bb7f631b33970b34c12997637447e4127db1bf580b339807637a86e0248cbcf8e1d30ae6fe053e2f9b7b3d0f9e3f4813af908b633560779012f9e06af00e252bb0df9f0caf7d1e82f8deb2ede21d13f406dd9ea69445d50844c95c921d8d1cbc8afbc5ddcd4157e65cbfbbafe2670e9146a5643db049a8d696f0eae07c3d4099447ef78bdb90fc05d7cc97bf9b9dee8719464ec6b9e6de866f73914a80396dea3900a9f7b43a47e648e20a9504da92c47ac65368813e5453e82020f8861aba2534346e6137e71adb28a5ff080365d6ea26dfc30ef5500d0760749d6e4e0f93aaebed544832308b19f72e92ebb8eaec2492c6ea7972fd359a8b67a1f4053bfb1a3c6fb720b5925a7a827e59b3bd0651b8014c77b25d61db17eb169cc2fa2442c82f68fb42200c59baa468a9fc92f13273ff071124f8b31e2b4b2517ee622d29489997ecb5676fb52e3002371c01004c214757b1f510091c2377a08d058209d18feb9b524a41712b6df4b92f2b14c583d3196749f367b3bbc8ab5e9e2615c511f23ba5fb1bac2ee9436dd8d162bd96f1fb663d2b520ba7e8ddfc2a4d549b63714654cfbb37ee1dca5f723139187ada8f8d5b42ad09ff196b70720d2527b4466d44f33cce486ef2e86311c75ead31a17b16989dc63bacf0d465379d9138df7ea2ebc71f4cc3b6662e24895050e2553dbc160a567d6722964a904d43bf2684206cee3562256e98addf3038e968cf6c09c921e2c89c9c249f6ba7afd20dd27587b4143f704f2738315a91c2d40c467111b4f3bae4f77bae402145e742ba83a527aeffca13ee2290988df882feaf5a3c24b416d59e06cf4f8832a016ce55419b7bd2028545557528a0af23f17942433e13fad089fdb79449bd9d99b0324b1828791249b6789a09cdfb6ec40c0fbaf8b28ea4f72d3df5159bea7a7965b94beb1bb01d87d76ae7ce47fc333fc152038ab4e7ca64a802f96f2e92bcc53ad9cae0242c622c99b2daf005e554cd6ba127991d84841ffe3ba0674eb7930509045dd00ab91a7c6acd2f4a40e7ffc9959929851e40d417f488a29f7bb5af3847a8caa5daa0682aea870ac8b866ccfdc435971e3d862c2f651cc6eb8a33fca313a56ab8228ee9ac7dce14ea3c3fba4f58c70888ae558d8cd632a2723ba54a3d538f4e20936a2ee543e9b2141e06095c72d4ee19908febf7c248c03a78655420da644746e2d508c31ceb0b648800d95dceec72f7576502046e5dce54b5a097f625001bfc92d6e4633b293cdfa63b1fca5de9e26d03ba2f1cf3647dbdad5359ed76bf702f0621c057dea3617af678016aa13360ebb02c6cb2fa0d3f137a1a3c639c989e12383841ab7ca5a84f84c08af4b85416ce7ec3ed91636a79add207bedf9dfb2ff626387f20cb3315502b2b06f361cbf6a51fb507598af41c5a5b9cd95ba1894ca372c5e1851e62a0d3d78dab6f92bd43ba6fcd71230b6cfd843d89268872b75e3c5b471db530b7ab5451dbe63fa0bdaa7d74907cb376643e129febbe6ce10b5dffbf323dc973f097d2081e06aad65e674c5a41bb81b80556fd78691fe6b5bfad47fd1b64db577f27f22f17973cbff3a7c4aa43569bbe6843d773a2f933f472650e88e0ec6643f87dfd37e7fba915c7386a130b8d4f0ff4d0e99a633d1f863f3e8ce4e1ac5e31438d89c3b6d5ace3aa6e14e7073164ea01e853958bece389316023127f9916297a47c5d6ab5513bab874c1ae3bf2850cfab9018cbf50a7febe03ff3e8e4e55ae5632812b6a147edf051b461bfe56f01a6ab571e0553e37a57a3a9811f4fda2e189d79b74215d6fe199595d18c6543c747572f8cdc61a53ce09d9ca96b43a5af5b56b53148dd4fdfc1e22c9958caa783f2d112d8d5fd39e6955df75d35c59a1967fc0d8d3293e39a6cdf82d6846b39a74b1a538372c266b3f12d7ccf464ff7e32fe54342994f51d344302b3b2e11eed2187a741eec99ef0a79a19a854c03d8bd3fcd557b9d8bfb35f0976da327fc7e8d95fb43db8e66be5b373385fc1b68099566c7e88aefe92c7c521d084c15c8d403d87bbc975e8d687e2a51e5ce53191e3db5bdc50f475853cda7cc5a7365c41035aecb61444c2a48492a600b58300b2805be97b4e9e30526e9e62bb3248a17c3809219307ca85351495c943a865359c783cf615a809c739cce0786c6045d9c8071797001434cbae571d42cef415e28ed6adab09ed10e0713dc1412ed80b8d26d549964321559137483c81b19203080b36abcd68e841f4c78b5302da79fd6e555f390322ae67e54c55749491889d79eb2982fc4428086bd1060c4113137ddb4dd7c9b690b802e805999d4f5127f66f6b1d397dc3509504e2196513b5787407b45b928cfc3c437523daa4f876dfe061e351cb3bad99ea205ab276c4f2a5ccee1027104f09adaf55cd282d4e9e44ac2b65f7e423da1cebb0ac70691347e7a7bd0de8bc9fb2e7a08afc0075a0e85902316cd6ec9a5802c51a6d65bf3251ae712ae0f66de6cba1e51efbad53ad7e769f851799caf5fb81ef35b4da814915dcfa67553f1c67158154707d16804be27af2115559e4758b313b9da4a1131718b29a75970b3f0a5e2f2c11a0a1ed47f238c145dc4fe9e8e963d8395c67dfa94a232b8133a0d953b05455f79e0bdff0bc3de9c04d93d97084ab99229622cfe3958ac5fda6757de1696b575f6250b441e6368386751b1d2f6007d254d152fe76578fbbe164af49cda805b9325f7ea47f5e18f3de1ce38006ae1bf027d3e354d6f923d8bc6286aaf9b9a7b9e7a7fbd36a31db0d88166dc68e7eb567d8164bed1e279a8810fc21656621ff7cb42a21ee04e6086924bb62dddd16c3343db69250f7ed95aba953202640bef18dfb6c00f1ee03c670a5cc6c0f3cd7cb006590dddffa6f19d450860e289f85edb4fb0dbbd2f992eebba09cddc1b20a3c98d8739ad1875a514b09b1f23cf406c4c55cc4266e0b8b283fa445849316c30bd19254e9d035756d2773cab7f5fd56d6d3a094a717ccca43251201cfddf80ba1aa0dad34f5a3acf8476b784fd53a1aff1307a7838705112650bd25dfea21b991d801f018a5dae26edb9dd5a0ab940a94b7bbb90fd1f30f9d1dd2ea3aad6d0a2a3c42fd2641233c7d624314c3a54ce616d2ca5683d04f6fc0924f0b667be32f4de8820f9cfab963a287a1c708857ebabed9b5bcc35d539ef9bc170636cd528ba86a620195134cacbc2b8e742376124b67ed8155ab53979e281f97b184c60355b008f15f45c8b7a506b1c1f511e4aaf0bc32fee27b656b01ed6afaa4053ed674a60175b6c89a77d42963111d0940730db02ff67534fe6a296e0e01e2db6b3f0fe9648286a0f3420cd4393163662751deed6457abbb370f83ed92e9da86a0181df13b8ef33e5718ce524a700ba5f2b40f3f973a67c1c412dc251c19e6b7ceb279dc1dfc36a3567e3a98a9d96ef52b0d0734f57bd9edebedd925167f230b1c81ca938e94ceebe43d2573735873a436331a8b76c1169c6a869889cb74e5d33721bbb99ec87f160c025f570f1d11c2e3ae6a52580785d854790139510179b003418dbcee1f4fd4fa39fc134521ffd7f29cee650472638dd04d8331ee439eaa32c57b56c4fd9c9ba87516a8236dc99b8d6e4c2a48e53a6779d5e13bbd73cc7917f0cfb8e231218bf33bc3c213599eb76476558f0e38a3979cdaad6ac6b03bd0ef0aefec634fbe0e1e87bd78123a19b7352326b9def856ecfc02b06622f94e8cb2a1cb6cf10d020f789a7db775063030f15b463f08878219636f2bb94ed11a3ed9689d797a3253809c7f2e0c60672e8476a9e272075c7f808258901e611c4d535a11bfe01daccaec3a26a187ab45a9fd0bb9a7ecf2e9c4aa3177ddaca1449f19f78ebe26be2e25bca012a10649b56899339f5418925648f3253bd716336dcf65e6b4f16d2ae51fed1acbc8335c103f721f46023cc2043f568ddb033aa5f2157e52b89eed4571cb523fcc66ef5cddc90679633c2a46f45f1a86c975db4f6f37f9fcfe54809ccf75305bc9f242f26f30a0ad5f3cd71cbd31ac45ceed2dc8571142a09b7d3091a4838727b9a067927e17b7559076649b405dfd480627881489d52339d4a8943ca396e92b92066e45d525acf7785a944345d25d721d6a354b1a9f3e2afd379d1c341badd0dd913a3471a5b78a81c0b338a2984e115d003b1deec1b44fd19824279d742017248fb4434cf47ad07fc87df86e634b2d8f6e0aa572088678b9a9f767404f06c84ea8cbf65d46effbde7de1f090d3d4b9e7c7c3b2b1dfa9e591efe12ffe0fc82c9eeb7fcd9f25fe438b39c46614438d0be7e1dad11bce8b91396f867531e8c45d8c01119abc2b20be253779b5e651bd80536854e2aabccddc5f4fbfb3497111fe9a8f8a417ab4dd806745c82126524ec325c931ac1f31a3cea19e159e1dbfbfcff761cccabefad38062872fe8a45a14781ba12551befb31c21150a56ccacf9815d8f458b1f591c71ba7b0459e7c09a4eac5c9e5b2984314ecd2f7054ed055ba082204f7ed62b1d513cd0992bc10c28bc745e30b27f6ca28ac84dec6cf0ef73c971ce12b2ddcc0d6264d8f7dfbba0a20f8ff1d7387cd9d9872f4b345b409950d66ababa9852f7f5ee634dad6085666956b97e4c9142dbdce96bf42d1334c61d04ffed5ac8f12a5075ac87a7416fd52579a876c89e22008759a93ebc57279215e178662a064bca65670089ec688532468c07161f56bbafbfa5655768123e713c7aff52852978e9d6004ab3a434d9b5c73f0d90dd1fe742a169a84f0e96a189bfc5265d8c5e2d9e42f5503d04ce01f9a912bf8b9bd8c282a4d40bbeca55d14971d1d305a16eb85d02b4edd8d35baea56156ba12f4e344dc4cb34509fc780ee97d24173a75e49960ec32055710bf8119d005447c6c391365737a0cff68d9f44868b97b2357dc051ed7fcf590b32292624545935e87f25e56b3e4a2b9c39c4936b5be9030b4711f246623264e0370291b675e75e1ce9cb425e5fabcfb55e25f084ea8a1b84870135ad997f7b700876691939cf268204669790a10ddd3d38cd22252226a09fddd395482deb561ee834ba452750d5b8e0de63c77c85a7446dd5bb29df2620f98e07bdac4cb59af8b9dc64d427dab780257e252e8d6793fd1b99f7c3162b4233a418526ab227d40b9deadc943d0f108a38d7a6b075465a44c920c0146338504eadf826cae345e864452e94706c8dceac5cca87469f2183a9c918295c09eef65f747b7a3d7fb3d259c4f531ffe48a5c338717ceb45efb557a47a593fac85cfaa4c263c109d385c01a3193a6ad1be5923d6a53e6c369a2b5e704cd6ac3ac255954c3fca1079895c596596873c1309fdcc5f36fe039d06806dd16cb00bd028edd6b44fb1e9ce4a020362824bef6a59502cce4e1d3d3884d7d865823deb092916a215ee73bdae1d4baf7f294caac7f63a36c2a15a40517438b8cecb93a5da3e11c25ff228ef3e7281360a2ce3ac66e69a2f136a83fbdbc44dd1737e9a31bdce16df9e118345ec1d9a9c47bfa60502722c9813d31c9f1b0364e2e25d77a0816db52f7e86bade9aff644df50b1cea9a339e76e869fa1fa50101f8182a2a6aee2e90d242d4b4d6b999d1c358a8d9297b6e0e2ec141c2b3692d70b141a213d477e87c52a2c87a5c6d1f0fb091f35f50915878ac70000000000000000000000000000000009111b212a32363b",
+ "hash": "0xe37a3c437aacfb3f7abe9bd9da80fb8a50398a56e6b60e6fd29f08abd049d9d7",
+ "intrinsicGasEstimate": "236504"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-1.json b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-1.json
new file mode 100755
index 000000000..2ad914461
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-1.json
@@ -0,0 +1,6 @@
+{
+ "id": "wrong-chain-ml-dsa-1",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 1,
+ "raw": "0x50f90ec5820af080843b9aca0084773594008302d5709400000000000000000000000000000000000000010180c001b90520372c0f4874450fb92ace74d41bc0326c7f739589f9b86a97afa87ef65d5939e608c81a44909e41f41931349f744b7aedff8d5270b91c4a2f61192e2bb6e3e6d12231deab235359e78ccada386becb6a6a1105afc0999243ab8b363f7cd2c19b2b741c9969dcf20252f20d130dc05d9244f58d6de9b4fb4b6f0125c43b60ebe3c7272b6ae7578f1abb4bb5e2dcb31eebf4aa7089aa2bf40a0ba5eb73aaa90e45472168738cb0e866547e079075d0341c4728ed794cd449d0cdeceaf64d09173a2677e3f2621b56014df58ee8de2bbcf8cb2bf369e57a28e40b24df6d0b15d3417b7b7fce3c49230b3bb7c7080c4f1344380db37299d8c0c29a7c9e95bfc4f3ec70b767895be6ad798449f94c92f320696f8f9ec844fc9451f5ab30874e6c78673b932e24a918d5bc03f4fa647c8679631ad8b30ba4f9a1a790a535104f5079f781fa4c4aad807777327e08bd6e14b957e527650d39e2de7d30da7b2b27457d3539c2f99903054bd1a6d6301b2f83249db80dedc911059b047b5552407ed32b79b57ea4968198decf978fed532277fb189841d0c17f261f1a7c4618c33b258a71cb6b2b921c48735c1fbc375a80fe2d702e9f70db34547147f6d65153f1c508ff90aaf57dfde59ce6e56c5c52049b10fbc2640cd937bf5027d755444cd5e84aad66be4ccf04f710f0b970cbe7fc5e4e7a44f5d8fc2af94ec6df87862dabe0d85dd17e43728800d5dc8ff9e9e1fd349b9d6431f264836a447646a1ee2d73e6a4d1803d71b98510d94d53b5d07764400f413b7837f463e273980296ad5e78a62c83fb91354c25c2e28bfa19480ca41b0ca2d8beed456029eabc0ba69cf3504cf1207ab21bed0e3a60795f5b066019132212a9bd20e98b43bb32484454b7693bc63764d0ba8768da4336ad16a979b1d3e8b06e89afc4caafaddead83ad861a4596814062468d8cb2e131e71cf38c4e335bb3d1d9629251fd50a4273999a20e11d9a881fa2465c2ef32301fa8805ccb38b4656e3c815b54ef42f292d05847c0e5149b0a2ffd1719fcad10730b763406e9e453d2e4a556c397a984a7d8622466522e79f715f980279cb2d1d74d5fd15f8beb8df9c0a1fb93f0d5494ab701cd60cf2b613b484a191d873449c4815f44eebb62658ef90f7033a5e48d40c8f4ec9a25d4f1b73a150e5b03a4feec9142362e77d74d364bb8a40f9873efa2d9f458d84277fdb0063642d9ebc794356368a0b4e53f6ab0d9acf4418fa42d05c11db12cb67d6c4cbbfde4d85358abaf8042510db53c1540fcb40045b334bc54a17608e82433d1e9e53c99769b86b69b8cf1914584cdef479061718a2cc5bec5c31272e0463139721c0c3523a6ea31832b5c15aa59819304c217fbc51a2636bfff331e6dc1037e89be15c17d6708762976329353612f312b828e525c09b81afafa5ae5c25d82b70b6e55f892429a93e5eb4048ade675583e828da988f9d253123a06c0ed047adf4d93d20cc6c865f5a761fec27811305165cd4bda05f563215d0612944b88ade9d64477ae8fb441978720e70b0d77e2edafd3a2c571cd28a42cca2f289d157cec813c24e7f56051b4f28c153adfbb2c1ff90ea1fbc03cb89603387169072442f5d3081140e2256ebadcd775d2f1da92c15a9ff1ce6e980b3b1e91a7e379081ed46a4259fada21536af318eb2043ea16cece60b73acd415d239389cad9212e15bad1b1ae38f93c756635a9b87417faa844e4f43bae1f1ae68641a04f0ff1d55f9045cf7e3ed59fde5c07219b9113329356d4300885ee19c9955c5757db33c6ae75b49d035003171d02ccbd7321d6a14db0bd011d4877f04070dbda3b67bf22d083eb90974dbb3fe4443f9160a432bb4e436b97eb1dddeb445ac5e99b3ecb7573e7d8306ca2c9ca81e4c0b9cb4bc8a19222f0f45910a0982bd3c78abccf395a5d87c9ee78cfd7d902808c21483a0e99137edc77073a35ad680dfe59c284e489272a85481bbbdd14158024750fb2762a931e06a16079056458fe2bb97ed55419da0798f94ec35767c7511ce7ccc0e626152f8b566bd71377dace697520cfa5aff622276c0e5cb0a970cc3795c889258daa614042dbe34dcf258b8aa52423035182399130f3b140164baf8caef8e9767f31db5beac2872907bce2550f448ebd74184f8bd28fc2ef9aa9e2e6625895fca23bc190983377c16b98ffb338e78ca6d64bc95fa90258a375240d11fc8cbbd8ea8f18ea28567ac02184342e61d6c6dcb3fe04cdb8ce967cec1c9e205114304839c81d5af6895401ba809bb81cac66062bb5159cdbb36b644927d99bd2ad337ef7fde1850b6b4776b7f484f4aa0b9a2a3bc69b4ae541bb6adc3cd5d8f9de83a5543941a97b2e0ff61700f834e90a74c2de3a0e02066685c94e3e08964b9f876772aa3e04be45979dc7e1df55e8c81d45bd07379d3f672509fd5faec33122e17f08c158948dc23a1bce964f6f665e7cb41e8994ddd2f01e8d5552227925c85985517e703dd10c79f4d77721bc28872048f7feda6197ccbfb0560be1e013953c76b9262a178642b0be5628880950fdb8bea2ed6b301b2751a8fe1876b8ab4d5f34dec3bc95b3d01dd1c53897c8cca238b7b7ce99175e3bb8547daef19d7399db5029106cb37b67d70dd131d6cbf97ccadff5fd2bdf83b0210d94ec7b1ee8c1efdc5646d704fc79544026b62c176259f3bb3de1d0a0be8ccd9d95370083a78fe4a0269484907e88051f16ed1e9da53180f28980e0951b897e3ab2694412ef3fab73ecf4ccaa14b236d4aac95b1d943d563c0194b6fdbccef0c92bded1d856684b98e76ee8832c64921f999f1908c5d8ebb9d5895ac48f976e60d636b99f327532932b44170e94db91b268e5e1024e2e15ed126800e7cef347cc58743fd57a9b7511e4e95d422a8e6b1022cd6ab7816a6afe1fcdedba4915ebf5a459e8b26d3c848276ee3b0a8202a3140e968a2686506d34960d96e86b309864754fcbfd128b816346fdcc04b8d14faff7cf5ea31c7422ebea74a7a524548bc57cb38bcc8d8689c90a469d8f0105a6f0cf2e7c24933a7993988389f5066bb7385e1ed75992c75c3df24c0a08c3f2162f5bab574b13dae648904d6754f92e1354190e706f1bc45ac71473c465fa73d784c09fe7fcab408e1d808dc5c318a0a6db8219121958f35046abcfed9d874f60dd18376fcd844c333ae7dc13353449082c79f46e9d7a2eaf71a7c54867b04dccef0e3593ce939e12e395e5b69a9a133e4a2f3140f17f89894b70bb7f21082621742249f544464f1995693f37ade71ead1de00701beade7e60d857c7c00c5431a4129c42803d00cce4f3765a9dff1ca90fbd27ee23f3a75baa049fe6205a24aa0a621ac5126649644c4b0cd3cb78d5db9460dff55761e5ffbae250c6365e632d953291efb1f891a614d52c8f882a7c867725c427eeeea2229c424bfc00ee7f4b186c8c68daff492d317733795f6674a44e3bc276e013f28c75fd176c53d8f6fe39675562bf7e0957a631587c0e76112da49f057786a976110ec3fa93e589117f1346180af06f2954b49ac60b4369e49b53b8ac068aac4e107294791eec204ac6ad869342cd55e90257893f92e3ae3c598be9cce120d674a8c128e46951a6b8817033aeebf46c55a1c9aa23d48c03b24ce63786fd7946c4be1f1dde7e6beb733f8f3a8ac8363ed03e1434669e7aa048ae77176b393c9ee6dc5febb7b8ca0b343e78601ca958f87600561c3bc4d32cbc0a31c0c026ab7b5f7659c15ea8d71709b9c5d3d377702097345ef51efc9c9384cddadae853e0d889cb835cbac3ac59370fa6395f9ca44a4a6250fb55181c83d14c1e4b5ec25ba3211abe634fac46163998739787b76a9f253eb83d0e9a9955859748cc42503b95624516bc41bdc12fce27d495c7326cce0e25d831261ebb157954913fefefc24021d90dfb342749507a899441028a24c5a678b636b26c8389737dd40c10f37c0d07ec8655247f149cc9dbb3567b2c81507c07f17944cf617477d692b6024d2000416fd75de3463eab6752130eef9d3400362c82c44fdc950ea47ac75ae25bc133b8c48f8bb9bdc6d0c7c109aadd7965b87a122544a14e72e219d58d237e7795cd3132e7802b8c370e8c14c170ec3026b5572e393e62cedb243a376d302e6573d75397c72b507a0e39a4b9c87c8fd6f49330e35248724217cc9782bcb408f5ec6f1510d334e31978c6ef5baac79444fb7ed56bd6eaf034d0dc32a66e3827886aa3c10327cb9bb7c9fab27bcd9a97c4d4181d06b7fe82204a369a079c6bbe454de03b87daee2b76390c701a26372cead63e99513d354dedea2a0b5f1788302ace68679fb52d6f11a17ea658616d4f625c1d3da587949e048acf37c4980125ea1e8666f85e37ef13af70c2a4219d9cc12fc0855713ec9c139f1bf41f34f0b787a08afc33814ff0e7530c22946d0b33ecba6d7be579e0a5644f6a4ee5a4088bbec8ab100faba7edbee3238a8fe55f4a19b45babb17d10cad5919a01839e67c256b66c84571a460f2ef287c367562be9e02bcf5e2a2bf1036b4a61e0393d58acc5554691847f8d972f48cedd46902b7c4711841bcd9d6186cfa462df62a78cb924429994a56f8edc2466fe9de98bb87c75d771cf41528174d7e0858b00b3398e59a7cd32a64ab4958b03724dd05f00915d08ae5356d605494a2728bd06fdbabbcb6b1bedbb83239a91a5ea9132f1aff725414898b5a848279c0f789900ad0c57b9a8c8aa3f10a19095b77e14f08389423411c59651ccf228fc0c0e94d0a057a894acdf7280c05fd56c7171659686383ebc6b19a93c47139f3ed455c0e642a49bea837a451cb0c6ab2073ce13f6b72eb71cb138ffaf668d41b8a6e94f1a9c216a33bf0532f9e9b4ed22944599f90ccc7162a0132113359dacb2793aa80c1077dfda1799414bf3dd0d2ebf84663c0f5762429c9ac94755562a7c62d90eb6b99233531d3bb7115b346c4644e94e78ea0a11ec4b1d18ee61891aa47bcf3988bae06fc01428dc32d5012ff32d1d2c17e1a7e23bfba427ac10a5462d6fecd35161296da85d00e3a59d5e6a68a38dd0e3f3f03b157321ab52d551bdadf30223f81df4d9a477bbf25c8ba80bf835f3e1012783270bbabc02b4f29ddb269784ae6d1323416f8a9799a1a9afc8e2e3e7f5fe0d1d2e4b4f5a858d9c9fa9b6bdbfd0d405091112383b44a3acb5bdcbccdef2f6475867838bb2c6e5eef4f9fa00000000000000000000000000000000000000001020303c"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-2.json b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-2.json
new file mode 100755
index 000000000..cf1ebcd49
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-2.json
@@ -0,0 +1,6 @@
+{
+ "id": "wrong-chain-ml-dsa-2",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 2,
+ "raw": "0x50f914be820af080843b9aca008477359400830383209400000000000000000000000000000000000000010180c002b907a05424000ae9a496294dd6b99046cfdbb235ae71031b379ce274c13b0c96411740cb61021a5390fbe8fb56b642b4e5e5abb7aeab143e0037f8db283b9f2febd650265ed6b05f1b867c124aef245c1811422f92414447fd0b20844e0f1b1cb4eec052400aad52b9d773aae0015c0c390bfdde3d367bd8ef9c3c73bca3164b9d418ecbb2d25303bbd12739a858c5fac4cbfa0203b9f3c319e9bc89d17a7a244b57d6613b5caabdb528f077eff9727015b9c266d777c0ba11920118c7ec4dd59b380c40e361a5b23ce04be4c61e12a1c21e091fa0d890687cbf588944db3e34253c75cdf797378de79162e0b4ca309f550365a289f652dd6d559478912cff70a5417589f73f14640970694d7b5a6bd8f000a65c632f0326ed3d128fda96dbea68cb812634dd75e9f63813a5645336681378b6a63220c066550aba43a5b937131d41f08752d13949a115a74bf96fa1925ff4338e10df0301abe40aaa49e14a1a1d58eef005a0f1d0299267002cebeda20cadcea7419cd0c365c53aede1aa36efaf764d3d36169747cdc8ee9a09e0a0ac6bcaeaeded0cd303c965d705d1b91a8b35f408ad8a033b02ff57610bddbfa60e2114e53f20f8fcad15dffac6a494c3f4f631590f2be3422af14cba7c900c9c38796952e20c3069bea2ab54bf0edf9315903aa5cf68549f878eafcc77561b36f8b78d950871ed4914417316f868a2bc54c72d3c9929f0138a2f0cbccb7c4141e94bb8a7ae11f660861cbbe498697d7327709271460a75bd4e024de3d4d6fe5af066944c96ba87459fa948a95eeb61abbaf643190ccaa9cd18591eb6f249a6eb92db89fc95616d21b41d7d15424b80a750938a12cd57d50ef95aaf222025dc4d81df320d9bc32c608b1c5a1aac8bd14c0f7a4c4380cdd65c793a6287050ff4d609102fd91e47e7365fb55513aeca273618528c199f7bb151e9c11a0bf202147734d1be9d5d0e9318096fa567317ed9fa6a8efe201b915b9aa05ca0d19e15c9a80449cc130b398ebbac3d938f55eea8f74e024b0e33dfecdbea02b920ddc5b277146685916194bfa1f8ac7784c7ed76923d4ff9ed97d3ceac283f9b26977df0133c5fa4fb5fcec577bc152e926529f06ff50c204c083c0b4d6b8d474cf5cf7cfcf7acf76921225443eb0abf5e4c76d0a3f524243ee4e372e80ff0f76dd9d135f240114a2ebe6d69609b6c60d275f251d7dceadc600d18e0cf8bc8fa8392e61fa32b8f7481c4883e19d820b51af0f87d3f7faae44e3b908fc759c6de59361487d8e424ffbd662d57a68801110e9cb099214143253949cc479eaae0e321fecab90c63b06819ce3cf56fc2fc1419408075c658024a28950aa47d549bcdb8b5bc9aeab463466c7834ca7d73058c206a95a023f0c8ac95badd383e63041e1f0ef69f51634f5ce2f48d80f8f2e92f4a1fb5322930141fc50e1e20bd235a8b8d768d473b46711257d028e710f82f0b6bd923da05ca64ae805f708577e125b3fca2feb5656f61ded034eaae481a195628801c82db85345f9ffdc72c860cffe2264ba4be2a08fdb37a4f5f80276baba4ea637847335c89dbd35504389f68b2d61ea66d4eac5fd0057d9e757d929214a7d83daf2fc2b3f840e083792d20d772584b252ba955ae8ae8c36af648c59ae0b25d3bca19413fbd749077b6969db5847409d13e4a67387e59116fe3836a733f3253d47f9919f49618fac8edf5fd711a4239447655d6c40f479f86ef3c9d4dc1a6f9683a3f1bc5c9730025e76ea1588d43494f59823f42c207e34412f73c7e2a126501b8fb810f12995c213063d909a5a9c2653d3511ceb809efa69c638f4c977d46a2a305cc831ecc0feebf5d9356ede6c780da78fe2ad683b3312282d5142612c0d1f85108de04de5c3d5414b62826d5b75f8887dc2d932c40f306c08e5d4f69ef4d344fe4317552df9890d0961e3d857bd9b2c5b44536d8606f62f66d14ddd43b0e5d3379cf66d664616df12b1c62385a57f6a562c34e120b79d64ca39d8b23e1e07b2c03910d711f09df5b54cb0e133dd751bea7832fdb38de2f1dafae69fbdf82b6887ff0a92940299020a835b958bb01b25b8699a0846614cb256a6621ef92e4a0947df9141ed4f91eca527aef25862158a8fa712dd60dda947f6a16e077810e29542a56f9244c34a73454b9ad0d8e8c40bd503efe12c4e5bf7d0ff8e6ab642a039f4e8b575d33c0c3de77a1abfa60b0252d7a549dd791d9630c8b848988157608448d77938bfb27beaea8f9b4a259263797c5b2fbdc7f469b2769f7dcb7b9478cdf5f109322eb2f0a83163469b72d8121fe8e01df227563cbd941a1f63961e2a010c6322a812a014279583a0066492a17d1a15c07024f6b8b1561041b3db608ec1c7475ce4d086e60523e85d7a955841558a35535d6e52cb166669a69049646b94d2fdb901ffbb1446a2d7f58696bce000ccbbb6942b0ad6480d006602c228218d3a2f0bc6a5d5c73acda9fc4b0b496a7d527050f8d77b71641f030368e9494bfe8e9dbf6dd4040426da1b0423739b40450273f4a8d551637e5fe3ca8d54fc476e6278e75cebf4a4ac3ac8ef3807041c4b274568797c8caaffae7df08c6c158d92411db981ea02cc212064c3ad6a9cd1cc02087acce5ceb8d7cddaec429d199c3d90670288be6e88e6826d1f6c417df5f35139c71a62c0267adfce7cb3aa49e827165b28c8cc157a691cb52ef103d8d7ca0ebfc628904d0b2d365dd3401b620d6d93cef670e2fb90ced0f4116f56457e97077c6728c16d27e9876b13275f1e5fdaacdf89ed7d20f7d53cc974910a84cdc1aa3c1289de7ce0a80dd983de4463d77f3390e4a9c64baa94cd0f8e31cb21844698ec396abb704d0886c9ef5239451d5a9c328564fdcf5203a0f6cca322d20e25a21a6d96246cd64ac993e175af68aa3ed24b210cb1822e8526257427552a8a896fc3ad77ac0a87bb1d574405d7ced0467b62c49470365adf9e16c492eb671ccfc637e4b9dd0a32f9de2a51a8970d431d8ad92e0cc265d8c6d165469da63fca1f189d70c51e911f624c3786b42e3b3a8c372842cbae99d6afdd2281251c28adeefde311b8bfd0c45e67ce6a6ec16193fd9bbeaff975331eb112c326b303748bd0d28535b73bb1a179b4ef4eba08f42c2dda78366631dfcd78944bdc9058169461baf34386bfd505b119ab6b2c9b84b9b130bb7723e601ce99257925bf06fa80f5ac9f0bd3d00044f71451e72354c0e20408548cbf68de3efdcf93b4383820d93c5fcbae49ecf9fa027660bd9f91613be07d7eb3cf2153588094db67c578447d1302b402283a05e03265d33c0f0a7bd7fffc77c2092a67a4a0983d0a6539bed110abca2a292c7c8f5eec9ad3cfc085708394705bd63d386eea1aa4b22daae2ed1685f17161b7df3ede14455504195692c683908273d73f0503ed4cc7c1c61288a17193923780fb50f9b020e08977c6d25ef33373ba13ebda30c38fc1a2d87d79b846f2ec4511e2fe77eb60fdc46811f055a646bd93de0b342177919f009be73913e21a9171584a1b5051f258fcf079fd474bcdb731b003a37403826cdee0e8ed0dbc9ca9b56cdc7e6d47c653561b47f3b3542a2c8c28777c13c72f4290e832452decb15cc5dd8c06283750af8c67694b40a8902e8f631d7b9447c84ff2122bf310f86cae68147e2357f8af55bbeff3d80b74f55c3e097681e593d0aa6a11ef2c3f55832f21f21bcefda9ebd539e4a11960ee8af8c609b7cdbda9580b278094058a30c5047f7a90b5b87aafb222afb7b80570cec0e3dac70d56592cce38ff1c4ae0b588f6cccd46ca44c77381a529aa712c8e4a806b1938ac1f1363912762be173e7d3f9e1c2dc2ca36ce29038463fa8697c268e68bb614e40ab18084c27746eb8b6b4a71ff53d509b877ac2532807d57694c7cbb1bc095092728374272e29dfb865393b9fedfb9ff0e67fec861da566318a65937254e65889cfe4c506e72e05db17c6094c7ee6ba48af6882582f5928d885daa934ceeedb494fcb8012f10253368df32f5951d8c6f319dd7800ac3fa437234265efb3fae1559aac30295de2d0c3e191551adea1d5da29bdb0fb81d8e1f6ff0e4579c31c8d5d958b06b2c9be37de43fe83317e079c18805836d72eda19cf86a97912187b39c0350bc790e0b760361c3b1558bae5fe841932dea5b84ac413661da37af425631c5f68ff4040d3c3f7b4bae3c74b0764d776d39cbde0b3c5d75f142ba111d4f604227900c3fa913b6d78d5fcd20df306b8b8f6dcf2321b1f90f55f81cec1b2599bbad1adabec95a2c4b0cfe0d429e056878af68871308cd2e21f94f6d6fef8b29fc9273aa97e6150d20c916e68710baa9b3de541b1022135151b61ce965d87d850eeccd4d74e201312d9ddf6952cb11f756f96558947f31adbf036179029c62dbc27815ddfee70b6652f257702a449381e1a7b66b5f550bf83cf23baac996f0b66fb405f5ed1400b5937d89e897dd40d70973bf716c97c81c1f9e36f83273e63cf489b26772a6d582fe3675137b934d1251cbb3d5bd4ab78ba886103ebe9864367a3048c3c0995e2bd2b76c97bb2e5c1d9e9c51244c202d33cd6a706f6958eff96bb47996a36f19e95350a4b2cd5a5d9a3e4c5240b5c6daa2bea47d43b4a10c767767ef81cab30be74d4891c6b64f0528d82a1e3053ea34231a2d10efa129d8d42ac32f9d8d0cdb559043cfcbc38968c8b031e40da7bc4add0f003c7e50216ad414ca3badb380de9c45713eb46965f8ccf77eae0beeb62529f21431597682605f4e07210a9ab9790b4614917c7b8f4db754cd57a031d03365317d6126de0a89ebe6ef2f877a64a9ec824ca8e6d0017c5249fcad3df09bdf09ced66cd6f840f151ec8a4db239bba62385779742ade58fbe56c4c79c0e8b271f77880953b8a39be239e729bc5fcc831993ae3fe8eb687527956a451dc7031428ebc64c9c426f77827adadd46b9384028a12bbbc4ec7cf7280f2d3fb2dffed142f13aa17f7d42405049d80dbb6ac9762ef56b947baff7012cf08c416935629de0ca1bd8a6f637d7416b780e898413284b16da24bf585eb288c85cac3520927bbcd07a1dfb8373b12ac7ab31f894074a15db8b033659c8e6160e743dc42228594e1db9f8b69f7d8334e75ec6288ab0da7cff63435ca2405f3d1e94b235dea4d61865f5e5ef73b3e86e28e624cab6fee2dd09d01f62d72d18a9fed6f77e660ac1cb3049a6cf0856d5373cda997bff223b10f59d76d6707fa7afc8c2dffe7a5a967f1340a18abfe9b64e3fc0822651a6c52c28b342842b830630c65c5e8cc82e8d06cba10b394207e72a4711d991e5851b3b5ca8e479c445b8c951d759b731b88ed7646f742a276cb4aedb8916c298a22c46103924f0b785febbc0d67acc5a869ba1fa1afda456fdd1a7bed9b29bcb5982fa0ee7eb2da5682f62e16b3a9754ac227df6b703e1b929d3b1142c6c616329d8a564e4a525a0e84194b365d1bd011c5bcac9812195ae3f60f6ec946f46cc2ad0ec7adade8ec2e5f70f1d6e65b20de2714f118ddd25dfa24c1b9c821af013cd54d363c0881a0295cf7129feead0336e2ff7df676665a392f57faf8bf1581715f3634049b2431c077709b3edba503de7a238eafc0c616f29ca4ed0b526ce819a6372f8e25e3f902e1fd7f7387b341948bd79bf3a1f81559138cdd455a098e49a68e64869b15806d363e7a5cd10c8e04ef7c7c28a2281e29daa999bf2aafcfdadf5d55b97c0dbf1b8e77a5351b26069b2eece2515fc08799a6f30896360b3eed3ca9056d5f2c1d8f761458fcc6d9e82091f6f0b3e954f73b9dc682c1b2e2be3d86c6da5b586ecb6d5ec9a57210e1c69467be07c9ebd1e363359274b27fdee6896043272af11e89ca047c388aa35d594d004c580fa87a46744f4f8be181ff374a362e753c8a48a9cf1060d176c08f01cef66e49b2ffc9b2280041ca8bd9cfcd10bc8e0058798ad72a45ed4566a9eed14aa4d03b6f691090515522b9466ee017f38cfdea83c92476f6640f7506862004d1a29c78575b8960cc50aac4092764ea5694dc21d84d65902f5c89384b687b9021ef3e66ed6d45a2f13c198ca722845f1d24b8729a766d2d1383573888b3405a30952c17e90cc6d4a9174bee6f1b0cbc8b449a36dea4593005938735ab45992733414e1bef4ec12368e575f5edd51a7b414fe67ad2c4fbdedb93bd350242fd4e285684e75ab4710982193459f779f7bd5ac12804098b53205bdfef7ae96f7615a52e35227ff29b8a1bd3ca54bfa1eaeaf2e84324119864ed4483fd9ca40fbc00fd5f72d7ca00ff9abfcbade3a8085392e70425691f8158c1ef9e173c10666843f3e14ba2fd5c78bd516e4a6503a11e06f39f6a5bbd657765317b1163f2ed9cbc687ec95515ec56ae75b64cc743c02442d02915e47b8c706ac70b0b5901fb61a5aa8bdc9057eaa42d43b37a5381266ecddd7510dd2a18138805758c2d41e896934cab73c61370ac959447e43bf5b629b904e7bba5ae8f959f923aa7844a898d150df35672635f304f8c55177e9185de1ef8ba82516d56bd27c7e7ba2b139a570f44f4085b275fa05d8f8e65b87a6e30570fa6846d227584ab63ae6293c0d0b8299fb53979a6e796eae7fe8f3439aa3a51889a8a5b1a4514ce597365a27cf5bec9e91558393ebfeeccc6462b7c25f6c03e251546d9fb603b1c25ab756044e042e2f325af8fc2cbb79fcf6f414bad1217cf96f21bb0d48c95c35abee171486d8bd0fa0b485b32f0e73dcf6f05a5475f95f3359634c4de53f44d1c53e4ec3264a82f635258c5b4d8bc912ba3b5503c53b1b239d44d3799a62dd3913871b0ed6fc87f186db1a40b2fe81ed197ab0df57c63de250f72ad592da936177e9f154b90625f76e86cbc2cd2f310d427330559b8b26f685a0a81d652562a3e3c70dd17e31b10b1c55208a551daec05aad5c5dfb32eb37a9dbfb4e43afdeb2d2dd27528c8dac2d043b0548ea7c2b0ca74ebf7dc4da83a8205d227e813d21808b11dec1ed78cc9fb489a0149eccc352e5d22f69b0c65993ec5de6f0ad0c20c936d35c26eb0f4cc61a0f64a376bd91ef980392fe99ef9e1845f1ccffd52b13679d164c7e917816daaee828a733ce4baeb1763ad59e9309ad1f6569dc7882b947032ce67ff0bb1f80362779455ce5741708931b8972ad67943161f6d2a9e4b376b07e3f5cdaff63b769b463be0c2e0a848211071e38709ce089d0413bf7bf9464fcccd03f16ae31c3a607716ff8f52eedabfc4f645c2ed293dee63f3434fb12b5024bb5cc16b0c03ebb2e8c2af1ef088e863cb75ecdcfbbb61ccd394954357e3baf7f7f2a137416073d0dbec002a60a5cadb5d678cbfe91d84bcd31b2144454c5677e64f9ff400000000000000000000000000000000000000000000070d12161e21"
+}
diff --git a/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-3.json b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-3.json
new file mode 100755
index 000000000..85f6fec1b
--- /dev/null
+++ b/ethereum/core/src/test/resources/aere/pqtx/wrong-chain-ml-dsa-3.json
@@ -0,0 +1,6 @@
+{
+ "id": "wrong-chain-ml-dsa-3",
+ "expect": "WRONG_CHAIN_ID (when validated on 28001)",
+ "alg": 3,
+ "raw": "0x50f91c64820af080843b9aca00847735940083045f289400000000000000000000000000000000000000010180c003b90a20fd3c43f5fc7807747a73e1d8e78cd9e611ad6bbba9b264534594174b49082aeab827927b335526cc50c2f0368fc666efb79c34af8ee90427d1718736acaad47f5959b9b26457619c07c2dda553d55a7498e30a37c92909f6b37c246dca4e8fd24d4cccd811396d276e5d11f1e8d14bb9eb4d5ec49798202422edd57ea4d8c0e8c6388e9c93a0ff2e52f7ca2303e40300c50c926a7da22919be462e2dcbdb3ec235b14290a282ee76a04f4bf7c5e2ec5c8fc0aaac72ce4f8fcf0d42b9fc3c4049ab6dfdfa12623d89c0d96434a8e13cb6f79ad6f4a8102f9a0bfe582d967372d8928ff9d7d7393b22ec1386ee91dd196eb9c349a6a12f7504e66a096eec0a8ae98e62275f6b84fb40a81a390c6ef0102c8fd2c11d303745b8fc49e638e6f3004961724a977a18d81efc67e37d0d44558e28cf9015dfa08eff82004c4a53dfa40c2451fa03a987f70c855dbee37e36480863044165e6d46d4c43278091317beab6f301d61c8f54f94ee88fa358c9aed6e55b80b4196e79a3d7251ede25c4baef8129882a69789df3a8262941199ded7bd381de00c257199c18e9086d9ce3f72c6d95c0a4d109a3a15474805f0dc06649a16a7805e8d74bd1af7658f5f9ef726d560595ff9f072d4cfaaf61283087843b904b0f5670ca551079c759d4a2839a71505e007cb5d49b0437b87a080fab5e2efdedd1d01f0f1ab72f0e6129a2525fc6e9829b56ce9d9f287a5bd80be8b1556e4ca82eafc60ec22315448768a72e45d4d956c16ee48a0658e307f81ee0f695f1b1b747d1d533d8da720f088b64608b1edb2d4d27247b2cd35e3d94e1256a3c5c944bbafe07b55ca74df4ec0b869733ddb466717a16e98af4ec310d046c90046c024fb33fbb2ffbb105d41bdd0e0af27b1239aa4d92b6ef8d727e51372fefc3b5c8bc6eb585a0ae2dd9970009555c2c2ced5e5a1e97c659565b6139dc4f3bae788e21f9658affa8fdb6f4733f7fa83fefab91a030f8ec976b8263c17abcef46dc22456d5347eea7c30dd25bdc3caad7cb2010f06573d56b6e5d28e6e847d8df8f18d6a2655ea66fe3c8e7e4ef192b5a8aeb35f8469277657b77155142c7b1653d5eb9cf9c4d69bbc5746e0c1876e330f9016a2f5343ec60b2f35ea380169a2bdf102888e6aae7e797d0bce73834f418018e8e55492da8236a542a999d9eea55bd52ee2e59feb0329d716c78c0bfcd79dc27cd9639399d2fd99d2fc9c4900ad60bdb8221501038ec4baadd2ac4830b2bfe1e20804c818c8e089661e7d842bc4e566fa0bc2d7968a44f8df0d4e88e494fc7bebdb695d3a8edf6a2703817b0f8c1a55569ac4a8ff0931137f075797e9744135a3fec6c767af26d4592a9022271a4052b1f1f24f072bd5ceb1d19e02b0bbf31251a7bb8b723bd3da02f59ca1c0c91bc10896970a1e0f8e0fd5b755da58d70be8935f65661629a9f833b35810113ce80125f8ed7a031cfd5eb1475b597856b4ce7629a9429d840a3457bbd70c05c73c6ce84dd59f917a24d06ca8743225ab8c266e209fbadf57cdb587df96eedf54c04fb3f83ec0dddd1d8bf9051c6de4db3aa099f1779f3f30f61f432e5c8f6b7ac4ee6c6dd6fce667556df155ddb2002735fb7addd8acf74863ccfe04a3088317634eb47e56b18c79f31318ac5e448a9094b5c2c70b44dbbbff7c235cef4701d504723b032726d009c6d7f527e645a23fc1ab478e6e2699211694d575bd436d778e7ae53868c63dfb78f591d82b979585cec8bbcde61f375e783e97e8f787fb392fa4f0bc3e9010aa9ec3cf6471bb16355c3ed3fdf2ee5b95ade86371d60fb0699a851770a212d0e0eeb3f20df78ab180343fd79a9d04d8dc56d9fe3d820b27d98d12275a40d270f4181aa1a18305c8d3469a954b2e85405a394684cc234702a6cb01c04ccc941a4392cf64ba31bea700d339152fce6abb0dbe84823b8d3b18258a29414fd52c91ccbc198e101287b79d8bd0e5f4b05a14a07055e66ea37d781934840a204638bffda400113bb1344126fe1c2ac1e57bb861c3d35349b1fba0c11e12921262ae52fb2e0bee444f8197e2817b9356e10af67e794a7967055936bfcb51f4be6fc5602a8df97ddcd73afe83c02f00d4f1d8302bd2e826d4c50fd3ded9a74debd0e807b694e912a8a3a800f5b983e171898874b77ea305ede4abdf0db5ca84a8a60b184374c08066537b08d42a609b97039ff8905bccc4454188b051c5d1e574e1e8b74cc5cbded064a5374c55f17002ee9b17447fdc324a12e3f2f414b491cccf20c9f98820461f4c7d61355a30f1a6cbb2fe7403b90587298fcc9500519451e44225c750b8b32a649ea288eda389e596390a5386652dea5d0e096ee270bcab9da0c3c4ba464f44172732a748e339cbfc8f0c1ee3187225e2fb29e67ffbd84df8acf759c817d628e03a245e9ae0cf00939fa12964e8dc124659eea8798b097ba52480532fa11194e4623ff63f6cc1d17c7080bb2c1459fe8cc9b197b89ba91986b7bfa61e514bf5c60f981e63baffd9fce44af87ad73fba197e46790fc03f8a46aa6d7590f47e08daedd7f564685208ee87da84b04b11cdc0c020bb26b0abdad3c1340649130e26af9c7651533313301e8b517a84c807d86a4c0cff68566d34da4111d67bdc77ef5f49ec7d83af24a143bceaee020acce02499c725ebc341a86d91c7f63dd962ffcc09fc0b5673873ee55cea4bba69b5058e4b364fb3802832d5118774790dd12eed78330412dc877cc034309a7e292ebee955a431fd46faf7884cf3bd5ab03d02b8784af2a84bb907ba5f021fc332f638a2d4b6451ea0a2cdee6ff1621d698eadfc99d6f405003f300e321a9e80ed3b577a899fa7dd891b53cab8acaa9fd3ce02640eaa75646f134c190817675b9e4a688d0668528fa3b378749bb6b1a0bd16873e89dfc927dcf568fc3cf94ac49d289ba1fb9c58a74574c8fbac321db256bf919e9432d6a8ae9a0dae900901f436b13d0c2b753a5eb6fcef03301d7faa15ff32ec0730335b13394bff66ea83a7043f9e1df5962671ff2d2759db234a4a4fa47fd3a9359bb14ef5b5fc398836d42afcc5d5f252b1b061afc6a0815b3a7586d25eed5ee52c56d2389b8f2438649ee652b431d3cc4262c6e5ea1c0ccec21aa6123e88b4bc933098576bd78cf5bcbbc278ee682029e05e91aac2043ad3ec1d3d97f6ebc6bd5faffa5bc71328cd4351bcb9a0d8d1ea9253b97b08c8c53b20e29703568d5d7dfa2bfa6aeb3a93043e4123116a125311695a11c8538658210971d7763ed7870c1309893909e306df22fe968612531e58a91d19dfe2c658ade19c8e0900c779af8ec333d19552e42cdedbe13ff85d99b10baf8daf70951290db56bc7ea049e6b468b6546a7f3ae77c2e14770eed1ea345f0d139336af4eee686ac2e73bd4262cb802e0173fb872a77cd2c0f3421c497b0260be79ae29d04d9a9da9d7bc101ae3ec9dace1133332f05b7b82aaee577c06c0d2a8eaa8a96db8b899cb3240cc4dca4f8eab513ad5b3529063b5df3664dde0db1e0ae5c29e69f011076fc7edc4261d043f38f1c68645466c9a5e685a07393b7e2f8f74db86742ba5ac089b45a42df3f943842747674c1653aa2a8ef282f64e7ec2ce1fada994288a5f9b95da4bc083ea008308b91213821ea6fa73a5016d6bbd3227853ecb797d9d49be7e4f6fa69ba1f84c4f509491e1a07ad0af5fad203717c10931dbc67c1c1a9d90591f8951f595dc96357d91e202ebae7955f0e45245936c750840ffd8df89e0f2789e427c79ac48d58982a6e087bf4235920efc666854459d6e4979a308594b7284181a9cdc011b48e1520454c48443228ba54f286952331533db7bcfb04df5e4cde37ff417dc4444adf86a4c4cb15be04b0fc9cf292ff313ff1ab5d1ecbffd14fe67526d4b6bc29c838ccbb2a442d08df1f8686da94e80867f9cef8b96b62656778cbad55c43f24b0915e6ace48353025c135a5c33bce233363ded2753716e61f213b04f2c429a797460e1e4166fed83575632b70540218afe616cd89fb77a981f60952c58a2246bbecf6606c005fe50caa3c3669c5b019e3ba52773aecf0fdf06d570d4ebe10241fd5694127365088a8045523fa639f6df29c6ed9ecb839c27582b133867f2f4b9395cae52c2606176d8ef04d32ce7bd563fbd3f2f3b9f7fc0468bbb8c770a563c278e22acb2d8a59e5e37538f07b98fbcadee17f23e625e93e76188bd1ea77152cf39cf05e568b95a3f5188920c0e8ab46e4ad9d9e6533de563334cf5ed7cd4e62b43a8e9455d4d232903dda4774c7dd9bcd39b01c2744ad47b361469c54aa589a35c798365bf8e6748465c7fffa0b688007f5f814953f87c03c6b3bf682ba6e70adc817596410d1e581e8c0f237e889bb4d4a09be8514707573b6299414845ef8ba7c9fade369afd8b1d7078031ad82bea47e516a2e5827a67591e85e628930bc81f20a5733270b8285922eb6fdd1f23cbc47f34563578db8433eeb007c428e5815e15bf6232d1801a39deabbb77a1a2bef02d16cc88b975e1835c105bdc813f7faaf6eecf601a4a67e30053c7fc92aae3cfc52900e471c3e8b70da92395c6f46cb6930f1ca80fcbffe73d5c02208b62d5f5368d0c7fb25ee9229284e10ac2278556f7026ba0d3bd5fcd1e04120b728a2f308366757fe15d176f72df5e566a31aaa809a97745a20352d4d698d945da8476defb6052414fe086e326b558b64447e3c9dac0b1f4ce5a06e678426d48f3436597cba43cf8af80b94c3813832bacbcd5d7c167fdaa1ad13afdc0ced8c3da011c695a33724bcdd9902eb545ec9aaf7038cf39600b9dad3091adc79a8b0e6b2fb457260f7ff789dbf78431ac839802a8f435e0b29b3c236a4cf8c7c138896b6724ae5b3690503ca21977bc6c5e29506702292a120e59ef8269682389ecbd41fb5aae0f6f04d0bd1942a527bb5152eb57843c6f64944996972eee48cce5d8a69ced00b240345dea932b5e32e4056f959b77051f10da85b06e6b6b6e4e191463e5105f55f1772d8117448f4b5511a2423475130ce26bdec44150b872116667791aea4c083f3b0abe44f19f841019911236179d280653dab71efc7fcd82bbeb56e5ede3bd7958a94b9a1ff082d82586ea876f6f3f059dec352b6c69ea86043137e547b62937e7a806a445528fa15b71e8cc987c587d3382ac00bd307b2c2ae5ff99f30bd1d1deb08976f9214788735d772b2ef04d827280e6dd836de156d1ac3a4eb530cb4c701ca69d51de13a6681de8d57dda2787a14bb5ebd934993596f6a98fcbd50339f0222da1df81247c5a0d620f6cb4f5ef311bdc66546bd3a5e2a5af0efa3c6158d7a6bb493ea89d8eaca4c07ec56189283118b7cadf32abbe1f65293973a1a55bae933f09feaaa3c6058083bec065f15fc795dc8e824f1ce941fa09f4d3512f4edd6fcc4c5b2f10d059087638d2bfcdd3f9e24383fd7466a1982226f8696abc5df1e51648fc165c46a0012c49e33a0de4ed6ba6215889cc923c8746407d38d856eee5c6f81ddd1b12d0511c79c0c6d0e88d09fc5f2f16e3f09b4c1754e26aa554840e707836cf3cedce57e463e0aa1a7be552d07594f3dd77cb0e76d9412faa917abdd50b3ce779d8c81019ec9d947f5717cee5a4e98c3e30e60fd4f34c66b29be5dd96d0ec235f6340464948976334d47a0e49198e77980acb97bcf77243f5c9eafdb8e742120065b8eb4348027a7dd251e9244ff3a2776d1783a449bcfb4dc4b3370362bb68ae3a61f842def75fcdb248634441092e25530db3b7bc2ce203231387d34c8195dbf293a2e680a2dff9b74e30f2f00ce4e84a309f1255ab55af3b2ce5b7a50712cd1d13ebcbb48dfa08b5edda1621ad30eb3e72562a2d3baeeb741514ddba8234d365e67ee35adc7a7902df9ac3f3f885da7a9fc4b6580d97f2dfbfd110b2fe313dd2b023ae1e98488742cad89bf33303ea235ce1bfb87577a04dfd3c1e1f952422bec2c5ef6a90aef6c39777d2c1fc283261b734fe19ff85777a63ddf6da7b6434e2ea8a2f6d0db84fff632a1d8e596fdb92b8d93a7a9a9d2a113032f96b1ba8ccc804c797f9ea6f65453c0ac308d10113abdab820817805547c0f1c392eacdf950a1bb88a85679461d2e2dff041037822062476311fd328173a9718934c3f2eeb8e6cff5316d44d5a870bb90407936c8188b9f8d4a26e92124a220f64dba55fd4ca34c39fc575899f8bba24d846fdd53ea0c0be00a9a5079406fbee0e83cdf8f360238e2e2c36b1c61b525c42a60d86bb79240bffc2fe6e0f5d46b09bc745ca7919a872461409298c61deb8648ed88774eb701ef565a0e1fa69bbefb87157441546e21371b98925e06d51124161b7ae678b84ce504360206a84f388557b99ee7774fdd0f411f300198c9abf5dc20a4f97d675dfa194e77266b7d8d47b101a8cac292d8b9945d1ad42d1878e8f5f35b0ec80281f02d7bfeb65226ad77704d7f6bc30fbcc6a4be54c8d162fe9529af1370f44ceb0da10ea36d389b6936fc9957f04a19ea796d2c5face0c8ee7bb23ff2db8a0b77a1cff4b169ece8d636663a3bcfd2d35bf44c251b8689338b76914d17f968ceff5e8de1719631729429371e5faf9cbb2067e891c658d0cb98276b16851b432b885d94d8efaa43e40ce4d09a97c1b7dca5d94d595629c44b41e75d2cda9bbcfef02adee54b5367a687428f005a1324eb8411f4468b0565ffc6b17953fc42a015e9acd9ae1e078a54ddd3b7355109c0eb56ab28263a02ec012993ebefa4060e1dd6347414681e634843baf9ee268fdbe7d00f22d05356231488042d08658f350b47c525d468bf63517758bad63c83821375d1c9f1165d7a3c829ac39a41200aabfbf03e8bde55c379e0f8ea8f81f59784212ec997612fa1aaed3f3ab82035cb761365982d4acb7e4713b9850511c3ad88b0844910e0968333ea3dba07068ad671208d1f4704e8d4d5b55b6b3ea7a4a70d2cffea0e8927bb215c1c628fbdaa6ea2d62d9fbcf274b56d7ffd5639ff2626b37ebba7f7add88dd978a5743d673e4ec7c82836de153d84ead5d378d290b2fffb2e5095496e7ca773d2db364896700ca09f0148df30d7c9ad70448503849831a428f602182eef6353db3c68f3100501e2575e31f658ad8fbe6f6f21f6d7dd369ecd1aab3f944d25ccb12c5fb2cecc39d32587b479f787482e38d60da3b15757816c4d0de0ac1dbfa4f6feab2e15be5b343227dbcc11fda877e9231d0d4cce4fdb0e9b73d0946fb60241613d51b658a2fd828d0931b1d2b7cdd50ee00c6aa454b0483747647b33d3eb9a4ce5f46755ea957202286a0e414940c570f7b8da652f3c7a0ebb28dcdfbc0a922f9f19bde6101563f898877ae298a51264cf5c692d97c62efab162d6265ea36aa59ffc86ba42d9f17979df28eb2f77045dbbd99d53e3d4553a9b8d4c7cec4d74f4f3d6a24129f7d48ef74dabd2804acaceb715fae1462446a06da637d196f19d02830a3f7ba8f0de5df1d080dfca719d6992317284a5d250c644e9dfd86930fd7224f199c4f52b7dfffc9767c003d066c43e980516a1bb2fcc92a3d5de9787b5f34e3bfee0ae38b97f84bc9f521b2f4e5c34787a8ea0a4c4daae98753a15af3481c41caa45b78cf98452cb7ec13ece08355d16be12f2c5cfc6aab958cb6273117bcff01a34940ef94ee8afa76360afac39aaeed3f54e7de726c3dc224de85cd92f57f3b105db6ad3e5f194fa33646984de36299958effd36bb1f9510b79f975bfdada10b334ab6a7f0f8337f084a7bc3db1e7af1b8d6b6a2e7061a80efb4ff5d7198175eba1c12e6acbf5092f0de03789a7de9b0cb0b385ed38f8db4c65628f674768ae91d256faa8152595d1270ca3d54249a3b1df84097f81d618297bb042750aca4f20d5a056689a5e8cebca0c3e36cc6333a16b9c7052517b5793552c1f625f8ec14a860cfdda306fafad0b77c47b47136f61ed8b9baf08ae974012c43bc00501f8044109125d5ebb450063fc6a954ab1bdee806882f8e04404ba28b6136c94f8f0a9fed264f5943e90d0c0edec69c668813d34d54bb6e43d90a9509d9dd7761431cf02109cefe77ff28cbd8915c116023f38e8457638dc11e9fef20ff2a6fb5623760981c8d267a18a64e19b1b58bf038a54dc90ea235346bd44ec79f37a20c6171ddbaab5276ca4dac6ebd79e5683727ed773ed29993b07de6905a295fb90d01f2f275d6a4cbcb1b6856593451083b988d1a0fb1bfd316e94e9f006a8011809413d695316d7477ee7dc327451aa7abfd1b91984ee887708153ffe1a4294aa561692db5d097dc9df1136c2bf29758760a422afb7e562d8be5769dd192c46aa95e3c8f9b6ec7d618b365137908987a75be43e511bb99f94936f1ab5fd6f5c93dcbaf8d0c017f6a24740b9cd49a1cb38a4e34397ce65265ed7276706d875a98adc60a7267a30e7fb39ee43fc930e697bc23972aecbe8c4c9059b8a43a26d4214d5162de2b80e8317b2877d2396164bd7240b411517ca0f57eed764e3319aee03e3e13570e75292ae6fb8c09a70f270325add11b3c7b0095ec721a35adf071b8db007d7b9a2408b62c1b17f0388250bfbee0dd7b9aef7eb8ce50df5bb18c441154a9da18773c57731a4345354ae6e03d4e863504e2adaffd618aa7aa44789269f83af69fb32a9cfc7fbdd6b316d03e2a9ce31509e05a07cb6c6ee6e127dd3b1c13d89e50f7407fc2e9ab99c1f6c7129589a1c77242392e1e08724fe2f6de96e87b4c4506a963e84eb3461bc9e0cab6094b7dd291e8e421823a6bc48d0d1a242fb8b0ca0a7b1f4124e4c262d5294b465eeaba288047cf6f24b26bf17dfdb70b09082384bad7c357a9ba33e7b97f290b540906b944240a88efbf89bc909a917f533d2bd3881847458dd8c58032949b43e21323af420a7d90c23977162d68627fa8f8f28659cbf497876b9dba0f2916b89f447d76167acf7ae5fa9769847feeef93deaa892e1e3ba4fbd3be85c9fad2ac7f403614c2a67d06ce3417529a8a866a22c5c10aa5bf07e195ad79556cc366ed3ab2d2f713d60e7e62a1af637aa9bec3ed96ff952fcd7162da28cbcc5999a38b926cee893a7704e325f0724ac383bb2d6e48e3c35d0bae557963a675674d3bcb058531b8b12d1c692b61078dd9bf9b2eeec94ce172b434941eafffb982dcc73e22812cabace33b2516fa45ec3eb82d2ce5b0204340f7f153d4ec65b2f42ce29e3dc5bb38531b666e4fed6485d2c3fecd536719bf758eade6c96086b258947dc694be765b3b9d8286852b18c25f15eca74ab745ac106bb91e2275b69b129cbd14b1c07348d0d157c90bbbfc11af6b4960fbc666cb3c9e4a3c408e6f595a67179e4ca2349c270ffa3d1581d8b9ebf6e9684067d358b6de326c0e6b890bc05e3175662f4c6f44e09ed3305ed04cb16d0635ee07377a106c24e42abeae5efa977446f88b7bb5def5aca2dbbf51e519521d018b5c668622e2b55e66b9b8fdfcde3b8491852907848ca86732810216ea19a9964842c6a3811078e6d1e73ac0d876d14272bd649dc6502816d2e20f7bbbc3026cbef63c6ae6ce07af82a832a06e634c59ca060b9b385a23a8c8bb2651a98f94ba138bf84e5f5a2e60c51962597df442438d9ff5447595d4919ccb4eb362fef3ba49fd94ab48a47f88e2ff009aa09f83ceb512524ea34ccbaf392492aa19ba75a480c16ea43beb1bfe8e1077f2735543aa1131daaf325e1895da07dd555f5a03d9387ee8d0ecdaa134950b7cb1a006587d3121060f97d3ca36e72dc9934a49f6fda29d7dd7fa6755379a0db48f97cd8bdf6ff252b08534b7d377a55bb91e616263467fd381ab0a12947c590cda2d43febbb45ba5fdd9a90d306c20e1b661e62c76232003ba0cde7da5e40e40b6b10cc9b9cca21e4f13daa7a05572e808b2205c37e0628566aef675caf08fa26ac299e866bb58c9fbc420acb2f02bfa6802da6fe81a065de34185dc38a6ec1ddd4b6aa188faa7f5c515614dd1c8bf6870eadf7d2595ddd56185b073be9f18f21285999c6c64a928572d7859e76520132b42398596d7f808392a2da2640546b6ea4c21d24520d59748ea4b2bdc10887a4cc15161acdd462639ab2cde2040e333543525f6c82dce50000000000000000000000000000000000000000000000080f121a1e232934"
+}
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java
index 4c7a60bdc..077f2be57 100644
--- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.eth.transactions;
import static org.hyperledger.besu.ethereum.core.kzg.CKZG4844Helper.CELL_PROOFS_PER_BLOB;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_ENTRY_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_STORAGE_KEY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOBS_WITH_COMMITMENTS_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_PROOF_BUNDLE_SIZE_V0;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_PROOF_BUNDLE_SIZE_V1;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.CODE_DELEGATION_ENTRY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.EIP1559_AND_EIP4844_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_PROOF_CONTAINER_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_PROOF_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CHAIN_ID_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_TO_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PAYLOAD_SHALLOW_SIZE;
@@ -143,77 +149,91 @@ public abstract class PendingTransaction
public void decrementScore() {
// use temp var to avoid non-atomic update of volatile var
final byte newScore = (byte) (score - 1);
// check to avoid underflow
if (newScore < score) {
score = newScore;
}
}
public abstract PendingTransaction detachedCopy();
private int computeMemorySize() {
return switch (transaction.getType()) {
case FRONTIER -> computeFrontierMemorySize();
case ACCESS_LIST -> computeAccessListMemorySize();
case EIP1559 -> computeEIP1559MemorySize();
case BLOB -> computeBlobMemorySize();
case DELEGATE_CODE -> computeDelegateCodeMemorySize();
+ case AERE_PQ -> computeAerePqMemorySize();
}
+ PENDING_TRANSACTION_SHALLOW_SIZE;
}
private int computeFrontierMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize();
}
private int computeAccessListMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
+ computeAccessListEntriesMemorySize();
}
private int computeEIP1559MemorySize() {
return EIP1559_AND_EIP4844_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
+ computeAccessListEntriesMemorySize();
}
private int computeBlobMemorySize() {
return computeEIP1559MemorySize()
+ OPTIONAL_SHALLOW_SIZE // for the versionedHashes field
+ computeBlobWithCommitmentsMemorySize();
}
private int computeDelegateCodeMemorySize() {
return computeEIP1559MemorySize() + computeCodeDelegationListMemorySize();
}
+ // AIP-20: an EIP-1559 shape plus the post-quantum authorization (record + two Bytes wrappers + the
+ // raw key and signature bytes, up to 7,219 of them for ML-DSA-87).
+ private static final int AERE_PQ_AUTHORIZATION_SHALLOW_SIZE = 64;
+
+ private int computeAerePqMemorySize() {
+ return computeEIP1559MemorySize()
+ + OPTIONAL_SHALLOW_SIZE
+ + transaction
+ .getPqAuthorization()
+ .map(a -> AERE_PQ_AUTHORIZATION_SHALLOW_SIZE + a.authorizationByteCount())
+ .orElse(0);
+ }
+
private int computeBlobWithCommitmentsMemorySize() {
final int blobCount = transaction.getBlobCount();
return switch (transaction.getBlobsWithCommitments().get().getBlobType()) {
case KZG_PROOF ->
OPTIONAL_SHALLOW_SIZE
+ BLOBS_WITH_COMMITMENTS_SIZE
+ calculateListShallowSize(blobCount) // list of KZGProofBundle
+ BLOB_PROOF_BUNDLE_SIZE_V0 * blobCount;
case KZG_CELL_PROOFS ->
OPTIONAL_SHALLOW_SIZE
+ BLOBS_WITH_COMMITMENTS_SIZE
+ calculateListShallowSize(blobCount) // list of KZGProofBundle
+ (BLOB_PROOF_BUNDLE_SIZE_V1
+ KZG_PROOF_CONTAINER_SHALLOW_SIZE
+ KZG_PROOF_SIZE * CELL_PROOFS_PER_BLOB)
* blobCount;
};
}
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java
index fe525c431..1ad11b019 100644
--- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.eth.transactions;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MAX_SCORE;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolStructuredLogUtils.logInvalid;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolStructuredLogUtils.logStart;
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolStructuredLogUtils.logStop;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.CHAIN_HEAD_NOT_AVAILABLE;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.INTERNAL_ERROR;
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.TRANSACTION_ALREADY_KNOWN;
import static org.hyperledger.besu.ethereum.trie.pathbased.common.provider.WorldStateQueryParams.withBlockHeaderAndNoUpdateNodeHead;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
@@ -432,40 +438,49 @@ public class TransactionPool implements BlockAddedObserver {
// Strict replay protection is enabled but the tx is not replay-protected
return ValidationResultAndAccount.invalid(
TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURE_REQUIRED);
}
if (transaction.getGasLimit() > chainHeadBlockHeader.getGasLimit()) {
return ValidationResultAndAccount.invalid(
TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT,
String.format(
"Transaction gas limit of %s exceeds block gas limit of %s",
transaction.getGasLimit(), chainHeadBlockHeader.getGasLimit()));
}
if (transaction.getType().equals(TransactionType.EIP1559) && !feeMarket.implementsBaseFee()) {
return ValidationResultAndAccount.invalid(
TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
"EIP-1559 transaction are not allowed yet");
} else if (transaction.getType().equals(TransactionType.BLOB)
&& transaction.getBlobsWithCommitments().isEmpty()) {
return ValidationResultAndAccount.invalid(
TransactionInvalidReason.INVALID_BLOBS, "Blob transaction must have at least one blob");
}
+ // AIP-20: not admitted to the pool before the activation height (the next block is judged).
+ if (transaction.getType().supportsPqAuthorization()
+ && !org.hyperledger.besu.ethereum.mainnet.AerePqTransactionSupport.isActiveAt(
+ chainHeadBlockHeader.getNumber() + 1)) {
+ return ValidationResultAndAccount.invalid(
+ TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
+ org.hyperledger.besu.ethereum.mainnet.AerePqTransactionSupport.inactiveMessage(
+ chainHeadBlockHeader.getNumber() + 1));
+ }
// Call the transaction validator plugin
final Optional<String> maybePluginInvalid =
configuration
.getTransactionPoolValidatorService()
.createTransactionValidator()
.validateTransaction(transaction, isLocal, hasPriority);
if (maybePluginInvalid.isPresent()) {
return ValidationResultAndAccount.invalid(
TransactionInvalidReason.PLUGIN_TX_POOL_VALIDATOR, maybePluginInvalid.get());
}
try (final var worldState =
protocolContext
.getWorldStateArchive()
.getWorldState(withBlockHeaderAndNoUpdateNodeHead(chainHeadBlockHeader))
.orElseThrow()) {
if (worldState instanceof BonsaiWorldState bonsaiWorldState) {
bonsaiWorldState.disableCacheMerkleTrieLoader();
}
diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java
index 86592933a..f3b958463 100644
--- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java
+++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.eth.transactions.layered;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.TransactionTestFixture.createSignedCodeDelegation;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MAX_SCORE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobType;
import org.hyperledger.besu.datatypes.CodeDelegation;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.Transaction;
@@ -173,40 +179,43 @@ public class BaseTransactionPoolTest extends TrustedSetupClassLoaderExtension {
final TransactionType txType = TransactionType.values()[randomizeTxType.nextInt(4)];
return switch (txType) {
case FRONTIER, ACCESS_LIST, EIP1559 ->
createTransaction(txType, nonce, maxGasPrice, payloadSize, null, keys);
case BLOB ->
createTransaction(
txType,
nonce,
maxGasPrice,
maxGasPrice.divide(10),
payloadSize,
1,
BlobType.KZG_PROOF,
null,
keys);
case DELEGATE_CODE ->
createTransaction(
txType, nonce, maxGasPrice, payloadSize, List.of(CODE_DELEGATION_SENDER_1), keys);
+ case AERE_PQ ->
+ throw new IllegalArgumentException(
+ "AIP-20 transactions need ML-DSA keys and are not generated by this test");
};
}
protected Transaction createTransaction(
final TransactionType type,
final long nonce,
final Wei maxGasPrice,
final int payloadSize,
final List<CodeDelegation> codeDelegations,
final KeyPair keys) {
return createTransaction(
type,
nonce,
maxGasPrice,
maxGasPrice.divide(10),
payloadSize,
0,
BlobType.KZG_PROOF,
codeDelegations,
keys);
diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java
index 1b48609ac..ccbf03c38 100644
--- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java
+++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java
@@ -1,33 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.ethereum.eth.transactions.layered;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.awaitility.Awaitility.await;
import static org.hyperledger.besu.datatypes.TransactionType.ACCESS_LIST;
import static org.hyperledger.besu.datatypes.TransactionType.BLOB;
import static org.hyperledger.besu.datatypes.TransactionType.DELEGATE_CODE;
import static org.hyperledger.besu.datatypes.TransactionType.EIP1559;
import static org.hyperledger.besu.datatypes.TransactionType.FRONTIER;
import static org.hyperledger.besu.ethereum.core.TransactionTestFixture.createSignedCodeDelegation;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.INVALIDATED;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.AuthorityAndNonce.NO_DELEGATIONS;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.AuthorityAndNonce.delegation;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.AuthorityAndNonce.toCodeDelegations;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.Sender.S1;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.Sender.S2;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.Sender.S3;
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayersTest.Sender.S4;
@@ -1789,40 +1795,43 @@ public class LayersTest extends BaseTransactionPoolTest {
return this;
}
private PendingTransaction create(
final Sender sender,
final TransactionType type,
final AuthorityAndNonce[] authorityAndNonces,
final long nonce) {
if (liveTxsBySender.get(sender).containsKey(nonce)) {
fail(
"Transaction for sender " + sender.name() + " with nonce " + nonce + " already exists");
}
final var newPendingTx =
switch (type) {
case FRONTIER -> createFrontierPendingTransaction(sender, nonce);
case ACCESS_LIST -> createAccessListPendingTransaction(sender, nonce);
case EIP1559 -> createEIP1559PendingTransaction(sender, nonce);
case BLOB -> createBlobPendingTransaction(sender, nonce);
case DELEGATE_CODE ->
createEIP7702PendingTransaction(sender, nonce, authorityAndNonces);
+ case AERE_PQ ->
+ throw new IllegalArgumentException(
+ "AIP-20 transactions need ML-DSA keys and are not generated by this test");
};
liveTxsBySender.get(sender).put(nonce, newPendingTx);
return newPendingTx;
}
private PendingTransaction replace(final Sender sender, final PendingTransaction pendingTx) {
final var replaceTx =
createRemotePendingTransaction(
createTransactionReplacement(pendingTx.getTransaction(), sender.key),
sender.hasPriority);
liveTxsBySender.get(sender).replace(pendingTx.getNonce(), replaceTx);
return replaceTx;
}
private Optional<PendingTransaction> getMaybe(final Sender sender, final long nonce) {
return Optional.ofNullable(liveTxsBySender.get(sender).get(nonce));
}
private PendingTransaction get(final Sender sender, final long nonce) {
return getMaybe(sender, nonce).get();
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
index 52771a088..4dd3f52d5 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
@@ -1,33 +1,39 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
+ *
+ * Modifications Copyright contributors to the Aere Network.
+ *
+ * This file was modified by contributors to the Aere Network, as required by section 4(b) of the
+ * Apache License 2.0. The copyright header above is the upstream one and is left exactly as it was
+ * found, as section 4(c) requires. The change itself is in patches/0006-aere-pq-transactions.patch.
*/
package org.hyperledger.besu.evm.gascalculator;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.internal.Words.clampedMultiply;
import static org.hyperledger.besu.evm.internal.Words.clampedToInt;
import static org.hyperledger.besu.evm.internal.Words.numWords;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.ExpOperation;
import java.util.function.Supplier;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
@@ -139,40 +145,53 @@ public class FrontierGasCalculator implements GasCalculator {
return clampedAdd(getMinimumTransactionCost(), dynamicIntrinsicGasCost);
}
/**
* Calculates the dynamic part of the intrinsic gas cost
*
* @param transaction the transaction
* @param baselineGas how much gas is used by access lists and code delegations
* @return the dynamic part of the intrinsic gas cost
*/
protected long dynamicIntrinsicGasCost(final Transaction transaction, final long baselineGas) {
final int payloadSize = transaction.getPayload().size();
long cost =
clampedAdd(callDataCost(payloadSize, transaction.getPayloadZeroBytes()), baselineGas);
if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
return cost;
}
+ // AIP-20: the post-quantum authorization bytes are charged like non-zero calldata (16 per byte)
+ // and the verification itself at the algorithm's flat cost. Zero for every other type.
+ final long pqCost =
+ transaction
+ .getPqAuthorization()
+ .map(a -> clampedAdd(16L * a.authorizationByteCount(), a.algorithm().verifyGas()))
+ .orElse(0L);
+ cost = clampedAdd(cost, pqCost);
+
+ if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
+ return cost;
+ }
+
if (transaction.isContractCreation()) {
cost = clampedAdd(cost, contractCreationCost(payloadSize));
if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
return cost;
}
}
return cost;
}
/**
* Calculates the cost of the call data
*
* @param payloadSize the total size of the payload
* @param zeroBytes the number of zero bytes in the payload
* @return the cost of the call data
*/
protected long callDataCost(final long payloadSize, final long zeroBytes) {
return clampedAdd(