22826 lines
2.1 MiB
22826 lines
2.1 MiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aere Network <node@aere.network>
|
|
Date: Thu, 01 Oct 2026 12:18:51 +0000
|
|
Subject: [PATCH] Aere Network: AIP-22 stages 1 to 3 and the rest of the chain-2800 fleet distribution of 2026-09-29
|
|
|
|
AERE patch 0008: AIP-22 stages 1 to 3, and everything else the chain-2800 fleet runs
|
|
|
|
Why this patch exists: from block 20,836,228 (AIP-22 stage 3, 2026-09-30) the header
|
|
of every chain-2800 block and qbft_getValidatorsByBlockNumber name the validators by
|
|
post-quantum ids (registry v3) instead of ECDSA addresses. A node built from patches
|
|
0001 to 0007 cannot read that list and stops at block 20,836,227. This patch brings
|
|
the recipe to the exact source tree the chain-2800 fleet distribution of 2026-09-29
|
|
was built from, so that a node built from it follows the chain past that height.
|
|
|
|
What it changes, as one delta over the tree produced by patches 0001 and 0003 to 0007:
|
|
- AIP-22 stage 1 (anchor threshold schedule, at least seven of ten seals per scheme
|
|
from block 20,715,632; a configuration value, read by code already in 0003) and
|
|
stage 2 (a per-scheme anchor interval in aere.pq.schemeSchedule: Falcon-512 at every
|
|
32nd block and SLH-DSA-SHA2-128s at every 128th from block 20,746,736);
|
|
- AIP-22 stage 3: the registry v3 format and its loader (PqRegistryV3, with its
|
|
conformance vectors), post-quantum validator ids in the header, the vote tally and
|
|
the validator peers (AerePqIdentity), read through aere.pq.identityBlock,
|
|
aere.pq.registryV3, aere.pq.registryV3.hashes and aere.pq.registryV3.keysFrom;
|
|
- the code of AIP-22 stages 4 and 5 (AerePqFinality, PqHeaderSealRule, AerePqHeaderSeal,
|
|
PqCheckpointRule, the finalized tag AerePqFinalityTags). It is inactive unless its
|
|
own activation properties are set; run-node.sh does not set them and chain 2800 has
|
|
not activated those stages;
|
|
- SLH-DSA-SHA2-128s signing split across threads and done once per round, with the
|
|
same signature bytes;
|
|
- blocks that carry withdrawals are rejected on BFT chains (QBFT/IBFT2 have no
|
|
withdrawals); tighter bounds on consensus message lists and rounds; a gas-cap check;
|
|
- the optional Block-STM parallel block processor and its wiring in
|
|
MainnetProtocolSpecs, and the JSON-RPC read path that reports an unavailable state
|
|
as an error instead of resolving "latest" to a null state during import. These two
|
|
were the known differences between this recipe and the fleet before this revision;
|
|
they are now in the recipe as well.
|
|
|
|
Files that are only backups or notes in the fleet tree (*.bak-*, BAZA.txt) are not in
|
|
this patch. Nothing else is left out: patches 0001 and 0003 to 0008 applied on a
|
|
pristine d2032017 checkout reproduce the fleet source tree file for file, apart from
|
|
the in-file licence notices described below and three lines where the fleet sources
|
|
named internal machines: one comment in QbftRound (rewritten with the same number of
|
|
lines, so the compiled class is identical) and the report path and header line of a
|
|
benchmark test, which is not part of the distribution; and one line added to a test
|
|
vector file, declaring that the 32-byte value in it is the public key of a test
|
|
vector (no private key is in this patch).
|
|
|
|
The upstream copyright header ("Copyright contributors to Besu" or the ConsenSys
|
|
header) of every modified file is kept unchanged, per Apache License 2.0 section 4(c).
|
|
Every upstream Java file this patch modifies for the first time receives, in this diff,
|
|
the in-file modification notice that section 4(b) requires, naming this patch; files
|
|
already modified by patches 0003 to 0007 keep the notice naming the patch that first
|
|
modified them (the fleet sources of 2026-09-29 do not carry those notices; the recipe
|
|
does, and this diff leaves them in place). The changed files are also listed above
|
|
the diff, which is the statement of modification that section 4(b) requires.
|
|
---
|
|
app/src/main/java/org/hyperledger/besu/controller/PqTipAdoptionGate.java | 278 +++++++++++
|
|
.../java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java | 110 ++++
|
|
.../java/org/hyperledger/besu/controller/PqTipAdoptionGateModeTest.java | 180 +++++++
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinality.java | 194 ++++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTags.java | 202 ++++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/AerePqHeaderSeal.java | 95 ++++
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentity.java | 561 +++++++++++++++++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/BftBlockHashing.java | 8 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/BftBlockInterface.java | 7 +-
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/BftExtraData.java | 58 +++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/FalconSealSupport.java | 206 +++++++-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/HybridSealProducer.java | 109 +++-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/HybridSealSupport.java | 90 +++-
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchor.java | 5 +-
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapse.java | 24 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/PqRegistryHashTool.java | 14 +-
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3.java | 963 ++++++++++++++++++++++++++++++++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/PqSchemeSchedule.java | 134 ++++-
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/PqSealed.java | 61 +++
|
|
.../besu/consensus/common/bft/blockcreation/BftBlockCreator.java | 23 +-
|
|
.../besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java | 9 +-
|
|
.../besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java | 14 +-
|
|
.../besu/consensus/common/bft/blockcreation/PqAnchorProducer.java | 18 +-
|
|
.../hyperledger/besu/consensus/common/bft/messagewrappers/BftMessage.java | 12 +
|
|
.../org/hyperledger/besu/consensus/common/bft/network/ValidatorPeers.java | 18 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java | 19 +-
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ADRS.java | 10 +-
|
|
.../main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/Fors.java | 10 +-
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/HT.java | 22 +-
|
|
.../org/hyperledger/besu/consensus/common/bft/slhdsa/IndexedDigest.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/JdkDigest.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/NodeEntry.java | 10 +-
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/PK.java | 10 +-
|
|
.../org/hyperledger/besu/consensus/common/bft/slhdsa/ParallelSigning.java | 257 ++++++++++
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_FORS.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_XMSS.java | 10 +-
|
|
.../src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SK.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngine.java | 10 +-
|
|
.../hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngineProvider.java | 10 +-
|
|
.../besu/consensus/common/bft/slhdsa/SLHDSAKeyGenerationParameters.java | 10 +-
|
|
.../besu/consensus/common/bft/slhdsa/SLHDSAKeyPairGenerator.java | 10 +-
|
|
.../hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyParameters.java | 10 +-
|
|
.../org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAParameters.java | 10 +-
|
|
.../besu/consensus/common/bft/slhdsa/SLHDSAPrivateKeyParameters.java | 10 +-
|
|
.../besu/consensus/common/bft/slhdsa/SLHDSAPublicKeyParameters.java | 10 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSASigner.java | 17 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/slhdsa/WotsPlus.java | 10 +-
|
|
.../org/hyperledger/besu/consensus/common/bft/tools/PqRegistryV3Tool.java | 288 +++++++++++
|
|
.../hyperledger/besu/consensus/common/validator/blockbased/VoteTally.java | 25 +
|
|
.../besu/consensus/common/validator/blockbased/VoteTallyUpdater.java | 18 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/AereKeysFromV3Test.java | 192 +++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/AereLocalKeysV3Test.java | 164 ++++++
|
|
.../org/hyperledger/besu/consensus/common/bft/AerePqFinalityAuthorTest.java | 243 +++++++++
|
|
.../org/hyperledger/besu/consensus/common/bft/AerePqFinalityTagsTest.java | 235 +++++++++
|
|
.../java/org/hyperledger/besu/consensus/common/bft/AerePqIdentityTest.java | 135 +++++
|
|
.../org/hyperledger/besu/consensus/common/bft/HybridSealProducerTest.java | 29 ++
|
|
.../org/hyperledger/besu/consensus/common/bft/HybridSignerRegistryTest.java | 8 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapseTest.java | 64 +--
|
|
.../test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorTest.java | 28 +-
|
|
.../java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3Test.java | 509 +++++++++++++++++++
|
|
.../org/hyperledger/besu/consensus/common/bft/PqSchemeScheduleTest.java | 56 ++-
|
|
.../besu/consensus/common/bft/slhdsa/SlhDsaParallelSigningTest.java | 137 +++++
|
|
.../besu/consensus/common/validator/blockbased/VoteTallyIdentityTest.java | 75 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n01-format.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n02-chain.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n03-extra-field.json | 63 +++
|
|
.../common/src/test/resources/aere/registry-v3/n05-unknown-scheme.json | 64 +++
|
|
.../common/src/test/resources/aere/registry-v3/n06-required-scheme.json | 60 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n07-falcon-header.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n08-pop.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n09-id-derivation.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n10-duplicate-id.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n11-duplicate-key.json | 62 +++
|
|
.../common/src/test/resources/aere/registry-v3/n12-rotation-one-key.json | 50 ++
|
|
.../common/src/test/resources/aere/registry-v3/n12b-rotation-wrong-key.json | 51 ++
|
|
.../common/src/test/resources/aere/registry-v3/n13-rotation-unchanged.json | 55 ++
|
|
.../common/src/test/resources/aere/registry-v3/n14-ecdsa-wrong-key.json | 62 +++
|
|
.../common/src/test/resources/aere/registry-v3/n14b-ecdsa-missing.json | 58 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n15-transport.json | 62 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/n16-declared-hash.json | 63 +++
|
|
consensus/common/src/test/resources/aere/registry-v3/ok-epoch-a.json | 71 +++
|
|
.../common/src/test/resources/aere/registry-v3/ok-epoch-b-rotation.json | 60 +++
|
|
consensus/common/src/test/resources/vector-slh-dsa-noble-2026-09-03.json | 10 +
|
|
.../org/hyperledger/besu/consensus/qbft/core/messagewrappers/Proposal.java | 10 +-
|
|
.../hyperledger/besu/consensus/qbft/core/messagewrappers/RoundChange.java | 8 +-
|
|
.../besu/consensus/qbft/core/network/QbftMessageTransmitter.java | 4 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/payload/CommitPayload.java | 16 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/payload/MessageFactory.java | 8 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/payload/PreparePayload.java | 17 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/payload/ProposalPayload.java | 17 +-
|
|
.../hyperledger/besu/consensus/qbft/core/payload/RoundChangePayload.java | 22 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java | 100 +++-
|
|
.../hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java | 9 +-
|
|
.../org/hyperledger/besu/consensus/qbft/core/statemachine/RoundState.java | 10 +
|
|
.../org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java | 16 +
|
|
.../hyperledger/besu/consensus/qbft/core/validation/CommitValidator.java | 5 +-
|
|
.../besu/consensus/qbft/core/validation/PqCommitEnforcement.java | 55 +-
|
|
.../besu/consensus/qbft/core/validation/PqFinalityLayersGuard.java | 181 +++++++
|
|
.../besu/consensus/qbft/core/validation/RoundChangePayloadValidator.java | 7 +-
|
|
.../besu/consensus/qbft/core/messagewrappers/AereD434ListBoundsTest.java | 73 +++
|
|
.../besu/consensus/qbft/core/statemachine/PqCommitSealsSignedOnceTest.java | 210 ++++++++
|
|
.../besu/consensus/qbft/core/validation/AereD434RoundCapTest.java | 61 +++
|
|
.../besu/consensus/qbft/core/validation/AereFinalityMessageTest.java | 204 ++++++++
|
|
.../besu/consensus/qbft/core/validation/AereFinalityVectorsWriter.java | 206 ++++++++
|
|
.../besu/consensus/qbft/core/validation/AereIdentityMessageTest.java | 165 ++++++
|
|
.../besu/consensus/qbft/core/validation/PqFinalityLayersGuardTest.java | 130 +++++
|
|
.../besu/consensus/qbft/core/validation/PqHybridEnforcementTest.java | 39 ++
|
|
.../besu/consensus/qbft/core/validation/PqHybridRotationV3Test.java | 171 +++++++
|
|
.../besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java | 13 +-
|
|
.../main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java | 40 +-
|
|
.../hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java | 32 ++
|
|
.../org/hyperledger/besu/consensus/qbft/adaptor/QbftFinalStateImpl.java | 12 +-
|
|
.../besu/consensus/qbft/headervalidationrules/PqAnchorDigestRule.java | 8 +-
|
|
.../besu/consensus/qbft/headervalidationrules/PqAnchorSealsRule.java | 42 +-
|
|
.../besu/consensus/qbft/headervalidationrules/PqCheckpointRule.java | 133 +++++
|
|
.../besu/consensus/qbft/headervalidationrules/PqHeaderSealRule.java | 259 ++++++++++
|
|
.../java/org/hyperledger/besu/consensus/qbft/AereIdentityHeaderTest.java | 144 ++++++
|
|
.../consensus/qbft/headervalidationrules/PqAnchorDisarmedWindowTest.java | 92 +++-
|
|
.../besu/consensus/qbft/headervalidationrules/PqAnchorV2RulesTest.java | 34 ++
|
|
.../besu/consensus/qbft/headervalidationrules/PqCheckpointRuleTest.java | 75 +++
|
|
.../besu/consensus/qbft/headervalidationrules/PqHeaderSealStage5Test.java | 478 ++++++++++++++++++
|
|
.../besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java | 20 +-
|
|
.../hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java | 23 +-
|
|
.../besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java | 20 +-
|
|
.../besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java | 27 +-
|
|
.../java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java | 82 ++-
|
|
.../api/jsonrpc/internal/methods/AereStateUnavailableIsAnErrorTest.java | 138 ++++++
|
|
.../org/hyperledger/besu/ethereum/api/query/AereHeadStateRetryTest.java | 140 ++++++
|
|
.../java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java | 28 +-
|
|
.../org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java | 6 +-
|
|
.../java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsValidator.java | 37 ++
|
|
.../org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmEngine.java | 528 ++++++++++++++++++++
|
|
.../besu/ethereum/mainnet/blockstm/AereBlockStmPreprocessing.java | 119 +++++
|
|
.../hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmProcessor.java | 160 ++++++
|
|
.../java/org/hyperledger/besu/ethereum/mainnet/blockstm/BaseReader.java | 67 +++
|
|
.../java/org/hyperledger/besu/ethereum/mainnet/blockstm/BlockStmStats.java | 38 ++
|
|
.../org/hyperledger/besu/ethereum/mainnet/blockstm/FlatBaseSnapshot.java | 165 ++++++
|
|
.../main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvAccount.java | 82 +++
|
|
.../java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvBaseLayer.java | 149 ++++++
|
|
.../main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvContext.java | 55 ++
|
|
.../src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvKey.java | 156 ++++++
|
|
.../main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvMemory.java | 266 ++++++++++
|
|
.../main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/Scheduler.java | 390 +++++++++++++++
|
|
.../org/hyperledger/besu/ethereum/mainnet/AereD432GasCapUnsignedTest.java | 103 ++++
|
|
.../org/hyperledger/besu/ethereum/mainnet/AereD433BftWithdrawalsTest.java | 75 +++
|
|
.../besu/ethereum/mainnet/feemarket/LondonFeeMarketAereFloorTest.java | 129 +++++
|
|
.../besu/ethereum/mainnet/parallelization/AereBlockStmBenchmarkTest.java | 620 +++++++++++++++++++++++
|
|
.../besu/ethereum/mainnet/parallelization/AereBlockStmSmokeTest.java | 130 +++++
|
|
.../src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java | 100 +++-
|
|
.../org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java | 19 +
|
|
.../org/hyperledger/besu/ethereum/eth/sync/PropagatedBlockAdoptionGate.java | 103 ++++
|
|
.../main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java | 47 +-
|
|
.../java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java | 88 ++++
|
|
ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java | 26 +
|
|
evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java | 10 +-
|
|
evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java | 18 +-
|
|
.../org/hyperledger/besu/evm/precompile/P256VerifyPrecompiledContract.java | 8 +-
|
|
158 files changed, 14209 insertions(+), 336 deletions(-)
|
|
|
|
diff --git a/app/src/main/java/org/hyperledger/besu/controller/PqTipAdoptionGate.java b/app/src/main/java/org/hyperledger/besu/controller/PqTipAdoptionGate.java
|
|
new file mode 100644
|
|
index 0000000000..5daabf7a6a
|
|
--- /dev/null
|
|
+++ b/app/src/main/java/org/hyperledger/besu/controller/PqTipAdoptionGate.java
|
|
@@ -0,0 +1,278 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.controller;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqHeaderSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftHelpers;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
+import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.eth.sync.PropagatedBlockAdoptionGate;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.HashSet;
|
|
+import java.util.List;
|
|
+import java.util.Set;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AERE D-412 (2026-09-26), Rule C, the consensus-aware implementation of {@link
|
|
+ * PropagatedBlockAdoptionGate.Gate}.
|
|
+ *
|
|
+ * <p>A validator does not ADOPT, as the new canonical head, a block that arrived by propagation at the
|
|
+ * tip of its own consensus height unless it holds a post-quantum COMMIT quorum for that exact block
|
|
+ * hash - the Falcon-512 commit seals it heard on AIP-21 Commit messages, re-verified now against the
|
|
+ * anchored registry. From H_hdr the header carries only the proposer's single seal, so a valid header no
|
|
+ * longer proves quorum agreement; that agreement lives in the seal cache, and a single-key forgery has
|
|
+ * none. The block stays VALID (this is fork choice, not validation), so:
|
|
+ *
|
|
+ * <ul>
|
|
+ * <li>Below H_hdr the gate is inert (the header's ECDSA committed-seals rule already proves a quorum).
|
|
+ * <li>A reader (not in the validator set) is not gated: it hears no commit seals, so it could never
|
|
+ * clear the gate and would stall; its canonicity is Rule B, out of this milestone's scope.
|
|
+ * <li>The sync downloader is a different code path and does not consult this gate, so a validator that
|
|
+ * fell behind catches up freely and only rejoins the gated tip once it hears commits again.
|
|
+ * </ul>
|
|
+ *
|
|
+ * <p>The quorum proof is cryptographic: each cached seal is re-verified with Falcon over {@link
|
|
+ * PqAnchor#commitMessage} (the exact message a commit seal signs from the anchor form, which holds at
|
|
+ * every height at or above H_hdr), and only distinct verified signer indexes are counted, so junk in the
|
|
+ * cache cannot forge the proof. To clear the gate an adversary would need the commit quorum's distinct
|
|
+ * Falcon signatures over the block's commit message - which is exactly the agreement D-412 shows a single
|
|
+ * key cannot produce.
|
|
+ *
|
|
+ * <p><b>OBSERVE by default, since D-419 (2026-09-27).</b> Measured on testnet 28001: validator
|
|
+ * aere-testnet@1 spent five seconds importing its own 3,366-transaction block, missed the commit messages of
|
|
+ * the next height, and this gate then refused the block the other four had decided - 226 times over 1 h 45
|
|
+ * min - while its own consensus climbed to round 10 and could never decide that height again, and the sync
|
|
+ * downloader never engaged ({@code eth_syncing=false} 4,000 blocks behind). The third bullet above was the
|
|
+ * premise, and it did not hold. Meanwhile the one scenario the gate was written for had been measured on
|
|
+ * 2026-09-26 WITHOUT the gate: honest validators holding the honest block at the tip did not adopt the forged
|
|
+ * one (0 of 3), because the honest block wins the race; the real D-412 exposure is readers and catch-up,
|
|
+ * which Rule B1 (finality tags) and the anchor bound (PqAnchorSealsRule) cover. So the gate now defaults to
|
|
+ * OBSERVE: it computes exactly the same verdict and logs every block it WOULD refuse ({@value
|
|
+ * #OBSERVE_MARKER}), and adopts it. ENFORCE ({@value #PROPERTY_MODE}=enforce or {@value #ENV_MODE}=enforce)
|
|
+ * keeps the old behaviour and must be asked for; it has no release condition yet, so it can wedge a validator
|
|
+ * that missed a height. A safe release needs evidence one key cannot forge (a certified anchor above the
|
|
+ * refused block), not a timeout: a proposer that stays silent and waits for the timeout is the D-412 attack.
|
|
+ */
|
|
+public class PqTipAdoptionGate implements PropagatedBlockAdoptionGate.Gate {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(PqTipAdoptionGate.class);
|
|
+
|
|
+ /** System property selecting the gate mode: {@code enforce} or {@code observe} (the default). */
|
|
+ public static final String PROPERTY_MODE = "aere.d412.adoptionGate";
|
|
+
|
|
+ /** Environment twin of {@link #PROPERTY_MODE}. */
|
|
+ public static final String ENV_MODE = "AERE_D412_ADOPTION_GATE";
|
|
+
|
|
+ /** Logged, in observe mode, for every propagated block the enforce mode would have refused. */
|
|
+ public static final String OBSERVE_MARKER = "AERE D-412 OBSERVE: would NOT adopt";
|
|
+
|
|
+ /**
|
|
+ * Whether the configuration asks for ENFORCE. Anything other than {@code enforce} (after trimming, any
|
|
+ * case), including nothing at all, is OBSERVE: enforcing must be an explicit request.
|
|
+ *
|
|
+ * @param property the system property value, possibly null
|
|
+ * @param env the environment value, possibly null
|
|
+ * @return true only for an explicit enforce
|
|
+ */
|
|
+ static boolean enforceRequested(final String property, final String env) {
|
|
+ final String v = property != null && !property.isBlank() ? property : env;
|
|
+ if (v == null || v.isBlank()) {
|
|
+ return false;
|
|
+ }
|
|
+ final String m = v.trim().toLowerCase(java.util.Locale.ROOT);
|
|
+ if (!m.equals("enforce") && !m.equals("observe")) {
|
|
+ LOG.warn(
|
|
+ "AERE D-412: unknown adoption gate mode '{}' ({} / {}); using OBSERVE", m, PROPERTY_MODE, ENV_MODE);
|
|
+ }
|
|
+ return m.equals("enforce");
|
|
+ }
|
|
+
|
|
+ /** Verifies one Falcon seal over the commit message of a block; injectable for tests. */
|
|
+ @FunctionalInterface
|
|
+ public interface SealVerifier {
|
|
+ /**
|
|
+ * Verify.
|
|
+ *
|
|
+ * @param blockNumber the height
|
|
+ * @param validatorIndex the signer index in the anchored registry
|
|
+ * @param message the commit message that was signed
|
|
+ * @param signature the Falcon signature
|
|
+ * @return true iff it verifies against the key bound at that height
|
|
+ */
|
|
+ boolean verify(long blockNumber, int validatorIndex, Bytes message, Bytes signature);
|
|
+ }
|
|
+
|
|
+ private final ValidatorProvider validatorProvider;
|
|
+ private final Address localEcdsaAddress;
|
|
+ private final long chainId;
|
|
+ private final PqSealCache cache;
|
|
+ private final SealVerifier verifier;
|
|
+ private final boolean enforce;
|
|
+ private final java.util.function.LongPredicate stage5Active;
|
|
+ private final java.util.concurrent.atomic.AtomicLong wouldRefuse =
|
|
+ new java.util.concurrent.atomic.AtomicLong();
|
|
+
|
|
+ /**
|
|
+ * Production wiring; the mode comes from {@link #PROPERTY_MODE} / {@link #ENV_MODE} (OBSERVE unless
|
|
+ * enforce is asked for).
|
|
+ *
|
|
+ * @param validatorProvider the validator provider (the set at a height; ids from H_id, addresses below)
|
|
+ * @param localEcdsaAddress this node's ECDSA address (from its node key)
|
|
+ * @param chainId the chain id every commit message carries
|
|
+ */
|
|
+ public PqTipAdoptionGate(
|
|
+ final ValidatorProvider validatorProvider, final Address localEcdsaAddress, final long chainId) {
|
|
+ this(
|
|
+ validatorProvider,
|
|
+ localEcdsaAddress,
|
|
+ chainId,
|
|
+ PqSealCache.instance(),
|
|
+ (n, i, m, s) -> PqSignerRegistry.falconSealSupport().verifyAtHistoric(n, i, m, s),
|
|
+ enforceRequested(System.getProperty(PROPERTY_MODE), System.getenv(ENV_MODE)),
|
|
+ AerePqHeaderSeal::active);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Full wiring, for tests.
|
|
+ *
|
|
+ * @param validatorProvider the validator provider
|
|
+ * @param localEcdsaAddress this node's ECDSA address
|
|
+ * @param chainId the chain id
|
|
+ * @param cache the seal cache to read
|
|
+ * @param verifier the seal verifier
|
|
+ * @param enforce true to refuse (ENFORCE), false to log and adopt (OBSERVE)
|
|
+ * @param stage5Active whether a height is at or above H_hdr (production: {@link AerePqHeaderSeal#active})
|
|
+ */
|
|
+ PqTipAdoptionGate(
|
|
+ final ValidatorProvider validatorProvider,
|
|
+ final Address localEcdsaAddress,
|
|
+ final long chainId,
|
|
+ final PqSealCache cache,
|
|
+ final SealVerifier verifier,
|
|
+ final boolean enforce,
|
|
+ final java.util.function.LongPredicate stage5Active) {
|
|
+ this.validatorProvider = validatorProvider;
|
|
+ this.localEcdsaAddress = localEcdsaAddress;
|
|
+ this.chainId = chainId;
|
|
+ this.cache = cache;
|
|
+ this.verifier = verifier;
|
|
+ this.enforce = enforce;
|
|
+ this.stage5Active = stage5Active;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether this gate refuses (ENFORCE) or only logs (OBSERVE).
|
|
+ *
|
|
+ * @return true in ENFORCE mode
|
|
+ */
|
|
+ public boolean isEnforcing() {
|
|
+ return enforce;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * How many propagated blocks this gate judged without a post-quantum commit quorum (refused in ENFORCE,
|
|
+ * logged and adopted in OBSERVE).
|
|
+ *
|
|
+ * @return the count since start
|
|
+ */
|
|
+ public long wouldRefuseCount() {
|
|
+ return wouldRefuse.get();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean mayAdopt(final BlockHeader header, final BlockHeader parent) {
|
|
+ final long h = header.getNumber();
|
|
+ // Below H_hdr the header still carries a quorum of ECDSA committed seals, whose upstream rule
|
|
+ // already refuses a single-key block; nothing to add here.
|
|
+ if (!stage5Active.test(h)) {
|
|
+ return true;
|
|
+ }
|
|
+ final Collection<Address> validators = validatorProvider.getValidatorsForBlock(parent);
|
|
+ if (validators == null || validators.isEmpty()) {
|
|
+ return true;
|
|
+ }
|
|
+ // Only a validator hears commit seals; a reader would never clear the gate, so it is not gated
|
|
+ // (its canonicity is Rule B). isLocal matches this node as an ECDSA address OR its v3 id, so it is
|
|
+ // correct below H_id (addresses) and from stage 5 (ids), where the set carries ids.
|
|
+ boolean localIsValidator = false;
|
|
+ for (final Address v : validators) {
|
|
+ if (AerePqIdentity.isLocal(v, localEcdsaAddress)) {
|
|
+ localIsValidator = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!localIsValidator) {
|
|
+ return true;
|
|
+ }
|
|
+ final int quorum = BftHelpers.calculateRequiredValidatorQuorum(validators.size());
|
|
+ if (quorum <= 0) {
|
|
+ return true;
|
|
+ }
|
|
+ final Bytes32 message = PqAnchor.commitMessage(chainId, h, header.getHash().getBytes());
|
|
+ final List<FalconSeal> heard = cache.sealsFor(h, header.getHash());
|
|
+ final Set<Integer> verified = new HashSet<>();
|
|
+ for (final FalconSeal seal : heard) {
|
|
+ if (seal == null || seal.getValidatorIndex() < 0 || seal.getSignature() == null) {
|
|
+ continue;
|
|
+ }
|
|
+ try {
|
|
+ if (verifier.verify(h, seal.getValidatorIndex(), message, seal.getSignature())) {
|
|
+ verified.add(seal.getValidatorIndex());
|
|
+ }
|
|
+ } catch (final RuntimeException e) {
|
|
+ // a seal this node cannot judge is not counted; never a pass
|
|
+ LOG.debug("AERE D-412: seal of index {} for block {} could not be verified ({})", seal.getValidatorIndex(), h, e.toString());
|
|
+ }
|
|
+ }
|
|
+ final boolean ok = verified.size() >= quorum;
|
|
+ if (ok) {
|
|
+ return true;
|
|
+ }
|
|
+ wouldRefuse.incrementAndGet();
|
|
+ if (!enforce) {
|
|
+ // D-419: OBSERVE. Same verdict, recorded, and the block is adopted as before the gate existed.
|
|
+ LOG.info(
|
|
+ "{} propagated block {} at tip height {}: it holds {} verified post-quantum commit seal(s), "
|
|
+ + "quorum is {}; adopting it (observe mode, D-419).",
|
|
+ OBSERVE_MARKER,
|
|
+ header.getHash(),
|
|
+ h,
|
|
+ verified.size(),
|
|
+ quorum);
|
|
+ return true;
|
|
+ }
|
|
+ LOG.info(
|
|
+ "AERE D-412: propagated block {} at tip height {} holds {} verified post-quantum commit "
|
|
+ + "seal(s), quorum is {}; NOT adopting it via propagation - this node's own consensus "
|
|
+ + "decides this height.",
|
|
+ header.getHash(),
|
|
+ h,
|
|
+ verified.size(),
|
|
+ quorum);
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
diff --git a/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
|
|
index 252f655834..afca7aca58 100644
|
|
--- a/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
|
|
+++ b/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
|
|
@@ -13,40 +13,44 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.controller;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
import org.hyperledger.besu.config.BftConfigOptions;
|
|
import org.hyperledger.besu.config.BftFork;
|
|
import org.hyperledger.besu.config.JsonGenesisConfigOptions;
|
|
import org.hyperledger.besu.config.QbftConfigOptions;
|
|
import org.hyperledger.besu.config.QbftFork;
|
|
import org.hyperledger.besu.consensus.common.BftValidatorOverrides;
|
|
import org.hyperledger.besu.consensus.common.EpochManager;
|
|
import org.hyperledger.besu.consensus.common.ForksSchedule;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinalityTags;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqHeaderSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
|
|
import org.hyperledger.besu.consensus.common.bft.BftContext;
|
|
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExecutors;
|
|
import org.hyperledger.besu.consensus.common.bft.BftProcessor;
|
|
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
|
|
import org.hyperledger.besu.consensus.common.bft.BftRoundExpiryTimeCalculator;
|
|
import org.hyperledger.besu.consensus.common.bft.BlockTimer;
|
|
import org.hyperledger.besu.consensus.common.bft.EthSynchronizerUpdater;
|
|
import org.hyperledger.besu.consensus.common.bft.EventMultiplexer;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.MessageTracker;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorConfig;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorSyncModeGuard;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorThresholdGuard;
|
|
import org.hyperledger.besu.consensus.common.bft.PqRegistryHash;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
|
|
@@ -71,61 +75,63 @@ import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCreatorFactoryAdapto
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor;
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockchainAdaptor;
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftFinalStateImpl;
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftProtocolScheduleAdaptor;
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorModeTransitionLoggerAdaptor;
|
|
import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorProviderAdaptor;
|
|
import org.hyperledger.besu.consensus.qbft.blockcreation.QbftBlockCreatorFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftBlockHeightManagerFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftController;
|
|
import org.hyperledger.besu.consensus.qbft.core.statemachine.QbftRoundFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftMessage;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider;
|
|
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory;
|
|
+import org.hyperledger.besu.consensus.qbft.core.validation.PqFinalityLayersGuard;
|
|
import org.hyperledger.besu.consensus.qbft.jsonrpc.QbftJsonRpcMethods;
|
|
import org.hyperledger.besu.consensus.qbft.network.QbftGossiperImpl;
|
|
import org.hyperledger.besu.consensus.qbft.protocol.Istanbul100SubProtocol;
|
|
import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider;
|
|
import org.hyperledger.besu.consensus.qbft.validator.TransactionValidatorProvider;
|
|
import org.hyperledger.besu.consensus.qbft.validator.ValidatorContractController;
|
|
import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
|
|
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.chain.MinedBlockObserver;
|
|
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
|
import org.hyperledger.besu.ethereum.core.Util;
|
|
import org.hyperledger.besu.ethereum.eth.EthProtocol;
|
|
import org.hyperledger.besu.ethereum.eth.SnapProtocol;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
|
|
import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager;
|
|
+import org.hyperledger.besu.ethereum.eth.sync.PropagatedBlockAdoptionGate;
|
|
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
|
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
|
import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
|
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
|
|
import org.hyperledger.besu.util.Subscribers;
|
|
|
|
import java.time.Duration;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/** The Qbft Besu controller builder. */
|
|
public class QbftBesuControllerBuilder extends BesuControllerBuilder {
|
|
|
|
@@ -416,40 +422,101 @@ public class QbftBesuControllerBuilder extends BesuControllerBuilder {
|
|
.getChainId()
|
|
.map(java.math.BigInteger::longValue)
|
|
.orElse(0L),
|
|
pqRegistrySchedule);
|
|
|
|
// AERE SINCRONIZARE (2026-08-02): the anchor is only a defence if it applies to the history this
|
|
// node ACCEPTS, and not only to the blocks it is offered as proposals. Outside FULL sync the
|
|
// header import path never instantiates a header validator at all, so both anchor rules would be
|
|
// skipped for the entire span between checkpoint and pivot. Refuse to start rather than run a
|
|
// node that believes it is protected and is not.
|
|
//
|
|
// Placed with the other two startup guards and for the same reason: a chain head exists here, the
|
|
// network is not up and the QBFT state machine has not been created, so this is a clean refusal
|
|
// to start. Inert when aere.pq.anchorBlock is unset, which is chain 2800 as it stands today.
|
|
// AERE GARDA-PRAG (2026-08-02): read the anchor configuration ONCE, here, and hand the SAME
|
|
// object to every guard that needs it. Two calls to fromSystemConfiguration would print the
|
|
// ARMED banner twice and, worse, would give two guards two independent chances to disagree
|
|
// about what is actually configured on this node.
|
|
final PqAnchorConfig aereAnchorConfig = PqAnchorConfig.fromSystemConfiguration();
|
|
|
|
+ // AERE AIP-22 stage 3: the post-quantum identity switch, read ONCE here beside the anchor
|
|
+ // configuration; the schemes every v3 row must carry are the ones the scheme schedule names at
|
|
+ // H_id. Inert when aere.pq.identityBlock is unset.
|
|
+ AerePqIdentity.installFromSystemProperties(
|
|
+ aereAnchorConfig.chainId(),
|
|
+ hId ->
|
|
+ HybridSealSupport.instance()
|
|
+ .schedule()
|
|
+ .map(s -> (java.util.List<String>) new java.util.ArrayList<>(s.schemesAt(hId)))
|
|
+ .orElse(java.util.List.of("falcon-512")));
|
|
+ // AERE AIP-22 stage 3b: at H_k the SOURCE of the keys that seal moves to the v3 epochs; the continuity
|
|
+ // guard proves, before the node joins anything, that no key moves with it (every key of the epoch at
|
|
+ // H_k equals the key the existing registries give at H_k - 1). Inert when H_k is not configured.
|
|
+ AerePqIdentity.verifyKeyContinuity(
|
|
+ (index, scheme) -> {
|
|
+ final long before =
|
|
+ AerePqIdentity.installed()
|
|
+ .map(c -> c.keysFrom() - 1L)
|
|
+ .orElseThrow(() -> new IllegalStateException("identity not installed"));
|
|
+ return "falcon-512".equals(scheme)
|
|
+ ? FalconSealSupport.instance().publicKeyBytesAtHistoric(before, index)
|
|
+ : HybridSealSupport.instance().registry().flatMap(r -> r.publicKey(index, scheme));
|
|
+ });
|
|
+ // AERE AIP-22 stage 3b-ii: in every v3 epoch from H_k where this node is a registered validator it must
|
|
+ // hold its row's keys, or it would go mute at that epoch; refuse to start instead. Inert without H_k.
|
|
+ FalconSealSupport.instance()
|
|
+ .verifyLocalKeysCoverV3EpochsOrAbort(Util.publicKeyToAddress(nodeKey.getPublicKey()));
|
|
+ HybridSealSupport.instance()
|
|
+ .verifyLocalKeysCoverV3EpochsOrAbort(Util.publicKeyToAddress(nodeKey.getPublicKey()));
|
|
+ // AERE AIP-22 stage 4: H_fin (aere.pq.finalityBlock), from which a message's author is the id of its post-quantum seal's
|
|
+ // index once that seal verifies, and the envelope's ECDSA is not read; refuses unless the keys are read from the v3 epochs
|
|
+ // at or below it (AERE-PQC-FIN-01). Inert when unset, which is every chain today.
|
|
+ AerePqFinality.installFromSystemProperties(aereAnchorConfig.chainId());
|
|
+ // ...and the four seal layers must be armed at or below it (AERE-PQC-FIN-02): the commit layer is the one that judges a
|
|
+ // COMMIT's seal (its author is bound to the commit seal's signer), and the layers stay the second judge of the rest.
|
|
+ PqFinalityLayersGuard.verifyOrAbort(AerePqFinality.finalityBlock());
|
|
+ // ...and a node that seals must seal all four messages from H_fin, or it would be mute there (AERE-PQC-FIN-03)
|
|
+ PqFinalityLayersGuard.verifyEmissionOrAbort(
|
|
+ AerePqFinality.finalityBlock(),
|
|
+ FalconSealSupport.instance().signingEnabled(),
|
|
+ FalconSealSupport.instance().attachBlock(),
|
|
+ FalconSealSupport.proposalAttachBlock(),
|
|
+ FalconSealSupport.prepareAttachBlock(),
|
|
+ FalconSealSupport.roundChangeAttachBlock());
|
|
+ // AERE AIP-22 stage 5: H_hdr (aere.pq.headerBlock), from which a header carries the proposer's post-quantum seal
|
|
+ // and no ECDSA committed seal; refuses unless H_fin is at or below it (AERE-PQC-HDR-01). Inert when unset.
|
|
+ AerePqHeaderSeal.installFromSystemProperties();
|
|
+ if (AerePqHeaderSeal.headerBlock() != AerePqIdentity.NEVER) {
|
|
+ LOG.info(
|
|
+ "AERE PQ HEADER: H_hdr armed at {}; from it a header carries the proposer's post-quantum seal and NO ECDSA"
|
|
+ + " committed seal",
|
|
+ AerePqHeaderSeal.headerBlock());
|
|
+ }
|
|
+ if (AerePqFinality.finalityBlock() != AerePqIdentity.NEVER) {
|
|
+ LOG.info(
|
|
+ "AERE PQ FINALITY: H_fin armed at {}; from it a message's author is the id of its VERIFIED post-quantum seal and the"
|
|
+ + " envelope's ECDSA is not read (four seal layers armed at or below it, this node seals: {})",
|
|
+ AerePqFinality.finalityBlock(),
|
|
+ FalconSealSupport.instance().signingEnabled());
|
|
+ }
|
|
+
|
|
PqAnchorSyncModeGuard.verifySyncModeOrAbort(
|
|
syncConfig == null || syncConfig.getSyncMode() == null
|
|
? null
|
|
: syncConfig.getSyncMode().name(),
|
|
aereAnchorConfig);
|
|
|
|
// AERE PERSISTENTA-SIGILII (2026-08-05): THE SECOND HALF of the chain death on a whole-fleet
|
|
// restart. The first half is repaired above (BLOCAJ-REPORNIRE): the registry now arms at startup
|
|
// from the chain head state, and all seven nodes reported SUCCEEDED. The chain died anyway, the
|
|
// refusal only changing shape: "registry address-bound=TRUE ... Heard 0 seal(s)", frozen 150 s
|
|
// on the first restart and 298 s on the second.
|
|
//
|
|
// WHY. Falcon seals over M(head) travel ONLY on the Commit messages of the head block. Those
|
|
// messages are never repeated after a restart, and they exist nowhere else: the head block
|
|
// carries in element 6 the certificate over its PARENT, not over itself. So every node started
|
|
// with zero seals, nobody reached K, nobody could propose, and so nobody sent another Commit.
|
|
// The same circular deadlock, one level down.
|
|
//
|
|
// WHY THIS IS NOT A8 IN NEW CLOTHES, and this is the whole security argument: the seal is
|
|
// SELF-VERIFYING. Every seal read from the file is cryptographically verified again against the
|
|
@@ -526,40 +593,83 @@ public class QbftBesuControllerBuilder extends BesuControllerBuilder {
|
|
transactionPool,
|
|
protocolContext,
|
|
bftProtocolSchedule,
|
|
qbftForksSchedule,
|
|
miningConfiguration,
|
|
localAddress,
|
|
qbftExtraDataCodec,
|
|
ethProtocolManager.ethContext().getScheduler());
|
|
|
|
final ValidatorProvider validatorProvider;
|
|
if (qbftConfig.getStartBlock().isPresent()) {
|
|
validatorProvider =
|
|
protocolContext
|
|
.getConsensusContext(BftContext.class, qbftConfig.getStartBlock().getAsLong())
|
|
.getValidatorProvider();
|
|
} else {
|
|
validatorProvider =
|
|
protocolContext.getConsensusContext(BftContext.class).getValidatorProvider();
|
|
}
|
|
|
|
+ // AERE D-412 (2026-09-26), Rule C: arm the propagation adoption gate. From AIP-22 stage 5 a valid
|
|
+ // header carries only the proposer's single Falcon seal, so it no longer proves a quorum agreed the
|
|
+ // block; a single key could forge one and, until this gate, honest validators adopted it via NewBlock
|
|
+ // and built on top (measured on rep28098). The gate lets this node refuse to ADOPT such a propagated
|
|
+ // block at the tip of its own consensus height unless it holds a post-quantum commit quorum for it
|
|
+ // (heard on AIP-21 Commit seals). Block VALIDITY is unchanged (sync still imports it); only
|
|
+ // ADOPTION-at-the-tip is gated, only for a validator, only from H_hdr. Inert here on any chain whose
|
|
+ // H_hdr is unset, which is chain 2800 today. Placed after the validator set is resolved (localAddress
|
|
+ // and validatorProvider both exist) and before the network and the QBFT machine start.
|
|
+ // D-419 (2026-09-27): the gate defaults to OBSERVE (logs every block it would refuse, adopts it); ENFORCE
|
|
+ // wedged a validator that missed one height's commits on testnet 28001 and must be asked for explicitly.
|
|
+ if (aereAnchorConfig.everActive()) {
|
|
+ final PqTipAdoptionGate tipGate =
|
|
+ new PqTipAdoptionGate(validatorProvider, localAddress, aereAnchorConfig.chainId());
|
|
+ PropagatedBlockAdoptionGate.install(tipGate);
|
|
+ LOG.info(
|
|
+ "AERE D-412: propagation adoption gate armed in {} mode; a propagated block at the tip {} "
|
|
+ + "without a post-quantum commit quorum from H_hdr={} (unset means never on this node).",
|
|
+ tipGate.isEnforcing() ? "ENFORCE" : "OBSERVE",
|
|
+ tipGate.isEnforcing() ? "is NOT adopted" : "is adopted and logged",
|
|
+ AerePqHeaderSeal.headerBlock());
|
|
+ }
|
|
+
|
|
+ // AERE D-412 (2026-09-26), Rule B1: post-quantum FINALITY TAGS (see AerePqFinalityTags). finalized/safe = the parent of the
|
|
+ // last canonical anchor that carries a certificate (v1 Falcon list OR v2 scheme-tagged certificate); monotonic; never moved
|
|
+ // back by a reorg (AERE-PQC-FIN-01). No validity, fork-choice or import is touched. Proven live on rep28098 2026-09-26.
|
|
+ if (aereAnchorConfig.everActive()) {
|
|
+ final QbftExtraDataCodec codecForTags = qbftExtraDataCodec;
|
|
+ AerePqFinalityTags.install(
|
|
+ aereAnchorConfig,
|
|
+ blockchain,
|
|
+ h -> {
|
|
+ try {
|
|
+ return AerePqFinalityTags.carriesCertificate(codecForTags.decodeRaw(h.getExtraData()));
|
|
+ } catch (final RuntimeException e) {
|
|
+ return false; // an undecodable header carries nothing this rule can rely on
|
|
+ }
|
|
+ });
|
|
+ LOG.info(
|
|
+ "AERE D-412 B1: finalized/safe tags follow the last certified anchor's parent (interval {} at the head).",
|
|
+ aereAnchorConfig.intervalAt(blockchain.getChainHeadBlockNumber()));
|
|
+ }
|
|
+
|
|
// AERE GARDA-PRAG (2026-08-02): refuse to start on a seal threshold that STOPS the chain.
|
|
//
|
|
// Measured before this line was written: nothing anywhere refused a threshold value. Searched
|
|
// the whole fork tree for any occurrence of minSeals near quorum, throw, refuse, abort or
|
|
// Illegal, and there were ZERO. PqAnchorConfig rejects a negative K and a step scheduled below
|
|
// the activation height, and nothing else; the only other check, PqAnchorProducer's
|
|
// warnIfActivationHeightCanRefuse, writes one LOG.error and returns. So a value at or above the
|
|
// QBFT quorum was a configuration a node accepted in silence and then halted on.
|
|
//
|
|
// Placed here rather than beside the other three startup guards because this is the FIRST point
|
|
// at which the validator set is resolved, and the bound is a function of its size. It is still
|
|
// before the network exists (ValidatorPeers is built below) and before the QBFT state machine is
|
|
// created, so a refusal here is a clean refusal to start rather than a mid-flight halt.
|
|
PqAnchorThresholdGuard.verifyThresholdAgainstQuorumOrAbort(
|
|
aereAnchorConfig, validatorProvider.getValidatorsAtHead().size());
|
|
final QbftValidatorProvider qbftValidatorProvider =
|
|
new QbftValidatorProviderAdaptor(validatorProvider);
|
|
|
|
final QbftBlockInterface qbftBlockInterface = new QbftBlockInterfaceAdaptor(bftBlockInterface);
|
|
|
|
diff --git a/app/src/test/java/org/hyperledger/besu/controller/PqTipAdoptionGateModeTest.java b/app/src/test/java/org/hyperledger/besu/controller/PqTipAdoptionGateModeTest.java
|
|
new file mode 100644
|
|
index 0000000000..1e87f3b984
|
|
--- /dev/null
|
|
+++ b/app/src/test/java/org/hyperledger/besu/controller/PqTipAdoptionGateModeTest.java
|
|
@@ -0,0 +1,180 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.controller;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.Mockito.mock;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
+import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * D-419 (2026-09-27): the Rule C tip adoption gate in its two modes. OBSERVE (the default) computes the same
|
|
+ * verdict as ENFORCE, counts the blocks it would refuse, and adopts them; ENFORCE refuses. Every case has its
|
|
+ * opposite: the same block without a quorum is refused under ENFORCE and adopted under OBSERVE, and a quorum of
|
|
+ * seals that do NOT verify is refused under ENFORCE, so the gate verifies seals and does not merely count them.
|
|
+ */
|
|
+class PqTipAdoptionGateModeTest {
|
|
+
|
|
+ private static final long H_HDR = 100L;
|
|
+ private static final long CHAIN_ID = 28098L;
|
|
+ private static final Address LOCAL = Address.fromHexString("0x00000000000000000000000000000000000000a1");
|
|
+ private static final List<Address> SET =
|
|
+ List.of(
|
|
+ LOCAL,
|
|
+ Address.fromHexString("0x00000000000000000000000000000000000000a2"),
|
|
+ Address.fromHexString("0x00000000000000000000000000000000000000a3"),
|
|
+ Address.fromHexString("0x00000000000000000000000000000000000000a4"));
|
|
+ // a distinct timestamp per header, so every test reads its own seal-cache entry from the shared singleton
|
|
+ private static final AtomicLong TS = new AtomicLong(1_900_000_000L);
|
|
+
|
|
+ private ValidatorProvider provider;
|
|
+
|
|
+ @BeforeEach
|
|
+ void setUp() {
|
|
+ // no v3 identity installed: isLocal falls back to address equality, which is what this set uses
|
|
+ AerePqIdentity.uninstall();
|
|
+ provider = mock(ValidatorProvider.class);
|
|
+ when(provider.getValidatorsForBlock(any())).thenReturn(SET);
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ void tearDown() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private static BlockHeader header(final long number) {
|
|
+ return new BlockHeaderTestFixture().number(number).timestamp(TS.incrementAndGet()).buildHeader();
|
|
+ }
|
|
+
|
|
+ private PqTipAdoptionGate gate(final boolean enforce, final boolean sealsVerify) {
|
|
+ return new PqTipAdoptionGate(
|
|
+ provider,
|
|
+ LOCAL,
|
|
+ CHAIN_ID,
|
|
+ PqSealCache.instance(),
|
|
+ (n, i, m, s) -> sealsVerify,
|
|
+ enforce,
|
|
+ h -> h >= H_HDR);
|
|
+ }
|
|
+
|
|
+ private static void recordSeals(final BlockHeader h, final int count) {
|
|
+ final List<FalconSeal> seals =
|
|
+ java.util.stream.IntStream.range(0, count)
|
|
+ .mapToObj(i -> new FalconSeal(i, Bytes.of(i + 1)))
|
|
+ .toList();
|
|
+ PqSealCache.instance().record(h.getNumber(), h.getHash(), seals);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void enforceRefusesATipBlockWithoutAQuorum() {
|
|
+ final BlockHeader h = header(150);
|
|
+ final PqTipAdoptionGate g = gate(true, true);
|
|
+ assertThat(g.mayAdopt(h, header(149))).isFalse();
|
|
+ assertThat(g.wouldRefuseCount()).isEqualTo(1);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void observeAdoptsTheSameBlockAndCountsIt() {
|
|
+ final BlockHeader h = header(150);
|
|
+ final PqTipAdoptionGate g = gate(false, true);
|
|
+ assertThat(g.mayAdopt(h, header(149))).isTrue();
|
|
+ assertThat(g.wouldRefuseCount()).isEqualTo(1);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void enforceAdoptsWithAVerifiedQuorum() {
|
|
+ final BlockHeader h = header(151);
|
|
+ recordSeals(h, 3); // quorum of 4 validators is 3
|
|
+ final PqTipAdoptionGate g = gate(true, true);
|
|
+ assertThat(g.mayAdopt(h, header(150))).isTrue();
|
|
+ assertThat(g.wouldRefuseCount()).isZero();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void enforceRefusesAQuorumOfSealsThatDoNotVerify() {
|
|
+ final BlockHeader h = header(152);
|
|
+ recordSeals(h, 4);
|
|
+ final PqTipAdoptionGate g = gate(true, false);
|
|
+ assertThat(g.mayAdopt(h, header(151))).isFalse();
|
|
+ assertThat(g.wouldRefuseCount()).isEqualTo(1);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void belowHdrNeitherModeGatesOrCounts() {
|
|
+ final BlockHeader h = header(H_HDR - 1);
|
|
+ final PqTipAdoptionGate e = gate(true, true);
|
|
+ final PqTipAdoptionGate o = gate(false, true);
|
|
+ assertThat(e.mayAdopt(h, header(H_HDR - 2))).isTrue();
|
|
+ assertThat(o.mayAdopt(h, header(H_HDR - 2))).isTrue();
|
|
+ assertThat(e.wouldRefuseCount()).isZero();
|
|
+ assertThat(o.wouldRefuseCount()).isZero();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aNodeOutsideTheSetIsNotGatedEvenInEnforce() {
|
|
+ when(provider.getValidatorsForBlock(any())).thenReturn(SET.subList(1, 4));
|
|
+ final PqTipAdoptionGate g = gate(true, true);
|
|
+ assertThat(g.mayAdopt(header(153), header(152))).isTrue();
|
|
+ assertThat(g.wouldRefuseCount()).isZero();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void enforceMustBeAskedForExplicitly() {
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested(null, null)).isFalse();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested("", " ")).isFalse();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested("observe", null)).isFalse();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested("bogus", null)).isFalse();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested("enforce", null)).isTrue();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested(" ENFORCE ", null)).isTrue();
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested(null, "enforce")).isTrue();
|
|
+ // the system property wins over the environment when both are set
|
|
+ assertThat(PqTipAdoptionGate.enforceRequested("observe", "enforce")).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theProductionConstructorDefaultsToObserve() {
|
|
+ final String before = System.getProperty(PqTipAdoptionGate.PROPERTY_MODE);
|
|
+ try {
|
|
+ System.clearProperty(PqTipAdoptionGate.PROPERTY_MODE);
|
|
+ if (System.getenv(PqTipAdoptionGate.ENV_MODE) == null) {
|
|
+ assertThat(new PqTipAdoptionGate(provider, LOCAL, CHAIN_ID).isEnforcing()).isFalse();
|
|
+ }
|
|
+ System.setProperty(PqTipAdoptionGate.PROPERTY_MODE, "enforce");
|
|
+ assertThat(new PqTipAdoptionGate(provider, LOCAL, CHAIN_ID).isEnforcing()).isTrue();
|
|
+ } finally {
|
|
+ if (before == null) {
|
|
+ System.clearProperty(PqTipAdoptionGate.PROPERTY_MODE);
|
|
+ } else {
|
|
+ System.setProperty(PqTipAdoptionGate.PROPERTY_MODE, before);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinality.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinality.java
|
|
new file mode 100644
|
|
index 0000000000..64dec0d1e1
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinality.java
|
|
@@ -0,0 +1,194 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+
|
|
+/**
|
|
+ * AERE AIP-22 stage 4 (plan 9.6.8): from H_fin ({@code aere.pq.finalityBlock}) the ECDSA signature of a
|
|
+ * consensus message's envelope is no longer a criterion. The author of a message is the post-quantum id
|
|
+ * of the row its seal's index names in the v3 epoch in force at the message's height, and ONLY once that
|
|
+ * seal VERIFIES: a PROPOSAL, PREPARE or ROUND-CHANGE seal over its own domain, through the same verifier
|
|
+ * the seal layers use; a COMMIT's index only when it names the id of the commit seal's signer (the commit
|
|
+ * layer, armed at or below H_fin by AERE-PQC-FIN-02, judges the seal itself). The envelope's recovered
|
|
+ * ECDSA address is not read for authorship, so a validator may sign the envelope with any secp256k1 key.
|
|
+ * Anything else at or above H_fin has no author ({@link #NO_AUTHOR}, never in a set).
|
|
+ *
|
|
+ * <p>WHY HERE AND NOT ONLY IN THE LAYERS (read in the code 2026-09-23 ~18:02Z): QbftController relays a message
|
|
+ * as soon as its author is in the set, BEFORE the layers judge it. An author read from an unverified
|
|
+ * index would let anyone make every validator relay garbage in any validator's name; before H_fin that
|
|
+ * needed a validator's ECDSA key. The layers keep judging exactly as before.
|
|
+ *
|
|
+ * <p>Requires the post-quantum identity (stage 3) and the keys read from the v3 epochs (stage 3b):
|
|
+ * H_fin must be at or above H_k, else startup is refused (AERE-PQC-FIN-01). Unset: never, which is
|
|
+ * every chain today.
|
|
+ */
|
|
+public final class AerePqFinality {
|
|
+
|
|
+ /** The system property naming H_fin. */
|
|
+ public static final String PROPERTY = "aere.pq.finalityBlock";
|
|
+
|
|
+ /** The author of a message that cannot have one from H_fin (no seal, or an index with no row). */
|
|
+ public static final Address NO_AUTHOR = Address.ZERO;
|
|
+
|
|
+ /** Verifies a Falcon seal of a registry index at a height (the seal layers' verifier in production). */
|
|
+ @FunctionalInterface
|
|
+ public interface SealVerifier {
|
|
+ /**
|
|
+ * Whether the seal verifies.
|
|
+ *
|
|
+ * @param height the message's height
|
|
+ * @param index the seal's registry index
|
|
+ * @param message the message the seal signs
|
|
+ * @param signature the seal's signature
|
|
+ * @return true when it verifies under that index's key
|
|
+ */
|
|
+ boolean verify(long height, int index, Bytes message, Bytes signature);
|
|
+ }
|
|
+
|
|
+ private static volatile long finalityBlock = AerePqIdentity.NEVER;
|
|
+ private static volatile long chainId;
|
|
+ private static volatile SealVerifier verifier = (h, i, m, s) -> false;
|
|
+
|
|
+ private AerePqFinality() {}
|
|
+
|
|
+ /**
|
|
+ * Arms H_fin (tests and the startup path).
|
|
+ *
|
|
+ * @param hFin H_fin, or {@link AerePqIdentity#NEVER}
|
|
+ * @param chain the chain id every seal message carries
|
|
+ * @param sealVerifier the verifier of the seal layers
|
|
+ */
|
|
+ public static void install(final long hFin, final long chain, final SealVerifier sealVerifier) {
|
|
+ if (hFin != AerePqIdentity.NEVER) {
|
|
+ final long keysFrom =
|
|
+ AerePqIdentity.installed().map(AerePqIdentity.Config::keysFrom).orElse(AerePqIdentity.NEVER);
|
|
+ if (keysFrom == AerePqIdentity.NEVER || hFin < keysFrom) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-FIN-01: "
|
|
+ + PROPERTY
|
|
+ + "="
|
|
+ + hFin
|
|
+ + " needs the post-quantum identity and the keys read from the v3 epochs (aere.pq.registryV3.keysFrom)"
|
|
+ + " at or below it (keysFrom "
|
|
+ + (keysFrom == AerePqIdentity.NEVER ? "unset" : Long.toString(keysFrom))
|
|
+ + ")");
|
|
+ }
|
|
+ if (chain <= 0 || sealVerifier == null) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-FIN-01: "
|
|
+ + PROPERTY
|
|
+ + "="
|
|
+ + hFin
|
|
+ + " needs the chain id (aere.pq.chainId) and a seal verifier: every author it gives is a verified seal");
|
|
+ }
|
|
+ }
|
|
+ finalityBlock = hFin;
|
|
+ chainId = chain;
|
|
+ verifier = sealVerifier == null ? (h, i, m, s) -> false : sealVerifier;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * H_fin as armed on this node.
|
|
+ *
|
|
+ * @return H_fin, or {@link AerePqIdentity#NEVER} when unset
|
|
+ */
|
|
+ public static long finalityBlock() {
|
|
+ return finalityBlock;
|
|
+ }
|
|
+
|
|
+ /** Disarms (tests). */
|
|
+ public static void uninstall() {
|
|
+ finalityBlock = AerePqIdentity.NEVER;
|
|
+ chainId = 0;
|
|
+ verifier = (h, i, m, s) -> false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Arms from {@link #PROPERTY}; unset means never. Call after the identity is installed.
|
|
+ *
|
|
+ * @param chain the chain id of the anchor configuration (aere.pq.chainId)
|
|
+ */
|
|
+ public static void installFromSystemProperties(final long chain) {
|
|
+ final String v = System.getProperty(PROPERTY);
|
|
+ if (v == null || v.isBlank()) {
|
|
+ uninstall();
|
|
+ return;
|
|
+ }
|
|
+ final long h;
|
|
+ try {
|
|
+ h = Long.parseLong(v.trim());
|
|
+ } catch (final NumberFormatException e) {
|
|
+ throw new IllegalStateException("AERE-PQC-FIN-01: " + PROPERTY + "='" + v + "' is not a height", e);
|
|
+ }
|
|
+ final PqSignerRegistry layers = PqSignerRegistry.falconSealSupport();
|
|
+ install(h, chain, layers::verifyAtOwnHead);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether the post-quantum seal is the author of messages at this height.
|
|
+ *
|
|
+ * @param height the message's height
|
|
+ * @return true from H_fin when armed
|
|
+ */
|
|
+ public static boolean active(final long height) {
|
|
+ return height >= finalityBlock;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The author of a message from H_fin: the id of its seal's index at the message's height, once the
|
|
+ * seal verifies (a COMMIT: once the index names the commit seal signer's id).
|
|
+ *
|
|
+ * @param payload the message payload
|
|
+ * @param height the message's height
|
|
+ * @return the id, or {@link #NO_AUTHOR}
|
|
+ */
|
|
+ public static Address authorFromSeal(final Payload payload, final long height) {
|
|
+ if (!(payload instanceof PqSealed sealed)) {
|
|
+ return NO_AUTHOR;
|
|
+ }
|
|
+ final Optional<FalconSeal> seal = sealed.getFalconSeal();
|
|
+ if (seal.isEmpty()) {
|
|
+ return NO_AUTHOR;
|
|
+ }
|
|
+ final int index = seal.get().getValidatorIndex();
|
|
+ final Optional<Address> id = AerePqIdentity.v3IdAt(height, index);
|
|
+ if (id.isEmpty()) {
|
|
+ return NO_AUTHOR;
|
|
+ }
|
|
+ try {
|
|
+ final Optional<Address> commitSigner = sealed.commitSealSigner();
|
|
+ if (commitSigner.isPresent()) {
|
|
+ return id.get().equals(AerePqIdentity.author(commitSigner.get(), height)) ? id.get() : NO_AUTHOR;
|
|
+ }
|
|
+ final Optional<Bytes32> message = sealed.pqSealMessage(chainId);
|
|
+ if (message.isEmpty()) {
|
|
+ return NO_AUTHOR;
|
|
+ }
|
|
+ return verifier.verify(height, index, message.get(), seal.get().getSignature())
|
|
+ ? id.get()
|
|
+ : NO_AUTHOR;
|
|
+ } catch (final RuntimeException e) {
|
|
+ // a seal we cannot judge authors nothing: "cannot judge" is never a pass
|
|
+ return NO_AUTHOR;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTags.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTags.java
|
|
new file mode 100755
|
|
index 0000000000..e5e11c939f
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTags.java
|
|
@@ -0,0 +1,202 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
|
|
+import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+// in this Besu base (26.4.0-dev, d2032017b) the event type enum lives in the plugin API, not nested in BlockAddedEvent
|
|
+// (measured 2026-09-26: "cannot find symbol EventType in class BlockAddedEvent" on the first harness run)
|
|
+import org.hyperledger.besu.plugin.data.AddedBlockContext.EventType;
|
|
+
|
|
+import java.util.Optional;
|
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AERE D-412 Rule B1 (2026-09-26): the post-quantum FINALITY TAGS.
|
|
+ *
|
|
+ * <p><b>What this closes, read in the code and measured on the chain.</b> From AIP-22 stage 5 a valid
|
|
+ * between-anchor header carries only the proposer's Falcon-512 seal, so a single validator key can
|
|
+ * forge a header a reader imports as valid and, if that reader is syncing or eclipsed, adopts as its
|
|
+ * canonical tip (D-412, corrected severity). Such a forged tail is bounded: at the next anchor height
|
|
+ * {@code PqAnchorSealsRule} (R2, FULL validation, which {@code PqAnchorSyncModeGuard} makes the only
|
|
+ * sync mode) requires K distinct valid Falcon-512 seals over the parent's commit message, which one key
|
|
+ * cannot produce, so the tail dies within one anchor interval. What remains is that the reader's
|
|
+ * {@code latest} can transiently name a forged block, and a consumer who asks for {@code finalized} or
|
|
+ * {@code safe} - the tags bridges, exchanges and rollups use - received, on every node of chain 2800 and
|
|
+ * 28001 measured 2026-09-26, the error {@code Unknown block}: QBFT never sets them.
|
|
+ *
|
|
+ * <p><b>The rule.</b> {@code finalized} and {@code safe} name the last block COVERED BY A VALID ANCHOR
|
|
+ * CERTIFICATE: when a canonical head at an anchor height carries a certificate, the anchor's PARENT
|
|
+ * becomes finalized (the certificate's K seals sign the parent's commit message, AIP-15, and R1/R2 have
|
|
+ * already refused the header if that certificate does not bind or does not verify). Between anchors
|
|
+ * the tags do not move. A forged between-anchor block can therefore never be reported final: it is
|
|
+ * never an anchor's certified parent. This is exactly the finality AIP-22 section 1 defines ("the
|
|
+ * finality of the block is established only by the covering anchor"), exposed on the API the world
|
|
+ * already reads.
|
|
+ *
|
|
+ * <p><b>What it deliberately does NOT do.</b> It does not touch fork-choice, block validity or import:
|
|
+ * nothing here can stop the chain or refuse a block, and a node that lags still catches up exactly as
|
|
+ * before. It only writes the two tags, monotonically: a later event can only move them forward. If a
|
|
+ * canonical reorg ever drops below the finalized block (which would mean K validators signed two
|
|
+ * conflicting anchors, outside this rule's adversary), it is logged as {@code AERE-PQC-FIN-01} at
|
|
+ * ERROR and the tags are left where they were, never moved back in silence.
|
|
+ *
|
|
+ * <p><b>At startup</b> the tags are initialised by scanning back from the head to the most recent
|
|
+ * anchor height that carries a certificate (at most two intervals), so a freshly started node answers
|
|
+ * {@code finalized} before it imports its next anchor.
|
|
+ *
|
|
+ * <p>Inert on a chain where the anchor was never active (the node never installs it); inert below
|
|
+ * the activation height (no anchor height applies there). Stated, not measured here: the behaviour on
|
|
+ * the live fleet, which is the rehearsal's job.
|
|
+ */
|
|
+public final class AerePqFinalityTags {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(AerePqFinalityTags.class);
|
|
+
|
|
+ /** Logged when a canonical reorg would move finality backwards; the tags are not moved. */
|
|
+ public static final String CODE_REORG_BELOW_FINALIZED = "AERE-PQC-FIN-01";
|
|
+
|
|
+ private final PqAnchorConfig config;
|
|
+ private final MutableBlockchain blockchain;
|
|
+ private final Predicate<BlockHeader> carriesCertificate;
|
|
+ private final AtomicLong finalizedNumber = new AtomicLong(-1L);
|
|
+
|
|
+ AerePqFinalityTags(
|
|
+ final PqAnchorConfig config,
|
|
+ final MutableBlockchain blockchain,
|
|
+ final Predicate<BlockHeader> carriesCertificate) {
|
|
+ this.config = config;
|
|
+ this.blockchain = blockchain;
|
|
+ this.carriesCertificate = carriesCertificate;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Install the tags on a blockchain: initialise from the current head, then follow every block added.
|
|
+ *
|
|
+ * @param config the anchor configuration (activation height, interval schedule)
|
|
+ * @param blockchain the chain whose finalized/safe tags are written
|
|
+ * @param carriesCertificate whether a header carries a (validated) anchor certificate
|
|
+ * @return the installed instance, for inspection
|
|
+ */
|
|
+ public static AerePqFinalityTags install(
|
|
+ final PqAnchorConfig config,
|
|
+ final MutableBlockchain blockchain,
|
|
+ final Predicate<BlockHeader> carriesCertificate) {
|
|
+ final AerePqFinalityTags tags = new AerePqFinalityTags(config, blockchain, carriesCertificate);
|
|
+ tags.initialiseFromHead();
|
|
+ blockchain.observeBlockAdded(tags::onBlockAdded);
|
|
+ return tags;
|
|
+ }
|
|
+
|
|
+ /** The height currently reported as finalized, or -1 when none has been set by this rule. */
|
|
+ public long finalizedNumber() {
|
|
+ return finalizedNumber.get();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether a decoded header carries an anchor certificate. A header carries the v1 Falcon list OR
|
|
+ * the v2 scheme-tagged certificate, never both ({@link BftExtraData}), and from AIP-22 stage 5
|
|
+ * every anchor carries the v2 certificate while {@code getFalconSeals()} is empty. So a predicate
|
|
+ * that only looked at the v1 list ({@code getFalconSeals()}) never fired on a stage-5 chain -
|
|
+ * measured 2026-09-26 on the rep28098 rehearsal, where {@code finalized} stayed 0 while the chain
|
|
+ * ran past certified anchors 1920 and 1952. Both fields are checked here, in one place both the
|
|
+ * controller and the test read, so the two cannot drift.
|
|
+ *
|
|
+ * @param extraData the decoded BFT extra data of the header
|
|
+ * @return true when the header carries a (v1 or v2) anchor certificate
|
|
+ */
|
|
+ public static boolean carriesCertificate(final BftExtraData extraData) {
|
|
+ return !extraData.getFalconSeals().isEmpty() || !extraData.getHybridSeals().isEmpty();
|
|
+ }
|
|
+
|
|
+ /** Scan back from the head, at most two anchor intervals, to the last certified anchor. */
|
|
+ void initialiseFromHead() {
|
|
+ final BlockHeader head = blockchain.getChainHeadHeader();
|
|
+ if (head == null) {
|
|
+ return;
|
|
+ }
|
|
+ final long top = head.getNumber();
|
|
+ final long floor = Math.max(0L, top - 2L * Math.max(1, config.intervalAt(top)));
|
|
+ for (long h = top; h >= floor; h--) {
|
|
+ if (!config.anchorAppliesAt(h)) {
|
|
+ continue;
|
|
+ }
|
|
+ final Optional<BlockHeader> header = blockchain.getBlockHeader(h);
|
|
+ if (header.isPresent() && carriesCertificate.test(header.get())) {
|
|
+ set(header.get().getParentHash(), h - 1L, "startup scan");
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ LOG.info(
|
|
+ "AERE PQ FINALITY (B1): no certified anchor between {} and the head {}; finalized/safe stay "
|
|
+ + "unset until the next anchor is imported.",
|
|
+ floor,
|
|
+ top);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Follow a block added to the chain.
|
|
+ *
|
|
+ * @param event the event
|
|
+ */
|
|
+ void onBlockAdded(final BlockAddedEvent event) {
|
|
+ if (event == null || !event.isNewCanonicalHead()) {
|
|
+ return;
|
|
+ }
|
|
+ final BlockHeader header = event.getHeader();
|
|
+ if (header == null) {
|
|
+ return;
|
|
+ }
|
|
+ if (event.getEventType() == EventType.CHAIN_REORG && finalizedNumber.get() >= 0) {
|
|
+ final Hash ancestorHash = event.getCommonAncestorHash();
|
|
+ final Optional<BlockHeader> ancestor =
|
|
+ ancestorHash == null ? Optional.empty() : blockchain.getBlockHeader(ancestorHash);
|
|
+ if (ancestor.isPresent() && ancestor.get().getNumber() < finalizedNumber.get()) {
|
|
+ LOG.error(
|
|
+ "{}: a canonical reorg to {} (common ancestor {}) went BELOW the finalized block {}. "
|
|
+ + "Finality tags are NOT moved back. Under the anchor rules this needs K validators to "
|
|
+ + "have certified two conflicting anchors; investigate before anything else.",
|
|
+ CODE_REORG_BELOW_FINALIZED,
|
|
+ header.getNumber(),
|
|
+ ancestor.get().getNumber(),
|
|
+ finalizedNumber.get());
|
|
+ }
|
|
+ }
|
|
+ final long h = header.getNumber();
|
|
+ if (config.anchorAppliesAt(h) && carriesCertificate.test(header)) {
|
|
+ set(header.getParentHash(), h - 1L, "anchor " + h);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void set(final Hash finalHash, final long finalNumber, final String why) {
|
|
+ if (finalNumber <= finalizedNumber.get()) {
|
|
+ return; // monotonic: never backwards, never twice for the same height
|
|
+ }
|
|
+ blockchain.setFinalized(finalHash);
|
|
+ blockchain.setSafeBlock(finalHash);
|
|
+ finalizedNumber.set(finalNumber);
|
|
+ LOG.info(
|
|
+ "AERE PQ FINALITY (B1): finalized/safe = {} ({}), covered by the certificate of {}.",
|
|
+ finalNumber,
|
|
+ finalHash,
|
|
+ why);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqHeaderSeal.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqHeaderSeal.java
|
|
new file mode 100644
|
|
index 0000000000..4f3a7c76c0
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqHeaderSeal.java
|
|
@@ -0,0 +1,95 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+/**
|
|
+ * AERE AIP-22 stage 5 (plan 9.7): from H_hdr ({@code aere.pq.headerBlock}) a header carries no ECDSA
|
|
+ * committed seal; its seventh extraData element is the proposer's Falcon-512 seal, the PROPOSAL layer's
|
|
+ * seal over the proposal digest, and a header is admitted between anchors iff that seal verifies for
|
|
+ * its {@code coinbase} (an id) at its height. Finality stays with the anchors (stage 4). H_hdr must be
|
|
+ * at or above H_fin, because the seal it relies on is only an AUTHOR from H_fin (AERE-PQC-HDR-01).
|
|
+ * Unset: never, which is every chain today.
|
|
+ */
|
|
+public final class AerePqHeaderSeal {
|
|
+
|
|
+ /** The system property naming H_hdr. */
|
|
+ public static final String PROPERTY = "aere.pq.headerBlock";
|
|
+
|
|
+ private static volatile long headerBlock = AerePqIdentity.NEVER;
|
|
+
|
|
+ private AerePqHeaderSeal() {}
|
|
+
|
|
+ /**
|
|
+ * Arms H_hdr.
|
|
+ *
|
|
+ * @param hHdr H_hdr, or {@link AerePqIdentity#NEVER}
|
|
+ */
|
|
+ public static void install(final long hHdr) {
|
|
+ if (hHdr != AerePqIdentity.NEVER) {
|
|
+ final long hFin = AerePqFinality.finalityBlock();
|
|
+ if (hFin == AerePqIdentity.NEVER || hHdr < hFin) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-HDR-01: "
|
|
+ + PROPERTY
|
|
+ + "="
|
|
+ + hHdr
|
|
+ + " needs H_fin (aere.pq.finalityBlock) armed at or below it (H_fin "
|
|
+ + (hFin == AerePqIdentity.NEVER ? "unset" : Long.toString(hFin))
|
|
+ + "): the proposer's seal in the header is an author only from H_fin");
|
|
+ }
|
|
+ }
|
|
+ headerBlock = hHdr;
|
|
+ }
|
|
+
|
|
+ /** Disarms (tests). */
|
|
+ public static void uninstall() {
|
|
+ headerBlock = AerePqIdentity.NEVER;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * H_hdr as armed.
|
|
+ *
|
|
+ * @return H_hdr, or {@link AerePqIdentity#NEVER}
|
|
+ */
|
|
+ public static long headerBlock() {
|
|
+ return headerBlock;
|
|
+ }
|
|
+
|
|
+ /** Arms from {@link #PROPERTY}; unset means never. Call after H_fin is installed. */
|
|
+ public static void installFromSystemProperties() {
|
|
+ final String v = System.getProperty(PROPERTY);
|
|
+ if (v == null || v.isBlank()) {
|
|
+ uninstall();
|
|
+ return;
|
|
+ }
|
|
+ final long h;
|
|
+ try {
|
|
+ h = Long.parseLong(v.trim());
|
|
+ } catch (final NumberFormatException e) {
|
|
+ throw new IllegalStateException("AERE-PQC-HDR-01: " + PROPERTY + "='" + v + "' is not a height", e);
|
|
+ }
|
|
+ install(h);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether a header at this height carries the proposer's seal instead of ECDSA committed seals.
|
|
+ *
|
|
+ * @param height the header's height
|
|
+ * @return true from H_hdr
|
|
+ */
|
|
+ public static boolean active(final long height) {
|
|
+ return height >= headerBlock;
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentity.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentity.java
|
|
new file mode 100644
|
|
index 0000000000..99778b62ab
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentity.java
|
|
@@ -0,0 +1,561 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the post-quantum validator identity, in ONE place.
|
|
+ *
|
|
+ * WHAT IT DOES. From the activation height H_id, a validator is its 20-byte id (PqRegistryV3), not its
|
|
+ * ECDSA address. Upstream QBFT works entirely on two 20-byte things - the AUTHOR of a signed message and
|
|
+ * the validator LIST - so the switch is a TRANSLATION applied at the few places where an ECDSA address
|
|
+ * is born, and nowhere else (the choke points are listed in the AIP-22 plan, section 9.4):
|
|
+ *
|
|
+ * author(recovered, h) the author of a message or commit seal at height h: the id of the v3 row
|
|
+ * whose ecdsa.addr is the recovered address when h >= H_id, the address itself
|
|
+ * otherwise (an address with no row is then simply not in the set, and its
|
|
+ * message does not count - the upstream checks already say so)
|
|
+ * translateSet(set, b) the validator set after block b = H_id - 1 becomes the sorted ids of its
|
|
+ * members (VoteTallyUpdater), so extraData(H_id) carries ids and H_id is the
|
|
+ * first block sealed by ids; a member without a v3 row is a configuration
|
|
+ * FAULT that throws, never a silent drop
|
|
+ * local(address, h) this node's own identity at height h (coinbase, proposer check)
|
|
+ * isLocal(candidate, a) whether a 20-byte value is this node, in either form
|
|
+ * transportTargets(ids) the RLPx node-key addresses to send consensus messages to, from the rows'
|
|
+ * transport field; empty when some id lists none (send to every peer then)
|
|
+ *
|
|
+ * DISARMED unless installed: with no configuration every function is the identity, so a build that
|
|
+ * carries this class and is never configured behaves exactly as before, byte for byte.
|
|
+ *
|
|
+ * Configuration (system properties, like every AERE rule, read once at startup):
|
|
+ * aere.pq.identityBlock H_id
|
|
+ * aere.pq.registryV3 comma list of v3 manifests (JSON), each bound at its own bindHeight
|
|
+ * aere.pq.registryV3.hashes comma list "bindHeight:0xhash" - the pinned hash of every epoch; an
|
|
+ * epoch without a pin refuses startup (a registry nobody pinned is a file)
|
|
+ *
|
|
+ * NOT here (stated): the PQ seal registry lookups (index -> address) move to ids through the v3 epoch
|
|
+ * entering the registry schedule; the per-message PQ seal authorship check (SPEC 2.6 rule 2) then
|
|
+ * compares id with id.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.NavigableMap;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+import java.util.TreeSet;
|
|
+
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import com.google.common.base.Splitter;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/** The AIP-22 identity translation. */
|
|
+public final class AerePqIdentity {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(AerePqIdentity.class);
|
|
+
|
|
+ /** H_id. */
|
|
+ public static final String PROPERTY_BLOCK = "aere.pq.identityBlock";
|
|
+
|
|
+ /** The v3 manifests. */
|
|
+ public static final String PROPERTY_REGISTRIES = "aere.pq.registryV3";
|
|
+
|
|
+ /** The pinned hashes of the v3 manifests. */
|
|
+ public static final String PROPERTY_HASHES = "aere.pq.registryV3.hashes";
|
|
+
|
|
+ /**
|
|
+ * AIP-22 stage 3b: H_k, the height from which the keys that SEAL come from the v3 epoch in force
|
|
+ * (instead of the Falcon registry schedule and the hybrid registry). Must be the bindHeight of a v3
|
|
+ * epoch and at or above H_id. Unset: the keys stay where they are (stage 3a).
|
|
+ */
|
|
+ public static final String PROPERTY_KEYS_FROM = "aere.pq.registryV3.keysFrom";
|
|
+
|
|
+ /** No H_k: the v3 epochs never supply keys. */
|
|
+ public static final long NEVER = Long.MAX_VALUE;
|
|
+
|
|
+ /**
|
|
+ * An installed configuration.
|
|
+ *
|
|
+ * @param identityBlock H_id
|
|
+ * @param epochs v3 epochs by bindHeight
|
|
+ * @param keysFrom H_k, or {@link #NEVER}
|
|
+ */
|
|
+ public record Config(
|
|
+ long identityBlock, NavigableMap<Long, PqRegistryV3.Registry> epochs, long keysFrom) {
|
|
+
|
|
+ /**
|
|
+ * A stage-3a configuration: identity only, keys stay in the existing registries.
|
|
+ *
|
|
+ * @param identityBlock H_id
|
|
+ * @param epochs v3 epochs by bindHeight
|
|
+ */
|
|
+ public Config(final long identityBlock, final NavigableMap<Long, PqRegistryV3.Registry> epochs) {
|
|
+ this(identityBlock, epochs, NEVER);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** A configuration fault of the identity switch. */
|
|
+ public static final class IdentityException extends RuntimeException {
|
|
+ private static final long serialVersionUID = 1L;
|
|
+
|
|
+ /**
|
|
+ * A fault.
|
|
+ *
|
|
+ * @param message what is wrong
|
|
+ */
|
|
+ public IdentityException(final String message) {
|
|
+ super("AERE-PQC-ID: " + message);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static volatile Config config;
|
|
+
|
|
+ private AerePqIdentity() {}
|
|
+
|
|
+ /**
|
|
+ * Installs a configuration (startup, or a test). Checks that H_id has an epoch bound at or below it.
|
|
+ *
|
|
+ * @param c the configuration, or null to disarm
|
|
+ */
|
|
+ public static void install(final Config c) {
|
|
+ if (c != null && c.epochs().floorEntry(c.identityBlock()) == null) {
|
|
+ throw new IdentityException(
|
|
+ "no v3 registry epoch is bound at or below the identity height " + c.identityBlock());
|
|
+ }
|
|
+ if (c != null && c.keysFrom() != NEVER) {
|
|
+ // H_k switches where the keys come FROM; it must fall on an epoch boundary at or after H_id, so
|
|
+ // the epoch that starts supplying keys is a whole epoch, verified and pinned like every other
|
|
+ if (c.keysFrom() < c.identityBlock() || !c.epochs().containsKey(c.keysFrom())) {
|
|
+ throw new IdentityException(
|
|
+ PROPERTY_KEYS_FROM
|
|
+ + "="
|
|
+ + c.keysFrom()
|
|
+ + " must be the bindHeight of a v3 epoch at or above the identity height "
|
|
+ + c.identityBlock()
|
|
+ + " (epochs "
|
|
+ + c.epochs().keySet()
|
|
+ + ")");
|
|
+ }
|
|
+ }
|
|
+ config = c;
|
|
+ if (c != null) {
|
|
+ LOG.info(
|
|
+ "AERE PQ IDENTITY: ARMED - validators are post-quantum ids from height {}; v3 epochs {}{}",
|
|
+ c.identityBlock(),
|
|
+ c.epochs().keySet(),
|
|
+ c.keysFrom() == NEVER
|
|
+ ? ""
|
|
+ : "; the keys that seal come from the v3 epoch in force from height " + c.keysFrom());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** Disarms (tests). */
|
|
+ public static void uninstall() {
|
|
+ config = null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The installed configuration.
|
|
+ *
|
|
+ * @return it, if armed
|
|
+ */
|
|
+ public static Optional<Config> installed() {
|
|
+ return Optional.ofNullable(config);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Reads the configuration from the system properties and installs it. No property: stays disarmed.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param requiredAt the schemes every row must carry, as the scheme schedule names them at a height
|
|
+ */
|
|
+ public static void installFromSystemProperties(
|
|
+ final long chainId, final java.util.function.LongFunction<List<String>> requiredAt) {
|
|
+ final String block = System.getProperty(PROPERTY_BLOCK);
|
|
+ if (block == null || block.isBlank()) {
|
|
+ return;
|
|
+ }
|
|
+ final long h = Long.parseLong(block.trim());
|
|
+ final List<String> requiredSchemes = requiredAt.apply(h);
|
|
+ final String files = System.getProperty(PROPERTY_REGISTRIES, "");
|
|
+ final String hashes = System.getProperty(PROPERTY_HASHES, "");
|
|
+ final TreeMap<Long, Bytes32> pins = new TreeMap<>();
|
|
+ for (final String p : Splitter.on(',').omitEmptyStrings().trimResults().split(hashes)) {
|
|
+ final int i = p.indexOf(':');
|
|
+ if (i < 0) {
|
|
+ throw new IdentityException(PROPERTY_HASHES + " entry '" + p + "' is not bindHeight:0xhash");
|
|
+ }
|
|
+ pins.put(Long.parseLong(p.substring(0, i)), Bytes32.fromHexString(p.substring(i + 1)));
|
|
+ }
|
|
+ final ObjectMapper m = new ObjectMapper();
|
|
+ final List<PqRegistryV3.Registry> loaded = new ArrayList<>();
|
|
+ PqRegistryV3.Registry previous = null;
|
|
+ final List<Path> paths = new ArrayList<>();
|
|
+ for (final String f : Splitter.on(',').omitEmptyStrings().trimResults().split(files)) {
|
|
+ paths.add(Path.of(f));
|
|
+ }
|
|
+ // epochs are loaded in bindHeight order, each against the one before it (rotations)
|
|
+ final TreeMap<Long, com.fasterxml.jackson.databind.JsonNode> byHeight = new TreeMap<>();
|
|
+ for (final Path p : paths) {
|
|
+ try {
|
|
+ final com.fasterxml.jackson.databind.JsonNode j = m.readTree(Files.readString(p));
|
|
+ byHeight.put(j.path("bindHeight").asLong(-1), j);
|
|
+ } catch (final IOException e) {
|
|
+ throw new IdentityException("cannot read v3 manifest " + p + ": " + e.getMessage());
|
|
+ }
|
|
+ }
|
|
+ for (final var e : byHeight.entrySet()) {
|
|
+ final Bytes32 pin = pins.get(e.getKey());
|
|
+ if (pin == null) {
|
|
+ throw new IdentityException(
|
|
+ "the v3 epoch bound at " + e.getKey() + " has no pinned hash in " + PROPERTY_HASHES);
|
|
+ }
|
|
+ final boolean switchEpoch = previous == null;
|
|
+ final PqRegistryV3.Registry r =
|
|
+ PqRegistryV3.loadPinned(e.getValue(), chainId, requiredSchemes, previous, switchEpoch, pin);
|
|
+ loaded.add(r);
|
|
+ previous = r;
|
|
+ }
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ for (final PqRegistryV3.Registry r : loaded) {
|
|
+ epochs.put(r.bindHeight(), r);
|
|
+ }
|
|
+ final String keysFrom = System.getProperty(PROPERTY_KEYS_FROM);
|
|
+ install(
|
|
+ new Config(
|
|
+ h,
|
|
+ Collections.unmodifiableNavigableMap(epochs),
|
|
+ keysFrom == null || keysFrom.isBlank() ? NEVER : Long.parseLong(keysFrom.trim())));
|
|
+ }
|
|
+
|
|
+ // ---------------------------------------------------------------------------------------------
|
|
+ // AIP-22 stage 3b: the keys that seal, from the v3 epoch in force
|
|
+
|
|
+ /**
|
|
+ * Whether the keys that seal at this height come from the v3 epoch in force (at or above H_k).
|
|
+ * Every key lookup asks this first; below H_k (and disarmed) it answers false and the caller uses
|
|
+ * its existing registry, untouched.
|
|
+ *
|
|
+ * @param height the height the key is asked for, in the caller's own convention (the parent of an
|
|
+ * anchor for a certificate seal)
|
|
+ * @return true from H_k when armed
|
|
+ */
|
|
+ public static boolean keysFromV3(final long height) {
|
|
+ final Config c = config;
|
|
+ return c != null && height >= c.keysFrom();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The public key of a registry index for a scheme at a height, from the v3 epoch in force, in the
|
|
+ * form the existing registries carry it: Falcon-512 WITHOUT the 0x09 header byte (the 896-byte h
|
|
+ * that {@code FalconPublicKeyParameters} takes), SLH-DSA-SHA2-128s as its 32 bytes. Empty when the
|
|
+ * epoch has no such row or key: the caller then has NO key (fail closed), it never falls back to
|
|
+ * the old registries, because above H_k they are no longer the key set the chain requires.
|
|
+ *
|
|
+ * @param height the height (see {@link #keysFromV3})
|
|
+ * @param index the registry index carried by the seal
|
|
+ * @param schemeId e.g. "falcon-512"
|
|
+ * @return the key, or empty
|
|
+ */
|
|
+ public static Optional<byte[]> v3KeyAt(final long height, final int index, final String schemeId) {
|
|
+ return epochAt(height)
|
|
+ .filter(r -> index >= 0 && index < r.rows().size())
|
|
+ .map(r -> r.rows().get(index))
|
|
+ .flatMap(row -> row.key(schemeId))
|
|
+ .map(
|
|
+ k ->
|
|
+ "falcon-512".equals(schemeId)
|
|
+ ? java.util.Arrays.copyOfRange(k.publicKey(), 1, k.publicKey().length)
|
|
+ : k.publicKey().clone());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AIP-22 stage 3b-ii: the index of the row of the v3 epoch in force that carries a given public key
|
|
+ * for a scheme (the key in the registry form of {@link #v3KeyAt}). How a node finds, per epoch,
|
|
+ * which row is its own: indices move between epochs, so a key file's index cannot say it.
|
|
+ *
|
|
+ * @param height the height
|
|
+ * @param schemeId e.g. "falcon-512"
|
|
+ * @param publicKey the key, registry form
|
|
+ * @return the row index, or empty when no row of that epoch carries the key
|
|
+ */
|
|
+ public static Optional<Integer> v3IndexOfKey(
|
|
+ final long height, final String schemeId, final byte[] publicKey) {
|
|
+ final Optional<PqRegistryV3.Registry> r = epochAt(height);
|
|
+ if (r.isEmpty() || publicKey == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ for (final PqRegistryV3.Row row : r.get().rows()) {
|
|
+ final Optional<byte[]> k = v3KeyAt(height, row.index(), schemeId);
|
|
+ if (k.isPresent() && java.util.Arrays.equals(k.get(), publicKey)) {
|
|
+ return Optional.of(row.index());
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The id of a registry index at a height, from the v3 epoch in force (stage 3b: the index names
|
|
+ * the v3 row directly, from H_k).
|
|
+ *
|
|
+ * @param height the height
|
|
+ * @param index the registry index
|
|
+ * @return the 20-byte id as an address, or empty when the epoch has no such row
|
|
+ */
|
|
+ public static Optional<Address> v3IdAt(final long height, final int index) {
|
|
+ return epochAt(height)
|
|
+ .filter(r -> index >= 0 && index < r.rows().size())
|
|
+ .map(r -> Address.wrap(Bytes.wrap(r.rows().get(index).id())));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * THE CONTINUITY GUARD, run once at startup when H_k is configured: switching the SOURCE of the
|
|
+ * keys at H_k must not change any key. Every key of every row of the epoch in force at H_k must be
|
|
+ * exactly the key the existing registries give that index just below H_k; only a LATER epoch may
|
|
+ * rotate, and only through the rotation signatures of the old keys, which the v3 loader verifies.
|
|
+ * A mismatch, or a key the existing registries cannot produce, refuses startup (fail closed): a
|
|
+ * node that swapped keys at H_k would accept seals no other node accepts.
|
|
+ *
|
|
+ * @param keysBefore (index, schemeId) to the key the existing registries give at H_k - 1, in the
|
|
+ * registry form (see {@link #v3KeyAt})
|
|
+ */
|
|
+ public static void verifyKeyContinuity(
|
|
+ final java.util.function.BiFunction<Integer, String, Optional<byte[]>> keysBefore) {
|
|
+ final Config c = config;
|
|
+ if (c == null || c.keysFrom() == NEVER) {
|
|
+ return;
|
|
+ }
|
|
+ final PqRegistryV3.Registry r = c.epochs().get(c.keysFrom());
|
|
+ int checked = 0;
|
|
+ for (final PqRegistryV3.Row row : r.rows()) {
|
|
+ for (final PqRegistryV3.Key k : row.keys().values()) {
|
|
+ final String scheme = k.scheme().id();
|
|
+ final byte[] v3 = v3KeyAt(c.keysFrom(), row.index(), scheme).orElseThrow();
|
|
+ final Optional<byte[]> before = keysBefore.apply(row.index(), scheme);
|
|
+ if (before.isEmpty() || !java.util.Arrays.equals(before.get(), v3)) {
|
|
+ throw new IdentityException(
|
|
+ "continuity at "
|
|
+ + PROPERTY_KEYS_FROM
|
|
+ + "="
|
|
+ + c.keysFrom()
|
|
+ + ": row "
|
|
+ + row.index()
|
|
+ + " "
|
|
+ + scheme
|
|
+ + (before.isEmpty()
|
|
+ ? " has no key in the existing registries at " + (c.keysFrom() - 1)
|
|
+ : " differs from the key the existing registries give at " + (c.keysFrom() - 1))
|
|
+ + "; switching the key source must not change a key (a rotation belongs in a later"
|
|
+ + " epoch, signed by the old keys)");
|
|
+ }
|
|
+ checked++;
|
|
+ }
|
|
+ }
|
|
+ LOG.info(
|
|
+ "AERE PQ IDENTITY: key continuity at {} verified, {} keys of {} rows equal the existing"
|
|
+ + " registries at {}",
|
|
+ c.keysFrom(),
|
|
+ checked,
|
|
+ r.rows().size(),
|
|
+ c.keysFrom() - 1);
|
|
+ }
|
|
+
|
|
+ // ---------------------------------------------------------------------------------------------
|
|
+
|
|
+ /**
|
|
+ * Whether ids are the identity at this height.
|
|
+ *
|
|
+ * @param height the height
|
|
+ * @return true from H_id when armed
|
|
+ */
|
|
+ public static boolean active(final long height) {
|
|
+ final Config c = config;
|
|
+ return c != null && height >= c.identityBlock();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The v3 epoch in force at a height.
|
|
+ *
|
|
+ * @param height the height
|
|
+ * @return the epoch, if armed and one is bound at or below it
|
|
+ */
|
|
+ public static Optional<PqRegistryV3.Registry> epochAt(final long height) {
|
|
+ final Config c = config;
|
|
+ if (c == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final var e = c.epochs().floorEntry(height);
|
|
+ return e == null ? Optional.empty() : Optional.of(e.getValue());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The author of a message or commit seal whose ECDSA signature recovered to this address.
|
|
+ *
|
|
+ * @param recovered the recovered address
|
|
+ * @param height the height the message or seal is for
|
|
+ * @return the id from H_id (when a row links the address), the address otherwise
|
|
+ */
|
|
+ public static Address author(final Address recovered, final long height) {
|
|
+ if (!active(height)) {
|
|
+ return recovered;
|
|
+ }
|
|
+ return idOfEcdsa(recovered.getBytes().toArrayUnsafe(), height)
|
|
+ .map(i -> Address.wrap(Bytes.wrap(i)))
|
|
+ .orElse(recovered);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The id an ECDSA address links to at a height. The ecdsa link is required only in the switch epoch
|
|
+ * (AIP-22 3.2) and a later epoch may omit it, while messages still travel with an ECDSA signature
|
|
+ * until stage 4; so the link is INHERITED by id: the most recent epoch at or below the height that
|
|
+ * links this address names the id, and that id must still be registered in the epoch in force (a
|
|
+ * removed id's old link means nothing). A new id that never carried a link has no ECDSA author, so
|
|
+ * its classical messages cannot count before stage 4: stated in the plan (9.5), not hidden.
|
|
+ */
|
|
+ private static Optional<byte[]> idOfEcdsa(final byte[] address, final long height) {
|
|
+ final Config c = config;
|
|
+ if (c == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final var head = c.epochs().floorEntry(height);
|
|
+ if (head == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ // ids that a NEWER epoch already links to some address: an older link of another address to such an
|
|
+ // id is superseded (the id moved its ECDSA key), so that older address no longer authors as the id
|
|
+ final java.util.Set<Bytes> relinked = new java.util.HashSet<>();
|
|
+ for (final PqRegistryV3.Registry e : c.epochs().headMap(height, true).descendingMap().values()) {
|
|
+ final Optional<PqRegistryV3.Row> linked = e.rowOfEcdsa(address);
|
|
+ if (linked.isPresent()) {
|
|
+ final byte[] i = linked.get().id();
|
|
+ return !relinked.contains(Bytes.wrap(i)) && head.getValue().rowOf(i).isPresent()
|
|
+ ? Optional.of(i)
|
|
+ : Optional.empty();
|
|
+ }
|
|
+ for (final PqRegistryV3.Row r : e.rows()) {
|
|
+ if (r.ecdsaAddress() != null) {
|
|
+ relinked.add(Bytes.wrap(r.id()));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * This node's identity at a height.
|
|
+ *
|
|
+ * @param localEcdsa the node's ECDSA address
|
|
+ * @param height the height
|
|
+ * @return the id from H_id when the node has a row, the address otherwise
|
|
+ */
|
|
+ public static Address local(final Address localEcdsa, final long height) {
|
|
+ return author(localEcdsa, height);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether a 20-byte value is this node, as an address or as its id in any epoch.
|
|
+ *
|
|
+ * @param candidate the value
|
|
+ * @param localEcdsa the node's ECDSA address
|
|
+ * @return whether it is this node
|
|
+ */
|
|
+ public static boolean isLocal(final Address candidate, final Address localEcdsa) {
|
|
+ if (candidate.equals(localEcdsa)) {
|
|
+ return true;
|
|
+ }
|
|
+ final Config c = config;
|
|
+ if (c == null) {
|
|
+ return false;
|
|
+ }
|
|
+ for (final PqRegistryV3.Registry r : c.epochs().values()) {
|
|
+ final Optional<PqRegistryV3.Row> row = r.rowOfEcdsa(localEcdsa.getBytes().toArrayUnsafe());
|
|
+ if (row.isPresent() && candidate.equals(Address.wrap(Bytes.wrap(row.get().id())))) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether the set after this block changes form (armed, and the block is H_id - 1). Callers ask
|
|
+ * first so that, disarmed or at any other block, the upstream code path is untouched - not even an
|
|
+ * extra call on the tally (upstream VoteTallyUpdaterTest asserts exactly that).
|
|
+ *
|
|
+ * @param blockNumber the block
|
|
+ * @return true only at H_id - 1 when armed
|
|
+ */
|
|
+ public static boolean translatesAfter(final long blockNumber) {
|
|
+ final Config c = config;
|
|
+ return c != null && blockNumber == c.identityBlock() - 1L;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The validator set after block {@code blockNumber}, translated when that block is H_id - 1.
|
|
+ *
|
|
+ * @param set the set after the block, as upstream computed it
|
|
+ * @param blockNumber the block
|
|
+ * @return the same set, or its sorted ids at H_id - 1
|
|
+ */
|
|
+ public static Collection<Address> translateSetAfter(
|
|
+ final Collection<Address> set, final long blockNumber) {
|
|
+ final Config c = config;
|
|
+ if (c == null || blockNumber != c.identityBlock() - 1L) {
|
|
+ return set;
|
|
+ }
|
|
+ final PqRegistryV3.Registry r =
|
|
+ epochAt(c.identityBlock())
|
|
+ .orElseThrow(() -> new IdentityException("no v3 epoch at " + c.identityBlock()));
|
|
+ final TreeSet<Address> ids = new TreeSet<>();
|
|
+ for (final Address a : set) {
|
|
+ final Optional<PqRegistryV3.Row> row = r.rowOfEcdsa(a.getBytes().toArrayUnsafe());
|
|
+ if (row.isEmpty()) {
|
|
+ throw new IdentityException(
|
|
+ "validator "
|
|
+ + a
|
|
+ + " is in the set after block "
|
|
+ + blockNumber
|
|
+ + " and has no row in the v3 epoch bound at "
|
|
+ + r.bindHeight()
|
|
+ + "; the identity switch refuses rather than dropping a validator");
|
|
+ }
|
|
+ ids.add(Address.wrap(Bytes.wrap(row.get().id())));
|
|
+ }
|
|
+ LOG.info(
|
|
+ "AERE PQ IDENTITY: the set after block {} is translated to {} post-quantum ids",
|
|
+ blockNumber,
|
|
+ ids.size());
|
|
+ return ids;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The RLPx node-key addresses consensus messages for these recipients go to.
|
|
+ *
|
|
+ * @param recipients validator identities (ids or addresses)
|
|
+ * @return the transport addresses; EMPTY when some id lists no transport, meaning "every peer"
|
|
+ */
|
|
+ public static Optional<Collection<Address>> transportTargets(final Collection<Address> recipients) {
|
|
+ final Config c = config;
|
|
+ if (c == null) {
|
|
+ return Optional.of(recipients);
|
|
+ }
|
|
+ final PqRegistryV3.Registry head = c.epochs().lastEntry().getValue();
|
|
+ final List<Address> out = new ArrayList<>();
|
|
+ for (final Address a : recipients) {
|
|
+ final Optional<PqRegistryV3.Row> row = head.rowOf(a.getBytes().toArrayUnsafe());
|
|
+ if (row.isEmpty()) {
|
|
+ out.add(a); // a classical address (below H_id), sent to as before
|
|
+ } else if (row.get().transport() == null) {
|
|
+ return Optional.empty();
|
|
+ } else {
|
|
+ out.add(Address.wrap(Bytes.wrap(row.get().transport())));
|
|
+ }
|
|
+ }
|
|
+ return Optional.of(out);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockHashing.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockHashing.java
|
|
index 94dc41b354..06cb610099 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockHashing.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockHashing.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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
|
|
import org.hyperledger.besu.ethereum.core.Util;
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
|
|
import java.util.List;
|
|
import java.util.function.Supplier;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/** The Bft block hashing. */
|
|
public class BftBlockHashing {
|
|
private final BftExtraDataCodec bftExtraDataCodec;
|
|
|
|
@@ -85,41 +91,41 @@ public class BftBlockHashing {
|
|
final BftExtraData bftExtraData = bftExtraDataCodec.decode(header);
|
|
return Hash.hash(
|
|
serializeHeader(
|
|
header,
|
|
() -> bftExtraDataCodec.encodeWithoutCommitSealsAndRoundNumber(bftExtraData),
|
|
bftExtraDataCodec));
|
|
}
|
|
|
|
/**
|
|
* Recovers the {@link Address} for each validator that contributed a committed seal to the block.
|
|
*
|
|
* @param header the block header that was signed by the committed seals
|
|
* @param bftExtraData the parsed {@link BftExtraData} from the header
|
|
* @return the addresses of validators that provided a committed seal
|
|
*/
|
|
public List<Address> recoverCommitterAddresses(
|
|
final BlockHeader header, final BftExtraData bftExtraData) {
|
|
final Hash committerHash = calculateDataHashForCommittedSeal(header, bftExtraData);
|
|
|
|
return bftExtraData.getSeals().stream()
|
|
- .map(p -> Util.signatureToAddress(p, committerHash))
|
|
+ .map(p -> AerePqIdentity.author(Util.signatureToAddress(p, committerHash), header.getNumber()))
|
|
.collect(Collectors.toList());
|
|
}
|
|
|
|
/**
|
|
* Serialize header bytes.
|
|
*
|
|
* @param header the header
|
|
* @param extraDataSerializer the extra data serializer
|
|
* @param bftExtraDataCodec the bft extra data codec
|
|
* @return the bytes
|
|
*/
|
|
public static Bytes serializeHeader(
|
|
final BlockHeader header,
|
|
final Supplier<Bytes> extraDataSerializer,
|
|
final BftExtraDataCodec bftExtraDataCodec) {
|
|
|
|
// create a block header which is a copy of the header supplied as parameter except of the
|
|
// extraData field
|
|
final BlockHeaderBuilder builder = BlockHeaderBuilder.fromHeader(header);
|
|
builder.blockHeaderFunctions(BftBlockHeaderFunctions.forOnchainBlock(bftExtraDataCodec));
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockInterface.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockInterface.java
|
|
index 77af53d688..acefe61665 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockInterface.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftBlockInterface.java
|
|
@@ -100,63 +100,66 @@ public class BftBlockInterface implements BlockInterface {
|
|
*
|
|
* @param block the block
|
|
* @param round the round
|
|
* @param blockHeaderFunctions the block header functions
|
|
* @return the block
|
|
*/
|
|
public Block replaceRoundInBlock(
|
|
final Block block, final int round, final BlockHeaderFunctions blockHeaderFunctions) {
|
|
final BftExtraData prevExtraData = bftExtraDataCodec.decode(block.getHeader());
|
|
final BftExtraData substituteExtraData =
|
|
new BftExtraData(
|
|
prevExtraData.getVanityData(),
|
|
prevExtraData.getSeals(),
|
|
prevExtraData.getVote(),
|
|
round,
|
|
prevExtraData.getValidators(),
|
|
prevExtraData.getFalconSeals(),
|
|
// AERE ANCHOR V2 (2026-09-03, D-328): the scheme-tagged certificate rides along too. Without
|
|
// this line every v2 header lost its certificate at the round substitution and the fleet
|
|
// refused its own first v2 anchor (testnet 28001, block 168032, 3 hours stalled).
|
|
- prevExtraData.getHybridSeals());
|
|
+ prevExtraData.getHybridSeals(),
|
|
+ // AERE AIP-22 stage 5: and the proposer's seal (element 6), for the same reason; it sits outside
|
|
+ // both hash pre-images, so carrying it changes no hash
|
|
+ prevExtraData.getPqProposerSeal());
|
|
|
|
final BlockHeaderBuilder headerBuilder = BlockHeaderBuilder.fromHeader(block.getHeader());
|
|
headerBuilder
|
|
.extraData(bftExtraDataCodec.encode(substituteExtraData))
|
|
.blockHeaderFunctions(blockHeaderFunctions);
|
|
|
|
final BlockHeader newHeader = headerBuilder.buildBlockHeader();
|
|
|
|
return new Block(newHeader, block.getBody());
|
|
}
|
|
|
|
/**
|
|
* Gets extra data.
|
|
*
|
|
* @param header the header
|
|
* @return the extra data
|
|
*/
|
|
public BftExtraData getExtraData(final BlockHeader header) {
|
|
return bftExtraDataCodec.decode(header);
|
|
}
|
|
|
|
/**
|
|
* Gets committers.
|
|
*
|
|
* @param header the header
|
|
* @return the committers
|
|
*/
|
|
public List<Address> getCommitters(final BlockHeader header) {
|
|
final BftExtraData bftExtraData = bftExtraDataCodec.decode(header);
|
|
|
|
final Hash committerHash =
|
|
Hash.hash(
|
|
BftBlockHashing.serializeHeader(
|
|
header,
|
|
() -> bftExtraDataCodec.encodeWithoutCommitSeals(bftExtraData),
|
|
bftExtraDataCodec));
|
|
|
|
return bftExtraData.getSeals().stream()
|
|
- .map(p -> Util.signatureToAddress(p, committerHash))
|
|
+ .map(p -> AerePqIdentity.author(Util.signatureToAddress(p, committerHash), header.getNumber()))
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExtraData.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExtraData.java
|
|
index c444a1514d..4e9ea6f783 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExtraData.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExtraData.java
|
|
@@ -32,40 +32,46 @@ import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/** The Bft extra data. */
|
|
public class BftExtraData implements ParsedExtraData {
|
|
private final Bytes vanityData;
|
|
private final Collection<SECPSignature> seals;
|
|
private final Collection<Address> validators;
|
|
private final Optional<Vote> vote;
|
|
private final int round;
|
|
|
|
/**
|
|
* Parallel, ADDITIVE post-quantum (Falcon-512) seals. These sit alongside the decisive ECDSA
|
|
* {@link #seals} and are excluded from every signed pre-image, so they never disturb the ECDSA
|
|
* committed seals or the block/header hash.
|
|
*/
|
|
private final Collection<FalconSeal> falconSeals;
|
|
/** AERE ANCHOR V2: the scheme-tagged certificate; empty on every header below the v2 height. */
|
|
private final List<SchemeSeal> hybridSeals;
|
|
+ /**
|
|
+ * AERE AIP-22 stage 5: the proposer's post-quantum seal (element 6 of the stored extraData, from
|
|
+ * H_hdr), the PROPOSAL layer's seal over the proposal digest; outside every hash, like the
|
|
+ * certificate. Empty on every header below H_hdr.
|
|
+ */
|
|
+ private final Optional<FalconSeal> proposerSeal;
|
|
|
|
/**
|
|
* Instantiates a new Bft extra data (no Falcon seals). Retained for callers, notably the IBFT
|
|
* codec, that never carry a parallel post-quantum seal.
|
|
*
|
|
* @param vanityData the vanity data
|
|
* @param seals the seals
|
|
* @param vote the vote
|
|
* @param round the round
|
|
* @param validators the validators
|
|
*/
|
|
public BftExtraData(
|
|
final Bytes vanityData,
|
|
final Collection<SECPSignature> seals,
|
|
final Optional<Vote> vote,
|
|
final int round,
|
|
final Collection<Address> validators) {
|
|
this(vanityData, seals, vote, round, validators, Collections.emptyList());
|
|
}
|
|
|
|
@@ -86,41 +92,67 @@ public class BftExtraData implements ParsedExtraData {
|
|
final int round,
|
|
final Collection<Address> validators,
|
|
final Collection<FalconSeal> falconSeals) {
|
|
this(vanityData, seals, vote, round, validators, falconSeals, Collections.emptyList());
|
|
}
|
|
|
|
/**
|
|
* Full constructor.
|
|
*
|
|
* @param hybridSeals the scheme-tagged (v2) certificate, or empty; a header carries the v1 Falcon
|
|
* list OR the v2 certificate, never both
|
|
*/
|
|
public BftExtraData(
|
|
final Bytes vanityData,
|
|
final Collection<SECPSignature> seals,
|
|
final Optional<Vote> vote,
|
|
final int round,
|
|
final Collection<Address> validators,
|
|
final Collection<FalconSeal> falconSeals,
|
|
final List<SchemeSeal> hybridSeals) {
|
|
+ this(vanityData, seals, vote, round, validators, falconSeals, hybridSeals, Optional.empty());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Full constructor with the proposer's post-quantum seal (AIP-22 stage 5).
|
|
+ *
|
|
+ * @param vanityData the vanity data
|
|
+ * @param seals the ECDSA committed seals (from H_hdr: empty)
|
|
+ * @param vote the vote
|
|
+ * @param round the round
|
|
+ * @param validators the validators
|
|
+ * @param falconSeals the v1 Falcon certificate, or empty
|
|
+ * @param hybridSeals the v2 certificate, or empty
|
|
+ * @param proposerSeal the proposer's seal (element 6), or empty
|
|
+ */
|
|
+ public BftExtraData(
|
|
+ final Bytes vanityData,
|
|
+ final Collection<SECPSignature> seals,
|
|
+ final Optional<Vote> vote,
|
|
+ final int round,
|
|
+ final Collection<Address> validators,
|
|
+ final Collection<FalconSeal> falconSeals,
|
|
+ final List<SchemeSeal> hybridSeals,
|
|
+ final Optional<FalconSeal> proposerSeal) {
|
|
checkNotNull(vanityData);
|
|
+ checkNotNull(proposerSeal);
|
|
+ this.proposerSeal = proposerSeal;
|
|
checkNotNull(hybridSeals);
|
|
if (!hybridSeals.isEmpty() && falconSeals != null && !falconSeals.isEmpty()) {
|
|
throw new IllegalArgumentException(
|
|
"AERE ANCHOR V2: a header carries the v1 Falcon list OR the v2 certificate, not both");
|
|
}
|
|
this.hybridSeals = List.copyOf(hybridSeals);
|
|
checkNotNull(seals);
|
|
checkNotNull(validators);
|
|
checkNotNull(falconSeals);
|
|
this.vanityData = vanityData;
|
|
this.seals = seals;
|
|
this.validators = validators;
|
|
this.vote = vote;
|
|
this.round = round;
|
|
this.falconSeals = falconSeals;
|
|
}
|
|
|
|
/**
|
|
* Gets vanity data.
|
|
*
|
|
@@ -167,40 +199,66 @@ public class BftExtraData implements ParsedExtraData {
|
|
}
|
|
|
|
/**
|
|
* Gets the parallel post-quantum Falcon seals.
|
|
*
|
|
* @return the Falcon seals (possibly empty, never null)
|
|
*/
|
|
public Collection<FalconSeal> getFalconSeals() {
|
|
return falconSeals;
|
|
}
|
|
|
|
/**
|
|
* The scheme-tagged (v2) certificate.
|
|
*
|
|
* @return the v2 seals, canonical order; empty below the v2 height
|
|
*/
|
|
public List<SchemeSeal> getHybridSeals() {
|
|
return hybridSeals;
|
|
}
|
|
|
|
+ /**
|
|
+ * The proposer's post-quantum seal (AIP-22 stage 5, element 6).
|
|
+ *
|
|
+ * @return the seal, or empty below H_hdr
|
|
+ */
|
|
+ public Optional<FalconSeal> getPqProposerSeal() {
|
|
+ return proposerSeal;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The same extra data with another proposer seal and ECDSA seals, everything else carried over
|
|
+ * (the certificate included): the one way to seal a stage-5 header, so no caller can drop the
|
|
+ * certificate while adding the seal (the lesson of 2026-09-03, D-328).
|
|
+ *
|
|
+ * @param newSeals the ECDSA committed seals (from H_hdr: empty)
|
|
+ * @param newProposerSeal the proposer's seal
|
|
+ * @return the new extra data
|
|
+ */
|
|
+ public BftExtraData withSeals(
|
|
+ final Collection<SECPSignature> newSeals, final Optional<FalconSeal> newProposerSeal) {
|
|
+ return new BftExtraData(
|
|
+ vanityData, newSeals, vote, round, validators, falconSeals, hybridSeals, newProposerSeal);
|
|
+ }
|
|
+
|
|
@Override
|
|
public String toString() {
|
|
return "BftExtraData{"
|
|
+ "vanityData="
|
|
+ vanityData
|
|
+ ", seals="
|
|
+ seals
|
|
+ ", validators="
|
|
+ validators
|
|
+ ", vote="
|
|
+ vote
|
|
+ ", round="
|
|
+ round
|
|
+ ", falconSeals="
|
|
+ falconSeals
|
|
+ ", hybridSeals="
|
|
+ hybridSeals
|
|
+ + ", proposerSeal="
|
|
+ + proposerSeal
|
|
+ '}';
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/FalconSealSupport.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/FalconSealSupport.java
|
|
index 7049b84147..8482c3d47e 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/FalconSealSupport.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/FalconSealSupport.java
|
|
@@ -134,40 +134,61 @@ public final class FalconSealSupport {
|
|
|
|
/** Storage slot (0) at the anchor address holding the manifest hash. 64-hex, no 0x prefix. */
|
|
private static final String ANCHOR_SLOT =
|
|
"0000000000000000000000000000000000000000000000000000000000000000";
|
|
|
|
/** How many seals this node emitted on its own PREPAREs. See {@link #preparesSealed()}. */
|
|
private final java.util.concurrent.atomic.AtomicLong preparesSealed =
|
|
new java.util.concurrent.atomic.AtomicLong();
|
|
|
|
/** How many seals this node emitted on its own PROPOSALs since startup. */
|
|
private final java.util.concurrent.atomic.AtomicLong proposalsSealed =
|
|
new java.util.concurrent.atomic.AtomicLong();
|
|
|
|
/** How many seals this node emitted on its own ROUND-CHANGEs since startup. */
|
|
private final java.util.concurrent.atomic.AtomicLong roundChangesSealed =
|
|
new java.util.concurrent.atomic.AtomicLong();
|
|
|
|
private final boolean signingEnabled;
|
|
private final int localIndex;
|
|
private final FalconPrivateKeyParameters localPrivateKey;
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii: this node's NEXT Falcon keys ({@code aere.falcon.keys.next} /
|
|
+ * {@code AERE_FALCON_KEYS_NEXT}, comma list of key files in the same format as {@code
|
|
+ * aere.falcon.key}), for the v3 epochs that rotate its key. From H_k the key and the index this node
|
|
+ * signs with at a height are the ones of the v3 row that carries one of its keys (see {@link
|
|
+ * #localAt}); the file's "index" property then means nothing, because indices move between epochs.
|
|
+ */
|
|
+ private final java.util.List<FalconPrivateKeyParameters> nextPrivateKeys;
|
|
+
|
|
+ /** The local key and index resolved per v3 epoch (bindHeight), from H_k. */
|
|
+ private final Map<Long, java.util.Optional<LocalKey>> localByEpoch = new ConcurrentHashMap<>();
|
|
+
|
|
+ /**
|
|
+ * A local signing key with the registry index it signs as.
|
|
+ *
|
|
+ * @param key the private key
|
|
+ * @param index the registry index at the height it was resolved for
|
|
+ */
|
|
+ private record LocalKey(FalconPrivateKeyParameters key, int index) {}
|
|
+
|
|
private final Map<Integer, FalconPublicKeyParameters> registry;
|
|
|
|
/**
|
|
* Validator ADDRESS bound to each registry index (AUD-CONSENSUS-1 fix). Populated in lockstep
|
|
* with {@link #registry} from an address-bound manifest; empty for the legacy pubkey-only source.
|
|
* This is the map that makes {@code currentValidators INTERSECT registry} computable.
|
|
*/
|
|
private final Map<Integer, Address> indexToAddress;
|
|
|
|
private final boolean genesisAnchored;
|
|
|
|
/**
|
|
* AERE A8: the registry file this node ACTUALLY used, and which of the three sources it came from.
|
|
* Recorded so the consensus-binding guard can re-read exactly that file and hash it, rather than
|
|
* hashing something adjacent to it. Null when no registry is configured at all.
|
|
*/
|
|
private final String registrySourcePath;
|
|
|
|
private final PqRegistryHash.SourceKind registrySourceKind;
|
|
|
|
@@ -573,40 +594,70 @@ public final class FalconSealSupport {
|
|
try (InputStream in = new FileInputStream(keyPath)) {
|
|
final Properties p = new Properties();
|
|
p.load(in);
|
|
idx = Integer.parseInt(p.getProperty("index").trim());
|
|
final byte[] f = Bytes.fromHexStringLenient(p.getProperty("f").trim()).toArray();
|
|
final byte[] g = Bytes.fromHexStringLenient(p.getProperty("g").trim()).toArray();
|
|
final byte[] bigF = Bytes.fromHexStringLenient(p.getProperty("F").trim()).toArray();
|
|
final byte[] pk = Bytes.fromHexStringLenient(p.getProperty("pk").trim()).toArray();
|
|
priv = new FalconPrivateKeyParameters(FalconParameters.falcon_512, f, g, bigF, pk);
|
|
LOG.info(
|
|
"AERE PQC: loaded local Falcon signing key for validator index {} from {}",
|
|
idx,
|
|
keyPath);
|
|
} catch (final Exception e) {
|
|
LOG.warn("AERE PQC: failed to load Falcon signing key from {}: {}", keyPath, e.toString());
|
|
idx = -1;
|
|
priv = null;
|
|
}
|
|
}
|
|
|
|
+ // AERE AIP-22 stage 3b-ii: the next keys, same file format; a file that does not load refuses
|
|
+ // startup, because a validator that silently lacks its rotated key goes mute at the rotation epoch
|
|
+ final java.util.List<FalconPrivateKeyParameters> next = new java.util.ArrayList<>();
|
|
+ final String nextPaths = resolve("aere.falcon.keys.next", "AERE_FALCON_KEYS_NEXT");
|
|
+ if (nextPaths != null) {
|
|
+ for (final String np : com.google.common.base.Splitter.on(',').omitEmptyStrings().trimResults().split(nextPaths)) {
|
|
+ if (np.isBlank()) {
|
|
+ continue;
|
|
+ }
|
|
+ try (InputStream in = new FileInputStream(np.trim())) {
|
|
+ final Properties p = new Properties();
|
|
+ p.load(in);
|
|
+ next.add(
|
|
+ new FalconPrivateKeyParameters(
|
|
+ FalconParameters.falcon_512,
|
|
+ Bytes.fromHexStringLenient(p.getProperty("f").trim()).toArray(),
|
|
+ Bytes.fromHexStringLenient(p.getProperty("g").trim()).toArray(),
|
|
+ Bytes.fromHexStringLenient(p.getProperty("F").trim()).toArray(),
|
|
+ Bytes.fromHexStringLenient(p.getProperty("pk").trim()).toArray()));
|
|
+ LOG.info("AERE PQC: loaded a NEXT Falcon signing key from {} (AIP-22 stage 3b-ii)", np.trim());
|
|
+ } catch (final Exception e) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-KEY-NEXT-01: cannot load the next Falcon key from '"
|
|
+ + np.trim()
|
|
+ + "': "
|
|
+ + e.getMessage());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ this.nextPrivateKeys = java.util.List.copyOf(next);
|
|
this.registry = reg;
|
|
this.indexToAddress = regAddr;
|
|
this.localIndex = idx;
|
|
this.localPrivateKey = priv;
|
|
this.signingEnabled = priv != null && idx >= 0;
|
|
this.manifestHash = mHash;
|
|
this.genesisAnchored = anchored;
|
|
this.pendingLate = late;
|
|
this.pendingLateAddresses = lateAddr;
|
|
this.pendingLateHash = lateHash;
|
|
this.anchorContractAddress = anchorAddr;
|
|
|
|
// AERE A8: remember WHICH file the registry came from, so the consensus-binding guard hashes
|
|
// the file this node is really running on and not a different one that happens to be nearby.
|
|
if (genesisPath != null) {
|
|
this.registrySourcePath = genesisPath;
|
|
this.registrySourceKind = PqRegistryHash.SourceKind.GENESIS_MANIFEST;
|
|
} else if (manifestPath != null && anchorProp != null) {
|
|
this.registrySourcePath = manifestPath;
|
|
this.registrySourceKind = PqRegistryHash.SourceKind.MANIFEST_JSON;
|
|
@@ -2507,40 +2558,123 @@ public final class FalconSealSupport {
|
|
"AERE PQC: LATE-ANCHOR ACTIVATED - Falcon registry ({} entries, address-bound={}) is now "
|
|
+ "live; keccak256(manifest)=0x{} MATCHES the on-chain anchor at contract {} slot 0 "
|
|
+ "(readable via eth_getStorageAt). Hybrid PQC certificate can now be verified on an "
|
|
+ "already-live chain with NO re-genesis.",
|
|
registry.size(),
|
|
addressBound(),
|
|
pendingLateHash,
|
|
anchorContractAddress);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Whether this node holds a Falcon signing key and should attach a parallel seal.
|
|
*
|
|
* @return true if signing is enabled
|
|
*/
|
|
public boolean signingEnabled() {
|
|
return signingEnabled;
|
|
}
|
|
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii. The key this node signs with at a height, and the index it signs as.
|
|
+ * Below H_k (and disarmed): the key of aere.falcon.key and its file index, exactly as before. From
|
|
+ * H_k: the v3 row of the epoch in force whose Falcon key is the public key of one of this node's
|
|
+ * keys (the base key or a next key); indices move between epochs, so the index is that row's. No
|
|
+ * row carries any of this node's keys: null, so nothing is signed (the startup guard {@link
|
|
+ * #verifyLocalKeysCoverV3EpochsOrAbort} refuses a validator that would end up there).
|
|
+ */
|
|
+ private LocalKey localAt(final long height) {
|
|
+ if (!AerePqIdentity.keysFromV3(height)) {
|
|
+ return localPrivateKey == null ? null : new LocalKey(localPrivateKey, localIndex);
|
|
+ }
|
|
+ final long bind =
|
|
+ AerePqIdentity.epochAt(height).map(PqRegistryV3.Registry::bindHeight).orElse(-1L);
|
|
+ return localByEpoch
|
|
+ .computeIfAbsent(
|
|
+ bind,
|
|
+ b -> {
|
|
+ final java.util.List<FalconPrivateKeyParameters> mine = new java.util.ArrayList<>();
|
|
+ if (localPrivateKey != null) {
|
|
+ mine.add(localPrivateKey);
|
|
+ }
|
|
+ mine.addAll(nextPrivateKeys);
|
|
+ for (final FalconPrivateKeyParameters k : mine) {
|
|
+ final java.util.Optional<Integer> i =
|
|
+ AerePqIdentity.v3IndexOfKey(height, "falcon-512", k.getPublicKey());
|
|
+ if (i.isPresent()) {
|
|
+ return java.util.Optional.of(new LocalKey(k, i.get()));
|
|
+ }
|
|
+ }
|
|
+ return java.util.Optional.empty();
|
|
+ })
|
|
+ .orElse(null);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii. The registry index this node signs as at a height (the index of every
|
|
+ * other scheme's seal of this node too: an SLH-DSA seal must sit at the index of its Falcon seal).
|
|
+ *
|
|
+ * @param height the height
|
|
+ * @return the index, or -1 when this node holds no key of that height
|
|
+ */
|
|
+ public int localIndexAt(final long height) {
|
|
+ final LocalKey lk = localAt(height);
|
|
+ return lk == null ? -1 : lk.index();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii, THE STARTUP GUARD of the local keys: in every v3 epoch from H_k in which
|
|
+ * this node's identity is registered, this node must hold the Falcon key of its row, otherwise it
|
|
+ * refuses to start. A validator whose rotated key is missing would sign nothing from the rotation
|
|
+ * epoch on: mute, while every gate that asks "is it configured?" stays green (D-307).
|
|
+ *
|
|
+ * @param thisNodeAddress this node's own validator (ECDSA) address
|
|
+ */
|
|
+ public void verifyLocalKeysCoverV3EpochsOrAbort(final Address thisNodeAddress) {
|
|
+ final java.util.Optional<AerePqIdentity.Config> c = AerePqIdentity.installed();
|
|
+ if (c.isEmpty() || c.get().keysFrom() == AerePqIdentity.NEVER || thisNodeAddress == null) {
|
|
+ return;
|
|
+ }
|
|
+ for (final PqRegistryV3.Registry e : c.get().epochs().tailMap(c.get().keysFrom(), true).values()) {
|
|
+ final Address me = AerePqIdentity.author(thisNodeAddress, e.bindHeight());
|
|
+ if (e.rowOf(me.getBytes().toArrayUnsafe()).isEmpty()) {
|
|
+ continue; // this node is not a registered validator in this epoch: nothing to sign
|
|
+ }
|
|
+ if (localAt(e.bindHeight()) == null) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-KEY-NEXT-02: REFUSING TO START. This node ("
|
|
+ + thisNodeAddress
|
|
+ + ", id "
|
|
+ + me
|
|
+ + ") is registered in the v3 epoch bound at "
|
|
+ + e.bindHeight()
|
|
+ + " but holds no Falcon key of its row there (aere.falcon.key / aere.falcon.keys.next);"
|
|
+ + " from that height it would sign nothing.");
|
|
+ }
|
|
+ LOG.info(
|
|
+ "AERE PQC: local Falcon key covers the v3 epoch bound at {} (index {}).",
|
|
+ e.bindHeight(),
|
|
+ localAt(e.bindHeight()).index());
|
|
+ }
|
|
+ }
|
|
+
|
|
/**
|
|
* This node's validator index in the Falcon registry.
|
|
*
|
|
* @return the local validator index, or -1 if signing is disabled
|
|
*/
|
|
public int localIndex() {
|
|
return localIndex;
|
|
}
|
|
|
|
/**
|
|
* Number of validators in the Falcon registry.
|
|
*
|
|
* @return the registry size
|
|
*/
|
|
public int registrySize() {
|
|
return registry.size();
|
|
}
|
|
|
|
// ---- AERE audit fix (AUD-CONSENSUS-1 / -2): address binding + eligible-signer set ----
|
|
|
|
@@ -3443,47 +3577,51 @@ public final class FalconSealSupport {
|
|
* Falcon-sign a commit hash with this node's Falcon key, producing a parallel seal. Never throws.
|
|
*
|
|
* <p>AERE FIX-OPRIRE-CONSENS (b): the block number is MANDATORY and the attachment gate is
|
|
* checked here, at the single point where a seal can be produced. There is deliberately no
|
|
* height-less overload, so no call site can attach a seal without passing the gate.
|
|
*
|
|
* @param blockNumber the number of the block whose commit is being sealed
|
|
* @param commitHash the same 32-byte commit hash the ECDSA committed seal signs
|
|
* @return the Falcon seal, or empty if signing is disabled, gated off, or failed
|
|
*/
|
|
public Optional<FalconSeal> sign(final long blockNumber, final Bytes32 commitHash) {
|
|
if (!signingEnabled) {
|
|
return Optional.empty();
|
|
}
|
|
if (!attachmentArmed(blockNumber)) {
|
|
return Optional.empty();
|
|
}
|
|
// AERE AGILITY step 4 (2026-08-24): signing goes through the scheme layer. The same
|
|
// FalconSigner underneath, but the path is now the one the hybrid will use too; the 751
|
|
// baseline tests prove the equivalence.
|
|
+ final LocalKey lk = localAt(blockNumber); // AERE AIP-22 stage 3b-ii
|
|
+ if (lk == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
final java.util.Optional<byte[]> sig =
|
|
- ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(localPrivateKey, commitHash.toArray());
|
|
+ ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(lk.key(), commitHash.toArray());
|
|
if (sig.isEmpty()) {
|
|
LOG.warn("AERE PQC: Falcon signing failed (ECDSA seal unaffected)");
|
|
return Optional.empty();
|
|
}
|
|
- return Optional.of(new FalconSeal(localIndex, Bytes.wrap(sig.get())));
|
|
+ return Optional.of(new FalconSeal(lk.index(), Bytes.wrap(sig.get())));
|
|
}
|
|
|
|
/**
|
|
* Property naming the first height at which this node ATTACHES a post-quantum seal to its own
|
|
* PREPARE messages. Absent = never, which is the configuration of every node today.
|
|
*
|
|
* <p>SEPARATE from {@code aere.falcon.attachBlock}, and the separation is mandatory: if PREPARE
|
|
* emission started together with commit emission, rolling the binary onto the fleet would become
|
|
* a flag day. This way the binary can sit on every node for months before any of them emits
|
|
* anything new.
|
|
*/
|
|
public static final String PREPARE_ATTACH_PROPERTY = "aere.pq.preparePq.attachBlock";
|
|
|
|
/** Environment fallback for {@link #PREPARE_ATTACH_PROPERTY}. */
|
|
public static final String PREPARE_ATTACH_ENV = "AERE_PQ_PREPAREPQ_ATTACHBLOCK";
|
|
|
|
/**
|
|
* The configured PREPARE attachment height, read fresh on every call.
|
|
*
|
|
* <p>Absent = {@link Long#MAX_VALUE}, i.e. never. A value that is PRESENT but unreadable REFUSES
|
|
@@ -3531,63 +3669,67 @@ public final class FalconSealSupport {
|
|
* <li>its own height, above.
|
|
* </ul>
|
|
*
|
|
* <p>NEVER THROWS except for the strict configuration case above: a signing failure is a log line
|
|
* and an empty value, exactly as at commit, because the ECDSA path must not be disturbed.
|
|
*
|
|
* @param blockNumber the height being prepared
|
|
* @param message the domain-separated PREPARE message (see PqAnchor.prepareMessage)
|
|
* @return the seal, or empty when any gate is shut
|
|
*/
|
|
public Optional<FalconSeal> signPrepare(final long blockNumber, final Bytes32 message) {
|
|
if (!signingEnabled) {
|
|
return Optional.empty();
|
|
}
|
|
if (!attachmentArmed(blockNumber)) {
|
|
return Optional.empty();
|
|
}
|
|
if (blockNumber < prepareAttachBlock()) {
|
|
return Optional.empty();
|
|
}
|
|
+ final LocalKey lk = localAt(blockNumber); // AERE AIP-22 stage 3b-ii
|
|
+ if (lk == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
final java.util.Optional<byte[]> sig =
|
|
- ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(localPrivateKey, message.toArray());
|
|
+ ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(lk.key(), message.toArray());
|
|
if (sig.isEmpty()) {
|
|
LOG.warn("AERE PQ PREPARE: Falcon signing failed (ECDSA path unaffected)");
|
|
return Optional.empty();
|
|
}
|
|
final long n = preparesSealed.incrementAndGet();
|
|
// LOG VOLUME IS A DECISION, not an oversight. One line per PREPARE would be two lines per
|
|
// second per node, which is exactly the kind of log that gets trained away (see D-153, where a
|
|
// permanent ERROR made an entire log worthless). The first emission is worth a line, because it
|
|
// is the moment the node starts doing something new; after that, one line every 500, so a
|
|
// testnet still has a number to count.
|
|
if (n == 1L) {
|
|
LOG.info(
|
|
"AERE PQ PREPARE: this node EMITTED its first post-quantum seal on a PREPARE, at "
|
|
+ "height {} (gate {}={}). From here on its PREPAREs carry a seal.",
|
|
blockNumber,
|
|
PREPARE_ATTACH_PROPERTY,
|
|
prepareAttachBlock());
|
|
} else if (n % 500L == 0L) {
|
|
LOG.info("AERE PQ PREPARE: {} seals emitted on PREPAREs since startup.", n);
|
|
}
|
|
- return Optional.of(new FalconSeal(localIndex, Bytes.wrap(sig.get())));
|
|
+ return Optional.of(new FalconSeal(lk.index(), Bytes.wrap(sig.get())));
|
|
}
|
|
|
|
/**
|
|
* How many seals this node has emitted on PREPAREs since startup.
|
|
*
|
|
* <p>It exists so that the COVERAGE step can be measured: without a number, arming enforcement
|
|
* would be a bet. Read from the log on a testnet, and from this value in tests.
|
|
*
|
|
* @return the count
|
|
*/
|
|
public long preparesSealed() {
|
|
return preparesSealed.get();
|
|
}
|
|
|
|
/**
|
|
* Property naming the first height at which this node ATTACHES a post-quantum seal to its own
|
|
* PROPOSAL messages. Absent = never, which is the configuration of every node today.
|
|
*
|
|
* <p>SEPARATE from both the commit and the PREPARE gates, same reason: three layers that arm on
|
|
* three independent decisions must not share a switch, or the day one is turned on becomes a flag
|
|
@@ -3636,60 +3778,64 @@ public final class FalconSealSupport {
|
|
*
|
|
* <p>Same three requirements as {@link #signPrepare}, for the same three reasons: a key, the
|
|
* commit-layer coverage conditions, and its own height. NEVER throws except for the strict
|
|
* configuration case: a signing failure is a log line and an empty value, because the ECDSA path
|
|
* must not be disturbed.
|
|
*
|
|
* @param blockNumber the height being proposed
|
|
* @param message the domain-separated PROPOSAL message (see PqAnchor.proposalMessage)
|
|
* @return the seal, or empty when any gate is shut
|
|
*/
|
|
public Optional<FalconSeal> signProposal(final long blockNumber, final Bytes32 message) {
|
|
if (!signingEnabled) {
|
|
return Optional.empty();
|
|
}
|
|
if (!attachmentArmed(blockNumber)) {
|
|
return Optional.empty();
|
|
}
|
|
if (blockNumber < proposalAttachBlock()) {
|
|
return Optional.empty();
|
|
}
|
|
+ final LocalKey lk = localAt(blockNumber); // AERE AIP-22 stage 3b-ii
|
|
+ if (lk == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
final java.util.Optional<byte[]> sig =
|
|
- ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(localPrivateKey, message.toArray());
|
|
+ ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(lk.key(), message.toArray());
|
|
if (sig.isEmpty()) {
|
|
LOG.warn("AERE PQ PROPOSAL: Falcon signing failed (ECDSA path unaffected)");
|
|
return Optional.empty();
|
|
}
|
|
final long n = proposalsSealed.incrementAndGet();
|
|
// Same log-volume decision as at PREPARE: a proposal is at most one per round per proposer, so
|
|
// this is quieter by nature, but the counter still steps so a testnet has a number to count.
|
|
if (n == 1L) {
|
|
LOG.info(
|
|
"AERE PQ PROPOSAL: this node EMITTED its first post-quantum seal on a PROPOSAL, at "
|
|
+ "height {} (gate {}={}). From here on its proposals carry a seal.",
|
|
blockNumber,
|
|
PROPOSAL_ATTACH_PROPERTY,
|
|
proposalAttachBlock());
|
|
} else if (n % 500L == 0L) {
|
|
LOG.info("AERE PQ PROPOSAL: {} seals emitted on PROPOSALs since startup.", n);
|
|
}
|
|
- return Optional.of(new FalconSeal(localIndex, Bytes.wrap(sig.get())));
|
|
+ return Optional.of(new FalconSeal(lk.index(), Bytes.wrap(sig.get())));
|
|
}
|
|
|
|
/**
|
|
* How many seals this node has emitted on its own PROPOSALs since startup. Exists so the
|
|
* coverage step can be measured, exactly as at PREPARE.
|
|
*
|
|
* @return the count
|
|
*/
|
|
public long proposalsSealed() {
|
|
return proposalsSealed.get();
|
|
}
|
|
|
|
/**
|
|
* The property that opens the ROUND-CHANGE attachment gate: from this height on, this node's own
|
|
* round-changes carry a Falcon seal. Emission only - enforcement is {@code
|
|
* aere.pq.roundChangePq.forkBlock}, deliberately separate so the fleet can emit long before any
|
|
* node refuses, exactly as at PREPARE and PROPOSAL.
|
|
*/
|
|
public static final String ROUNDCHANGE_ATTACH_PROPERTY = "aere.pq.roundChangePq.attachBlock";
|
|
|
|
@@ -3735,60 +3881,64 @@ public final class FalconSealSupport {
|
|
*
|
|
* <p>Same three requirements as {@link #signPrepare} and {@link #signProposal}, for the same
|
|
* three reasons: a key, the commit-layer coverage conditions, and its own height. NEVER throws
|
|
* except for the strict configuration case: a signing failure is a log line and an empty value,
|
|
* because the ECDSA path must not be disturbed.
|
|
*
|
|
* @param blockNumber the height the round-change targets
|
|
* @param message the domain-separated ROUND-CHANGE message (see PqAnchor.roundChangeMessage)
|
|
* @return the seal, or empty when any gate is shut
|
|
*/
|
|
public Optional<FalconSeal> signRoundChange(final long blockNumber, final Bytes32 message) {
|
|
if (!signingEnabled) {
|
|
return Optional.empty();
|
|
}
|
|
if (!attachmentArmed(blockNumber)) {
|
|
return Optional.empty();
|
|
}
|
|
if (blockNumber < roundChangeAttachBlock()) {
|
|
return Optional.empty();
|
|
}
|
|
+ final LocalKey lk = localAt(blockNumber); // AERE AIP-22 stage 3b-ii
|
|
+ if (lk == null) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
final java.util.Optional<byte[]> sig =
|
|
- ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(localPrivateKey, message.toArray());
|
|
+ ((FalconSealScheme) SealSchemes.FALCON_512).signWithParams(lk.key(), message.toArray());
|
|
if (sig.isEmpty()) {
|
|
LOG.warn("AERE PQ ROUNDCHANGE: Falcon signing failed (ECDSA path unaffected)");
|
|
return Optional.empty();
|
|
}
|
|
final long n = roundChangesSealed.incrementAndGet();
|
|
// Round-changes only exist when rounds FAIL, so on a healthy chain this counter barely moves;
|
|
// it still steps so a testnet that forces round-changes has a number to count.
|
|
if (n == 1L) {
|
|
LOG.info(
|
|
"AERE PQ ROUNDCHANGE: this node EMITTED its first post-quantum seal on a ROUND-CHANGE, "
|
|
+ "at height {} (gate {}={}). From here on its round-changes carry a seal.",
|
|
blockNumber,
|
|
ROUNDCHANGE_ATTACH_PROPERTY,
|
|
roundChangeAttachBlock());
|
|
} else if (n % 100L == 0L) {
|
|
LOG.info("AERE PQ ROUNDCHANGE: {} seals emitted on ROUND-CHANGEs since startup.", n);
|
|
}
|
|
- return Optional.of(new FalconSeal(localIndex, Bytes.wrap(sig.get())));
|
|
+ return Optional.of(new FalconSeal(lk.index(), Bytes.wrap(sig.get())));
|
|
}
|
|
|
|
/**
|
|
* How many seals this node has emitted on its own ROUND-CHANGEs since startup. Exists so the
|
|
* coverage step can be measured, exactly as at PREPARE and PROPOSAL.
|
|
*
|
|
* @return the count
|
|
*/
|
|
public long roundChangesSealed() {
|
|
return roundChangesSealed.get();
|
|
}
|
|
|
|
/**
|
|
* Verify a Falcon seal against the registry public key for its validator index. Never throws.
|
|
*
|
|
* @param validatorIndex the signer index
|
|
* @param commitHash the commit hash that was signed
|
|
* @param signature the Falcon signature bytes
|
|
* @return true iff a registry public key exists for the index and the signature verifies
|
|
*/
|
|
@@ -3796,40 +3946,49 @@ public final class FalconSealSupport {
|
|
return verifyWithKey(registry.get(validatorIndex), validatorIndex, commitHash, signature);
|
|
}
|
|
|
|
/**
|
|
* D-081. The Falcon public key registered for an index AT A HEIGHT: the one carried by the
|
|
* registry the chain's schedule makes active there.
|
|
*
|
|
* <p>WHY A HEIGHT IS NEEDED AT ALL. A certificate inside a block at height h was produced under
|
|
* the key set the chain required at h. After a rotation the node's own head registry is a
|
|
* different key set, so checking an old block against it fails for a reason that has nothing to do
|
|
* with the block. Cosmos ADR-016 states the same requirement for the same reason and keeps a
|
|
* height-to-key mapping; the only difference here is that ours is never pruned, because this chain
|
|
* has no unbonding period and a node syncing from genesis verifies every block ever produced.
|
|
*
|
|
* <p>Returns the head registry's key when no binding is active at that height, which is every
|
|
* height below the schedule's first entry and every height on a chain with no schedule at all. So
|
|
* a node on chain 2800 as it stands today gets exactly what it got before D-081.
|
|
*/
|
|
private FalconPublicKeyParameters keyAt(
|
|
final long blockNumber, final int validatorIndex, final boolean historic) {
|
|
+ // AERE AIP-22 stage 3b: from H_k the key of an index is the one of the v3 epoch in force at this
|
|
+ // SAME height (the caller's convention is kept: the parent of an anchor for its certificate). No
|
|
+ // row or no key there means no key: never a fall-back to the registries below, which above H_k
|
|
+ // are no longer the key set the chain requires. Below H_k (and disarmed) nothing changes.
|
|
+ if (AerePqIdentity.keysFromV3(blockNumber)) {
|
|
+ return AerePqIdentity.v3KeyAt(blockNumber, validatorIndex, "falcon-512")
|
|
+ .map(pk -> new FalconPublicKeyParameters(FalconParameters.falcon_512, pk))
|
|
+ .orElse(null);
|
|
+ }
|
|
final PqRegistryHash.Schedule schedule = this.registryBindingSchedule;
|
|
final PqRegistryHash.RegistrySet set = this.registryBindingSet;
|
|
if (schedule == null || set == null) {
|
|
return headRegistryKeyOrRefuse(
|
|
blockNumber, validatorIndex, "no schedule was ever loaded", historic);
|
|
}
|
|
final Optional<PqRegistryHash.ScheduleEntry> required =
|
|
PqRegistryHash.requiredHashAt(schedule, blockNumber);
|
|
if (required.isEmpty()) {
|
|
// D-228. The only historical question ever asked one block below the schedule's first entry
|
|
// is about the certificate carried by the block at blockNumber+1, whose governing registry
|
|
// is the one bound EXACTLY at blockNumber+1. Answer it from that entry's VERIFIED bound
|
|
// registry, never from the unverified head file. Exactly one block: at blockNumber+2 below
|
|
// the schedule nothing changes.
|
|
final Optional<PqRegistryHash.ScheduleEntry> nextEntry =
|
|
PqRegistryHash.requiredHashAt(schedule, blockNumber + 1);
|
|
if (nextEntry.isPresent() && nextEntry.get().block() == blockNumber + 1) {
|
|
final Optional<PqRegistryHash.Registry> boundNext =
|
|
PqRegistryHash.registryAt(schedule, set, blockNumber + 1);
|
|
if (boundNext.isPresent()) {
|
|
@@ -3851,40 +4010,54 @@ public final class FalconSealSupport {
|
|
}
|
|
final Optional<PqRegistryHash.Registry> active =
|
|
PqRegistryHash.registryAt(schedule, set, blockNumber);
|
|
if (active.isEmpty()) {
|
|
// The entry active here is covered by nothing this node holds. Fail closed: no key, so no
|
|
// seal verifies, and the per-block binding rule has already refused the header for the same
|
|
// reason. Silence here would be the node deciding a question it cannot answer.
|
|
return null;
|
|
}
|
|
for (final PqRegistryHash.Entry e : active.get().entries()) {
|
|
if (e.index() == validatorIndex) {
|
|
final FalconPublicKeyParameters pub =
|
|
new FalconPublicKeyParameters(FalconParameters.falcon_512, e.publicKey());
|
|
historicalKeys.put(cacheKey, pub);
|
|
return pub;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b. The Falcon-512 public key (the 896-byte h, as the registries carry it) that
|
|
+ * the chain's registries give an index at a height, through the same history door as a received
|
|
+ * header. Used by the continuity guard at H_k - 1, where the v3 epochs do not yet supply keys.
|
|
+ *
|
|
+ * @param blockNumber the height
|
|
+ * @param validatorIndex the registry index
|
|
+ * @return the key, or empty when the registries give none there
|
|
+ */
|
|
+ public Optional<byte[]> publicKeyBytesAtHistoric(final long blockNumber, final int validatorIndex) {
|
|
+ final FalconPublicKeyParameters k = keyAt(blockNumber, validatorIndex, true);
|
|
+ return k == null ? Optional.empty() : Optional.of(k.getH().clone());
|
|
+ }
|
|
+
|
|
/**
|
|
* D-081. The validator ADDRESS bound to a registry index at a height.
|
|
*
|
|
* <p>D2 HARDENING (b-v2): PRIVATE, with the caller's motive as an argument. The two public
|
|
* doors are {@link #addressForIndexAtHistoric} and {@link #addressForIndexAtOwnHead}, each of
|
|
* which passes a constant. Nothing outside this file can choose the value, so the one shared
|
|
* resolution body cannot drift between the two paths and no caller can pick the wrong flag.
|
|
*
|
|
* @param blockNumber the height of the header being validated
|
|
* @param validatorIndex the registry index carried by a Falcon seal
|
|
* @param historic true when the subject is a header this node received, false when it is this
|
|
* node's own head or the block it is building
|
|
* @return the bound address, or null when the index is unregistered at that height or the
|
|
* registry active there is not address-bound
|
|
*/
|
|
private Address addressAt(
|
|
final long blockNumber, final int validatorIndex, final boolean historic) {
|
|
final PqRegistryHash.Schedule schedule = this.registryBindingSchedule;
|
|
final PqRegistryHash.RegistrySet set = this.registryBindingSet;
|
|
if (schedule == null || set == null) {
|
|
@@ -3983,52 +4156,65 @@ public final class FalconSealSupport {
|
|
* @param signature the Falcon signature bytes
|
|
* @return true iff a key exists for the index there and the signature verifies
|
|
*/
|
|
public boolean verifyAtOwnHead(
|
|
final long blockNumber,
|
|
final int validatorIndex,
|
|
final Bytes commitHash,
|
|
final Bytes signature) {
|
|
return verifyWithKey(
|
|
keyAt(blockNumber, validatorIndex, false), validatorIndex, commitHash, signature);
|
|
}
|
|
|
|
/**
|
|
* D-081 / D2 HARDENING (b-v2). THE HISTORY DOOR, address half. See {@link #verifyAtHistoric}.
|
|
*
|
|
* @param blockNumber the height of the header being validated
|
|
* @param validatorIndex the registry index carried by a Falcon seal
|
|
* @return the bound address, or null when nothing binds that index at that height
|
|
*/
|
|
public Address addressForIndexAtHistoric(final long blockNumber, final int validatorIndex) {
|
|
- return addressAt(blockNumber, validatorIndex, true);
|
|
+ // AERE AIP-22 stage 3b: from H_k the index names the v3 row directly (its id), like its key
|
|
+ if (AerePqIdentity.keysFromV3(blockNumber)) {
|
|
+ return AerePqIdentity.v3IdAt(blockNumber, validatorIndex).orElse(null);
|
|
+ }
|
|
+ return identityOf(addressAt(blockNumber, validatorIndex, true), blockNumber);
|
|
}
|
|
|
|
/**
|
|
* D2 HARDENING (b-v2). THE OWN-HEAD DOOR, address half. See {@link #verifyAtOwnHead}.
|
|
*
|
|
* @param blockNumber this node's own head, or the block it is building
|
|
* @param validatorIndex the registry index
|
|
* @return the bound address, or null
|
|
*/
|
|
public Address addressForIndexAtOwnHead(final long blockNumber, final int validatorIndex) {
|
|
- return addressAt(blockNumber, validatorIndex, false);
|
|
+ // AERE AIP-22 stage 3b: from H_k the index names the v3 row directly (its id), like its key
|
|
+ if (AerePqIdentity.keysFromV3(blockNumber)) {
|
|
+ return AerePqIdentity.v3IdAt(blockNumber, validatorIndex).orElse(null);
|
|
+ }
|
|
+ return identityOf(addressAt(blockNumber, validatorIndex, false), blockNumber);
|
|
+ }
|
|
+
|
|
+ /** AERE AIP-22 stage 3: the registry's classical address for an index, as the identity of the height. */
|
|
+ private static Address identityOf(final Address registryAddress, final long blockNumber) {
|
|
+ return registryAddress == null ? null : AerePqIdentity.author(registryAddress, blockNumber);
|
|
}
|
|
|
|
/**
|
|
* D2 HARDENING (b). The one decision the whole hardening turns on, isolated so that removing it is
|
|
* a one-line edit and the negative control can prove the D2 test goes red without it.
|
|
*
|
|
* <p>THE MEASURED DEFECT. Both height-resolved lookups used to answer a height they had no binding
|
|
* for by returning the HEAD registry - the key set in force right now. Below the arming height
|
|
* that is correct and costs nothing: no certificate is being judged there. At and above it, it is
|
|
* D2/T2 verbatim: "an armed node verifies a year-old header against the keys it holds today", so
|
|
* one rotation makes every block between the arming height and the rotation unverifiable, and the
|
|
* node reports success while doing it. Refusing is the only answer that does not assert a check
|
|
* that was not performed.
|
|
*
|
|
* <p>WHAT A REFUSAL COSTS AND WHY IT IS THE CHEAPER FAILURE. A null key makes every seal fail, so
|
|
* {@code PqAnchorSealsRule} refuses the header and the node stops at the first block at or above
|
|
* the arming height. It stops; it does not fork. A node that cannot say which keys were in force
|
|
* cannot forge a competing history either, and the repair is to configure {@code
|
|
* config.pqRegistryHash} plus {@code aere.falcon.registry.history} and restart. Compare the
|
|
* silence this replaces, where the same node imports the whole chain and calls it verified.
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducer.java
|
|
index 591ede15ed..8fd27c7a77 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducer.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducer.java
|
|
@@ -26,115 +26,218 @@ import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/** Produces the non-Falcon scheme seals a hybrid commit carries, gated on height. */
|
|
public final class HybridSealProducer {
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(HybridSealProducer.class);
|
|
|
|
/** The disarmed attachment height: no block ever reaches it, so nothing is ever emitted. */
|
|
public static final long NEVER = Long.MAX_VALUE;
|
|
|
|
private final long attachFromBlock;
|
|
private final PqSchemeSchedule schedule;
|
|
private final int validatorIndex;
|
|
private final Map<String, SealScheme.PrivateHandle> localKeys;
|
|
+ // AERE AIP-22 stage 3b-ii: this node's NEXT keys per scheme (rotations), and its local index by height (from H_k the index of
|
|
+ // its Falcon seal at that height, since an extra seal must sit at the index of its Falcon seal)
|
|
+ private final Map<String, List<SealScheme.PrivateHandle>> nextKeys;
|
|
+ private final java.util.function.LongToIntFunction localIndexAt;
|
|
+ private final Map<String, Optional<SealScheme.PrivateHandle>> v3KeyByEpoch = new java.util.concurrent.ConcurrentHashMap<>();
|
|
+ // the origin of every anchor grid of the chain (AIP-22 stage 2: per-scheme intervals count from it)
|
|
+ private final long anchorBlock;
|
|
// one shout per missing scheme, not one per block: a permanent alarm is learned and ignored
|
|
private final Set<String> alreadyShouted = new java.util.HashSet<>();
|
|
|
|
/**
|
|
+ * A producer for schedules WITHOUT per-scheme intervals (every named scheme at every anchor),
|
|
+ * which is every schedule written before AIP-22 stage 2; the grid origin is irrelevant then.
|
|
+ *
|
|
* @param attachFromBlock first height at which extras may be emitted; {@link #NEVER} to disarm
|
|
* @param schedule which schemes are required at which height; null disarms as well
|
|
* @param validatorIndex this node's index, written into every seal it produces
|
|
* @param localKeys the private handles this node holds, per scheme id
|
|
*/
|
|
public HybridSealProducer(
|
|
final long attachFromBlock,
|
|
final PqSchemeSchedule schedule,
|
|
final int validatorIndex,
|
|
final Map<String, SealScheme.PrivateHandle> localKeys) {
|
|
+ this(attachFromBlock, schedule, validatorIndex, localKeys, 0L);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * @param attachFromBlock first height at which extras may be emitted; {@link #NEVER} to disarm
|
|
+ * @param schedule which schemes are required at which height; null disarms as well
|
|
+ * @param validatorIndex this node's index, written into every seal it produces
|
|
+ * @param localKeys the private handles this node holds, per scheme id
|
|
+ * @param anchorBlock the chain's anchor activation height, origin of the per-scheme grids
|
|
+ */
|
|
+ public HybridSealProducer(
|
|
+ final long attachFromBlock,
|
|
+ final PqSchemeSchedule schedule,
|
|
+ final int validatorIndex,
|
|
+ final Map<String, SealScheme.PrivateHandle> localKeys,
|
|
+ final long anchorBlock) {
|
|
+ this.attachFromBlock = schedule == null ? NEVER : attachFromBlock;
|
|
+ this.schedule = schedule;
|
|
+ this.validatorIndex = validatorIndex;
|
|
+ this.localKeys = localKeys == null ? Map.of() : Map.copyOf(localKeys);
|
|
+ this.anchorBlock = anchorBlock;
|
|
+ this.nextKeys = Map.of();
|
|
+ this.localIndexAt = h -> FalconSealSupport.instance().localIndexAt(h);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii: a producer that also holds NEXT keys and resolves its index by height.
|
|
+ *
|
|
+ * @param attachFromBlock first height at which extras may be emitted; {@link #NEVER} to disarm
|
|
+ * @param schedule which schemes are required at which height; null disarms as well
|
|
+ * @param validatorIndex this node's index below H_k
|
|
+ * @param localKeys the private handles this node holds, per scheme id
|
|
+ * @param anchorBlock the chain's anchor activation height, origin of the per-scheme grids
|
|
+ * @param nextKeys the next private handles per scheme id, for v3 epochs that rotate this node's keys
|
|
+ * @param localIndexAt this node's index at a height (from H_k: the index of its Falcon seal there)
|
|
+ */
|
|
+ public HybridSealProducer(
|
|
+ final long attachFromBlock,
|
|
+ final PqSchemeSchedule schedule,
|
|
+ final int validatorIndex,
|
|
+ final Map<String, SealScheme.PrivateHandle> localKeys,
|
|
+ final long anchorBlock,
|
|
+ final Map<String, List<SealScheme.PrivateHandle>> nextKeys,
|
|
+ final java.util.function.LongToIntFunction localIndexAt) {
|
|
this.attachFromBlock = schedule == null ? NEVER : attachFromBlock;
|
|
this.schedule = schedule;
|
|
this.validatorIndex = validatorIndex;
|
|
this.localKeys = localKeys == null ? Map.of() : Map.copyOf(localKeys);
|
|
+ this.anchorBlock = anchorBlock;
|
|
+ this.nextKeys = nextKeys == null ? Map.of() : Map.copyOf(nextKeys);
|
|
+ this.localIndexAt = localIndexAt;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii: the key of a scheme this node signs with at a height from H_k, and the index it signs as: the local
|
|
+ * handle (base or next) whose probe signature verifies under the key of this node's row in the v3 epoch in force.
|
|
+ *
|
|
+ * @param scheme the scheme
|
|
+ * @param height the height
|
|
+ * @return the handle, or empty when this node holds no key of its row there (or has no row)
|
|
+ */
|
|
+ public Optional<SealScheme.PrivateHandle> v3KeyAt(final SealScheme scheme, final long height) {
|
|
+ final int index = localIndexAt.applyAsInt(height);
|
|
+ if (index < 0) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final long bind = AerePqIdentity.epochAt(height).map(PqRegistryV3.Registry::bindHeight).orElse(-1L);
|
|
+ return v3KeyByEpoch.computeIfAbsent(
|
|
+ bind + ":" + index + ":" + scheme.id(),
|
|
+ k -> {
|
|
+ final Optional<byte[]> rowKey = AerePqIdentity.v3KeyAt(height, index, scheme.id());
|
|
+ if (rowKey.isEmpty()) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final List<SealScheme.PrivateHandle> mine = new ArrayList<>();
|
|
+ if (localKeys.get(scheme.id()) != null) {
|
|
+ mine.add(localKeys.get(scheme.id()));
|
|
+ }
|
|
+ mine.addAll(nextKeys.getOrDefault(scheme.id(), List.of()));
|
|
+ final byte[] probe = ("AERE-HYBRID-KEY-PROBE-V3:" + bind + ":" + index).getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
|
+ for (final SealScheme.PrivateHandle h : mine) {
|
|
+ final Optional<byte[]> sig = scheme.sign(h, probe);
|
|
+ if (sig.isPresent() && scheme.verifyRaw(rowKey.get(), probe, sig.get())) {
|
|
+ return Optional.of(h);
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ });
|
|
}
|
|
|
|
/** A producer that never emits anything: the configuration of every node today. */
|
|
public static HybridSealProducer disarmed() {
|
|
return new HybridSealProducer(NEVER, null, -1, Map.of());
|
|
}
|
|
|
|
/**
|
|
* Whether extras may be emitted at this height at all.
|
|
*
|
|
* @param blockNumber the height
|
|
* @return true when the attachment gate is open
|
|
*/
|
|
public boolean attachmentArmedAt(final long blockNumber) {
|
|
return schedule != null && blockNumber >= attachFromBlock;
|
|
}
|
|
|
|
/**
|
|
* The extra scheme seals for this block, or an empty list.
|
|
*
|
|
* <p>Never throws: a producer fault must never take down the ECDSA commit path. Every refusal
|
|
* is a logged reason plus an empty list, exactly the stance of the Falcon signer.
|
|
*
|
|
+ * <p>The block being committed is the PARENT of the anchor the seals serve (the caller only asks
|
|
+ * at anchor parents, D-329), so the schemes are those the anchor at {@code blockNumber + 1}
|
|
+ * requires: with per-scheme intervals (AIP-22 stage 2) a scheme on a coarser grid is not
|
|
+ * signed at the parent of an anchor that does not demand it.
|
|
+ *
|
|
* @param blockNumber the height of the block being committed
|
|
* @param message the very bytes the Falcon seal of this commit signs
|
|
* @return the seals, or empty when the gate is shut, a key is missing, or signing failed
|
|
*/
|
|
public List<SchemeSeal> sealsFor(final long blockNumber, final Bytes message) {
|
|
if (!attachmentArmedAt(blockNumber) || message == null) {
|
|
return List.of();
|
|
}
|
|
try {
|
|
- final Set<String> required = schedule.schemesAt(blockNumber);
|
|
+ final Set<String> required = schedule.schemesRequiredForAnchor(blockNumber + 1L, anchorBlock);
|
|
final List<SchemeSeal> produced = new ArrayList<>();
|
|
for (final String schemeId : required) {
|
|
if (SealSchemes.FALCON_512.id().equals(schemeId)) {
|
|
continue; // Falcon has its own slot and its own signer; never duplicated here
|
|
}
|
|
final Optional<SealScheme> scheme = SealSchemes.byId(schemeId);
|
|
if (scheme.isEmpty()) {
|
|
shoutOnce(schemeId, "the schedule names scheme '" + schemeId
|
|
+ "' which this binary does not implement");
|
|
return List.of();
|
|
}
|
|
- final SealScheme.PrivateHandle key = localKeys.get(schemeId);
|
|
+ // AERE AIP-22 stage 3b-ii: from H_k the key of this node's row in the v3 epoch in force, at its Falcon index there
|
|
+ final boolean v3 = AerePqIdentity.keysFromV3(blockNumber);
|
|
+ final SealScheme.PrivateHandle key =
|
|
+ v3 ? v3KeyAt(scheme.get(), blockNumber).orElse(null) : localKeys.get(schemeId);
|
|
+ final int index = v3 ? localIndexAt.applyAsInt(blockNumber) : validatorIndex;
|
|
if (key == null) {
|
|
shoutOnce(schemeId, "this node holds NO " + schemeId
|
|
+ " signing key, so it cannot produce the certificate the schedule requires from"
|
|
+ " height " + blockNumber + " onwards");
|
|
return List.of();
|
|
}
|
|
final Optional<byte[]> signature = scheme.get().sign(key, message.toArray());
|
|
if (signature.isEmpty()) {
|
|
shoutOnce(schemeId, "signing with the local " + schemeId + " key FAILED");
|
|
return List.of();
|
|
}
|
|
produced.add(
|
|
- new SchemeSeal(scheme.get().wireId(), validatorIndex, Bytes.wrap(signature.get())));
|
|
+ new SchemeSeal(scheme.get().wireId(), index, Bytes.wrap(signature.get())));
|
|
}
|
|
// Canonical order, so two honest nodes signing the same block emit identical bytes and the
|
|
// certificate cannot become a source of gratuitous divergence.
|
|
produced.sort(PqAnchorV2.CANONICAL);
|
|
return List.copyOf(produced);
|
|
} catch (final RuntimeException e) {
|
|
LOG.warn("AERE HIBRID: producer fault at block {}, emitting nothing: {}",
|
|
blockNumber, e.getMessage());
|
|
return List.of();
|
|
}
|
|
}
|
|
|
|
private void shoutOnce(final String schemeId, final String what) {
|
|
if (alreadyShouted.add(schemeId)) {
|
|
LOG.error("AERE HIBRID: {} - NO hybrid certificate will be emitted by this node."
|
|
+ " Fix this BEFORE the enforcement height, not on the day.", what);
|
|
}
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealSupport.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealSupport.java
|
|
index 34f362d8d6..2bb8679682 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealSupport.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/HybridSealSupport.java
|
|
@@ -147,40 +147,60 @@ public final class HybridSealSupport {
|
|
"AERE-PQC-COMMIT-CONF-03: " + PROPERTY_SCHEDULE + " and " + PROPERTY_REGISTRY
|
|
+ " are a PAIR; configure both or neither. Half a hybrid configuration must"
|
|
+ " refuse at startup, never run half-armed in silence.");
|
|
}
|
|
if (rawSchedule == null) {
|
|
if (rawAttach != null) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-04: " + PROPERTY_ATTACH_BLOCK + " is set but the schedule and"
|
|
+ " registry are not: this node would EMIT seals nobody can verify.");
|
|
}
|
|
return new HybridSealSupport(null, null, HybridSealProducer.disarmed());
|
|
}
|
|
|
|
final PqSchemeSchedule schedule;
|
|
try {
|
|
schedule = PqSchemeSchedule.parse(rawSchedule);
|
|
} catch (final RuntimeException e) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-04: unparseable " + PROPERTY_SCHEDULE + ": " + e.getMessage());
|
|
}
|
|
+ // AIP-22 stage 2: a per-scheme interval must be a multiple of the anchor interval this node
|
|
+ // runs, otherwise the scheme would be demanded at heights that are not anchors at all, and
|
|
+ // the two grids are only known together here. Refuse at startup, never run half-armed.
|
|
+ final PqAnchorConfig anchorConfig =
|
|
+ org.hyperledger.besu.consensus.common.bft.blockcreation.PqAnchorProducer.config();
|
|
+ if (schedule.hasIntervals() && anchorConfig.anchorInterval().isPresent()) {
|
|
+ final int base = anchorConfig.anchorInterval().getAsInt();
|
|
+ for (final PqSchemeSchedule.Step step : schedule.steps()) {
|
|
+ for (final Map.Entry<String, Integer> e : step.intervals().entrySet()) {
|
|
+ if (e.getValue() % base != 0) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-HYBRID-CONF-06: " + PROPERTY_SCHEDULE + " gives scheme '" + e.getKey()
|
|
+ + "' the interval " + e.getValue() + " at " + step.fromBlock()
|
|
+ + ", which is not a multiple of this node's anchor interval " + base
|
|
+ + " (" + PqAnchorConfig.PROPERTY_ANCHOR_INTERVAL + "); the scheme would be"
|
|
+ + " demanded at heights that carry no certificate. Refusing to start.");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
final HybridSignerRegistry registry;
|
|
try {
|
|
final Properties p = new Properties();
|
|
p.load(
|
|
new java.io.StringReader(
|
|
new String(reader.file(rawRegistry), StandardCharsets.UTF_8)));
|
|
registry = HybridSignerRegistry.fromProperties(p, rawRegistry);
|
|
} catch (final IOException e) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-04: cannot read " + PROPERTY_REGISTRY + " '" + rawRegistry
|
|
+ "': " + e.getMessage());
|
|
}
|
|
|
|
long attachFrom = HybridSealProducer.NEVER;
|
|
if (rawAttach != null) {
|
|
try {
|
|
attachFrom = Long.parseLong(rawAttach.trim());
|
|
if (attachFrom < 0) {
|
|
throw new NumberFormatException("negative");
|
|
}
|
|
@@ -236,60 +256,128 @@ public final class HybridSealSupport {
|
|
if (sig.isEmpty() || !scheme.verifyRaw(pub.get(), probe, sig.get())) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-05: the local " + scheme.id() + " key at index " + index
|
|
+ " does NOT verify against the registry's public key. Wrong key, wrong index,"
|
|
+ " or wrong registry; refusing to start half-armed.");
|
|
}
|
|
if (boundIndex != null && boundIndex != index) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-05: local hybrid keys disagree on the validator index ("
|
|
+ boundIndex + " vs " + index + "). One node, one identity.");
|
|
}
|
|
boundIndex = index;
|
|
keys.put(scheme.id(), handle);
|
|
LOG.info(
|
|
"AERE HIBRID: loaded local {} signing key for validator index {} (probe verified"
|
|
+ " against the registry)",
|
|
scheme.id(),
|
|
index);
|
|
}
|
|
|
|
+ // AERE AIP-22 stage 3b-ii: this node's NEXT keys per scheme (aere.pq.hybrid.key.<scheme>.next, comma list, same file
|
|
+ // format). They belong to later v3 epochs, so no registry probe here: the startup guard checks each against its v3 row.
|
|
+ final Map<String, java.util.List<SealScheme.PrivateHandle>> next = new HashMap<>();
|
|
+ for (final SealScheme scheme : SealSchemes.all()) {
|
|
+ if (scheme.id().equals(SealSchemes.FALCON_512.id())) {
|
|
+ continue;
|
|
+ }
|
|
+ final String paths = reader.property(PROPERTY_KEY_PREFIX + scheme.id() + ".next");
|
|
+ if (paths == null) {
|
|
+ continue;
|
|
+ }
|
|
+ for (final String np : com.google.common.base.Splitter.on(',').omitEmptyStrings().trimResults().split(paths)) {
|
|
+ if (np.isBlank()) {
|
|
+ continue;
|
|
+ }
|
|
+ try {
|
|
+ final Properties kp = new Properties();
|
|
+ kp.load(new java.io.StringReader(new String(reader.file(np.trim()), StandardCharsets.UTF_8)));
|
|
+ final byte[] sk = Bytes.fromHexStringLenient(kp.getProperty("sk", "").trim()).toArray();
|
|
+ next.computeIfAbsent(scheme.id(), x -> new java.util.ArrayList<>())
|
|
+ .add(scheme.parsePrivateKey(sk).orElseThrow(() -> new IllegalStateException("bytes do not parse as a private key")));
|
|
+ LOG.info("AERE HIBRID: loaded a NEXT {} signing key from {} (AIP-22 stage 3b-ii)", scheme.id(), np.trim());
|
|
+ } catch (final IOException | RuntimeException e) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-KEY-NEXT-01: cannot load the next " + scheme.id() + " key from '" + np.trim() + "': " + e.getMessage());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
if (attachFrom != HybridSealProducer.NEVER && keys.isEmpty()) {
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-HYBRID-CONF-04: emission is armed from " + attachFrom + " but this node"
|
|
+ " holds no local hybrid key (" + PROPERTY_KEY_PREFIX + "<scheme> unset)."
|
|
+ " It would promise a certificate it cannot produce.");
|
|
}
|
|
|
|
final HybridSealProducer producer =
|
|
keys.isEmpty()
|
|
? HybridSealProducer.disarmed()
|
|
- : new HybridSealProducer(attachFrom, schedule, boundIndex, keys);
|
|
+ : new HybridSealProducer(
|
|
+ attachFrom,
|
|
+ schedule,
|
|
+ boundIndex,
|
|
+ keys,
|
|
+ anchorConfig.anchorBlock(),
|
|
+ next,
|
|
+ h -> FalconSealSupport.instance().localIndexAt(h));
|
|
return new HybridSealSupport(schedule, registry, producer);
|
|
}
|
|
|
|
private static String firstOf(final ConfigReader r, final String prop, final String env) {
|
|
final String p = r.property(prop);
|
|
return p != null ? p : r.environment(env);
|
|
}
|
|
|
|
/** Returns the schedule, when the hybrid pair is configured.
|
|
*
|
|
* @return the schedule, or empty */
|
|
public Optional<PqSchemeSchedule> schedule() {
|
|
return Optional.ofNullable(schedule);
|
|
}
|
|
|
|
/** Returns the registry, when the hybrid pair is configured.
|
|
*
|
|
* @return the registry, or empty */
|
|
public Optional<HybridSignerRegistry> registry() {
|
|
return Optional.ofNullable(registry);
|
|
}
|
|
|
|
/** Returns the producer; disarmed (never emits) when nothing is configured.
|
|
*
|
|
* @return the producer */
|
|
public HybridSealProducer producer() {
|
|
return producer;
|
|
}
|
|
+
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3b-ii, THE STARTUP GUARD of the local hybrid keys: in every v3 epoch from H_k where this node's identity is
|
|
+ * registered, it must hold, for every non-Falcon scheme the schedule names at that epoch, the key of its row. Otherwise it would
|
|
+ * produce no hybrid seal from that epoch on while every configuration gate stays green; refuse to start instead.
|
|
+ *
|
|
+ * @param thisNodeAddress this node's own validator (ECDSA) address
|
|
+ */
|
|
+ public void verifyLocalKeysCoverV3EpochsOrAbort(final org.hyperledger.besu.datatypes.Address thisNodeAddress) {
|
|
+ final Optional<AerePqIdentity.Config> c = AerePqIdentity.installed();
|
|
+ if (schedule == null || c.isEmpty() || c.get().keysFrom() == AerePqIdentity.NEVER || thisNodeAddress == null) {
|
|
+ return;
|
|
+ }
|
|
+ for (final PqRegistryV3.Registry e : c.get().epochs().tailMap(c.get().keysFrom(), true).values()) {
|
|
+ final org.hyperledger.besu.datatypes.Address me = AerePqIdentity.author(thisNodeAddress, e.bindHeight());
|
|
+ if (e.rowOf(me.getBytes().toArrayUnsafe()).isEmpty()) {
|
|
+ continue;
|
|
+ }
|
|
+ for (final String schemeId : schedule.schemesAt(e.bindHeight())) {
|
|
+ if (schemeId.equals(SealSchemes.FALCON_512.id())) {
|
|
+ continue;
|
|
+ }
|
|
+ final Optional<SealScheme> scheme = SealSchemes.byId(schemeId);
|
|
+ if (scheme.isEmpty() || producer.v3KeyAt(scheme.get(), e.bindHeight()).isEmpty()) {
|
|
+ throw new IllegalStateException(
|
|
+ "AERE-PQC-KEY-NEXT-02: REFUSING TO START. This node (id " + me + ") is registered in the v3 epoch bound at "
|
|
+ + e.bindHeight() + " but holds no " + schemeId + " key of its row there (aere.pq.hybrid.key." + schemeId
|
|
+ + "[.next]); from that height it would produce no hybrid seal.");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchor.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchor.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 32c634ee85..5524158c03
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchor.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchor.java
|
|
@@ -503,45 +503,46 @@ public final class PqAnchor {
|
|
* commits in a {@code LinkedHashMap} keyed on author and {@code values()} yields arrival order, so
|
|
* a producer that skips {@link #sortedByIndex(Collection)} writes an unsorted certificate and
|
|
* nothing downstream notices: the anchor digest is taken IN THE ORDER GIVEN, so those headers'
|
|
* digests are perfectly consistent with their own bytes. 36 such headers are canonical today.
|
|
*
|
|
* <p>Nodes already holding the chain never revalidate them, which is exactly why this was invisible
|
|
* for a day. A node syncing from genesis under the plain rule would reject header 13,267,824 and
|
|
* stop there forever. That is the same shape as the base-fee floor episode: the history is what it
|
|
* is, and the exception belongs at VALIDATION, where a header is accepted as written, not in any
|
|
* recomputation. A patch anywhere else moves the error instead of ending it.
|
|
*
|
|
* <p><b>What the exception does NOT relax.</b> Inside the window the certificate must still have
|
|
* non-negative and pairwise distinct indices. Measured 2026-08-11 on all 36 headers: distinct in
|
|
* every one, no negative index in any. So this accepts exactly the history that exists and nothing
|
|
* weaker, and the "repeat one seal to inflate k" attack stays unrepresentable at every height.
|
|
*
|
|
* <p><b>Producers must not call this.</b> {@code PqAnchorProducer} keeps requiring strict
|
|
* sortedness, so no new unsorted header can ever be written, at any height. The window is closed by
|
|
* construction: it is bounded above by a measured constant, so it cannot grow.
|
|
*
|
|
+ * @param chainId the chain of the header; the unordered exception exists on chain 2800 only (D-428)
|
|
* @param certificate the carried certificate
|
|
* @param blockNumber the number of the header carrying it
|
|
* @return true iff the ordering is acceptable for a header at that height
|
|
*/
|
|
public static boolean hasAcceptableIndices(
|
|
- final Collection<FalconSeal> certificate, final long blockNumber) {
|
|
+ final long chainId, final Collection<FalconSeal> certificate, final long blockNumber) {
|
|
if (hasStrictlyIncreasingIndices(certificate)) {
|
|
return true;
|
|
}
|
|
- return PqAnchorLapse.isDisarmed(blockNumber) && hasDistinctNonNegativeIndices(certificate);
|
|
+ return PqAnchorLapse.isDisarmed(chainId, blockNumber) && hasDistinctNonNegativeIndices(certificate);
|
|
}
|
|
|
|
/**
|
|
* Return the certificate sorted by validator index, ascending. Producers use this before writing
|
|
* the certificate into extraData; validators never sort, they require sortedness.
|
|
*
|
|
* @param certificate the seals in any order
|
|
* @return a new list sorted by validator index
|
|
*/
|
|
public static List<FalconSeal> sortedByIndex(final Collection<FalconSeal> certificate) {
|
|
final List<FalconSeal> sorted = new ArrayList<>(certificate);
|
|
sorted.sort(BY_INDEX);
|
|
return sorted;
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapse.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapse.java
|
|
index a7c8c9bf1a..0c4cc207f8 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapse.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapse.java
|
|
@@ -303,73 +303,89 @@ public final class PqAnchorLapse {
|
|
private PqAnchorLapse() {}
|
|
|
|
/**
|
|
* Every named range, ordered by first height.
|
|
*
|
|
* @return an unmodifiable list, never null, possibly empty
|
|
*/
|
|
public static List<Window> windows() {
|
|
return WINDOWS;
|
|
}
|
|
|
|
/**
|
|
* Whether the anchor rules were out of force ENTIRELY at this height.
|
|
*
|
|
* <p>This is the single question both anchor rules ask before they judge anything. They ask it
|
|
* through this one method, for the same reason they share {@code anchorAppliesAt}: two rules that
|
|
* each decided the boundary their own way could disagree about one header, and a header accepted
|
|
* by one rule and refused by the other is a chain break.
|
|
*
|
|
* <p>It is deliberately FALSE inside a threshold-only range. There the digest binding and the
|
|
- * ordering did hold and are still required; only {@link #historicMinSeals(long)} moves.
|
|
+ * ordering did hold and are still required; only {@link #historicMinSeals(long, long)} moves.
|
|
*
|
|
+ * <p>AERE D-428 (2026-09-28): the ranges are facts about chain {@value #CHAIN_ID} and about no other chain. Before this the
|
|
+ * predicates did not take the chain, so a node of ANY other network built from this source turned the anchor rules off over
|
|
+ * the same heights, while the second client (PqAnchorLapse.cs) never did: two clients judging one header differently.
|
|
+ *
|
|
+ * @param chainId the chain of the header being judged
|
|
* @param blockNumber the height being judged
|
|
* @return true iff the height falls inside a range where nothing was in force
|
|
*/
|
|
- public static boolean isDisarmed(final long blockNumber) {
|
|
+ public static boolean isDisarmed(final long chainId, final long blockNumber) {
|
|
+ if (chainId != CHAIN_ID) {
|
|
+ return false;
|
|
+ }
|
|
for (final Window window : WINDOWS) {
|
|
if (window.covers(blockNumber) && window.relaxation() == Relaxation.EVERYTHING) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* The seal threshold that was actually in force at this height, when it was lower than the
|
|
* configured schedule.
|
|
*
|
|
* <p>This is the same lever the fleet itself used at the time, the emergency ceiling, replayed
|
|
* from a fixed range instead of from a runtime option. A node validating history therefore asks
|
|
* the certificate for what was asked of the proposer that wrote it, and nothing more.
|
|
*
|
|
+ * @param chainId the chain of the header being judged; any chain but {@value #CHAIN_ID} gets empty (D-428)
|
|
* @param blockNumber the height being judged
|
|
* @return the threshold in force, or empty when the configured schedule applies unchanged
|
|
*/
|
|
- public static OptionalInt historicMinSeals(final long blockNumber) {
|
|
+ public static OptionalInt historicMinSeals(final long chainId, final long blockNumber) {
|
|
+ if (chainId != CHAIN_ID) {
|
|
+ return OptionalInt.empty();
|
|
+ }
|
|
for (final Window window : WINDOWS) {
|
|
if (window.covers(blockNumber) && window.relaxation() == Relaxation.THRESHOLD_ONLY) {
|
|
return OptionalInt.of(window.effectiveMinSeals());
|
|
}
|
|
}
|
|
return OptionalInt.empty();
|
|
}
|
|
|
|
/**
|
|
* The range covering a height, when there is one.
|
|
*
|
|
+ * @param chainId the chain of the header being judged; any chain but {@value #CHAIN_ID} gets empty (D-428)
|
|
* @param blockNumber the height being judged
|
|
* @return the range, or empty
|
|
*/
|
|
- public static Optional<Window> windowCovering(final long blockNumber) {
|
|
+ public static Optional<Window> windowCovering(final long chainId, final long blockNumber) {
|
|
+ if (chainId != CHAIN_ID) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
return WINDOWS.stream().filter(w -> w.covers(blockNumber)).findFirst();
|
|
}
|
|
|
|
/**
|
|
* The first height of the earliest named range, or empty when there is none.
|
|
*
|
|
* @return the earliest affected height
|
|
*/
|
|
public static Optional<Long> earliestAffectedBlock() {
|
|
return WINDOWS.stream().map(Window::firstBlock).min(Comparator.naturalOrder());
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryHashTool.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryHashTool.java
|
|
index 14071c5e4e..3617715f3e 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryHashTool.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryHashTool.java
|
|
@@ -151,95 +151,95 @@ public final class PqRegistryHashTool {
|
|
return 2;
|
|
}
|
|
final long h = Long.parseLong(armingHeightRaw);
|
|
final List<Path> files = files(o, "registry");
|
|
if (files.isEmpty()) {
|
|
System.out.println("NOT MEASURED: --registry is missing");
|
|
return 2;
|
|
}
|
|
// The epochs: the first at the arming height, then one per --rotation <height>=<file>.
|
|
final Map<Long, Path> epoci = new LinkedHashMap<>();
|
|
epoci.put(h, files.get(0));
|
|
for (final String rot : list(o.get("rotation"))) {
|
|
final int eq = rot.indexOf('=');
|
|
if (eq < 0) {
|
|
System.out.println("NOT MEASURED: --rotation is written <height>=<file>, got: " + rot);
|
|
return 2;
|
|
}
|
|
epoci.put(Long.parseLong(rot.substring(0, eq).trim()), Path.of(rot.substring(eq + 1).trim()));
|
|
}
|
|
|
|
- final List<Long> inaltimi = new ArrayList<>(epoci.keySet());
|
|
- inaltimi.sort(Long::compare);
|
|
- if (inaltimi.get(0) != h) {
|
|
- System.out.println("RED: the first epoch is at " + inaltimi.get(0) + ", not at the arming height " + h);
|
|
+ final List<Long> epochHeights = new ArrayList<>(epoci.keySet());
|
|
+ epochHeights.sort(Long::compare);
|
|
+ if (epochHeights.get(0) != h) {
|
|
+ System.out.println("RED: the first epoch is at " + epochHeights.get(0) + ", not at the arming height " + h);
|
|
return 1;
|
|
}
|
|
|
|
// NO COMMENT INSIDE THE FRAGMENT, and that is a measurement, not a matter of taste. The first
|
|
// form of this method put the file path after every entry, as `// /path/registry.json`.
|
|
// The fragment LOOKS fine and CANNOT BE USED: genesis is read with Jackson without
|
|
// ALLOW_COMMENTS, so a node handed one of those refuses to start with
|
|
// [AERE-PQC-REG-LOAD-13] "Unexpected character ('/')", and it then refuses EVERY header from
|
|
// the arming height upwards. Measured 2026-08-06, cases U3/U4 in d2-v2/dovezi/controale/.
|
|
// Whatever is explanation is printed outside the JSON, on lines beginning with #.
|
|
final StringBuilder json = new StringBuilder();
|
|
json.append(" \"pqRegistryHash\": [\n");
|
|
final StringBuilder history = new StringBuilder();
|
|
final StringBuilder harta = new StringBuilder();
|
|
- for (int i = 0; i < inaltimi.size(); i++) {
|
|
- final long b = inaltimi.get(i);
|
|
+ for (int i = 0; i < epochHeights.size(); i++) {
|
|
+ final long b = epochHeights.get(i);
|
|
final Path p = epoci.get(b);
|
|
final PqRegistryHash.Registry reg = PqRegistryHash.loadAuto(p);
|
|
// AERE D-C (2026-08-06). THIS IS THE DANGEROUS VERB: what is printed here gets pasted into
|
|
// genesis, and genesis is the document all seven nodes hold identical. hashV1 next to a
|
|
// registry that carries proofs writes into genesis a number the node's guard (hashFor) never
|
|
// produces, so all seven nodes start, all report the registry loaded, and the chain stops at
|
|
// H-1. A wrong indication is more dangerous than a missing one.
|
|
final String hash = PqRegistryHash.hashFor(reg, chainId);
|
|
// AERE D-B (2026-08-06). The recipe we print has to be the one the NEW code accepts. Since
|
|
// 2026-08-06 the node refuses to start (AERE-PQC-REG-BIND-08) on a registry forced in at a
|
|
// height its proofs did not sign. If the tool printed that recipe, it would manufacture
|
|
// exactly the configuration the node rejects, and it would do so in a file that reaches all
|
|
// seven at once.
|
|
if (reg.proofBound() && reg.bindHeight() != b) {
|
|
System.out.println(
|
|
"RED: registry "
|
|
+ p
|
|
+ " has bind height "
|
|
+ reg.bindHeight()
|
|
+ ", while here it is scheduled from block "
|
|
+ b
|
|
+ ". The two numbers must be EQUAL: every row of the registry carries a proof of "
|
|
+ "possession and a claim, and both sign the bind height. A registry forced in from "
|
|
+ "another block is an activation day no validator signed, and the node refuses to "
|
|
+ "start on it with AERE-PQC-REG-BIND-08. It is not repaired by editing the "
|
|
+ "bindHeight field: the proofs are over it, and the file would no longer load at "
|
|
+ "all (AERE-PQC-REG-BIND-03). It is repaired either by scheduling the epoch at "
|
|
+ reg.bindHeight()
|
|
+ ", or by re-signing the registry for "
|
|
+ b
|
|
+ ", which means the key ceremony and a NEW hash.");
|
|
return 1;
|
|
}
|
|
json.append(" {\"block\": ").append(b).append(", \"hash\": \"0x").append(hash).append("\"}");
|
|
- if (i < inaltimi.size() - 1) {
|
|
+ if (i < epochHeights.size() - 1) {
|
|
json.append(',');
|
|
}
|
|
json.append('\n');
|
|
harta.append("# block ").append(b).append(" -> ").append(p.toAbsolutePath()).append('\n');
|
|
if (history.length() > 0) {
|
|
history.append(',');
|
|
}
|
|
history.append(p.toAbsolutePath());
|
|
}
|
|
json.append(" ]");
|
|
|
|
System.out.println("# 1. In the genesis of chain " + chainId + ", inside the \"config\" object:");
|
|
System.out.println("# The fragment below is VALID JSON and is pasted as it stands. No comments");
|
|
System.out.println("# are added to it: genesis is read WITHOUT ALLOW_COMMENTS and the node refuses to start.");
|
|
System.out.println(json);
|
|
System.out.println("# Which registry file stands behind each epoch:");
|
|
System.out.print(harta);
|
|
System.out.println();
|
|
System.out.println("# 2. On EVERY node, the second client included, in BESU_OPTS:");
|
|
System.out.println("-Daere.falcon.registry.history=" + history);
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3.java
|
|
new file mode 100644
|
|
index 0000000000..3fb8a5c543
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3.java
|
|
@@ -0,0 +1,963 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the validator registry v3 (post-quantum identity).
|
|
+ *
|
|
+ * WHAT IT IS. One registry epoch as a JSON manifest: rows keyed "0".."count-1" plus formatVersion 3,
|
|
+ * chainId, bindHeight and count at top level. Each row names a validator by a 20-byte `id` derived
|
|
+ * from its Falcon-512 key (AIP-22 section 3.1, the AIP-20 sender derivation with alg id 0x20):
|
|
+ *
|
|
+ * id = keccak256(0x50 || 0x20 || falcon512_public_key_897)[12:32]
|
|
+ *
|
|
+ * and binds to it one public key per seal scheme, each with a proof of possession. The id is taken
|
|
+ * at the first registration and KEPT through key rotations: a later epoch may change a row's keys
|
|
+ * only with a rotation signature by EVERY key the previous epoch bound to that id. The `ecdsa`
|
|
+ * field ({addr, claim}) is the verifiable link from a classical validator address to the id, and is
|
|
+ * required in the epoch that performs the switch at H_id. `transport` names the RLPx node key a
|
|
+ * validator's client uses, for the peer-forwarding predicate (AIP-22 section 3.4).
|
|
+ *
|
|
+ * THE CANONICAL FORMS, pinned here and in the conformance vectors (AIP-22 section 3.2 names them;
|
|
+ * this class is where their bytes are fixed, and the Nethermind port and the public JS tool must
|
|
+ * produce the same bytes from the same vector files):
|
|
+ *
|
|
+ * row pre-image = "AERE-PQ-ROW-3" || u8(3) || u64be(chainId) || u64be(bindHeight) || u32be(count)
|
|
+ * || u32be(index) || id(20) || u8(nKeys)
|
|
+ * || for each key in ascending wire id: u8(wireId) || u32be(len pk) || pk
|
|
+ * || u32be(len pop) || pop
|
|
+ * || u8(hasTransport) [|| transport(20)]
|
|
+ * row hash = keccak256(row pre-image) (rotation and ecdsa are NOT in it)
|
|
+ * Merkle root = binary tree over the row hashes in index order; node = keccak256(0x01 || l || r);
|
|
+ * an odd node at any level is paired with itself; one row: the root is its hash
|
|
+ * registry hash = keccak256("AERE-PQ-REGISTRY-3" || u64be(chainId) || u64be(bindHeight)
|
|
+ * || u32be(count) || root)
|
|
+ * pop message = keccak256("AERE-PQ-POP-3" || u8(3) || u64be(chainId) || u64be(bindHeight)
|
|
+ * || u32be(count) || u32be(index) || id(20) || u8(wireId) || u32be(len pk) || pk)
|
|
+ * rotate message = keccak256("AERE-PQ-ROTATE-3" || new row hash)
|
|
+ * claim digest = keccak256(0x19 || 0x00 || context || new row hash), context = the low 20 bytes
|
|
+ * of keccak256("AERE-PQ-CLAIM-1" || u64be(chainId)), the EIP-191 envelope of v2
|
|
+ *
|
|
+ * The public key in the pre-images is the STANDARD encoding: Falcon-512 897 bytes (header 0x09 +
|
|
+ * the 896-byte h polynomial the v1/v2 registries store), SLH-DSA-SHA2-128s 32 bytes. Every field
|
|
+ * of the pop message earns its place for the reason given in PqRegistryBinding (domain tag against
|
|
+ * seal replay, key in the message against Falcon's missing exclusive ownership, chainId, index,
|
|
+ * bindHeight and count against lifting and truncation); the wire id keeps one scheme's proof from
|
|
+ * standing in for another's. The Merkle node tag 0x01 keeps an inner node from ever being read as
|
|
+ * a row hash, and the count bound into the registry hash keeps a duplicated odd leaf from making a
|
|
+ * tree of count+1 rows hash like one of count.
|
|
+ *
|
|
+ * LOADING IS STRICT, as for v1/v2: an ambiguous or incomplete file REFUSES with a named code, never
|
|
+ * hashes. Refusal codes AERE-PQC-REG3-01..16, listed at {@link Code}.
|
|
+ *
|
|
+ * WHAT IT DOES NOT DO (stated): it does not wire the ids into QBFT (the set translation at H_id,
|
|
+ * message authorship, coinbase, votes and peer forwarding are later parts of stage 3), and it
|
|
+ * does not pin the registry hash on chain (the anchor-contract slot or genesis pqRegistryHash
|
|
+ * does that, as today; {@link #loadPinned} compares against the pinned value).
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+
|
|
+import java.io.ByteArrayOutputStream;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
+import java.util.HashSet;
|
|
+import java.util.Iterator;
|
|
+import java.util.LinkedHashMap;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.Set;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.bouncycastle.crypto.digests.KeccakDigest;
|
|
+
|
|
+/** The v3 validator registry: canonical forms, strict loader, Merkle membership. */
|
|
+public final class PqRegistryV3 {
|
|
+
|
|
+ /** Format version of this registry. */
|
|
+ public static final int FORMAT_VERSION = 3;
|
|
+
|
|
+ /** Domain tag of the row pre-image. */
|
|
+ public static final String DOMAIN_ROW = "AERE-PQ-ROW-3";
|
|
+
|
|
+ /** Domain tag of the registry hash. */
|
|
+ public static final String DOMAIN_REGISTRY = "AERE-PQ-REGISTRY-3";
|
|
+
|
|
+ /** Domain tag of the proof-of-possession message. */
|
|
+ public static final String DOMAIN_POP = "AERE-PQ-POP-3";
|
|
+
|
|
+ /** Domain tag of the rotation message. */
|
|
+ public static final String DOMAIN_ROTATE = "AERE-PQ-ROTATE-3";
|
|
+
|
|
+ /** Tag byte of an inner Merkle node. */
|
|
+ public static final byte MERKLE_NODE_TAG = 0x01;
|
|
+
|
|
+ /** First byte of the id pre-image: the AIP-20 transaction type. */
|
|
+ public static final byte ID_TX_TYPE = 0x50;
|
|
+
|
|
+ /** Second byte of the id pre-image: the algorithm id AIP-20 reserves for Falcon-512. */
|
|
+ public static final byte ID_ALG_FALCON_512 = 0x20;
|
|
+
|
|
+ /** Header byte of the standard Falcon-512 public key encoding. */
|
|
+ public static final byte FALCON_512_PK_HEADER = 0x09;
|
|
+
|
|
+ /** Standard Falcon-512 public key length (header + 896-byte h). */
|
|
+ public static final int FALCON_512_PK_LENGTH = 897;
|
|
+
|
|
+ private static final int ECDSA_SIGNATURE_LENGTH = 65;
|
|
+
|
|
+ /** The named refusals of the strict loader. */
|
|
+ public enum Code {
|
|
+ /** formatVersion missing or not 3. */
|
|
+ REG3_01_FORMAT("AERE-PQC-REG3-01"),
|
|
+ /** chainId missing or not the node's chain. */
|
|
+ REG3_02_CHAIN("AERE-PQC-REG3-02"),
|
|
+ /** count missing, rows not exactly "0".."count-1", or an unknown top-level or row field. */
|
|
+ REG3_03_SHAPE("AERE-PQC-REG3-03"),
|
|
+ /** id missing, not hex, or not 20 bytes. */
|
|
+ REG3_04_ID("AERE-PQC-REG3-04"),
|
|
+ /** a key names a scheme this build does not know. */
|
|
+ REG3_05_UNKNOWN_SCHEME("AERE-PQC-REG3-05"),
|
|
+ /** a scheme the schedule requires has no key on a row. */
|
|
+ REG3_06_REQUIRED_SCHEME("AERE-PQC-REG3-06"),
|
|
+ /** a public key is not in its scheme's standard encoding. */
|
|
+ REG3_07_KEY_ENCODING("AERE-PQC-REG3-07"),
|
|
+ /** a proof of possession is missing or does not verify. */
|
|
+ REG3_08_POP("AERE-PQC-REG3-08"),
|
|
+ /** a NEW id is not the derivation of the row's Falcon-512 key. */
|
|
+ REG3_09_ID_DERIVATION("AERE-PQC-REG3-09"),
|
|
+ /** two rows carry the same id. */
|
|
+ REG3_10_DUPLICATE_ID("AERE-PQC-REG3-10"),
|
|
+ /** two rows carry the same public key. */
|
|
+ REG3_11_DUPLICATE_KEY("AERE-PQC-REG3-11"),
|
|
+ /** a changed row lacks a verifying rotation signature by every previous key of its id. */
|
|
+ REG3_12_ROTATION_MISSING("AERE-PQC-REG3-12"),
|
|
+ /** a rotation is present where none belongs (unchanged row, or a new id). */
|
|
+ REG3_13_ROTATION_UNEXPECTED("AERE-PQC-REG3-13"),
|
|
+ /** the ecdsa link is required and missing, does not recover to its address, or repeats one. */
|
|
+ REG3_14_ECDSA("AERE-PQC-REG3-14"),
|
|
+ /** transport is malformed. */
|
|
+ REG3_15_TRANSPORT("AERE-PQC-REG3-15"),
|
|
+ /** the computed registry hash is not the pinned (or the file's own declared) hash. */
|
|
+ REG3_16_HASH("AERE-PQC-REG3-16");
|
|
+
|
|
+ private final String text;
|
|
+
|
|
+ Code(final String text) {
|
|
+ this.text = text;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The refusal code as printed.
|
|
+ *
|
|
+ * @return e.g. AERE-PQC-REG3-08
|
|
+ */
|
|
+ public String text() {
|
|
+ return text;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** A refusal of the strict loader, carrying its named code. */
|
|
+ public static final class RegistryV3Exception extends RuntimeException {
|
|
+ private static final long serialVersionUID = 1L;
|
|
+
|
|
+ /** The named refusal. */
|
|
+ private final transient Code code;
|
|
+
|
|
+ /**
|
|
+ * A refusal.
|
|
+ *
|
|
+ * @param code the named code
|
|
+ * @param message what was wrong, in words
|
|
+ */
|
|
+ public RegistryV3Exception(final Code code, final String message) {
|
|
+ super(code.text() + ": " + message);
|
|
+ this.code = code;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The named code.
|
|
+ *
|
|
+ * @return the code
|
|
+ */
|
|
+ public Code code() {
|
|
+ return code;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * One key of a row.
|
|
+ *
|
|
+ * @param scheme the seal scheme
|
|
+ * @param publicKey the standard encoding (Falcon-512 897 bytes, SLH-DSA-SHA2-128s 32 bytes)
|
|
+ * @param pop the proof of possession by that key
|
|
+ */
|
|
+ public record Key(SealScheme scheme, byte[] publicKey, byte[] pop) {}
|
|
+
|
|
+ /**
|
|
+ * One row.
|
|
+ *
|
|
+ * @param index the row index
|
|
+ * @param id the 20-byte validator id
|
|
+ * @param keys the keys by wire id, ascending
|
|
+ * @param transport the RLPx node-key address, or null
|
|
+ * @param rotation scheme id to rotation signature (by the previous epoch's key of that scheme)
|
|
+ * @param ecdsaAddress the classical validator address, or null
|
|
+ * @param ecdsaClaim the EIP-191 claim by that address over the row hash, or null
|
|
+ */
|
|
+ public record Row(
|
|
+ int index,
|
|
+ byte[] id,
|
|
+ TreeMap<Integer, Key> keys,
|
|
+ byte[] transport,
|
|
+ Map<String, byte[]> rotation,
|
|
+ byte[] ecdsaAddress,
|
|
+ byte[] ecdsaClaim) {
|
|
+
|
|
+ /**
|
|
+ * The key of a scheme on this row.
|
|
+ *
|
|
+ * @param schemeId e.g. "falcon-512"
|
|
+ * @return the key, if the row carries one
|
|
+ */
|
|
+ public Optional<Key> key(final String schemeId) {
|
|
+ for (final Key k : keys.values()) {
|
|
+ if (k.scheme().id().equals(schemeId)) {
|
|
+ return Optional.of(k);
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * A loaded, verified epoch.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param bindHeight the activation height of this epoch
|
|
+ * @param count the number of rows
|
|
+ * @param rows the rows in index order
|
|
+ * @param rowHashes the row hashes in index order
|
|
+ * @param root the Merkle root over the row hashes
|
|
+ * @param hash the registry hash (what the chain pins)
|
|
+ */
|
|
+ public record Registry(
|
|
+ long chainId,
|
|
+ long bindHeight,
|
|
+ int count,
|
|
+ List<Row> rows,
|
|
+ List<Bytes32> rowHashes,
|
|
+ Bytes32 root,
|
|
+ Bytes32 hash) {
|
|
+
|
|
+ /**
|
|
+ * The row of an id.
|
|
+ *
|
|
+ * @param id the 20-byte id
|
|
+ * @return the row, if the id is registered in this epoch
|
|
+ */
|
|
+ public Optional<Row> rowOf(final byte[] id) {
|
|
+ for (final Row r : rows) {
|
|
+ if (Arrays.equals(r.id(), id)) {
|
|
+ return Optional.of(r);
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The row whose ecdsa link names this classical address.
|
|
+ *
|
|
+ * @param address the 20-byte address
|
|
+ * @return the row, if one links it
|
|
+ */
|
|
+ public Optional<Row> rowOfEcdsa(final byte[] address) {
|
|
+ for (final Row r : rows) {
|
|
+ if (r.ecdsaAddress() != null && Arrays.equals(r.ecdsaAddress(), address)) {
|
|
+ return Optional.of(r);
|
|
+ }
|
|
+ }
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private PqRegistryV3() {}
|
|
+
|
|
+ // =============================================================================================
|
|
+ // Canonical forms
|
|
+ // =============================================================================================
|
|
+
|
|
+ /**
|
|
+ * The validator id of a Falcon-512 key (AIP-22 section 3.1).
|
|
+ *
|
|
+ * @param falconStandard897 the 897-byte standard encoding
|
|
+ * @return the 20-byte id
|
|
+ */
|
|
+ public static byte[] idOf(final byte[] falconStandard897) {
|
|
+ final byte[] in = new byte[2 + falconStandard897.length];
|
|
+ in[0] = ID_TX_TYPE;
|
|
+ in[1] = ID_ALG_FALCON_512;
|
|
+ System.arraycopy(falconStandard897, 0, in, 2, falconStandard897.length);
|
|
+ return Arrays.copyOfRange(keccak(in), 12, 32);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The message a row key signs to prove possession.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param bindHeight the epoch's activation height
|
|
+ * @param count the number of rows
|
|
+ * @param index the row index
|
|
+ * @param id the row id
|
|
+ * @param wireId the scheme wire id
|
|
+ * @param publicKey the standard encoding of the key
|
|
+ * @return the 32-byte message
|
|
+ */
|
|
+ public static Bytes32 popMessage(
|
|
+ final long chainId,
|
|
+ final long bindHeight,
|
|
+ final int count,
|
|
+ final int index,
|
|
+ final byte[] id,
|
|
+ final byte wireId,
|
|
+ final byte[] publicKey) {
|
|
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ writeAll(out, DOMAIN_POP.getBytes(StandardCharsets.US_ASCII));
|
|
+ out.write(FORMAT_VERSION);
|
|
+ writeAll(out, uint64be(chainId));
|
|
+ writeAll(out, uint64be(bindHeight));
|
|
+ writeAll(out, uint32be(count));
|
|
+ writeAll(out, uint32be(index));
|
|
+ writeAll(out, id);
|
|
+ out.write(wireId);
|
|
+ writeAll(out, uint32be(publicKey.length));
|
|
+ writeAll(out, publicKey);
|
|
+ return Bytes32.wrap(keccak(out.toByteArray()));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The canonical pre-image of a row (without rotation and ecdsa).
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param bindHeight the epoch's activation height
|
|
+ * @param count the number of rows
|
|
+ * @param row the row
|
|
+ * @return the pre-image
|
|
+ */
|
|
+ public static byte[] rowPreimage(
|
|
+ final long chainId, final long bindHeight, final int count, final Row row) {
|
|
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ writeAll(out, DOMAIN_ROW.getBytes(StandardCharsets.US_ASCII));
|
|
+ out.write(FORMAT_VERSION);
|
|
+ writeAll(out, uint64be(chainId));
|
|
+ writeAll(out, uint64be(bindHeight));
|
|
+ writeAll(out, uint32be(count));
|
|
+ writeAll(out, uint32be(row.index()));
|
|
+ writeAll(out, row.id());
|
|
+ out.write(row.keys().size());
|
|
+ for (final Map.Entry<Integer, Key> e : row.keys().entrySet()) {
|
|
+ out.write(e.getKey());
|
|
+ writeAll(out, uint32be(e.getValue().publicKey().length));
|
|
+ writeAll(out, e.getValue().publicKey());
|
|
+ writeAll(out, uint32be(e.getValue().pop().length));
|
|
+ writeAll(out, e.getValue().pop());
|
|
+ }
|
|
+ if (row.transport() == null) {
|
|
+ out.write(0);
|
|
+ } else {
|
|
+ out.write(1);
|
|
+ writeAll(out, row.transport());
|
|
+ }
|
|
+ return out.toByteArray();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The row hash.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param bindHeight the epoch's activation height
|
|
+ * @param count the number of rows
|
|
+ * @param row the row
|
|
+ * @return keccak256 of the row pre-image
|
|
+ */
|
|
+ public static Bytes32 rowHash(
|
|
+ final long chainId, final long bindHeight, final int count, final Row row) {
|
|
+ return Bytes32.wrap(keccak(rowPreimage(chainId, bindHeight, count, row)));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The Merkle root over row hashes in index order.
|
|
+ *
|
|
+ * @param leaves the row hashes
|
|
+ * @return the root
|
|
+ */
|
|
+ public static Bytes32 merkleRoot(final List<Bytes32> leaves) {
|
|
+ if (leaves.isEmpty()) {
|
|
+ throw new IllegalArgumentException("a registry has at least one row");
|
|
+ }
|
|
+ List<Bytes32> level = leaves;
|
|
+ while (level.size() > 1) {
|
|
+ final List<Bytes32> next = new ArrayList<>();
|
|
+ for (int i = 0; i < level.size(); i += 2) {
|
|
+ final Bytes32 l = level.get(i);
|
|
+ final Bytes32 r = i + 1 < level.size() ? level.get(i + 1) : l;
|
|
+ next.add(node(l, r));
|
|
+ }
|
|
+ level = next;
|
|
+ }
|
|
+ return level.get(0);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The sibling path of one leaf, bottom-up.
|
|
+ *
|
|
+ * @param leaves the row hashes
|
|
+ * @param index the leaf index
|
|
+ * @return the siblings from the leaf level up
|
|
+ */
|
|
+ public static List<Bytes32> merkleProof(final List<Bytes32> leaves, final int index) {
|
|
+ if (index < 0 || index >= leaves.size()) {
|
|
+ throw new IllegalArgumentException("index " + index + " is not a row of " + leaves.size());
|
|
+ }
|
|
+ final List<Bytes32> proof = new ArrayList<>();
|
|
+ List<Bytes32> level = leaves;
|
|
+ int i = index;
|
|
+ while (level.size() > 1) {
|
|
+ final int sib = (i % 2 == 0) ? i + 1 : i - 1;
|
|
+ proof.add(sib < level.size() ? level.get(sib) : level.get(i));
|
|
+ final List<Bytes32> next = new ArrayList<>();
|
|
+ for (int j = 0; j < level.size(); j += 2) {
|
|
+ final Bytes32 l = level.get(j);
|
|
+ final Bytes32 r = j + 1 < level.size() ? level.get(j + 1) : l;
|
|
+ next.add(node(l, r));
|
|
+ }
|
|
+ level = next;
|
|
+ i /= 2;
|
|
+ }
|
|
+ return proof;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Checks a membership proof. The index MUST be below count: with the odd leaf paired with
|
|
+ * itself, a path for index == count would otherwise verify against a count-row tree.
|
|
+ *
|
|
+ * @param leaf the row hash
|
|
+ * @param index the claimed index
|
|
+ * @param count the number of rows
|
|
+ * @param proof the siblings, bottom-up
|
|
+ * @param root the root
|
|
+ * @return whether the leaf is row {@code index} of the tree with that root
|
|
+ */
|
|
+ public static boolean verifyMerkleProof(
|
|
+ final Bytes32 leaf,
|
|
+ final int index,
|
|
+ final int count,
|
|
+ final List<Bytes32> proof,
|
|
+ final Bytes32 root) {
|
|
+ if (index < 0 || index >= count || count < 1) {
|
|
+ return false;
|
|
+ }
|
|
+ int depth = 0;
|
|
+ for (int n = count; n > 1; n = (n + 1) / 2) {
|
|
+ depth++;
|
|
+ }
|
|
+ if (proof.size() != depth) {
|
|
+ return false;
|
|
+ }
|
|
+ Bytes32 acc = leaf;
|
|
+ int i = index;
|
|
+ for (final Bytes32 sib : proof) {
|
|
+ acc = (i % 2 == 0) ? node(acc, sib) : node(sib, acc);
|
|
+ i /= 2;
|
|
+ }
|
|
+ return acc.equals(root);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The registry hash the chain pins.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param bindHeight the epoch's activation height
|
|
+ * @param count the number of rows
|
|
+ * @param root the Merkle root
|
|
+ * @return the hash
|
|
+ */
|
|
+ public static Bytes32 registryHash(
|
|
+ final long chainId, final long bindHeight, final int count, final Bytes32 root) {
|
|
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ writeAll(out, DOMAIN_REGISTRY.getBytes(StandardCharsets.US_ASCII));
|
|
+ writeAll(out, uint64be(chainId));
|
|
+ writeAll(out, uint64be(bindHeight));
|
|
+ writeAll(out, uint32be(count));
|
|
+ writeAll(out, root.toArrayUnsafe());
|
|
+ return Bytes32.wrap(keccak(out.toByteArray()));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The message every previous key of an id signs to authorise a changed row.
|
|
+ *
|
|
+ * @param newRowHash the hash of the new row
|
|
+ * @return the 32-byte message
|
|
+ */
|
|
+ public static Bytes32 rotateMessage(final Bytes32 newRowHash) {
|
|
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ writeAll(out, DOMAIN_ROTATE.getBytes(StandardCharsets.US_ASCII));
|
|
+ writeAll(out, newRowHash.toArrayUnsafe());
|
|
+ return Bytes32.wrap(keccak(out.toByteArray()));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The digest the classical validator key signs to link its address to the row.
|
|
+ *
|
|
+ * @param chainId the chain
|
|
+ * @param rowHash the row hash
|
|
+ * @return the EIP-191 version-0 digest
|
|
+ */
|
|
+ public static Bytes32 claimDigest(final long chainId, final Bytes32 rowHash) {
|
|
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ out.write(0x19);
|
|
+ out.write(0x00);
|
|
+ writeAll(out, PqRegistryBinding.claimContext(chainId));
|
|
+ writeAll(out, rowHash.toArrayUnsafe());
|
|
+ return Bytes32.wrap(keccak(out.toByteArray()));
|
|
+ }
|
|
+
|
|
+ // =============================================================================================
|
|
+ // The strict loader
|
|
+ // =============================================================================================
|
|
+
|
|
+ /**
|
|
+ * Loads and verifies an epoch and compares its hash with the pinned one.
|
|
+ *
|
|
+ * @param json the manifest
|
|
+ * @param chainId the node's chain
|
|
+ * @param requiredSchemes the scheme ids every row must carry
|
|
+ * @param previous the previous v3 epoch (for rotations), or null for the first
|
|
+ * @param ecdsaRequired whether every row must carry the ecdsa link (the switch epoch)
|
|
+ * @param pinnedHash the hash the chain pins
|
|
+ * @return the verified epoch
|
|
+ */
|
|
+ public static Registry loadPinned(
|
|
+ final JsonNode json,
|
|
+ final long chainId,
|
|
+ final List<String> requiredSchemes,
|
|
+ final Registry previous,
|
|
+ final boolean ecdsaRequired,
|
|
+ final Bytes32 pinnedHash) {
|
|
+ final Registry r = load(json, chainId, requiredSchemes, previous, ecdsaRequired);
|
|
+ if (!r.hash().equals(pinnedHash)) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_16_HASH,
|
|
+ "the registry hashes to " + r.hash() + ", the chain pins " + pinnedHash + "; refusing");
|
|
+ }
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Loads and verifies an epoch (every proof, every uniqueness rule, every rotation).
|
|
+ *
|
|
+ * @param json the manifest
|
|
+ * @param chainId the node's chain
|
|
+ * @param requiredSchemes the scheme ids every row must carry
|
|
+ * @param previous the previous v3 epoch (for rotations), or null for the first
|
|
+ * @param ecdsaRequired whether every row must carry the ecdsa link
|
|
+ * @return the verified epoch
|
|
+ */
|
|
+ public static Registry load(
|
|
+ final JsonNode json,
|
|
+ final long chainId,
|
|
+ final List<String> requiredSchemes,
|
|
+ final Registry previous,
|
|
+ final boolean ecdsaRequired) {
|
|
+ if (json == null || !json.isObject()) {
|
|
+ throw new RegistryV3Exception(Code.REG3_03_SHAPE, "the manifest is not a JSON object");
|
|
+ }
|
|
+ if (!json.has("formatVersion") || json.get("formatVersion").asInt(-1) != FORMAT_VERSION
|
|
+ || !json.get("formatVersion").isIntegralNumber()) {
|
|
+ throw new RegistryV3Exception(Code.REG3_01_FORMAT, "formatVersion must be the number 3");
|
|
+ }
|
|
+ if (!json.has("chainId") || !json.get("chainId").isIntegralNumber()
|
|
+ || json.get("chainId").asLong() != chainId) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_02_CHAIN, "chainId must be the number " + chainId + " (this node's chain)");
|
|
+ }
|
|
+ if (!json.has("bindHeight") || !json.get("bindHeight").isIntegralNumber()
|
|
+ || json.get("bindHeight").asLong() < 0) {
|
|
+ throw new RegistryV3Exception(Code.REG3_03_SHAPE, "bindHeight must be a number >= 0");
|
|
+ }
|
|
+ if (!json.has("count") || !json.get("count").isIntegralNumber()
|
|
+ || json.get("count").asInt() < 1) {
|
|
+ throw new RegistryV3Exception(Code.REG3_03_SHAPE, "count must be a number >= 1");
|
|
+ }
|
|
+ final long bindHeight = json.get("bindHeight").asLong();
|
|
+ final int count = json.get("count").asInt();
|
|
+ final Set<String> allowedTop = new HashSet<>();
|
|
+ Collections.addAll(allowedTop, "formatVersion", "chainId", "bindHeight", "count", "registryHash");
|
|
+ for (int i = 0; i < count; i++) {
|
|
+ allowedTop.add(Integer.toString(i));
|
|
+ }
|
|
+ final Iterator<String> names = json.fieldNames();
|
|
+ while (names.hasNext()) {
|
|
+ final String n = names.next();
|
|
+ if (!allowedTop.contains(n)) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_03_SHAPE,
|
|
+ "unexpected top-level field '" + n + "' (rows are exactly \"0\"..\"" + (count - 1)
|
|
+ + "\")");
|
|
+ }
|
|
+ }
|
|
+ final List<Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < count; i++) {
|
|
+ final JsonNode e = json.get(Integer.toString(i));
|
|
+ if (e == null || !e.isObject()) {
|
|
+ throw new RegistryV3Exception(Code.REG3_03_SHAPE, "row " + i + " is missing");
|
|
+ }
|
|
+ rows.add(parseRow(i, e));
|
|
+ }
|
|
+ // required schemes, key encodings, possession proofs
|
|
+ for (final Row row : rows) {
|
|
+ for (final String s : requiredSchemes) {
|
|
+ if (row.key(s).isEmpty()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_06_REQUIRED_SCHEME, "row " + row.index() + " has no " + s + " key");
|
|
+ }
|
|
+ }
|
|
+ if (row.key(SealSchemes.FALCON_512.id()).isEmpty()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_06_REQUIRED_SCHEME,
|
|
+ "row " + row.index() + " has no falcon-512 key; the id is derived from it");
|
|
+ }
|
|
+ for (final Key k : row.keys().values()) {
|
|
+ final byte[] registryForm = registryForm(row.index(), k);
|
|
+ final Bytes32 msg =
|
|
+ popMessage(
|
|
+ chainId, bindHeight, count, row.index(), row.id(), k.scheme().wireId(),
|
|
+ k.publicKey());
|
|
+ if (k.pop() == null || k.pop().length == 0
|
|
+ || !k.scheme().verifyRaw(registryForm, msg.toArrayUnsafe(), k.pop())) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_08_POP,
|
|
+ "row " + row.index() + " " + k.scheme().id()
|
|
+ + ": the proof of possession does not verify for chainId=" + chainId
|
|
+ + " bindHeight=" + bindHeight + " count=" + count + " index=" + row.index());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // uniqueness of ids and of every public key
|
|
+ final Set<Bytes> ids = new HashSet<>();
|
|
+ final Set<Bytes> keys = new HashSet<>();
|
|
+ for (final Row row : rows) {
|
|
+ if (!ids.add(Bytes.wrap(row.id()))) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_10_DUPLICATE_ID, "id 0x" + hex(row.id()) + " appears on two rows");
|
|
+ }
|
|
+ for (final Key k : row.keys().values()) {
|
|
+ if (!keys.add(Bytes.wrap(k.publicKey()))) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_11_DUPLICATE_KEY,
|
|
+ "row " + row.index() + " " + k.scheme().id() + ": the key appears on another row");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // row hashes, then ids and rotations against the previous epoch
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final Row row : rows) {
|
|
+ hashes.add(rowHash(chainId, bindHeight, count, row));
|
|
+ }
|
|
+ for (final Row row : rows) {
|
|
+ final Optional<Row> prev = previous == null ? Optional.empty() : previous.rowOf(row.id());
|
|
+ if (prev.isEmpty()) {
|
|
+ final byte[] derived = idOf(row.key(SealSchemes.FALCON_512.id()).orElseThrow().publicKey());
|
|
+ if (!Arrays.equals(derived, row.id())) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_09_ID_DERIVATION,
|
|
+ "row " + row.index() + ": a new id must be keccak256(0x50||0x20||falcon)[12:32] = 0x"
|
|
+ + hex(derived) + ", the row says 0x" + hex(row.id()));
|
|
+ }
|
|
+ if (!row.rotation().isEmpty()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_13_ROTATION_UNEXPECTED,
|
|
+ "row " + row.index() + " is a new id and carries a rotation");
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ final boolean changed = !sameKeys(prev.get(), row);
|
|
+ if (!changed) {
|
|
+ if (!row.rotation().isEmpty()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_13_ROTATION_UNEXPECTED,
|
|
+ "row " + row.index() + " did not change its keys and carries a rotation");
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ final Bytes32 rot = rotateMessage(hashes.get(row.index()));
|
|
+ for (final Key old : prev.get().keys().values()) {
|
|
+ final byte[] sig = row.rotation().get(old.scheme().id());
|
|
+ if (sig == null
|
|
+ || !old.scheme()
|
|
+ .verifyRaw(registryForm(prev.get().index(), old), rot.toArrayUnsafe(), sig)) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_12_ROTATION_MISSING,
|
|
+ "row " + row.index() + " changed its keys; the previous " + old.scheme().id()
|
|
+ + " key of id 0x" + hex(row.id()) + " did not sign the new row (every previous"
|
|
+ + " key must)");
|
|
+ }
|
|
+ }
|
|
+ if (row.rotation().size() != prev.get().keys().size()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_13_ROTATION_UNEXPECTED,
|
|
+ "row " + row.index() + " carries a rotation signature for a scheme the previous row"
|
|
+ + " did not bind");
|
|
+ }
|
|
+ }
|
|
+ // the ecdsa link
|
|
+ final Set<Bytes> ecdsa = new HashSet<>();
|
|
+ for (final Row row : rows) {
|
|
+ if (row.ecdsaAddress() == null) {
|
|
+ if (ecdsaRequired) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_14_ECDSA,
|
|
+ "row " + row.index() + " has no ecdsa link; this epoch performs the switch and"
|
|
+ + " every row must carry one");
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ final Address rec = recover(claimDigest(chainId, hashes.get(row.index())), row.ecdsaClaim());
|
|
+ if (rec == null || !Arrays.equals(rec.getBytes().toArrayUnsafe(), row.ecdsaAddress())) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_14_ECDSA,
|
|
+ "row " + row.index() + ": the ecdsa claim does not recover to 0x"
|
|
+ + hex(row.ecdsaAddress()));
|
|
+ }
|
|
+ if (!ecdsa.add(Bytes.wrap(row.ecdsaAddress()))) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_14_ECDSA, "row " + row.index() + ": the ecdsa address appears on two rows");
|
|
+ }
|
|
+ }
|
|
+ final Bytes32 root = merkleRoot(hashes);
|
|
+ final Bytes32 hash = registryHash(chainId, bindHeight, count, root);
|
|
+ if (json.has("registryHash")) {
|
|
+ final Bytes32 declared = parseBytes32(json.get("registryHash"), "registryHash");
|
|
+ if (!declared.equals(hash)) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_16_HASH,
|
|
+ "the file declares registryHash " + declared + " and hashes to " + hash);
|
|
+ }
|
|
+ }
|
|
+ return new Registry(
|
|
+ chainId,
|
|
+ bindHeight,
|
|
+ count,
|
|
+ Collections.unmodifiableList(rows),
|
|
+ Collections.unmodifiableList(hashes),
|
|
+ root,
|
|
+ hash);
|
|
+ }
|
|
+
|
|
+ // =============================================================================================
|
|
+ // Parsing
|
|
+ // =============================================================================================
|
|
+
|
|
+ private static Row parseRow(final int index, final JsonNode e) {
|
|
+ final Set<String> allowed = Set.of("id", "keys", "pop", "rotation", "ecdsa", "transport");
|
|
+ final Iterator<String> fields = e.fieldNames();
|
|
+ while (fields.hasNext()) {
|
|
+ final String f = fields.next();
|
|
+ if (!allowed.contains(f)) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_03_SHAPE, "row " + index + " has an unknown field '" + f + "'");
|
|
+ }
|
|
+ }
|
|
+ final byte[] id = parseHex(e.get("id"), 20, Code.REG3_04_ID, "row " + index + " id");
|
|
+ final JsonNode keysNode = e.get("keys");
|
|
+ final JsonNode popNode = e.get("pop");
|
|
+ if (keysNode == null || !keysNode.isObject() || keysNode.size() == 0) {
|
|
+ throw new RegistryV3Exception(Code.REG3_03_SHAPE, "row " + index + " has no keys");
|
|
+ }
|
|
+ if (popNode == null || !popNode.isObject()) {
|
|
+ throw new RegistryV3Exception(Code.REG3_08_POP, "row " + index + " has no pop object");
|
|
+ }
|
|
+ final TreeMap<Integer, Key> keys = new TreeMap<>();
|
|
+ final Iterator<Map.Entry<String, JsonNode>> it = keysNode.fields();
|
|
+ while (it.hasNext()) {
|
|
+ final Map.Entry<String, JsonNode> k = it.next();
|
|
+ final SealScheme scheme =
|
|
+ SealSchemes.byId(k.getKey())
|
|
+ .orElseThrow(
|
|
+ () ->
|
|
+ new RegistryV3Exception(
|
|
+ Code.REG3_05_UNKNOWN_SCHEME,
|
|
+ "row " + index + " names the unknown scheme '" + k.getKey() + "'"));
|
|
+ final int len =
|
|
+ scheme == SealSchemes.FALCON_512 ? FALCON_512_PK_LENGTH : scheme.publicKeyLength();
|
|
+ final byte[] pk =
|
|
+ parseHex(k.getValue(), len, Code.REG3_07_KEY_ENCODING, "row " + index + " " + k.getKey());
|
|
+ if (scheme == SealSchemes.FALCON_512 && pk[0] != FALCON_512_PK_HEADER) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_07_KEY_ENCODING,
|
|
+ "row " + index + " falcon-512: the standard encoding starts with 0x09");
|
|
+ }
|
|
+ final JsonNode p = popNode.get(k.getKey());
|
|
+ if (p == null) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_08_POP, "row " + index + " " + k.getKey() + " has no proof of possession");
|
|
+ }
|
|
+ final byte[] pop = parseHex(p, -1, Code.REG3_08_POP, "row " + index + " pop " + k.getKey());
|
|
+ keys.put(scheme.wireId() & 0xff, new Key(scheme, pk, pop));
|
|
+ }
|
|
+ if (popNode.size() != keysNode.size()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_08_POP, "row " + index + " carries a proof for a scheme it has no key for");
|
|
+ }
|
|
+ byte[] transport = null;
|
|
+ final JsonNode t = e.get("transport");
|
|
+ if (t != null) {
|
|
+ if (!t.isObject() || t.size() != 1 || !t.has("secp256k1Address")) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_15_TRANSPORT, "row " + index + " transport must be {secp256k1Address}");
|
|
+ }
|
|
+ transport =
|
|
+ parseHex(t.get("secp256k1Address"), 20, Code.REG3_15_TRANSPORT, "row " + index + " transport");
|
|
+ }
|
|
+ final Map<String, byte[]> rotation = new LinkedHashMap<>();
|
|
+ final JsonNode rot = e.get("rotation");
|
|
+ if (rot != null) {
|
|
+ if (!rot.isObject() || rot.size() == 0) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_13_ROTATION_UNEXPECTED, "row " + index + " rotation must be a non-empty map");
|
|
+ }
|
|
+ final Iterator<Map.Entry<String, JsonNode>> ri = rot.fields();
|
|
+ while (ri.hasNext()) {
|
|
+ final Map.Entry<String, JsonNode> r = ri.next();
|
|
+ if (SealSchemes.byId(r.getKey()).isEmpty()) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_05_UNKNOWN_SCHEME,
|
|
+ "row " + index + " rotation names the unknown scheme '" + r.getKey() + "'");
|
|
+ }
|
|
+ rotation.put(
|
|
+ r.getKey(),
|
|
+ parseHex(r.getValue(), -1, Code.REG3_12_ROTATION_MISSING, "row " + index + " rotation"));
|
|
+ }
|
|
+ }
|
|
+ byte[] ecdsaAddress = null;
|
|
+ byte[] ecdsaClaim = null;
|
|
+ final JsonNode ec = e.get("ecdsa");
|
|
+ if (ec != null) {
|
|
+ if (!ec.isObject() || ec.size() != 2 || !ec.has("addr") || !ec.has("claim")) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_14_ECDSA, "row " + index + " ecdsa must be {addr, claim}");
|
|
+ }
|
|
+ ecdsaAddress = parseHex(ec.get("addr"), 20, Code.REG3_14_ECDSA, "row " + index + " ecdsa.addr");
|
|
+ ecdsaClaim =
|
|
+ parseHex(
|
|
+ ec.get("claim"), ECDSA_SIGNATURE_LENGTH, Code.REG3_14_ECDSA, "row " + index + " claim");
|
|
+ }
|
|
+ return new Row(index, id, keys, transport, rotation, ecdsaAddress, ecdsaClaim);
|
|
+ }
|
|
+
|
|
+ /** The form a scheme's parser takes: Falcon without the header byte, others as stored. */
|
|
+ private static byte[] registryForm(final int index, final Key k) {
|
|
+ if (k.scheme() == SealSchemes.FALCON_512) {
|
|
+ if (k.publicKey().length != FALCON_512_PK_LENGTH) {
|
|
+ throw new RegistryV3Exception(
|
|
+ Code.REG3_07_KEY_ENCODING, "row " + index + " falcon-512 key is not 897 bytes");
|
|
+ }
|
|
+ return Arrays.copyOfRange(k.publicKey(), 1, FALCON_512_PK_LENGTH);
|
|
+ }
|
|
+ return k.publicKey();
|
|
+ }
|
|
+
|
|
+ private static boolean sameKeys(final Row a, final Row b) {
|
|
+ if (a.keys().size() != b.keys().size()) {
|
|
+ return false;
|
|
+ }
|
|
+ for (final Map.Entry<Integer, Key> e : a.keys().entrySet()) {
|
|
+ final Key other = b.keys().get(e.getKey());
|
|
+ if (other == null || !Arrays.equals(other.publicKey(), e.getValue().publicKey())) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private static Address recover(final Bytes32 digest, final byte[] signature) {
|
|
+ if (signature == null || signature.length != ECDSA_SIGNATURE_LENGTH) {
|
|
+ return null;
|
|
+ }
|
|
+ try {
|
|
+ final SECPSignature s =
|
|
+ SignatureAlgorithmFactory.getInstance().decodeSignature(Bytes.wrap(signature));
|
|
+ return Util.signatureToAddress(s, Hash.wrap(digest));
|
|
+ } catch (final RuntimeException ex) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static byte[] parseHex(
|
|
+ final JsonNode n, final int len, final Code code, final String what) {
|
|
+ if (n == null || !n.isTextual()) {
|
|
+ throw new RegistryV3Exception(code, what + " must be a 0x-prefixed hex string");
|
|
+ }
|
|
+ final String s = n.asText();
|
|
+ if (!s.startsWith("0x") || (s.length() % 2) != 0 || !s.substring(2).matches("[0-9a-f]*")) {
|
|
+ throw new RegistryV3Exception(code, what + " is not lowercase 0x-hex of even length");
|
|
+ }
|
|
+ final byte[] b = Bytes.fromHexString(s).toArrayUnsafe();
|
|
+ if (len >= 0 && b.length != len) {
|
|
+ throw new RegistryV3Exception(code, what + " is " + b.length + " bytes, expected " + len);
|
|
+ }
|
|
+ return b;
|
|
+ }
|
|
+
|
|
+ private static Bytes32 parseBytes32(final JsonNode n, final String what) {
|
|
+ return Bytes32.wrap(parseHex(n, 32, Code.REG3_16_HASH, what));
|
|
+ }
|
|
+
|
|
+ private static Bytes32 node(final Bytes32 l, final Bytes32 r) {
|
|
+ final byte[] in = new byte[65];
|
|
+ in[0] = MERKLE_NODE_TAG;
|
|
+ System.arraycopy(l.toArrayUnsafe(), 0, in, 1, 32);
|
|
+ System.arraycopy(r.toArrayUnsafe(), 0, in, 33, 32);
|
|
+ return Bytes32.wrap(keccak(in));
|
|
+ }
|
|
+
|
|
+ private static void writeAll(final ByteArrayOutputStream out, final byte[] b) {
|
|
+ out.write(b, 0, b.length);
|
|
+ }
|
|
+
|
|
+ private static byte[] uint32be(final int v) {
|
|
+ return new byte[] {(byte) (v >>> 24), (byte) (v >>> 16), (byte) (v >>> 8), (byte) v};
|
|
+ }
|
|
+
|
|
+ private static byte[] uint64be(final long v) {
|
|
+ final byte[] b = new byte[8];
|
|
+ for (int i = 0; i < 8; i++) {
|
|
+ b[i] = (byte) (v >>> (56 - 8 * i));
|
|
+ }
|
|
+ return b;
|
|
+ }
|
|
+
|
|
+ private static byte[] keccak(final byte[] input) {
|
|
+ final KeccakDigest d = new KeccakDigest(256);
|
|
+ d.update(input, 0, input.length);
|
|
+ final byte[] out = new byte[32];
|
|
+ d.doFinal(out, 0);
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ private static String hex(final byte[] b) {
|
|
+ final StringBuilder sb = new StringBuilder(b.length * 2);
|
|
+ for (final byte x : b) {
|
|
+ sb.append(String.format(Locale.ROOT, "%02x", x & 0xff));
|
|
+ }
|
|
+ return sb.toString();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSchemeSchedule.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSchemeSchedule.java
|
|
index a4d1bd43e3..6a706ed712 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSchemeSchedule.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSchemeSchedule.java
|
|
@@ -1,135 +1,245 @@
|
|
/*
|
|
* AERE crypto-agility, step 5: the height-indexed scheme schedule.
|
|
*
|
|
* WHAT IT IS. The same shape as aere.pq.anchorMinSeals ("H:K,H:K,..."), but the value at each
|
|
* step is a SET of scheme ids: "14000000:falcon-512,15500000:falcon-512+slh-dsa-128s" reads
|
|
* "from 14,000,000 anchors carry Falcon; from 15,500,000 they carry Falcon AND SLH-DSA".
|
|
* Changing the mathematics of the chain becomes one property plus keys, never a code edit -
|
|
* that is the whole point of the abstraction layer.
|
|
*
|
|
+ * PER-SCHEME INTERVALS (AIP-22 stage 2, 2026-09-23). A scheme in a step may carry its own anchor
|
|
+ * interval, "scheme/interval": "H:falcon-512/32+slh-dsa-sha2-128s/128" reads "from H, Falcon-512
|
|
+ * is required at every anchor height on the 32 grid and SLH-DSA-SHA2-128s only at the anchor
|
|
+ * heights on the 128 grid", both grids counted from the chain's anchor activation height H0 (the
|
|
+ * one every anchor grid of this chain is counted from, so an anchor of the coarse grid is always
|
|
+ * an anchor of the fine one). A scheme without "/interval" is required at EVERY anchor height,
|
|
+ * which is exactly the behaviour before this change, so an existing schedule keeps its meaning
|
|
+ * byte for byte. The intervals are validated as positive multiples of the anchor grid unit; the
|
|
+ * cross-check against the interval the node actually runs is done where both are known
|
|
+ * (HybridSealSupport at load), never assumed here.
|
|
+ *
|
|
* THE D-147 LESSON, APPLIED AT THE LOADER. The min-seals schedule once accepted a shape whose
|
|
* DANGEROUS step was later in the schedule, because validation looked only at the first step.
|
|
* Here every rule runs over the WHOLE schedule at parse time, and the armability gate
|
|
* (firstUnsatisfied) walks every step against the registry's per-scheme coverage: arming a
|
|
* threshold K under a scheme whose coverage is below K is a chain stop, so it must be refused
|
|
* at configuration time, loudly, before any node boots with it.
|
|
*
|
|
* SEMANTICS OF "BEFORE THE FIRST STEP": schemesAt returns the empty set, which callers read as
|
|
* "the v2 scheme world is not armed here" (the legacy untagged Falcon certificate governs).
|
|
* Empty is never a default INSIDE the schedule: a step with zero schemes is a parse refusal.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft;
|
|
|
|
import com.google.common.base.Splitter;
|
|
|
|
import java.util.ArrayList;
|
|
+import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
+import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
|
|
/** Immutable, validated height-to-scheme-set schedule. */
|
|
public final class PqSchemeSchedule {
|
|
|
|
- /** One step: from {@code fromBlock} (inclusive) the anchor carries {@code schemeIds}. */
|
|
- public record Step(long fromBlock, Set<String> schemeIds) {}
|
|
+ /**
|
|
+ * The unit every anchor grid of an Aere chain is a multiple of (the base anchor interval of both
|
|
+ * chain 2800 and testnet 28001). A per-scheme interval that is not a multiple of it could never
|
|
+ * land on anchor heights, so it is refused at parse time.
|
|
+ */
|
|
+ public static final int GRID_UNIT = 32;
|
|
+
|
|
+ /**
|
|
+ * One step: from {@code fromBlock} (inclusive) the anchor carries {@code schemeIds}; a scheme
|
|
+ * present in {@code intervals} is required only at anchor heights on that interval's grid,
|
|
+ * a scheme absent from it at every anchor height.
|
|
+ */
|
|
+ public record Step(long fromBlock, Set<String> schemeIds, Map<String, Integer> intervals) {
|
|
+ /** Canonical form: defensive copies, never null. */
|
|
+ public Step(
|
|
+ final long fromBlock, final Set<String> schemeIds, final Map<String, Integer> intervals) {
|
|
+ this.fromBlock = fromBlock;
|
|
+ this.schemeIds = Set.copyOf(schemeIds);
|
|
+ this.intervals = intervals == null ? Map.of() : Map.copyOf(intervals);
|
|
+ }
|
|
+
|
|
+ /** A step whose schemes are all required at every anchor height (the pre-AIP-22 form). */
|
|
+ public Step(final long fromBlock, final Set<String> schemeIds) {
|
|
+ this(fromBlock, schemeIds, Map.of());
|
|
+ }
|
|
+ }
|
|
|
|
private final List<Step> steps;
|
|
|
|
private PqSchemeSchedule(final List<Step> steps) {
|
|
this.steps = steps;
|
|
}
|
|
|
|
- /** Parse "H:scheme[+scheme...],H:...". Refuses the WHOLE schedule on any defect: unknown or
|
|
- * repeated scheme in a step, empty step, non-increasing heights, negative height, garbage. */
|
|
+ /** Parse "H:scheme[/interval][+scheme[/interval]...],H:...". Refuses the WHOLE schedule on any
|
|
+ * defect: unknown or repeated scheme in a step, empty step, non-increasing heights, negative
|
|
+ * height, an interval that is not a positive multiple of {@link #GRID_UNIT}, garbage. */
|
|
public static PqSchemeSchedule parse(final String raw) {
|
|
if (raw == null || raw.isBlank()) {
|
|
throw new IllegalArgumentException("AERE PQ ORAR-SCHEME: empty schedule");
|
|
}
|
|
final List<Step> steps = new ArrayList<>();
|
|
long lastHeight = -1;
|
|
for (final String piesa : Splitter.on(',').split(raw)) {
|
|
final List<String> parti = Splitter.on(':').splitToList(piesa.trim());
|
|
if (parti.size() != 2) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: step '" + piesa.trim() + "' is not H:schemes");
|
|
}
|
|
final long h;
|
|
try {
|
|
h = Long.parseLong(parti.get(0).trim());
|
|
} catch (final NumberFormatException e) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: height '" + parti.get(0).trim() + "' is not a number");
|
|
}
|
|
if (h < 0) {
|
|
throw new IllegalArgumentException("AERE PQ ORAR-SCHEME: negative height " + h);
|
|
}
|
|
if (h <= lastHeight) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: heights must strictly increase ("
|
|
+ lastHeight
|
|
+ " then "
|
|
+ h
|
|
+ ") - a schedule read out of order would arm the wrong mathematics");
|
|
}
|
|
lastHeight = h;
|
|
final Set<String> schemes = new LinkedHashSet<>();
|
|
+ final Map<String, Integer> intervals = new LinkedHashMap<>();
|
|
for (final String id : Splitter.on('+').split(parti.get(1))) {
|
|
- final String curat = id.trim();
|
|
- if (curat.isEmpty()) {
|
|
+ final String piece = id.trim();
|
|
+ if (piece.isEmpty()) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: step at " + h + " carries an empty scheme name");
|
|
}
|
|
+ final int slash = piece.indexOf('/');
|
|
+ final String curat = slash < 0 ? piece : piece.substring(0, slash).trim();
|
|
if (SealSchemes.byId(curat).isEmpty()) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: step at " + h + " names UNKNOWN scheme '" + curat
|
|
+ "' - refusing the whole schedule");
|
|
}
|
|
if (!schemes.add(curat)) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: step at " + h + " repeats scheme '" + curat + "'");
|
|
}
|
|
+ if (slash >= 0) {
|
|
+ final String rawInterval = piece.substring(slash + 1).trim();
|
|
+ final int interval;
|
|
+ try {
|
|
+ interval = Integer.parseInt(rawInterval);
|
|
+ } catch (final NumberFormatException e) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE PQ ORAR-SCHEME: step at " + h + " gives scheme '" + curat
|
|
+ + "' the interval '" + rawInterval + "', which is not a number");
|
|
+ }
|
|
+ if (interval <= 0 || interval % GRID_UNIT != 0) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE PQ ORAR-SCHEME: step at " + h + " gives scheme '" + curat
|
|
+ + "' the interval " + interval + ", which is not a positive multiple of the"
|
|
+ + " anchor grid unit " + GRID_UNIT + " - such a scheme could never land on an"
|
|
+ + " anchor height");
|
|
+ }
|
|
+ intervals.put(curat, interval);
|
|
+ }
|
|
}
|
|
if (schemes.isEmpty()) {
|
|
throw new IllegalArgumentException(
|
|
"AERE PQ ORAR-SCHEME: step at " + h + " has no schemes at all");
|
|
}
|
|
- steps.add(new Step(h, Set.copyOf(schemes)));
|
|
+ steps.add(new Step(h, schemes, intervals));
|
|
}
|
|
return new PqSchemeSchedule(List.copyOf(steps));
|
|
}
|
|
|
|
- /** The scheme set in force at {@code height}: the last step at or below it, or the empty set
|
|
- * when the schedule has not started yet (= v2 not armed, legacy governs). */
|
|
- public Set<String> schemesAt(final long height) {
|
|
- Set<String> inForce = Set.of();
|
|
+ /** The step in force at {@code height}, or null before the first one. */
|
|
+ private Step stepAt(final long height) {
|
|
+ Step inForce = null;
|
|
for (final Step s : steps) {
|
|
if (s.fromBlock() <= height) {
|
|
- inForce = s.schemeIds();
|
|
+ inForce = s;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return inForce;
|
|
}
|
|
|
|
+ /** The scheme set in force at {@code height}: the last step at or below it, or the empty set
|
|
+ * when the schedule has not started yet (= v2 not armed, legacy governs). This is the set a
|
|
+ * node must hold KEYS for and the set the armability gate checks; which of them an anchor
|
|
+ * actually demands is {@link #schemesRequiredForAnchor}. */
|
|
+ public Set<String> schemesAt(final long height) {
|
|
+ final Step s = stepAt(height);
|
|
+ return s == null ? Set.of() : s.schemeIds();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The schemes an anchor at {@code anchorHeight} must carry, given that its scheme step is read
|
|
+ * at the PARENT height (the seals of a certificate are made when the parent is committed, so
|
|
+ * every consumer of this schedule already indexes it by the parent), and that a scheme with a
|
|
+ * per-scheme interval is required only when {@code (anchorHeight - anchorBlock)} is a multiple
|
|
+ * of that interval. Without per-scheme intervals this is exactly {@code schemesAt(anchorHeight
|
|
+ * - 1)}.
|
|
+ *
|
|
+ * @param anchorHeight the anchor height being produced, enforced or validated
|
|
+ * @param anchorBlock the chain's anchor activation height, the origin of every anchor grid
|
|
+ * @return the required scheme ids, possibly a strict subset of the step's schemes
|
|
+ */
|
|
+ public Set<String> schemesRequiredForAnchor(final long anchorHeight, final long anchorBlock) {
|
|
+ final Step s = stepAt(anchorHeight - 1);
|
|
+ if (s == null) {
|
|
+ return Set.of();
|
|
+ }
|
|
+ if (s.intervals().isEmpty()) {
|
|
+ return s.schemeIds();
|
|
+ }
|
|
+ final Set<String> required = new LinkedHashSet<>();
|
|
+ for (final String id : s.schemeIds()) {
|
|
+ final Integer interval = s.intervals().get(id);
|
|
+ if (interval == null || onGrid(anchorHeight, anchorBlock, interval)) {
|
|
+ required.add(id);
|
|
+ }
|
|
+ }
|
|
+ return Set.copyOf(required);
|
|
+ }
|
|
+
|
|
+ private static boolean onGrid(final long height, final long origin, final int interval) {
|
|
+ if (height < origin) {
|
|
+ return false;
|
|
+ }
|
|
+ return (height - origin) % interval == 0;
|
|
+ }
|
|
+
|
|
+ /** Whether any step carries a per-scheme interval (then the grid cross-check applies). */
|
|
+ public boolean hasIntervals() {
|
|
+ return steps.stream().anyMatch(s -> !s.intervals().isEmpty());
|
|
+ }
|
|
+
|
|
/** All steps, ascending. */
|
|
public List<Step> steps() {
|
|
return steps;
|
|
}
|
|
|
|
/** The armability gate: walk EVERY step and every scheme in it against the registry's
|
|
* per-scheme coverage; the first (height, scheme) whose coverage is below {@code minSeals}
|
|
* is returned as the refusal, with numbers. Empty means the whole schedule is armable.
|
|
* This is the D-147 discipline: the dangerous step may be the LAST one, so all are walked. */
|
|
public Optional<String> firstUnsatisfied(final HybridSignerRegistry registry, final int minSeals) {
|
|
for (final Step s : steps) {
|
|
for (final String scheme : s.schemeIds()) {
|
|
final int acoperire = registry.coverage(scheme);
|
|
if (acoperire < minSeals) {
|
|
return Optional.of(
|
|
"step at height " + s.fromBlock() + " arms scheme '" + scheme
|
|
+ "' with required seals " + minSeals + " but the registry covers only "
|
|
+ acoperire + " validator(s) - arming this would stop the chain");
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSealed.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSealed.java
|
|
new file mode 100644
|
|
index 0000000000..34049da6fc
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/PqSealed.java
|
|
@@ -0,0 +1,61 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+
|
|
+/**
|
|
+ * AERE AIP-22 stage 4: a consensus payload that carries a post-quantum seal {@code (index, signature)}.
|
|
+ * The four QBFT payloads (proposal, prepare, commit, round-change) implement it; from H_fin the author
|
|
+ * of a message is the id of its seal's index, and only once the seal is VERIFIED
|
|
+ * ({@link AerePqFinality#authorFromSeal}): the author decides whether a message is even relayed, which
|
|
+ * happens before the layers judge it.
|
|
+ */
|
|
+public interface PqSealed {
|
|
+
|
|
+ /**
|
|
+ * The post-quantum seal this payload carries, if any.
|
|
+ *
|
|
+ * @return the seal
|
|
+ */
|
|
+ Optional<FalconSeal> getFalconSeal();
|
|
+
|
|
+ /**
|
|
+ * The message this payload's seal signs over a chain, as the seal layer that judges it builds it
|
|
+ * (PREPARE, PROPOSAL and ROUND-CHANGE carry every field of it). Empty when the payload alone does not
|
|
+ * determine it (a COMMIT's seal signs the block's on-chain hash).
|
|
+ *
|
|
+ * @param chainId the chain id that goes into the message
|
|
+ * @return the message, or empty
|
|
+ */
|
|
+ default Optional<Bytes32> pqSealMessage(final long chainId) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * For a COMMIT, the address that signed its commit seal; empty for every other payload. From H_fin a
|
|
+ * COMMIT's author is its seal index's id only when that is this signer's id (the binding its seal
|
|
+ * layer checks), and the seal itself is judged by the commit layer, armed at or below H_fin.
|
|
+ *
|
|
+ * @return the commit seal's signer, or empty
|
|
+ */
|
|
+ default Optional<Address> commitSealSigner() {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java
|
|
index 82d86d5359..e43afaca83 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java
|
|
@@ -1,57 +1,65 @@
|
|
/*
|
|
* 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/aere-bft-prevrandao-block-creation.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.blockcreation;
|
|
|
|
import org.hyperledger.besu.config.BftConfigOptions;
|
|
import org.hyperledger.besu.consensus.common.ForksSchedule;
|
|
import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
|
|
import org.hyperledger.besu.consensus.common.bft.BftHelpers;
|
|
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
|
|
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
|
import org.hyperledger.besu.ethereum.core.SealableBlockHeader;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
|
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
|
|
|
import java.util.Collections;
|
|
import java.util.Optional;
|
|
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+
|
|
/** The Bft block creator. */
|
|
// This class is responsible for creating a block without committer seals (basically it was just
|
|
// too hard to coordinate with the state machine).
|
|
public class BftBlockCreator extends AbstractBlockCreator {
|
|
|
|
private final BftExtraDataCodec bftExtraDataCodec;
|
|
|
|
/**
|
|
* Instantiates a new Bft block creator.
|
|
*
|
|
* @param miningConfiguration the mining parameters
|
|
* @param forksSchedule the forks schedule
|
|
* @param localAddress the local address
|
|
* @param extraDataCalculator the extra data calculator
|
|
* @param transactionPool the pending transactions
|
|
* @param protocolContext the protocol context
|
|
* @param protocolSchedule the protocol schedule
|
|
* @param bftExtraDataCodec the bft extra data codec
|
|
* @param ethScheduler the scheduler for asynchronous block creation tasks
|
|
*/
|
|
@@ -68,67 +76,80 @@ public class BftBlockCreator extends AbstractBlockCreator {
|
|
super(
|
|
miningConfiguration.setCoinbase(localAddress),
|
|
miningBeneficiaryCalculator(protocolSchedule),
|
|
extraDataCalculator,
|
|
transactionPool,
|
|
protocolContext,
|
|
protocolSchedule,
|
|
ethScheduler);
|
|
this.bftExtraDataCodec = bftExtraDataCodec;
|
|
}
|
|
|
|
@Override
|
|
public BlockCreationResult createBlock(final long timestamp, final BlockHeader parentHeader) {
|
|
ProtocolSpec protocolSpec =
|
|
((BftProtocolSchedule) protocolSchedule)
|
|
.getByBlockNumberOrTimestamp(parentHeader.getNumber() + 1, timestamp);
|
|
|
|
if (protocolSpec.getWithdrawalsProcessor().isPresent()) {
|
|
return createEmptyWithdrawalsBlock(timestamp, parentHeader);
|
|
} else {
|
|
- return createBlock(Optional.empty(), Optional.empty(), timestamp, parentHeader);
|
|
+ return createBlock(
|
|
+ Optional.empty(),
|
|
+ Optional.empty(),
|
|
+ Optional.empty(),
|
|
+ Optional.of(Bytes32.wrap(BftHelpers.EXPECTED_MIX_HASH.getBytes())),
|
|
+ Optional.empty(),
|
|
+ Optional.empty(),
|
|
+ timestamp,
|
|
+ true,
|
|
+ parentHeader);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Construct a mining beneficiary calculator using the given protocolSchedule
|
|
*
|
|
* @param protocolSchedule protocol schedule
|
|
* @return mining beneficiary calculator
|
|
*/
|
|
public static MiningBeneficiaryCalculator miningBeneficiaryCalculator(
|
|
final ProtocolSchedule protocolSchedule) {
|
|
return (blockTimestamp, pendingHeader) -> {
|
|
BlockHeader newBlockHeader =
|
|
BlockHeaderBuilder.createDefault()
|
|
.coinbase(pendingHeader.getCoinbase())
|
|
.buildBlockHeader();
|
|
ProtocolSpec protocolSpec =
|
|
((BftProtocolSchedule) protocolSchedule)
|
|
.getByBlockNumberOrTimestamp(pendingHeader.getNumber(), blockTimestamp);
|
|
return protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(newBlockHeader);
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public BlockCreationResult createEmptyWithdrawalsBlock(
|
|
final long timestamp, final BlockHeader parentHeader) {
|
|
return createBlock(
|
|
Optional.empty(),
|
|
Optional.empty(),
|
|
Optional.of(Collections.emptyList()),
|
|
+ Optional.of(Bytes32.wrap(BftHelpers.EXPECTED_MIX_HASH.getBytes())),
|
|
+ Optional.empty(),
|
|
+ Optional.empty(),
|
|
timestamp,
|
|
+ true,
|
|
parentHeader);
|
|
}
|
|
|
|
@Override
|
|
protected BlockHeader createFinalBlockHeader(final SealableBlockHeader sealableBlockHeader) {
|
|
final BlockHeaderBuilder builder =
|
|
BlockHeaderBuilder.create()
|
|
.populateFrom(sealableBlockHeader)
|
|
.mixHash(BftHelpers.EXPECTED_MIX_HASH)
|
|
.nonce(0L)
|
|
.blockHeaderFunctions(BftBlockHeaderFunctions.forCommittedSeal(bftExtraDataCodec));
|
|
|
|
return builder.buildBlockHeader();
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java
|
|
index 1ecdcbf34e..cefa0a039f 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java
|
|
@@ -6,40 +6,41 @@
|
|
*
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.blockcreation;
|
|
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
|
|
import org.hyperledger.besu.config.BftConfigOptions;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.ConsensusHelpers;
|
|
import org.hyperledger.besu.consensus.common.ForksSchedule;
|
|
import org.hyperledger.besu.consensus.common.bft.BftContext;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
|
|
import org.hyperledger.besu.consensus.common.bft.Vote;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorVote;
|
|
import org.hyperledger.besu.consensus.common.validator.VoteProvider;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Wei;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
|
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
|
import org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification;
|
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
|
|
|
@@ -102,41 +103,42 @@ public class BftBlockCreatorFactory<T extends BftConfigOptions> {
|
|
this.transactionPool = transactionPool;
|
|
this.protocolContext = protocolContext;
|
|
this.protocolSchedule = protocolSchedule;
|
|
this.forksSchedule = forksSchedule;
|
|
this.localAddress = localAddress;
|
|
this.miningConfiguration = miningParams;
|
|
this.bftExtraDataCodec = bftExtraDataCodec;
|
|
this.ethScheduler = ethScheduler;
|
|
}
|
|
|
|
/**
|
|
* Create block creator.
|
|
*
|
|
* @param round the round
|
|
* @return the block creator
|
|
*/
|
|
public BlockCreator create(final int round) {
|
|
return new BftBlockCreator(
|
|
miningConfiguration,
|
|
forksSchedule,
|
|
- localAddress,
|
|
+ AerePqIdentity.local(
|
|
+ localAddress, protocolContext.getBlockchain().getChainHeadBlockNumber() + 1L),
|
|
ph -> createExtraData(round, ph),
|
|
transactionPool,
|
|
protocolContext,
|
|
protocolSchedule,
|
|
bftExtraDataCodec,
|
|
ethScheduler);
|
|
}
|
|
|
|
/**
|
|
* Sets min transaction gas price.
|
|
*
|
|
* @param minTransactionGasPrice the min transaction gas price
|
|
*/
|
|
public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) {
|
|
miningConfiguration.setMinTransactionGasPrice(minTransactionGasPrice);
|
|
}
|
|
|
|
/**
|
|
* Gets min transaction gas price.
|
|
*
|
|
@@ -169,41 +171,44 @@ public class BftBlockCreatorFactory<T extends BftConfigOptions> {
|
|
/**
|
|
* Build the extra data VALUE for a block on this parent, before it is encoded.
|
|
*
|
|
* <p>AERE ANCHOR V2: split out of {@link #createExtraData(int, BlockHeader)} with NO behaviour
|
|
* change, so a subclass can post-process the value (QBFT rewrites vanityData with the anchor
|
|
* digest and fills element 6 with the parent's certificate) without decoding and
|
|
* re-encoding bytes it just produced. IBFT, which shares this class, keeps the old path exactly:
|
|
* it never overrides this and never sees the anchor.
|
|
*
|
|
* @param round the round
|
|
* @param parentHeader the parent header
|
|
* @return the extra data value
|
|
*/
|
|
protected BftExtraData buildExtraData(final int round, final BlockHeader parentHeader) {
|
|
final BftContext bftContext = protocolContext.getConsensusContext(BftContext.class);
|
|
final ValidatorProvider validatorProvider = bftContext.getValidatorProvider();
|
|
Optional<VoteProvider> voteProviderAfterBlock =
|
|
validatorProvider.getVoteProviderAfterBlock(parentHeader);
|
|
checkState(voteProviderAfterBlock.isPresent(), "Bft requires a vote provider");
|
|
final Optional<ValidatorVote> proposal =
|
|
- voteProviderAfterBlock.get().getVoteAfterBlock(parentHeader, localAddress);
|
|
+ voteProviderAfterBlock
|
|
+ .get()
|
|
+ .getVoteAfterBlock(
|
|
+ parentHeader, AerePqIdentity.local(localAddress, parentHeader.getNumber() + 1L));
|
|
|
|
final List<Address> validators =
|
|
new ArrayList<>(validatorProvider.getValidatorsAfterBlock(parentHeader));
|
|
|
|
final BftExtraData extraData =
|
|
new BftExtraData(
|
|
ConsensusHelpers.zeroLeftPad(
|
|
miningConfiguration.getExtraData(), BftExtraDataCodec.EXTRA_VANITY_LENGTH),
|
|
Collections.emptyList(),
|
|
toVote(proposal),
|
|
round,
|
|
validators);
|
|
|
|
return extraData;
|
|
}
|
|
|
|
/**
|
|
* Change target gas limit.
|
|
*
|
|
* @param newTargetGasLimit the new target gas limit
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java
|
|
index 25474631c8..da4eeecd8c 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.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/aere-bft-coordinator-lifecycle-sync.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.blockcreation;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExecutors;
|
|
import org.hyperledger.besu.consensus.common.bft.BftProcessor;
|
|
import org.hyperledger.besu.consensus.common.bft.events.NewChainHead;
|
|
import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Wei;
|
|
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
|
|
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
|
|
import org.hyperledger.besu.ethereum.chain.BlockAddedObserver;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.core.Block;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.Transaction;
|
|
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents;
|
|
|
|
@@ -177,52 +183,56 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv
|
|
public void onInitialSyncCompleted() {
|
|
LOG.info("Starting BFT mining coordinator following initial sync");
|
|
enable();
|
|
start();
|
|
}
|
|
|
|
@Override
|
|
public void onInitialSyncRestart() {
|
|
// Nothing to do. The mining coordinator won't be started until
|
|
// sync has completed.
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void awaitStop() throws InterruptedException {
|
|
bftExecutors.awaitStop();
|
|
}
|
|
|
|
@Override
|
|
- public boolean enable() {
|
|
+ public synchronized boolean enable() {
|
|
+ // AERE D-434 (81a600236a, issue #10877): synchronized with start()/stop() so the multi-step
|
|
+ // state checks below cannot interleave with a concurrent lifecycle transition.
|
|
// Return true if we're already running or idle, or successfully switch to idle
|
|
if (state.get() == State.RUNNING
|
|
|| state.get() == State.IDLE
|
|
|| state.compareAndSet(State.PAUSED, State.IDLE)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
- public boolean disable() {
|
|
+ public synchronized boolean disable() {
|
|
+ // AERE D-434 (81a600236a, issue #10877): synchronized with start()/stop() so the multi-step
|
|
+ // state checks below cannot interleave with a concurrent lifecycle transition.
|
|
if (state.get() == State.PAUSED
|
|
|| state.compareAndSet(State.IDLE, State.PAUSED)
|
|
|| state.compareAndSet(State.RUNNING, State.PAUSED)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isMining() {
|
|
return state.get() == State.RUNNING;
|
|
}
|
|
|
|
@Override
|
|
public Wei getMinTransactionGasPrice() {
|
|
return blockCreatorFactory.getMinTransactionGasPrice();
|
|
}
|
|
|
|
@Override
|
|
public Wei getMinPriorityFeePerGas() {
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/PqAnchorProducer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/PqAnchorProducer.java
|
|
index a46b7d8874..e8fc683458 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/PqAnchorProducer.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/PqAnchorProducer.java
|
|
@@ -1,38 +1,39 @@
|
|
/*
|
|
* Copyright contributors to Besu / 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.consensus.common.bft.blockcreation;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.BftContext;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorConfig;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorNotReadyException;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorV2;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
|
|
import java.util.ArrayList;
|
|
@@ -363,75 +364,86 @@ public final class PqAnchorProducer {
|
|
* Falcon. vanityData becomes the v2 digest under "AERE-PQ-ANCHOR-2". Refuses, through the same
|
|
* not-ready exception the v1 path uses, rather than writing a certificate short of a scheme.
|
|
*/
|
|
private static BftExtraData applyV2(
|
|
final PqAnchorConfig cfg,
|
|
final long blockNumber,
|
|
final BlockHeader parentHeader,
|
|
final BftExtraData base,
|
|
final List<FalconSeal> falconCertificate,
|
|
final Bytes32 message,
|
|
final int required,
|
|
final int sealCap) {
|
|
final long parentNumber = parentHeader.getNumber();
|
|
final List<SchemeSeal> v2 = new ArrayList<>();
|
|
final Set<Integer> falconIndices = new LinkedHashSet<>();
|
|
for (final FalconSeal f : falconCertificate) {
|
|
v2.add(new SchemeSeal(SealSchemes.FALCON_512.wireId(), f.getValidatorIndex(), f.getSignature()));
|
|
falconIndices.add(f.getValidatorIndex());
|
|
}
|
|
final HybridSealSupport hybrid = HybridSealSupport.instance();
|
|
+ // AIP-22 stage 2: only the schemes THIS anchor height demands (per-scheme grids counted from
|
|
+ // the activation height); at a Falcon-only anchor no SLH-DSA seal is gathered or written, which
|
|
+ // is the whole disk saving of the two-grid design
|
|
final Set<String> schemes =
|
|
- hybrid.schedule().map(sch -> sch.schemesAt(parentNumber)).orElse(Set.of());
|
|
+ hybrid
|
|
+ .schedule()
|
|
+ .map(sch -> sch.schemesRequiredForAnchor(blockNumber, cfg.anchorBlock()))
|
|
+ .orElse(Set.of());
|
|
final List<SchemeSeal> heard =
|
|
PqSealCache.instance().extrasFor(parentNumber, parentHeader.getHash());
|
|
for (final String schemeId : schemes) {
|
|
if (SealSchemes.FALCON_512.id().equals(schemeId)) {
|
|
continue;
|
|
}
|
|
final Optional<SealScheme> scheme = SealSchemes.byId(schemeId);
|
|
if (scheme.isEmpty()) {
|
|
throw new PqAnchorNotReadyException(
|
|
parentNumber,
|
|
0,
|
|
required,
|
|
"the scheme schedule names '" + schemeId + "', which this binary does not implement");
|
|
}
|
|
final Optional<HybridSignerRegistry> registry = hybrid.registry();
|
|
- if (registry.isEmpty()) {
|
|
+ // AERE AIP-22 stage 3b: from H_k the keys come from the v3 epoch in force at the parent
|
|
+ final boolean v3Keys = AerePqIdentity.keysFromV3(parentNumber);
|
|
+ if (registry.isEmpty() && !v3Keys) {
|
|
throw new PqAnchorNotReadyException(
|
|
parentNumber,
|
|
0,
|
|
required,
|
|
"no hybrid registry is loaded on this node, so no " + schemeId + " seal can be verified");
|
|
}
|
|
int kept = 0;
|
|
int rejected = 0;
|
|
for (final SchemeSeal s : heard) {
|
|
if (s.getSchemeWireId() != scheme.get().wireId()) {
|
|
continue;
|
|
}
|
|
if (!falconIndices.contains(s.getValidatorIndex())) {
|
|
rejected++;
|
|
continue;
|
|
}
|
|
- final Optional<byte[]> pk = registry.get().publicKey(s.getValidatorIndex(), schemeId);
|
|
+ final Optional<byte[]> pk =
|
|
+ v3Keys
|
|
+ ? AerePqIdentity.v3KeyAt(parentNumber, s.getValidatorIndex(), schemeId)
|
|
+ : registry.get().publicKey(s.getValidatorIndex(), schemeId);
|
|
if (pk.isEmpty()
|
|
|| !scheme.get().verifyRaw(pk.get(), message.toArray(), s.getSignature().toArray())) {
|
|
rejected++;
|
|
continue;
|
|
}
|
|
v2.add(s);
|
|
kept++;
|
|
if (kept >= sealCap) {
|
|
break;
|
|
}
|
|
}
|
|
if (kept < required) {
|
|
throw new PqAnchorNotReadyException(
|
|
parentNumber,
|
|
kept,
|
|
required,
|
|
"V2: heard "
|
|
+ heard.size()
|
|
+ " extra seal(s) for parent hash "
|
|
+ parentHeader.getHash()
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/messagewrappers/BftMessage.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/messagewrappers/BftMessage.java
|
|
index 0a88b579fd..e52c52905e 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/messagewrappers/BftMessage.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/messagewrappers/BftMessage.java
|
|
@@ -1,60 +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/aere-bft-bounded-message-lists.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.messagewrappers;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.Authored;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.RoundSpecific;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
import org.hyperledger.besu.crypto.SECPSignature;
|
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
|
|
import java.util.Objects;
|
|
import java.util.StringJoiner;
|
|
import java.util.function.Function;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/**
|
|
* The Bft message.
|
|
*
|
|
* @param <P> the type of Payload
|
|
*/
|
|
public class BftMessage<P extends Payload> implements Authored, RoundSpecific {
|
|
|
|
+ /**
|
|
+ * Maximum number of entries permitted in any embedded list (round-changes, prepares) when
|
|
+ * decoding a BFT message. AERE D-434: ported from upstream hyperledger/besu dd4101c9ec.
|
|
+ */
|
|
+ public static final int MAX_LIST_ENTRIES = 512;
|
|
+
|
|
private final SignedData<P> payload;
|
|
|
|
/**
|
|
* Instantiates a new Bft message.
|
|
*
|
|
* @param payload the payload
|
|
*/
|
|
public BftMessage(final SignedData<P> payload) {
|
|
this.payload = payload;
|
|
}
|
|
|
|
@Override
|
|
public Address getAuthor() {
|
|
return payload.getAuthor();
|
|
}
|
|
|
|
@Override
|
|
public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
return payload.getPayload().getRoundIdentifier();
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/network/ValidatorPeers.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/network/ValidatorPeers.java
|
|
index f4fccecf3c..649fa75cf4 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/network/ValidatorPeers.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/network/ValidatorPeers.java
|
|
@@ -1,36 +1,43 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.network;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection.PeerNotConnected;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* Responsible for tracking the network peers which have a connection to this node, then
|
|
* multicasting packets to ONLY the peers which have been identified as being validators.
|
|
@@ -76,41 +83,46 @@ public class ValidatorPeers implements ValidatorMulticaster, PeerConnectionTrack
|
|
}
|
|
|
|
@Override
|
|
public void send(final MessageData message) {
|
|
sendMessageToSpecificAddresses(getLatestValidators(), message);
|
|
}
|
|
|
|
@Override
|
|
public void send(final MessageData message, final Collection<Address> denylist) {
|
|
final Collection<Address> includedValidators =
|
|
getLatestValidators().stream()
|
|
.filter(a -> !denylist.contains(a))
|
|
.collect(Collectors.toSet());
|
|
sendMessageToSpecificAddresses(includedValidators, message);
|
|
}
|
|
|
|
private void sendMessageToSpecificAddresses(
|
|
final Collection<Address> recipients, final MessageData message) {
|
|
LOG.trace(
|
|
"Sending message to peers messageCode={} recipients={}", message.getCode(), recipients);
|
|
- recipients.stream()
|
|
- .map(connectionsByAddress::get)
|
|
- .filter(Objects::nonNull)
|
|
+ // AERE AIP-22 stage 3: from H_id the recipients are ids; they are reached through the node-key
|
|
+ // address their v3 row lists as transport, or through every peer when a row lists none
|
|
+ final java.util.Optional<Collection<Address>> targets =
|
|
+ AerePqIdentity.transportTargets(recipients);
|
|
+ (targets.isPresent()
|
|
+ ? targets.get().stream().map(connectionsByAddress::get).filter(Objects::nonNull)
|
|
+ : connectionsByAddress.values().stream())
|
|
.flatMap(Set::stream)
|
|
+ .distinct()
|
|
.forEach(
|
|
connection -> {
|
|
try {
|
|
connection.sendForProtocol(protocolName, message);
|
|
} catch (final PeerNotConnected peerNotConnected) {
|
|
LOG.trace(
|
|
"Lost connection to a validator. remoteAddress={} peerInfo={}",
|
|
connection.getRemoteAddress(),
|
|
connection.getPeerInfo());
|
|
}
|
|
});
|
|
}
|
|
|
|
private Collection<Address> getLatestValidators() {
|
|
return validatorProvider.getValidatorsAtHead();
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java
|
|
index 00326eec42..2c59e698b6 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/payload/SignedData.java
|
|
@@ -1,77 +1,94 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.payload;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.crypto.SECPSignature;
|
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.core.Util;
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
|
|
import java.math.BigInteger;
|
|
import java.util.Objects;
|
|
import java.util.StringJoiner;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/**
|
|
* The type Signed data.
|
|
*
|
|
* @param <M> the type parameter of Payload
|
|
*/
|
|
public class SignedData<M extends Payload> implements Authored {
|
|
|
|
private static final BigInteger HALF_CURVE_ORDER =
|
|
SignatureAlgorithmFactory.getInstance().getHalfCurveOrder();
|
|
|
|
private final Address sender;
|
|
private final SECPSignature signature;
|
|
private final M unsignedPayload;
|
|
|
|
/**
|
|
* Create signed data.
|
|
*
|
|
* @param <T> the type parameter
|
|
* @param payload the payload
|
|
* @param signature the signature
|
|
* @return the signed data
|
|
* @throws IllegalArgumentException if the signature is invalid
|
|
*/
|
|
public static <T extends Payload> SignedData<T> create(
|
|
final T payload, final SECPSignature signature) {
|
|
final Hash msgHash = payload.hashForSignature();
|
|
- return new SignedData<>(payload, Util.signatureToAddress(signature, msgHash), signature);
|
|
+ // AERE AIP-22 stage 3: from H_id the author is the post-quantum id of the signer's v3 row
|
|
+ // AERE AIP-22 stage 4: from H_fin the author is the id of the row the message's post-quantum seal index names, and the
|
|
+ // envelope's ECDSA signature is not read for authorship (a message without a post-quantum seal has no author then)
|
|
+ final long aereHeight = payload.getRoundIdentifier().getSequenceNumber();
|
|
+ return new SignedData<>(
|
|
+ payload,
|
|
+ AerePqFinality.active(aereHeight)
|
|
+ ? AerePqFinality.authorFromSeal(payload, aereHeight)
|
|
+ : AerePqIdentity.author(Util.signatureToAddress(signature, msgHash), aereHeight),
|
|
+ signature);
|
|
}
|
|
|
|
private SignedData(final M unsignedPayload, final Address sender, final SECPSignature signature) {
|
|
if (!(signature.getS().compareTo(HALF_CURVE_ORDER) <= 0)) {
|
|
throw new IllegalArgumentException("Signature is invalid");
|
|
}
|
|
this.unsignedPayload = unsignedPayload;
|
|
this.sender = sender;
|
|
this.signature = signature;
|
|
}
|
|
|
|
@Override
|
|
public Address getAuthor() {
|
|
return sender;
|
|
}
|
|
|
|
/**
|
|
* Gets payload.
|
|
*
|
|
* @return the payload
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ADRS.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ADRS.java
|
|
index 7610cf8762..ca87df83d3 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ADRS.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ADRS.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
import org.bouncycastle.util.Pack;
|
|
|
|
@SuppressWarnings("all")
|
|
class ADRS
|
|
{
|
|
static final int WOTS_HASH = 0;
|
|
static final int WOTS_PK = 1;
|
|
static final int TREE = 2;
|
|
static final int FORS_TREE = 3;
|
|
static final int FORS_PK = 4;
|
|
static final int WOTS_PRF = 5;
|
|
static final int FORS_PRF = 6;
|
|
|
|
static final int OFFSET_LAYER = 0;
|
|
static final int OFFSET_TREE = 4;
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/Fors.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/Fors.java
|
|
index d89d83af86..803fca98b4 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/Fors.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/Fors.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.math.BigInteger;
|
|
import java.util.LinkedList;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
@SuppressWarnings("all")
|
|
class Fors
|
|
{
|
|
SLHDSAEngine engine;
|
|
|
|
public Fors(SLHDSAEngine engine)
|
|
{
|
|
this.engine = engine;
|
|
}
|
|
|
|
// Input: Secret seed SK.seed, start index s, target node height z, public seed PK.seed, address ADRS
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/HT.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/HT.java
|
|
index b7d96c16f8..88ff081efe 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/HT.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/HT.java
|
|
@@ -1,46 +1,60 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
@SuppressWarnings("all")
|
|
class HT
|
|
{
|
|
private final byte[] skSeed;
|
|
private final byte[] pkSeed;
|
|
SLHDSAEngine engine;
|
|
WotsPlus wots;
|
|
|
|
final byte[] htPubKey;
|
|
|
|
+ // AERE (D-337, 2026-09-26): the same object without htPubKey. The constructor below computes the
|
|
+ // top-layer public key (a full treehash of 2^H' WOTS+ leaves) on every signature, and signing never
|
|
+ // reads it. Used by ParallelSigning; key generation keeps the constructor below.
|
|
+ HT(SLHDSAEngine engine, byte[] skSeed, byte[] pkSeed, boolean withoutPublicKey)
|
|
+ {
|
|
+ this.skSeed = skSeed;
|
|
+ this.pkSeed = pkSeed;
|
|
+ this.engine = engine;
|
|
+ this.wots = new WotsPlus(engine);
|
|
+ this.htPubKey = null;
|
|
+ }
|
|
+
|
|
public HT(SLHDSAEngine engine, byte[] skSeed, byte[] pkSeed)
|
|
{
|
|
this.skSeed = skSeed;
|
|
this.pkSeed = pkSeed;
|
|
|
|
this.engine = engine;
|
|
this.wots = new WotsPlus(engine);
|
|
|
|
ADRS adrs = new ADRS();
|
|
adrs.setLayerAddress(engine.D - 1);
|
|
adrs.setTreeAddress(0);
|
|
|
|
if (skSeed != null)
|
|
{
|
|
htPubKey = xmss_PKgen(skSeed, pkSeed, adrs);
|
|
}
|
|
else
|
|
{
|
|
htPubKey = null;
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/IndexedDigest.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/IndexedDigest.java
|
|
index 8ff076d70d..49bf358925 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/IndexedDigest.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/IndexedDigest.java
|
|
@@ -1,26 +1,28 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class IndexedDigest
|
|
{
|
|
final long idx_tree;
|
|
final int idx_leaf;
|
|
final byte[] digest;
|
|
|
|
IndexedDigest(long idx_tree, int idx_leaf, byte[] digest)
|
|
{
|
|
this.idx_tree = idx_tree;
|
|
this.idx_leaf = idx_leaf;
|
|
this.digest = digest;
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/JdkDigest.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/JdkDigest.java
|
|
index c7a8e86fae..7edcab834a 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/JdkDigest.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/JdkDigest.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.security.DigestException;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import org.bouncycastle.crypto.ExtendedDigest;
|
|
import org.bouncycastle.util.Memoable;
|
|
|
|
/**
|
|
* A Bouncy Castle {@link ExtendedDigest} backed by the JDK's {@link MessageDigest}, so SLH-DSA's
|
|
* millions of short hashes run on the SHA-NI intrinsics. Measured 2026-09-04 on an EPYC host: 3M
|
|
* SHA-256 of 64 bytes, Bouncy Castle 2533 ms, JDK 335 ms; one sha2_128s signature 1364 ms before,
|
|
* 325 ms after. {@link Memoable} is how the SLH-DSA engine keeps the pk-seed prefix state: it is
|
|
* implemented here with {@link MessageDigest#clone()}, which the SUN provider supports for SHA-2.
|
|
*/
|
|
@SuppressWarnings("all")
|
|
final class JdkDigest implements ExtendedDigest, Memoable {
|
|
private final String algorithm;
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/NodeEntry.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/NodeEntry.java
|
|
index 4cd30cfff7..adaa9abe3e 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/NodeEntry.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/NodeEntry.java
|
|
@@ -1,24 +1,26 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class NodeEntry
|
|
{
|
|
final byte[] nodeValue;
|
|
final int nodeHeight;
|
|
|
|
NodeEntry(byte[] nodeValue, int nodeHeight)
|
|
{
|
|
this.nodeValue = nodeValue;
|
|
this.nodeHeight = nodeHeight;
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/PK.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/PK.java
|
|
index 4d0ef5fe2b..8e4b32ee25 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/PK.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/PK.java
|
|
@@ -1,24 +1,26 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class PK
|
|
{
|
|
final byte[] seed;
|
|
final byte[] root;
|
|
|
|
PK(byte[] seed, byte[] root)
|
|
{
|
|
this.seed = seed;
|
|
this.root = root;
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ParallelSigning.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ParallelSigning.java
|
|
new file mode 100755
|
|
index 0000000000..2a1505ddcb
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/ParallelSigning.java
|
|
@@ -0,0 +1,257 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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
|
|
+ *
|
|
+ * Written by AERE Network (not derived from Bouncy Castle); emitted into this package by
|
|
+ * consensus-pqc/slhdsa-fork/genereaza-motorul.py from ParallelSigning.java.sablon. DO NOT EDIT BY HAND.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.concurrent.Callable;
|
|
+import java.util.concurrent.ExecutionException;
|
|
+import java.util.concurrent.ExecutorService;
|
|
+import java.util.concurrent.Executors;
|
|
+import java.util.concurrent.Future;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+import org.bouncycastle.util.Arrays;
|
|
+
|
|
+/**
|
|
+ * SLH-DSA signing with the message-independent work spread over the cores; the SAME bytes as the
|
|
+ * sequential signer, which remains the fallback.
|
|
+ *
|
|
+ * <p>D-337, measured 2026-09-26 on chain 2800: the parent of every anchor took 1.69 s against 0.60 s
|
|
+ * for an ordinary block (import times on two validators, fifteen anchors each), because each
|
|
+ * validator signs its Commit with SLH-DSA-SHA2-128s there, on the QBFT thread, on one core. One
|
|
+ * signature on a validator's CPU (EPYC-Rome, one core): 0.47 s warm, 0.88-1.02 s cold, and a
|
|
+ * validator signs once every ~77 s. Almost all of it is message-independent: the authentication
|
|
+ * path of each of the D hypertree layers (2^H' - 1 WOTS+ leaves each) and the k FORS trees. Only
|
|
+ * the WOTS+ signature of each layer depends on the root of the layer below, and that chain is cheap.
|
|
+ * So the auth paths and FORS run as separate tasks on a small daemon pool, each with its own engine
|
|
+ * (the engines hold digest state and are not thread-safe), and the chain is then walked in order.
|
|
+ *
|
|
+ * <p>Also dropped: the HT constructor used by the sequential signer computes the top layer's public
|
|
+ * key (a full 2^H'-leaf treehash) on every signature, and signing never reads it.
|
|
+ *
|
|
+ * <p>Taken only with more than one core and unless {@code -Daere.pq.slhdsa.parallel=false}; any
|
|
+ * failure returns null and the caller runs the original Bouncy Castle code unchanged.
|
|
+ */
|
|
+@SuppressWarnings("all")
|
|
+final class ParallelSigning {
|
|
+
|
|
+ static final String SWITCH_PROPERTY = "aere.pq.slhdsa.parallel";
|
|
+
|
|
+ private static final int THREADS =
|
|
+ Math.max(1, Math.min(8, Runtime.getRuntime().availableProcessors()));
|
|
+
|
|
+ // counts tasks executed on the pool; the proof reads it to show the parallel path was the one taken
|
|
+ private static final AtomicInteger TASKS_RUN = new AtomicInteger();
|
|
+
|
|
+ private static volatile ExecutorService pool;
|
|
+
|
|
+ private ParallelSigning() {}
|
|
+
|
|
+ static boolean enabled() {
|
|
+ return THREADS > 1
|
|
+ && !"false".equalsIgnoreCase(System.getProperty(SWITCH_PROPERTY, "true").trim());
|
|
+ }
|
|
+
|
|
+ static int tasksRun() {
|
|
+ return TASKS_RUN.get();
|
|
+ }
|
|
+
|
|
+ static int tasksPerSignature(final SLHDSAParameters params) {
|
|
+ return 1 + 2 * params.getEngine().D;
|
|
+ }
|
|
+
|
|
+ private static ExecutorService pool() {
|
|
+ ExecutorService p = pool;
|
|
+ if (p == null) {
|
|
+ synchronized (ParallelSigning.class) {
|
|
+ p = pool;
|
|
+ if (p == null) {
|
|
+ final AtomicInteger n = new AtomicInteger();
|
|
+ p =
|
|
+ Executors.newFixedThreadPool(
|
|
+ THREADS,
|
|
+ r -> {
|
|
+ final Thread t = new Thread(r, "aere-slhdsa-sign-" + n.incrementAndGet());
|
|
+ t.setDaemon(true);
|
|
+ return t;
|
|
+ });
|
|
+ pool = p;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return p;
|
|
+ }
|
|
+
|
|
+ /** The signature, or null when this path is not taken; the caller then runs the original code. */
|
|
+ static byte[] trySign(
|
|
+ final SLHDSAPrivateKeyParameters privKey,
|
|
+ final byte[] msgPrefix,
|
|
+ final byte[] msg,
|
|
+ final byte[] optRand) {
|
|
+ if (!enabled()) {
|
|
+ return null;
|
|
+ }
|
|
+ try {
|
|
+ return sign(privKey, msgPrefix, msg, optRand);
|
|
+ } catch (final InterruptedException e) {
|
|
+ Thread.currentThread().interrupt();
|
|
+ return null;
|
|
+ } catch (final ExecutionException | RuntimeException e) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static byte[] sign(
|
|
+ final SLHDSAPrivateKeyParameters privKey,
|
|
+ final byte[] msgPrefix,
|
|
+ final byte[] msg,
|
|
+ final byte[] optRand)
|
|
+ throws InterruptedException, ExecutionException {
|
|
+ final SLHDSAParameters params = privKey.getParameters();
|
|
+ final byte[] skSeed = privKey.sk.seed;
|
|
+ final byte[] pkSeed = privKey.pk.seed;
|
|
+ final SLHDSAEngine engine = params.getEngine();
|
|
+ engine.init(pkSeed);
|
|
+
|
|
+ // the randomiser and the message digest, exactly as SLHDSASigner.internalGenerateSignature
|
|
+ final byte[] r = engine.PRF_msg(privKey.sk.prf, optRand, msgPrefix, msg);
|
|
+ final IndexedDigest idxDigest = engine.H_msg(r, pkSeed, privKey.pk.root, msgPrefix, msg);
|
|
+ final byte[] mHash = idxDigest.digest;
|
|
+ final long idxTree = idxDigest.idx_tree;
|
|
+ final int idxLeaf = idxDigest.idx_leaf;
|
|
+ final int d = engine.D;
|
|
+ final int hPrime = engine.H_PRIME;
|
|
+
|
|
+ // the (tree, leaf) each layer signs with: the walk HT.sign does, layer 0 first
|
|
+ final long[] tree = new long[d];
|
|
+ final int[] leaf = new int[d];
|
|
+ long t = idxTree;
|
|
+ int l = idxLeaf;
|
|
+ for (int j = 0; j < d; j++) {
|
|
+ if (j > 0) {
|
|
+ l = (int) (t & ((1 << hPrime) - 1));
|
|
+ t >>>= hPrime;
|
|
+ }
|
|
+ tree[j] = t;
|
|
+ leaf[j] = l;
|
|
+ }
|
|
+
|
|
+ final List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
|
|
+ tasks.add(forsTask(params, skSeed, pkSeed, mHash, idxTree, idxLeaf));
|
|
+ final byte[][][] auth = new byte[d][hPrime][];
|
|
+ for (int j = 0; j < d; j++) {
|
|
+ // two halves per layer: the top auth node alone is half of the tree's leaves, the rest the other half
|
|
+ tasks.add(authTask(params, skSeed, pkSeed, j, tree[j], leaf[j], hPrime - 1, hPrime, auth));
|
|
+ tasks.add(authTask(params, skSeed, pkSeed, j, tree[j], leaf[j], 0, hPrime - 1, auth));
|
|
+ }
|
|
+ final List<Future<Object>> done = pool().invokeAll(tasks);
|
|
+ final Object[] fors = (Object[]) done.get(0).get();
|
|
+ for (int i = 1; i < done.size(); i++) {
|
|
+ done.get(i).get(); // surfaces a failed task, which sends the caller to the original code
|
|
+ }
|
|
+ for (int j = 0; j < d; j++) {
|
|
+ for (int h = 0; h < hPrime; h++) {
|
|
+ if (auth[j][h] == null) {
|
|
+ throw new IllegalStateException("auth path of layer " + j + " height " + h + " missing");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ final SIG_FORS[] sigFors = (SIG_FORS[]) fors[0];
|
|
+ final byte[] pkFors = (byte[]) fors[1];
|
|
+
|
|
+ // the hypertree chain, in order: each layer's WOTS+ signs the root of the layer below (FORS for layer 0)
|
|
+ final HT ht = new HT(engine, skSeed, pkSeed, true);
|
|
+ byte[] m = pkFors;
|
|
+ final byte[][] htParts = new byte[d][];
|
|
+ for (int j = 0; j < d; j++) {
|
|
+ final ADRS adrs = new ADRS();
|
|
+ adrs.setLayerAddress(j);
|
|
+ adrs.setTreeAddress(tree[j]);
|
|
+ final ADRS wotsAdrs = new ADRS(adrs);
|
|
+ wotsAdrs.setTypeAndClear(ADRS.WOTS_HASH);
|
|
+ wotsAdrs.setKeyPairAddress(leaf[j]);
|
|
+ final SIG_XMSS xmss = new SIG_XMSS(ht.wots.sign(m, skSeed, pkSeed, wotsAdrs), auth[j]);
|
|
+ htParts[j] = Arrays.concatenate(xmss.sig, Arrays.concatenate(xmss.auth));
|
|
+ if (j < d - 1) {
|
|
+ m = ht.xmss_pkFromSig(leaf[j], xmss, m, pkSeed, adrs);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ final byte[][] parts = new byte[sigFors.length + 2][];
|
|
+ parts[0] = r;
|
|
+ for (int i = 0; i != sigFors.length; i++) {
|
|
+ parts[1 + i] = Arrays.concatenate(sigFors[i].sk, Arrays.concatenate(sigFors[i].authPath));
|
|
+ }
|
|
+ parts[parts.length - 1] = Arrays.concatenate(htParts);
|
|
+ return Arrays.concatenate(parts);
|
|
+ }
|
|
+
|
|
+ private static Callable<Object> forsTask(
|
|
+ final SLHDSAParameters params,
|
|
+ final byte[] skSeed,
|
|
+ final byte[] pkSeed,
|
|
+ final byte[] mHash,
|
|
+ final long idxTree,
|
|
+ final int idxLeaf) {
|
|
+ return () -> {
|
|
+ TASKS_RUN.incrementAndGet();
|
|
+ final SLHDSAEngine e = params.getEngine();
|
|
+ e.init(pkSeed);
|
|
+ final Fors fors = new Fors(e);
|
|
+ ADRS adrs = new ADRS();
|
|
+ adrs.setTypeAndClear(ADRS.FORS_TREE);
|
|
+ adrs.setTreeAddress(idxTree);
|
|
+ adrs.setKeyPairAddress(idxLeaf);
|
|
+ final SIG_FORS[] sigFors = fors.sign(mHash, skSeed, pkSeed, adrs);
|
|
+ adrs = new ADRS();
|
|
+ adrs.setTypeAndClear(ADRS.FORS_TREE);
|
|
+ adrs.setTreeAddress(idxTree);
|
|
+ adrs.setKeyPairAddress(idxLeaf);
|
|
+ return new Object[] {sigFors, fors.pkFromSig(sigFors, mHash, pkSeed, adrs)};
|
|
+ };
|
|
+ }
|
|
+
|
|
+ // the auth-path loop of HT.xmss_sign, for heights [fromHeight, toHeight) of one layer's tree
|
|
+ private static Callable<Object> authTask(
|
|
+ final SLHDSAParameters params,
|
|
+ final byte[] skSeed,
|
|
+ final byte[] pkSeed,
|
|
+ final int layer,
|
|
+ final long treeAddress,
|
|
+ final int idx,
|
|
+ final int fromHeight,
|
|
+ final int toHeight,
|
|
+ final byte[][][] auth) {
|
|
+ return () -> {
|
|
+ TASKS_RUN.incrementAndGet();
|
|
+ final SLHDSAEngine e = params.getEngine();
|
|
+ e.init(pkSeed);
|
|
+ final HT ht = new HT(e, skSeed, pkSeed, true);
|
|
+ final ADRS a = new ADRS();
|
|
+ a.setTypeAndClear(ADRS.TREE);
|
|
+ a.setLayerAddress(layer);
|
|
+ a.setTreeAddress(treeAddress);
|
|
+ for (int j = fromHeight; j < toHeight; j++) {
|
|
+ final int k = (idx >>> j) ^ 1;
|
|
+ auth[layer][j] = ht.treehash(skSeed, k << j, j, pkSeed, a);
|
|
+ }
|
|
+ return null;
|
|
+ };
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG.java
|
|
index fb6d817027..d9a4c3c79c 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class SIG
|
|
{
|
|
private final byte[] r;
|
|
private final SIG_FORS[] sig_fors;
|
|
private final SIG_XMSS[] sig_ht;
|
|
|
|
public SIG(int n, int k, int a, int d, int hPrime, int wots_len, byte[] signature)
|
|
{
|
|
this.r = new byte[n];
|
|
System.arraycopy(signature, 0, r, 0, n);
|
|
|
|
this.sig_fors = new SIG_FORS[k];
|
|
int offset = n;
|
|
for (int i = 0; i != k; i++)
|
|
{
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_FORS.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_FORS.java
|
|
index 7c00647622..5d3c5dcff0 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_FORS.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_FORS.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class SIG_FORS
|
|
{
|
|
final byte[][] authPath;
|
|
final byte[] sk;
|
|
|
|
SIG_FORS(byte[] sk, byte[][] authPath)
|
|
{
|
|
this.authPath = authPath;
|
|
this.sk = sk;
|
|
}
|
|
|
|
byte[] getSK()
|
|
{
|
|
return sk;
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_XMSS.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_XMSS.java
|
|
index f77ffaf1cb..0d64d2a7d9 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_XMSS.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SIG_XMSS.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class SIG_XMSS
|
|
{
|
|
final byte[] sig;
|
|
final byte[][] auth;
|
|
|
|
public SIG_XMSS(byte[] sig, byte[][] auth)
|
|
{
|
|
this.sig = sig;
|
|
this.auth = auth;
|
|
}
|
|
|
|
public byte[] getWOTSSig()
|
|
{
|
|
return sig;
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SK.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SK.java
|
|
index 8040421b15..4ea009d94d 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SK.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SK.java
|
|
@@ -1,24 +1,26 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
class SK
|
|
{
|
|
final byte[] seed;
|
|
final byte[] prf;
|
|
|
|
SK(byte[] seed, byte[] prf)
|
|
{
|
|
this.seed = seed;
|
|
this.prf = prf;
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngine.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngine.java
|
|
index bf7b40087f..69fcce3dea 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngine.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngine.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.crypto.Digest;
|
|
import org.bouncycastle.crypto.Xof;
|
|
import org.bouncycastle.crypto.digests.SHAKEDigest;
|
|
import org.bouncycastle.crypto.generators.MGF1BytesGenerator;
|
|
import org.bouncycastle.crypto.macs.HMac;
|
|
import org.bouncycastle.crypto.params.KeyParameter;
|
|
import org.bouncycastle.crypto.params.MGFParameters;
|
|
import org.bouncycastle.util.Arrays;
|
|
import org.bouncycastle.util.Bytes;
|
|
import org.bouncycastle.util.Memoable;
|
|
import org.bouncycastle.util.Pack;
|
|
|
|
@SuppressWarnings("all")
|
|
abstract class SLHDSAEngine
|
|
{
|
|
final int N;
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngineProvider.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngineProvider.java
|
|
index 791705d9ad..b15b4c7ae9 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngineProvider.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAEngineProvider.java
|
|
@@ -1,19 +1,21 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
interface SLHDSAEngineProvider
|
|
{
|
|
int getN();
|
|
|
|
SLHDSAEngine get();
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyGenerationParameters.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyGenerationParameters.java
|
|
index b3daec9773..12b23ac26a 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyGenerationParameters.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyGenerationParameters.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import org.bouncycastle.crypto.KeyGenerationParameters;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAKeyGenerationParameters
|
|
extends KeyGenerationParameters
|
|
{
|
|
private final SLHDSAParameters parameters;
|
|
|
|
public SLHDSAKeyGenerationParameters(SecureRandom random, SLHDSAParameters parameters)
|
|
{
|
|
super(random, -1);
|
|
this.parameters = parameters;
|
|
}
|
|
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyPairGenerator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyPairGenerator.java
|
|
index 58a32e8ea9..32879f8331 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyPairGenerator.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyPairGenerator.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
|
|
import org.bouncycastle.crypto.KeyGenerationParameters;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAKeyPairGenerator
|
|
implements AsymmetricCipherKeyPairGenerator
|
|
{
|
|
private SecureRandom random;
|
|
private SLHDSAParameters parameters;
|
|
|
|
public void init(KeyGenerationParameters param)
|
|
{
|
|
random = param.getRandom();
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyParameters.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyParameters.java
|
|
index 2999c4cac5..d13985c1d7 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyParameters.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAKeyParameters.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAKeyParameters
|
|
extends AsymmetricKeyParameter
|
|
{
|
|
private final SLHDSAParameters parameters;
|
|
|
|
protected SLHDSAKeyParameters(boolean isPrivate, SLHDSAParameters parameters)
|
|
{
|
|
super(isPrivate);
|
|
this.parameters = parameters;
|
|
}
|
|
|
|
public SLHDSAParameters getParameters()
|
|
{
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAParameters.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAParameters.java
|
|
index 4a5e422c8c..1d14c94d73 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAParameters.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAParameters.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAParameters
|
|
{
|
|
public static final int TYPE_PURE = 0;
|
|
public static final int TYPE_SHA2_256 = 1;
|
|
public static final int TYPE_SHA2_512 = 2;
|
|
public static final int TYPE_SHAKE128 = 3;
|
|
public static final int TYPE_SHAKE256 = 4;
|
|
|
|
// "Pure" SLH-DSA Parameters
|
|
// SHA-2
|
|
public static final SLHDSAParameters sha2_128f = new SLHDSAParameters(
|
|
"sha2-128f", new Sha2EngineProvider(16, 16, 22, 6, 33, 66), TYPE_PURE);
|
|
public static final SLHDSAParameters sha2_128s = new SLHDSAParameters(
|
|
"sha2-128s", new Sha2EngineProvider(16, 16, 7, 12, 14, 63), TYPE_PURE);
|
|
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPrivateKeyParameters.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPrivateKeyParameters.java
|
|
index da9c060bb4..64e42635c8 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPrivateKeyParameters.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPrivateKeyParameters.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAPrivateKeyParameters
|
|
extends SLHDSAKeyParameters
|
|
{
|
|
final SK sk;
|
|
final PK pk;
|
|
|
|
public SLHDSAPrivateKeyParameters(SLHDSAParameters parameters, byte[] skpkEncoded)
|
|
{
|
|
super(true, parameters);
|
|
int n = parameters.getN();
|
|
if (skpkEncoded.length != 4 * n)
|
|
{
|
|
throw new IllegalArgumentException("private key encoding does not match parameters");
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPublicKeyParameters.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPublicKeyParameters.java
|
|
index 544156c66c..5492012f73 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPublicKeyParameters.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSAPublicKeyParameters.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
@SuppressWarnings("all")
|
|
public class SLHDSAPublicKeyParameters
|
|
extends SLHDSAKeyParameters
|
|
{
|
|
private final PK pk;
|
|
|
|
public SLHDSAPublicKeyParameters(SLHDSAParameters parameters, byte[] pkValues)
|
|
{
|
|
super(false, parameters);
|
|
int n = parameters.getN();
|
|
if (pkValues.length != 2 * n)
|
|
{
|
|
throw new IllegalArgumentException("public key encoding does not match parameters");
|
|
}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSASigner.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSASigner.java
|
|
index 91fdef108b..720e4f2414 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSASigner.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SLHDSASigner.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import org.bouncycastle.crypto.CipherParameters;
|
|
import org.bouncycastle.crypto.params.ParametersWithContext;
|
|
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
|
import org.bouncycastle.pqc.crypto.MessageSigner;
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
/**
|
|
* SLH-DA signer.
|
|
* <p>
|
|
* This version is based on the 3rd submission with deference to the updated reference
|
|
* implementation on github as at November 9th 2021. This version includes the changes
|
|
* for the countermeasure for the long-message second preimage attack - see
|
|
* "https://github.com/sphincs/sphincsplus/commit/61cd2695c6f984b4f4d6ed675378ed9a486cbede"
|
|
* for further details.
|
|
@@ -174,40 +176,47 @@ public class SLHDSASigner
|
|
adrs.setKeyPairAddress(idx_leaf);
|
|
byte[] PK_FORS = new Fors(engine).pkFromSig(sig_fors, mHash, pubKey.getSeed(), adrs);
|
|
// verify HT signature
|
|
adrs.setTypeAndClear(ADRS.TREE);
|
|
adrs.setLayerAddress(0);
|
|
adrs.setTreeAddress(idx_tree);
|
|
adrs.setKeyPairAddress(idx_leaf);
|
|
HT ht = new HT(engine, null, pubKey.getSeed());
|
|
return ht.verify(PK_FORS, SIG_HT, pubKey.getSeed(), idx_tree, idx_leaf, pubKey.getRoot());
|
|
}
|
|
|
|
protected byte[] internalGenerateSignature(byte[] message, byte[] optRand)
|
|
{
|
|
return internalGenerateSignature(privKey, null, message, optRand);
|
|
}
|
|
|
|
private static byte[] internalGenerateSignature(SLHDSAPrivateKeyParameters privKey, byte[] msgPrefix, byte[] msg,
|
|
byte[] optRand)
|
|
{
|
|
// TODO Check init via privKey != null
|
|
+ // AERE (D-337, 2026-09-26): the same signature, bit for bit, with the message-independent work on
|
|
+ // the free cores (ParallelSigning). null = not taken, and the original code below runs unchanged.
|
|
+ byte[] aere = ParallelSigning.trySign(privKey, msgPrefix, msg, optRand);
|
|
+ if (aere != null)
|
|
+ {
|
|
+ return aere;
|
|
+ }
|
|
|
|
SLHDSAEngine engine = privKey.getParameters().getEngine();
|
|
engine.init(privKey.pk.seed);
|
|
|
|
Fors fors = new Fors(engine);
|
|
byte[] R = engine.PRF_msg(privKey.sk.prf, optRand, msgPrefix, msg);
|
|
|
|
IndexedDigest idxDigest = engine.H_msg(R, privKey.pk.seed, privKey.pk.root, msgPrefix, msg);
|
|
byte[] mHash = idxDigest.digest;
|
|
long idx_tree = idxDigest.idx_tree;
|
|
int idx_leaf = idxDigest.idx_leaf;
|
|
// FORS sign
|
|
ADRS adrs = new ADRS();
|
|
adrs.setTypeAndClear(ADRS.FORS_TREE);
|
|
adrs.setTreeAddress(idx_tree);
|
|
adrs.setKeyPairAddress(idx_leaf);
|
|
SIG_FORS[] sig_fors = fors.sign(mHash, privKey.sk.seed, privKey.pk.seed, adrs);
|
|
// get FORS public key - spec shows M?
|
|
adrs = new ADRS();
|
|
adrs.setTypeAndClear(ADRS.FORS_TREE);
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/WotsPlus.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/WotsPlus.java
|
|
index fe1a94e580..47600d14d3 100755
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/WotsPlus.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/slhdsa/WotsPlus.java
|
|
@@ -1,28 +1,30 @@
|
|
/*
|
|
* Derived from Bouncy Castle 1.80, package org.bouncycastle.pqc.crypto.slhdsa (MIT licence,
|
|
* Copyright (c) 2000-2025 The Legion of the Bouncy Castle Inc., see LICENTA-BOUNCYCASTLE.txt),
|
|
* regenerated into Aere Network by consensus-pqc/slhdsa-fork/genereaza-motorul.py on 2026-09-04 (D-337).
|
|
- * The ONLY change of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI
|
|
- * intrinsics) instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature
|
|
- * cost seconds on the QBFT thread at every anchor parent. Algorithm, key formats and signature bytes are
|
|
- * FIPS 205 as before; SlhDsaFastEngineTest pins that against the original, in both directions.
|
|
+ * Changes of substance: the SHA-2 engine hashes through the JDK's MessageDigest (SHA-NI intrinsics)
|
|
+ * instead of Bouncy Castle's pure-Java digests, which made one SLH-DSA-SHA2-128s signature cost seconds on
|
|
+ * the QBFT thread at every anchor parent; and (2026-09-26) signing first tries ParallelSigning, which
|
|
+ * spreads the message-independent work over the cores and gives the same bytes (HT gains a constructor
|
|
+ * without the unused top-layer public key). Algorithm, key formats and signature bytes are FIPS 205 as
|
|
+ * before; SlhDsaFastEngineTest and SlhDsaParallelSigningTest pin that against the original.
|
|
* DO NOT EDIT BY HAND: regenerate with the script above.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.bft.slhdsa;
|
|
|
|
import org.bouncycastle.util.Arrays;
|
|
import org.bouncycastle.util.Pack;
|
|
|
|
@SuppressWarnings("all")
|
|
class WotsPlus
|
|
{
|
|
private final SLHDSAEngine engine;
|
|
private final int w;
|
|
|
|
WotsPlus(SLHDSAEngine engine)
|
|
{
|
|
this.engine = engine;
|
|
this.w = this.engine.WOTS_W;
|
|
}
|
|
|
|
byte[] pkGen(byte[] skSeed, byte[] pkSeed, ADRS paramAdrs)
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/tools/PqRegistryV3Tool.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/tools/PqRegistryV3Tool.java
|
|
new file mode 100644
|
|
index 0000000000..ec81e7d03f
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/tools/PqRegistryV3Tool.java
|
|
@@ -0,0 +1,288 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the tool that makes a registry v3 epoch FROM THE KEYS ALREADY ON THE VALIDATORS.
|
|
+ *
|
|
+ * Two commands, and the split is the security property:
|
|
+ *
|
|
+ * row runs ON THE HOST that holds a validator's keys. It reads that validator's Falcon-512 key
|
|
+ * file (the same "index, f, g, F, pk" properties the node loads through aere.falcon.key),
|
|
+ * its SLH-DSA-SHA2-128s key file (the same "index, sk" the hybrid loader reads) and its ECDSA
|
|
+ * validator key (a file holding the 32-byte hex), and prints ONE row: the id derived from the
|
|
+ * Falcon key, both public keys in their standard encodings, a proof of possession by each, and
|
|
+ * the ecdsa link signed by the validator key. It prints no private key, nor any part of one.
|
|
+ * assemble runs anywhere (the laptop): it takes the rows, builds the manifest, LOADS it through the
|
|
+ * strict loader (every proof and claim is verified again) and prints the manifest and its
|
|
+ * registry hash - the value the chain pins.
|
|
+ *
|
|
+ * Nothing leaves a host but signatures and public keys, which is what "no new key material and nothing
|
|
+ * out of the vault" means for this ceremony (AIP-22 section 3.2, the plan's stage 3).
|
|
+ *
|
|
+ * java -cp '<besu lib>/*' org.hyperledger.besu.consensus.common.bft.tools.PqRegistryV3Tool row \
|
|
+ * --chain-id 28001 --bind H --count N --index i --falcon-key F --slh-key S --slh-pub HEX \
|
|
+ * --ecdsa-key-file K [--transport]
|
|
+ * java -cp '<besu lib>/*' ...PqRegistryV3Tool assemble --chain-id 28001 --bind H --count N \
|
|
+ * --required falcon-512,slh-dsa-sha2-128s row0.json row1.json ...
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft.tools;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.crypto.KeyPair;
|
|
+import org.hyperledger.besu.crypto.SECPPrivateKey;
|
|
+import org.hyperledger.besu.crypto.SignatureAlgorithm;
|
|
+import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.StringReader;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.HashMap;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.Map;
|
|
+import java.util.Properties;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import com.fasterxml.jackson.databind.SerializationFeature;
|
|
+import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.bouncycastle.pqc.crypto.falcon.FalconParameters;
|
|
+import org.bouncycastle.pqc.crypto.falcon.FalconPrivateKeyParameters;
|
|
+
|
|
+/** The registry v3 ceremony tool. */
|
|
+public final class PqRegistryV3Tool {
|
|
+
|
|
+ private static final ObjectMapper M = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
|
+
|
|
+ private PqRegistryV3Tool() {}
|
|
+
|
|
+ /**
|
|
+ * Entry point.
|
|
+ *
|
|
+ * @param args the command and its options
|
|
+ * @throws IOException on unreadable input
|
|
+ */
|
|
+ public static void main(final String[] args) throws IOException {
|
|
+ if (args.length == 0) {
|
|
+ usage();
|
|
+ System.exit(2);
|
|
+ }
|
|
+ final Map<String, String> o = new HashMap<>();
|
|
+ final List<String> files = new ArrayList<>();
|
|
+ for (int i = 1; i < args.length; i++) {
|
|
+ if (args[i].startsWith("--")) {
|
|
+ if (args[i].equals("--transport")) {
|
|
+ o.put("transport", "1");
|
|
+ } else if (i + 1 < args.length) {
|
|
+ o.put(args[i].substring(2), args[++i]);
|
|
+ } else {
|
|
+ usage();
|
|
+ System.exit(2);
|
|
+ }
|
|
+ } else {
|
|
+ files.add(args[i]);
|
|
+ }
|
|
+ }
|
|
+ switch (args[0]) {
|
|
+ case "keygen" -> keygen(o);
|
|
+ case "row" -> row(o);
|
|
+ case "assemble" -> assemble(o, files);
|
|
+ default -> {
|
|
+ usage();
|
|
+ System.exit(2);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AIP-22 stage 3b: a NEW key pair for a validator, generated ON THE HOST that will hold it (a rotation). Writes the Falcon-512
|
|
+ * key file (index, f, g, F, pk - the format aere.falcon.key and aere.falcon.keys.next read) and the SLH-DSA-SHA2-128s key file
|
|
+ * (index, alg, sk, pk - the format the hybrid loaders read), owner-only, refusing to overwrite anything; prints only the public
|
|
+ * keys.
|
|
+ */
|
|
+ private static void keygen(final Map<String, String> o) throws IOException {
|
|
+ final int index = Integer.parseInt(need(o, "index"));
|
|
+ final Path fOut = Path.of(need(o, "out-falcon"));
|
|
+ final Path sOut = Path.of(need(o, "out-slh"));
|
|
+ if (Files.exists(fOut) || Files.exists(sOut)) {
|
|
+ throw new IllegalStateException("refusing to overwrite an existing key file");
|
|
+ }
|
|
+ final java.security.SecureRandom rng =
|
|
+ org.hyperledger.besu.crypto.SecureRandomProvider.createSecureRandom();
|
|
+ final org.bouncycastle.pqc.crypto.falcon.FalconKeyPairGenerator g =
|
|
+ new org.bouncycastle.pqc.crypto.falcon.FalconKeyPairGenerator();
|
|
+ g.init(new org.bouncycastle.pqc.crypto.falcon.FalconKeyGenerationParameters(rng, FalconParameters.falcon_512));
|
|
+ final FalconPrivateKeyParameters fk = (FalconPrivateKeyParameters) g.generateKeyPair().getPrivate();
|
|
+ final SealScheme slh = SealSchemes.SLH_DSA_128S;
|
|
+ final SealScheme.GeneratedPair sp = slh.generate(rng);
|
|
+ final byte[] slhSk = slh.serializePrivateKey(sp.privateKey()).orElseThrow();
|
|
+ final String falconFile =
|
|
+ "index=" + index + "\nf=" + hx(fk.getSpolyf()).substring(2) + "\ng=" + hx(fk.getG()).substring(2)
|
|
+ + "\nF=" + hx(fk.getSpolyF()).substring(2) + "\npk=" + hx(fk.getPublicKey()).substring(2) + "\n";
|
|
+ final String slhFile =
|
|
+ "index=" + index + "\nalg=slh-dsa-sha2-128s\nsk=" + hx(slhSk).substring(2) + "\npk="
|
|
+ + hx(sp.publicRegistryForm()).substring(2) + "\n";
|
|
+ final java.nio.file.attribute.FileAttribute<?> ownerOnly =
|
|
+ java.nio.file.attribute.PosixFilePermissions.asFileAttribute(
|
|
+ java.nio.file.attribute.PosixFilePermissions.fromString("rw-------"));
|
|
+ Files.writeString(Files.createFile(fOut, ownerOnly), falconFile, StandardCharsets.UTF_8);
|
|
+ Files.writeString(Files.createFile(sOut, ownerOnly), slhFile, StandardCharsets.UTF_8);
|
|
+ final ObjectNode out = M.createObjectNode();
|
|
+ out.put("index", index);
|
|
+ out.put("falconPk", hx(fk.getPublicKey()));
|
|
+ out.put("slhPub", hx(sp.publicRegistryForm()));
|
|
+ System.out.println(M.writeValueAsString(out));
|
|
+ }
|
|
+
|
|
+ private static void row(final Map<String, String> o) throws IOException {
|
|
+ final long chain = Long.parseLong(need(o, "chain-id"));
|
|
+ final long bind = Long.parseLong(need(o, "bind"));
|
|
+ final int count = Integer.parseInt(need(o, "count"));
|
|
+ final int index = Integer.parseInt(need(o, "index"));
|
|
+ // Falcon: the node's own key file; the index inside must be the index asked for
|
|
+ final Properties fp = new Properties();
|
|
+ fp.load(new StringReader(Files.readString(Path.of(need(o, "falcon-key")), StandardCharsets.UTF_8)));
|
|
+ if (Integer.parseInt(fp.getProperty("index").trim()) != index) {
|
|
+ throw new IllegalArgumentException("the Falcon key file is for index " + fp.getProperty("index"));
|
|
+ }
|
|
+ final byte[] h = hex(fp.getProperty("pk"));
|
|
+ final FalconPrivateKeyParameters fsk =
|
|
+ new FalconPrivateKeyParameters(
|
|
+ FalconParameters.falcon_512, hex(fp.getProperty("f")), hex(fp.getProperty("g")),
|
|
+ hex(fp.getProperty("F")), h);
|
|
+ final byte[] falconStd = new byte[PqRegistryV3.FALCON_512_PK_LENGTH];
|
|
+ falconStd[0] = PqRegistryV3.FALCON_512_PK_HEADER;
|
|
+ System.arraycopy(h, 0, falconStd, 1, h.length);
|
|
+ // AIP-22 stage 3b: a ROTATED row keeps the id of its first registration (--id); a new row's id is its Falcon key's derivation
|
|
+ final byte[] id = o.containsKey("id") ? hex(o.get("id")) : PqRegistryV3.idOf(falconStd);
|
|
+ final byte[] falconPop =
|
|
+ falconSign(fsk, PqRegistryV3.popMessage(chain, bind, count, index, id, SealSchemes.FALCON_512.wireId(), falconStd));
|
|
+ // SLH-DSA: the hybrid key file; the public key is given (it is the registry's), and the private key
|
|
+ // must sign a probe that verifies under it before anything is printed
|
|
+ final Properties sp = new Properties();
|
|
+ sp.load(new StringReader(Files.readString(Path.of(need(o, "slh-key")), StandardCharsets.UTF_8)));
|
|
+ if (Integer.parseInt(sp.getProperty("index").trim()) != index) {
|
|
+ throw new IllegalArgumentException("the SLH-DSA key file is for index " + sp.getProperty("index"));
|
|
+ }
|
|
+ final SealScheme slh = SealSchemes.SLH_DSA_128S;
|
|
+ final SealScheme.PrivateHandle ssk =
|
|
+ slh.parsePrivateKey(hex(sp.getProperty("sk"))).orElseThrow(
|
|
+ () -> new IllegalArgumentException("the SLH-DSA key does not parse"));
|
|
+ final byte[] slhPub = hex(need(o, "slh-pub"));
|
|
+ final byte[] slhPop =
|
|
+ slh.sign(ssk, PqRegistryV3.popMessage(chain, bind, count, index, id, slh.wireId(), slhPub).toArrayUnsafe())
|
|
+ .orElseThrow();
|
|
+ if (!slh.verifyRaw(slhPub, PqRegistryV3.popMessage(chain, bind, count, index, id, slh.wireId(), slhPub).toArrayUnsafe(), slhPop)) {
|
|
+ throw new IllegalStateException("the SLH-DSA key file does not match the public key given; refusing");
|
|
+ }
|
|
+ // the ECDSA validator key: signs the link from its address to the row
|
|
+ final SignatureAlgorithm ec = SignatureAlgorithmFactory.getInstance();
|
|
+ final String ecHex = Files.readString(Path.of(need(o, "ecdsa-key-file")), StandardCharsets.UTF_8).trim();
|
|
+ final SECPPrivateKey ecsk = ec.createPrivateKey(Bytes32.fromHexString(ecHex));
|
|
+ final KeyPair kp = ec.createKeyPair(ecsk);
|
|
+ final byte[] addr = Util.publicKeyToAddress(kp.getPublicKey()).getBytes().toArrayUnsafe();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(SealSchemes.FALCON_512.wireId() & 0xff, new PqRegistryV3.Key(SealSchemes.FALCON_512, falconStd, falconPop));
|
|
+ keys.put(slh.wireId() & 0xff, new PqRegistryV3.Key(slh, slhPub, slhPop));
|
|
+ final byte[] transport = o.containsKey("transport") ? addr : null;
|
|
+ final Bytes32 rh =
|
|
+ PqRegistryV3.rowHash(chain, bind, count, new PqRegistryV3.Row(index, id, keys, transport, Map.of(), null, null));
|
|
+ final byte[] claim = ec.sign(PqRegistryV3.claimDigest(chain, rh), kp).encodedBytes().toArrayUnsafe();
|
|
+ final ObjectNode row = M.createObjectNode();
|
|
+ row.put("id", hx(id));
|
|
+ row.putObject("keys").put("falcon-512", hx(falconStd)).put("slh-dsa-sha2-128s", hx(slhPub));
|
|
+ row.putObject("pop").put("falcon-512", hx(falconPop)).put("slh-dsa-sha2-128s", hx(slhPop));
|
|
+ if (transport != null) {
|
|
+ row.putObject("transport").put("secp256k1Address", hx(transport));
|
|
+ }
|
|
+ row.putObject("ecdsa").put("addr", hx(addr)).put("claim", hx(claim));
|
|
+ // AIP-22 stage 3b: a rotation - EACH old key of the row signs the new row's hash (AERE-PQ-ROTATE-3); the loader requires
|
|
+ // one signature per scheme the previous epoch bound, by exactly that previous key
|
|
+ if (o.containsKey("old-falcon-key") || o.containsKey("old-slh-key")) {
|
|
+ final Bytes32 rot = PqRegistryV3.rotateMessage(rh);
|
|
+ final Properties of = new Properties();
|
|
+ of.load(new StringReader(Files.readString(Path.of(need(o, "old-falcon-key")), StandardCharsets.UTF_8)));
|
|
+ final FalconPrivateKeyParameters oldF =
|
|
+ new FalconPrivateKeyParameters(
|
|
+ FalconParameters.falcon_512, hex(of.getProperty("f")), hex(of.getProperty("g")),
|
|
+ hex(of.getProperty("F")), hex(of.getProperty("pk")));
|
|
+ final Properties os = new Properties();
|
|
+ os.load(new StringReader(Files.readString(Path.of(need(o, "old-slh-key")), StandardCharsets.UTF_8)));
|
|
+ final SealScheme.PrivateHandle oldS =
|
|
+ slh.parsePrivateKey(hex(os.getProperty("sk"))).orElseThrow(
|
|
+ () -> new IllegalArgumentException("the old SLH-DSA key does not parse"));
|
|
+ row.putObject("rotation")
|
|
+ .put("falcon-512", hx(falconSign(oldF, rot)))
|
|
+ .put("slh-dsa-sha2-128s", hx(slh.sign(oldS, rot.toArrayUnsafe()).orElseThrow()));
|
|
+ }
|
|
+ final ObjectNode out = M.createObjectNode();
|
|
+ out.put("index", index);
|
|
+ out.set("row", row);
|
|
+ System.out.println(M.writeValueAsString(out));
|
|
+ }
|
|
+
|
|
+ private static void assemble(final Map<String, String> o, final List<String> files) throws IOException {
|
|
+ final long chain = Long.parseLong(need(o, "chain-id"));
|
|
+ final long bind = Long.parseLong(need(o, "bind"));
|
|
+ final int count = Integer.parseInt(need(o, "count"));
|
|
+ final List<String> required = Arrays.asList(o.getOrDefault("required", "falcon-512").split(","));
|
|
+ final ObjectNode m = M.createObjectNode();
|
|
+ m.put("formatVersion", PqRegistryV3.FORMAT_VERSION);
|
|
+ m.put("chainId", chain);
|
|
+ m.put("bindHeight", bind);
|
|
+ m.put("count", count);
|
|
+ for (final String f : files) {
|
|
+ final JsonNode r = M.readTree(Files.readString(Path.of(f), StandardCharsets.UTF_8));
|
|
+ m.set(Integer.toString(r.get("index").asInt()), r.get("row"));
|
|
+ }
|
|
+ // AIP-22 stage 3b: an epoch after the switch epoch is loaded AGAINST the one before it (--previous), so every rotation it
|
|
+ // carries is verified; the switch epoch itself (no --previous) must carry every ecdsa link
|
|
+ PqRegistryV3.Registry previous = null;
|
|
+ if (o.containsKey("previous")) {
|
|
+ final JsonNode pj = M.readTree(Files.readString(Path.of(o.get("previous")), StandardCharsets.UTF_8));
|
|
+ previous = PqRegistryV3.load(pj, chain, required, null, true);
|
|
+ }
|
|
+ final PqRegistryV3.Registry reg = PqRegistryV3.load(m, chain, required, previous, previous == null);
|
|
+ m.put("registryHash", reg.hash().toHexString());
|
|
+ System.out.println(M.writeValueAsString(m));
|
|
+ System.err.println("registryHash " + reg.hash().toHexString() + " (" + count + " rows, bound at " + bind + ")");
|
|
+ }
|
|
+
|
|
+ private static byte[] falconSign(final FalconPrivateKeyParameters sk, final Bytes32 message) {
|
|
+ return ((FalconSealScheme) SealSchemes.FALCON_512)
|
|
+ .signWithParams(sk, message.toArrayUnsafe())
|
|
+ .orElseThrow(() -> new IllegalStateException("the Falcon key did not sign"));
|
|
+ }
|
|
+
|
|
+ private static String need(final Map<String, String> o, final String k) {
|
|
+ final String v = o.get(k);
|
|
+ if (v == null) {
|
|
+ throw new IllegalArgumentException("missing --" + k);
|
|
+ }
|
|
+ return v;
|
|
+ }
|
|
+
|
|
+ private static byte[] hex(final String s) {
|
|
+ return Bytes.fromHexStringLenient(s.trim()).toArrayUnsafe();
|
|
+ }
|
|
+
|
|
+ private static String hx(final byte[] b) {
|
|
+ final StringBuilder sb = new StringBuilder("0x");
|
|
+ for (final byte x : b) {
|
|
+ sb.append(String.format(Locale.ROOT, "%02x", x & 0xff));
|
|
+ }
|
|
+ return sb.toString();
|
|
+ }
|
|
+
|
|
+ private static void usage() {
|
|
+ System.err.println("usage: PqRegistryV3Tool row|assemble ... (see the class comment)");
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTally.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTally.java
|
|
index 8251f5c94b..fed8a2a5a7 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTally.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTally.java
|
|
@@ -1,36 +1,43 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.validator.blockbased;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorVote;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Map;
|
|
import java.util.NavigableSet;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
import com.google.common.collect.Maps;
|
|
|
|
/** Tracks the current list of validators and votes to add or drop validators. */
|
|
class VoteTally {
|
|
|
|
private final NavigableSet<Address> currentValidators;
|
|
|
|
@@ -93,40 +100,58 @@ class VoteTally {
|
|
return Optional.ofNullable(addVotesBySubject.get(subject)).orElse(Collections.emptySet());
|
|
}
|
|
|
|
Set<Address> getOutstandingRemoveVotesFor(final Address subject) {
|
|
return Optional.ofNullable(removeVotesBySubject.get(subject)).orElse(Collections.emptySet());
|
|
}
|
|
|
|
private int validatorLimit() {
|
|
return (currentValidators.size() / 2) + 1;
|
|
}
|
|
|
|
/**
|
|
* Reset the outstanding vote tallies as required at each epoch. The current validator list is
|
|
* unaffected.
|
|
*/
|
|
void discardOutstandingVotes() {
|
|
addVotesBySubject.clear();
|
|
removeVotesBySubject.clear();
|
|
}
|
|
|
|
+ /**
|
|
+ * AERE AIP-22 stage 3: after block H_id - 1 the validators become the sorted post-quantum ids of the
|
|
+ * same members, and votes still open on classical addresses are discarded (they name addresses the
|
|
+ * id space no longer contains). Anywhere else, and when the identity switch is not armed, nothing
|
|
+ * changes.
|
|
+ *
|
|
+ * @param blockNumber the block whose effects this tally now includes
|
|
+ */
|
|
+ void translateToIds(final long blockNumber) {
|
|
+ final Collection<Address> translated =
|
|
+ AerePqIdentity.translateSetAfter(currentValidators, blockNumber);
|
|
+ if (translated != currentValidators) {
|
|
+ currentValidators.clear();
|
|
+ currentValidators.addAll(translated);
|
|
+ discardOutstandingVotes();
|
|
+ }
|
|
+ }
|
|
+
|
|
/**
|
|
* The validator addresses
|
|
*
|
|
* @return The collection of validators after the voting at the most recent block has been
|
|
* finalised.
|
|
*/
|
|
Collection<Address> getValidators() {
|
|
return currentValidators;
|
|
}
|
|
|
|
VoteTally copy() {
|
|
final Map<Address, Set<Address>> addVotesBySubject = Maps.newHashMap();
|
|
final Map<Address, Set<Address>> removeVotesBySubject = Maps.newHashMap();
|
|
|
|
this.addVotesBySubject.forEach(
|
|
(key, value) -> addVotesBySubject.put(key, new TreeSet<>(value)));
|
|
this.removeVotesBySubject.forEach(
|
|
(key, value) -> removeVotesBySubject.put(key, new TreeSet<>(value)));
|
|
|
|
return new VoteTally(
|
|
diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyUpdater.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyUpdater.java
|
|
index bae5540aad..0da2c63f55 100644
|
|
--- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyUpdater.java
|
|
+++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyUpdater.java
|
|
@@ -1,38 +1,45 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.common.validator.blockbased;
|
|
|
|
import org.hyperledger.besu.consensus.common.BlockInterface;
|
|
import org.hyperledger.besu.consensus.common.EpochManager;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorVote;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Optional;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* Provides the logic to extract vote tally state from the blockchain and update it as blocks are
|
|
* added.
|
|
*/
|
|
class VoteTallyUpdater {
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(VoteTallyUpdater.class);
|
|
|
|
private final EpochManager epochManager;
|
|
@@ -56,26 +63,31 @@ class VoteTallyUpdater {
|
|
final BlockHeader epochBlock = blockchain.getBlockHeader(epochBlockNumber).get();
|
|
final Collection<Address> initialValidators = blockInterface.validatorsInBlock(epochBlock);
|
|
final VoteTally voteTally = new VoteTally(initialValidators);
|
|
for (long blockNumber = epochBlockNumber + 1;
|
|
blockNumber <= chainHeadBlockNumber;
|
|
blockNumber++) {
|
|
updateForBlock(blockchain.getBlockHeader(blockNumber).get(), voteTally);
|
|
}
|
|
return voteTally;
|
|
}
|
|
|
|
/**
|
|
* Update the vote tally to reflect changes caused by appending a new block to the chain.
|
|
*
|
|
* @param header the header of the block being added
|
|
* @param voteTally the vote tally to update
|
|
*/
|
|
void updateForBlock(final BlockHeader header, final VoteTally voteTally) {
|
|
if (epochManager.isEpochBlock(header.getNumber())) {
|
|
voteTally.discardOutstandingVotes();
|
|
- return;
|
|
+ } else {
|
|
+ final Optional<ValidatorVote> vote = blockInterface.extractVoteFromHeader(header);
|
|
+ vote.ifPresent(voteTally::addVote);
|
|
+ }
|
|
+ // AERE AIP-22 stage 3: after block H_id - 1 the set becomes the post-quantum ids of its members;
|
|
+ // asked first, so that disarmed (or at any other block) the tally sees no extra call at all
|
|
+ if (AerePqIdentity.translatesAfter(header.getNumber())) {
|
|
+ voteTally.translateToIds(header.getNumber());
|
|
}
|
|
- final Optional<ValidatorVote> vote = blockInterface.extractVoteFromHeader(header);
|
|
- vote.ifPresent(voteTally::addVote);
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereKeysFromV3Test.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereKeysFromV3Test.java
|
|
new file mode 100644
|
|
index 0000000000..ba91cd1b81
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereKeysFromV3Test.java
|
|
@@ -0,0 +1,192 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3b: probes of the keys that seal coming from the v3 epoch in force (AerePqIdentity
|
|
+ * keysFromV3 / v3KeyAt / v3IdAt / verifyKeyContinuity) and of the ecdsa link inherited by id, on the two
|
|
+ * shared registry v3 conformance vectors: ok-epoch-a (bound at 1000, three rows, each with its ecdsa link)
|
|
+ * and ok-epoch-b-rotation (bound at 2000: index 1 rotates both keys under its id, the id of A's index 2
|
|
+ * moves to index 0, A's index 0 leaves, a new id joins at index 2; no ecdsa links).
|
|
+ *
|
|
+ * What must hold, each with its negative: H_k falls on an epoch boundary at or above H_id or the node
|
|
+ * refuses to arm; below H_k nothing comes from v3; from H_k the key of an index is the key of THAT index in
|
|
+ * the epoch in force (Falcon without its 0x09 header, SLH-DSA as its 32 bytes), so the rotated key replaces
|
|
+ * the old one exactly at the rotation epoch and an index the epoch does not have gives NO key; the
|
|
+ * continuity guard accepts the same keys and refuses one changed byte or a missing key; and an author keeps
|
|
+ * its id across an epoch that omits the ecdsa links, but a removed id's address authors as nothing.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.InputStream;
|
|
+import java.util.Arrays;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class AereKeysFromV3Test {
|
|
+
|
|
+ private static final List<String> SCHEMES = List.of("falcon-512", "slh-dsa-sha2-128s");
|
|
+ private PqRegistryV3.Registry a;
|
|
+ private PqRegistryV3.Registry b;
|
|
+ private TreeMap<Long, PqRegistryV3.Registry> epochs;
|
|
+
|
|
+ private JsonNode vector(final String name) throws IOException {
|
|
+ try (InputStream in = getClass().getResourceAsStream("/aere/registry-v3/" + name + ".json")) {
|
|
+ assertThat(in).isNotNull();
|
|
+ return new ObjectMapper().readTree(in);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @BeforeEach
|
|
+ public void load() throws IOException {
|
|
+ final JsonNode va = vector("ok-epoch-a");
|
|
+ final JsonNode vb = vector("ok-epoch-b-rotation");
|
|
+ a = PqRegistryV3.load(va.get("manifest"), va.get("chainId").asLong(), SCHEMES, null, true);
|
|
+ b = PqRegistryV3.load(vb.get("manifest"), vb.get("chainId").asLong(), SCHEMES, a, false);
|
|
+ assertThat(a.bindHeight()).isEqualTo(1000L);
|
|
+ assertThat(b.bindHeight()).isEqualTo(2000L);
|
|
+ epochs = new TreeMap<>();
|
|
+ epochs.put(a.bindHeight(), a);
|
|
+ epochs.put(b.bindHeight(), b);
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private static byte[] key(final PqRegistryV3.Registry r, final int index, final String scheme) {
|
|
+ return r.rows().get(index).key(scheme).orElseThrow().publicKey();
|
|
+ }
|
|
+
|
|
+ private static Address id(final PqRegistryV3.Registry r, final int index) {
|
|
+ return Address.wrap(Bytes.wrap(r.rows().get(index).id()));
|
|
+ }
|
|
+
|
|
+ private static Address ecdsa(final PqRegistryV3.Registry r, final int index) {
|
|
+ return Address.wrap(Bytes.wrap(r.rows().get(index).ecdsaAddress()));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void keysFromMustBeAnEpochBoundaryAtOrAboveTheIdentityHeight() {
|
|
+ assertThatThrownBy(() -> AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 1999)))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class)
|
|
+ .hasMessageContaining("must be the bindHeight of a v3 epoch");
|
|
+ assertThatThrownBy(() -> AerePqIdentity.install(new AerePqIdentity.Config(2000, epochs, 1000)))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class);
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 2000));
|
|
+ assertThat(AerePqIdentity.installed().orElseThrow().keysFrom()).isEqualTo(2000L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void belowHkNothingComesFromV3AndStage3aNeverDoes() {
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 2000));
|
|
+ assertThat(AerePqIdentity.keysFromV3(1999)).isFalse();
|
|
+ assertThat(AerePqIdentity.keysFromV3(2000)).isTrue();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs));
|
|
+ assertThat(AerePqIdentity.keysFromV3(Long.MAX_VALUE - 1)).isFalse();
|
|
+ AerePqIdentity.uninstall();
|
|
+ assertThat(AerePqIdentity.keysFromV3(5000)).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theKeyIsThatIndexOfTheEpochInForceAndTheRotationTakesOverAtItsEpoch() {
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 1000));
|
|
+ final byte[] fa1 = AerePqIdentity.v3KeyAt(1999, 1, "falcon-512").orElseThrow();
|
|
+ final byte[] fb1 = AerePqIdentity.v3KeyAt(2000, 1, "falcon-512").orElseThrow();
|
|
+ // the registry form: 896 bytes, the 0x09 header dropped
|
|
+ assertThat(fa1).hasSize(896);
|
|
+ assertThat(fa1).isEqualTo(Arrays.copyOfRange(key(a, 1, "falcon-512"), 1, 897));
|
|
+ assertThat(fb1).isEqualTo(Arrays.copyOfRange(key(b, 1, "falcon-512"), 1, 897));
|
|
+ assertThat(fb1).isNotEqualTo(fa1);
|
|
+ final byte[] sa1 = AerePqIdentity.v3KeyAt(1999, 1, "slh-dsa-sha2-128s").orElseThrow();
|
|
+ assertThat(sa1).hasSize(32).isEqualTo(key(a, 1, "slh-dsa-sha2-128s"));
|
|
+ assertThat(AerePqIdentity.v3KeyAt(2000, 1, "slh-dsa-sha2-128s").orElseThrow())
|
|
+ .isEqualTo(key(b, 1, "slh-dsa-sha2-128s"))
|
|
+ .isNotEqualTo(sa1);
|
|
+ // indices belong to the epoch: at 2000 index 0 is the validator that was index 2 in epoch A
|
|
+ assertThat(AerePqIdentity.v3KeyAt(2000, 0, "falcon-512").orElseThrow())
|
|
+ .isEqualTo(Arrays.copyOfRange(key(a, 2, "falcon-512"), 1, 897));
|
|
+ assertThat(AerePqIdentity.v3IdAt(2000, 0)).contains(id(a, 2));
|
|
+ assertThat(AerePqIdentity.v3IdAt(2000, 2)).contains(id(b, 2));
|
|
+ // an index the epoch does not have: NO key (fail closed), never a fall-back
|
|
+ assertThat(AerePqIdentity.v3KeyAt(2000, 3, "falcon-512")).isEmpty();
|
|
+ assertThat(AerePqIdentity.v3KeyAt(2000, -1, "falcon-512")).isEmpty();
|
|
+ assertThat(AerePqIdentity.v3IdAt(2000, 3)).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theContinuityGuardAcceptsTheSameKeysAndRefusesAnyOther() {
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 1000));
|
|
+ // the existing registries give exactly the keys of epoch A: accepted
|
|
+ AerePqIdentity.verifyKeyContinuity(
|
|
+ (i, s) -> AerePqIdentity.v3KeyAt(1000, i, s).map(byte[]::clone));
|
|
+ // one byte of one SLH-DSA key differs: refused, naming the row and the scheme
|
|
+ assertThatThrownBy(
|
|
+ () ->
|
|
+ AerePqIdentity.verifyKeyContinuity(
|
|
+ (i, s) -> {
|
|
+ final byte[] k = AerePqIdentity.v3KeyAt(1000, i, s).orElseThrow().clone();
|
|
+ if (i == 2 && s.equals("slh-dsa-sha2-128s")) {
|
|
+ k[5] ^= 1;
|
|
+ }
|
|
+ return Optional.of(k);
|
|
+ }))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class)
|
|
+ .hasMessageContaining("row 2 slh-dsa-sha2-128s differs");
|
|
+ // a key the existing registries cannot produce: refused
|
|
+ assertThatThrownBy(
|
|
+ () ->
|
|
+ AerePqIdentity.verifyKeyContinuity(
|
|
+ (i, s) -> i == 0 ? Optional.empty() : AerePqIdentity.v3KeyAt(1000, i, s)))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class)
|
|
+ .hasMessageContaining("row 0");
|
|
+ // no H_k configured: the guard is inert even with a function that has no keys at all
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs));
|
|
+ AerePqIdentity.verifyKeyContinuity((i, s) -> Optional.empty());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theFalconSealSupportDoorsTakeTheirKeyAndIdFromV3FromHk() {
|
|
+ // the WIRING, not only the helper: FalconSealSupport.keyAt (behind every Falcon verification) and the index -> identity doors
|
|
+ // must answer from the v3 epoch in force from H_k. This node has no registry schedule at all, so any answer from H_k on can
|
|
+ // only come from v3; below H_k the doors fall back to the (absent) registries and answer nothing.
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 2000));
|
|
+ final FalconSealSupport fs = FalconSealSupport.instance();
|
|
+ assertThat(fs.publicKeyBytesAtHistoric(2000, 1))
|
|
+ .contains(Arrays.copyOfRange(key(b, 1, "falcon-512"), 1, 897));
|
|
+ assertThat(fs.publicKeyBytesAtHistoric(2000, 0))
|
|
+ .contains(Arrays.copyOfRange(key(a, 2, "falcon-512"), 1, 897));
|
|
+ assertThat(fs.publicKeyBytesAtHistoric(2000, 3)).isEmpty();
|
|
+ assertThat(fs.addressForIndexAtHistoric(2000, 2)).isEqualTo(id(b, 2));
|
|
+ assertThat(fs.addressForIndexAtOwnHead(2000, 0)).isEqualTo(id(a, 2));
|
|
+ assertThat(fs.addressForIndexAtHistoric(2000, 3)).isNull();
|
|
+ // below H_k: not from v3 (a v3 answer here would be the rotation taking effect early)
|
|
+ assertThat(fs.publicKeyBytesAtHistoric(1999, 1))
|
|
+ .isNotEqualTo(Optional.of(Arrays.copyOfRange(key(a, 1, "falcon-512"), 1, 897)));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void anAuthorKeepsItsIdAcrossAnEpochWithoutLinksAndARemovedIdAuthorsNothing() {
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 1000));
|
|
+ // epoch B carries no ecdsa links; the id of A's index 1 is still registered, so its address keeps it
|
|
+ assertThat(b.rows().get(1).ecdsaAddress()).isNull();
|
|
+ assertThat(AerePqIdentity.author(ecdsa(a, 1), 1999)).isEqualTo(id(a, 1));
|
|
+ assertThat(AerePqIdentity.author(ecdsa(a, 1), 2000)).isEqualTo(id(a, 1));
|
|
+ assertThat(AerePqIdentity.author(ecdsa(a, 2), 2500)).isEqualTo(id(a, 2));
|
|
+ // A's index 0 left in B: its address is itself again, which is not in the set
|
|
+ assertThat(AerePqIdentity.author(ecdsa(a, 0), 1999)).isEqualTo(id(a, 0));
|
|
+ assertThat(AerePqIdentity.author(ecdsa(a, 0), 2000)).isEqualTo(ecdsa(a, 0));
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereLocalKeysV3Test.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereLocalKeysV3Test.java
|
|
new file mode 100644
|
|
index 0000000000..e67a5bf730
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AereLocalKeysV3Test.java
|
|
@@ -0,0 +1,164 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3b-ii: probes of the LOCAL keys by height - a node signs, from H_k, with the key of its own row in the v3
|
|
+ * epoch in force and at that row's index - on two epochs built here with PROBA keys this test holds (the shared vectors carry no
|
|
+ * private keys): epoch A bound at 1000 (v0, v1, v2 at indices 0, 1, 2, the switch epoch) and epoch B bound at 2000 (v2 MOVED to
|
|
+ * index 0, v1 ROTATED both keys under its id at index 1 with the rotation signed by its old keys, v0 left, a new v3 at index 2).
|
|
+ *
|
|
+ * What must hold, each with its negative: a node finds its row by its key and the index moves with the epoch (a key that no row
|
|
+ * of the epoch carries finds nothing); the hybrid producer of a rotating node signs with its OLD key up to the rotation epoch and
|
|
+ * with its NEXT key from it, at the right index, each seal verifying under exactly one of the two keys; a moved node signs at its
|
|
+ * new index; and a node that lacks its rotated key produces nothing from the rotation epoch (the fact the startup guard refuses on).
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+import java.util.function.LongToIntFunction;
|
|
+
|
|
+import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class AereLocalKeysV3Test {
|
|
+
|
|
+ private static final List<String> SCHEMES = List.of("falcon-512", "slh-dsa-sha2-128s");
|
|
+ private static final String SLH = "slh-dsa-sha2-128s";
|
|
+ private PqRegistryV3Test.Proba v0;
|
|
+ private PqRegistryV3Test.Proba v1;
|
|
+ private PqRegistryV3Test.Proba v2;
|
|
+ private PqRegistryV3Test.Proba v1b;
|
|
+ private PqRegistryV3Test.Proba v3;
|
|
+
|
|
+ @BeforeEach
|
|
+ public void build() {
|
|
+ v0 = PqRegistryV3Test.proba();
|
|
+ v1 = PqRegistryV3Test.proba();
|
|
+ v2 = PqRegistryV3Test.proba();
|
|
+ v1b = PqRegistryV3Test.proba();
|
|
+ v3 = PqRegistryV3Test.proba();
|
|
+ final var d0 = new PqRegistryV3Test.Draft(PqRegistryV3.idOf(v0.falconStd()), PqRegistryV3Test.both(v0), v0);
|
|
+ final var d1 = new PqRegistryV3Test.Draft(PqRegistryV3.idOf(v1.falconStd()), PqRegistryV3Test.both(v1), v1);
|
|
+ final var d2 = new PqRegistryV3Test.Draft(PqRegistryV3.idOf(v2.falconStd()), PqRegistryV3Test.both(v2), v2);
|
|
+ final ObjectNode ma =
|
|
+ PqRegistryV3Test.manifest(
|
|
+ 1000,
|
|
+ List.of(
|
|
+ PqRegistryV3Test.rowJson(1000, 3, 0, d0, true, true),
|
|
+ PqRegistryV3Test.rowJson(1000, 3, 1, d1, true, false),
|
|
+ PqRegistryV3Test.rowJson(1000, 3, 2, d2, true, false)));
|
|
+ final PqRegistryV3.Registry a = PqRegistryV3.load(ma, PqRegistryV3Test.CHAIN, SCHEMES, null, true);
|
|
+ final var d1b = new PqRegistryV3Test.Draft(d1.id(), PqRegistryV3Test.both(v1b), v1);
|
|
+ final var d3 = new PqRegistryV3Test.Draft(PqRegistryV3.idOf(v3.falconStd()), PqRegistryV3Test.both(v3), v3);
|
|
+ final ObjectNode r1b = PqRegistryV3Test.rowJson(2000, 3, 1, d1b, false, false);
|
|
+ PqRegistryV3Test.rotate(r1b, 2000, 3, 1, List.of(v1.falcon(), v1.slh()));
|
|
+ final ObjectNode mb =
|
|
+ PqRegistryV3Test.manifest(
|
|
+ 2000,
|
|
+ List.of(
|
|
+ PqRegistryV3Test.rowJson(2000, 3, 0, d2, false, false),
|
|
+ r1b,
|
|
+ PqRegistryV3Test.rowJson(2000, 3, 2, d3, false, false)));
|
|
+ final PqRegistryV3.Registry b = PqRegistryV3.load(mb, PqRegistryV3Test.CHAIN, SCHEMES, a, false);
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(1000L, a);
|
|
+ epochs.put(2000L, b);
|
|
+ AerePqIdentity.uninstall();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(1000, epochs, 1000));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private static byte[] falcon(final PqRegistryV3Test.Proba p) {
|
|
+ return p.falcon().publicRegistryForm();
|
|
+ }
|
|
+
|
|
+ /** The local index a node holding these Falcon keys signs as at a height (what FalconSealSupport.localAt resolves). */
|
|
+ private static LongToIntFunction indexOf(final PqRegistryV3Test.Proba... keys) {
|
|
+ return h -> {
|
|
+ for (final PqRegistryV3Test.Proba k : keys) {
|
|
+ final Optional<Integer> i = AerePqIdentity.v3IndexOfKey(h, "falcon-512", falcon(k));
|
|
+ if (i.isPresent()) {
|
|
+ return i.get();
|
|
+ }
|
|
+ }
|
|
+ return -1;
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private static HybridSealProducer producer(
|
|
+ final PqRegistryV3Test.Proba base, final List<PqRegistryV3Test.Proba> next, final LongToIntFunction idx) {
|
|
+ return new HybridSealProducer(
|
|
+ 0L,
|
|
+ PqSchemeSchedule.parse("0:falcon-512+" + SLH),
|
|
+ -1,
|
|
+ Map.of(SLH, base.slh().privateKey()),
|
|
+ 0L,
|
|
+ next.isEmpty() ? Map.of() : Map.of(SLH, next.stream().map(p -> p.slh().privateKey()).toList()),
|
|
+ idx);
|
|
+ }
|
|
+
|
|
+ private static boolean verifies(final SchemeSeal s, final PqRegistryV3Test.Proba key, final Bytes msg) {
|
|
+ return SealSchemes.SLH_DSA_128S.verifyRaw(
|
|
+ key.slh().publicRegistryForm(), msg.toArrayUnsafe(), s.getSignature().toArrayUnsafe());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aNodeFindsItsRowByItsKeyAndTheIndexMovesWithTheEpoch() {
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(1999, "falcon-512", falcon(v2))).contains(2);
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(2000, "falcon-512", falcon(v2))).contains(0);
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(1999, "falcon-512", falcon(v1))).contains(1);
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(2000, "falcon-512", falcon(v1))).isEmpty();
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(2000, "falcon-512", falcon(v1b))).contains(1);
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(1999, "falcon-512", falcon(v1b))).isEmpty();
|
|
+ assertThat(AerePqIdentity.v3IndexOfKey(2000, "falcon-512", falcon(v0))).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aRotatingNodeSignsWithItsOldKeyUpToTheRotationEpochAndItsNextKeyFromIt() {
|
|
+ final HybridSealProducer p = producer(v1, List.of(v1b), indexOf(v1, v1b));
|
|
+ final Bytes msg = Bytes.wrap("AERE-TEST-COMMIT".getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
|
+ final List<SchemeSeal> before = p.sealsFor(1999, msg);
|
|
+ assertThat(before).hasSize(1);
|
|
+ assertThat(before.get(0).getValidatorIndex()).isEqualTo(1);
|
|
+ assertThat(verifies(before.get(0), v1, msg)).isTrue();
|
|
+ assertThat(verifies(before.get(0), v1b, msg)).isFalse();
|
|
+ final List<SchemeSeal> after = p.sealsFor(2000, msg);
|
|
+ assertThat(after).hasSize(1);
|
|
+ assertThat(after.get(0).getValidatorIndex()).isEqualTo(1);
|
|
+ assertThat(verifies(after.get(0), v1b, msg)).isTrue();
|
|
+ assertThat(verifies(after.get(0), v1, msg)).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aMovedNodeSignsAtItsNewIndex() {
|
|
+ final HybridSealProducer p = producer(v2, List.of(), indexOf(v2));
|
|
+ final Bytes msg = Bytes.wrap("AERE-TEST-COMMIT".getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
|
+ assertThat(p.sealsFor(1999, msg).get(0).getValidatorIndex()).isEqualTo(2);
|
|
+ final List<SchemeSeal> after = p.sealsFor(2000, msg);
|
|
+ assertThat(after.get(0).getValidatorIndex()).isEqualTo(0);
|
|
+ assertThat(verifies(after.get(0), v2, msg)).isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aNodeWithoutItsRotatedKeyProducesNothingFromTheRotationEpoch() {
|
|
+ final HybridSealProducer p = producer(v1, List.of(), indexOf(v1, v1b));
|
|
+ final Bytes msg = Bytes.wrap("AERE-TEST-COMMIT".getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
|
+ assertThat(p.sealsFor(1999, msg)).hasSize(1);
|
|
+ // its Falcon index is resolvable only through v1b, which this node does not hold: nothing, and the guard's basis is empty
|
|
+ final HybridSealProducer onlyOld = producer(v1, List.of(), indexOf(v1));
|
|
+ assertThat(onlyOld.sealsFor(2000, msg)).isEmpty();
|
|
+ assertThat(onlyOld.v3KeyAt(SealSchemes.SLH_DSA_128S, 2000)).isEmpty();
|
|
+ // holding the rotated Falcon key but not the rotated SLH-DSA key: the row's SLH key has no local match either
|
|
+ assertThat(p.v3KeyAt(SealSchemes.SLH_DSA_128S, 2000)).isEmpty();
|
|
+ assertThat(p.sealsFor(2000, msg)).isEmpty();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityAuthorTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityAuthorTest.java
|
|
new file mode 100644
|
|
index 0000000000..4b875f937b
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityAuthorTest.java
|
|
@@ -0,0 +1,243 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
+import org.hyperledger.besu.crypto.Hash;
|
|
+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.ethereum.core.Util;
|
|
+import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.InputStream;
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4 (iii): from H_fin the author of a message is the id of its post-quantum seal's index,
|
|
+ * ONCE THE SEAL VERIFIES, and the ECDSA signature of the envelope is not read. Every message here is
|
|
+ * signed by a FOREIGN key (not any validator's), so a validator's id can only come from the seal. The
|
|
+ * verifier is injected with the seal layers' contract (height, index, message, signature): it accepts
|
|
+ * exactly the signature {@code keccak(index || message)}, so a seal of another index, over another
|
|
+ * message, or of any other bytes does not verify. A COMMIT's author is its index's id only when that is
|
|
+ * the commit seal signer's id. Below H_fin, and with H_fin unset, the author is the (translated) ECDSA
|
|
+ * signer, as in stage 3. The runner's negative controls plant "H_fin never active" and "every seal
|
|
+ * verifies" at run time and these probes turn red.
|
|
+ */
|
|
+public class AerePqFinalityAuthorTest {
|
|
+
|
|
+ private static final SignatureAlgorithm ALG = SignatureAlgorithmFactory.getInstance();
|
|
+ private static final long CHAIN = 28001L;
|
|
+ private static final AerePqFinality.SealVerifier V =
|
|
+ (h, i, m, s) -> s.equals(sigFor(i, m));
|
|
+
|
|
+ private long hId;
|
|
+ private final List<Address> id = new ArrayList<>();
|
|
+ private final List<Address> ecdsa = new ArrayList<>();
|
|
+ private final KeyPair foreign = ALG.generateKeyPair();
|
|
+
|
|
+ private static Bytes sigFor(final int index, final Bytes message) {
|
|
+ // the index as its 32 bits (a negative index has a signature too, it just names no row)
|
|
+ return Hash.keccak256(Bytes.concatenate(Bytes.ofUnsignedLong(Integer.toUnsignedLong(index)), message));
|
|
+ }
|
|
+
|
|
+ private static Bytes32 messageAt(final long height) {
|
|
+ return Hash.keccak256(Bytes.concatenate(Bytes.wrap("t4-msg".getBytes(java.nio.charset.StandardCharsets.US_ASCII)), Bytes.ofUnsignedLong(height)));
|
|
+ }
|
|
+
|
|
+ /** A PREPARE-like payload: its seal signs {@link #messageAt}(height); a COMMIT-like one names a commit seal signer. */
|
|
+ private static final class Sealed implements Payload, PqSealed {
|
|
+ private final long height;
|
|
+ private final Optional<FalconSeal> seal;
|
|
+ private final Optional<Address> commitSigner;
|
|
+ private final boolean messageThrows;
|
|
+
|
|
+ Sealed(final long height, final Optional<FalconSeal> seal, final Optional<Address> commitSigner, final boolean messageThrows) {
|
|
+ this.height = height;
|
|
+ this.seal = seal;
|
|
+ this.commitSigner = commitSigner;
|
|
+ this.messageThrows = messageThrows;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void writeTo(final RLPOutput out) {
|
|
+ out.startList();
|
|
+ out.writeLongScalar(height);
|
|
+ out.endList();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getMessageType() {
|
|
+ return 0x12;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public org.hyperledger.besu.datatypes.Hash hashForSignature() {
|
|
+ return org.hyperledger.besu.datatypes.Hash.hash(Bytes.ofUnsignedLong(height));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
+ return new ConsensusRoundIdentifier(height, 0);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Optional<FalconSeal> getFalconSeal() {
|
|
+ return seal;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Optional<Bytes32> pqSealMessage(final long chainId) {
|
|
+ if (messageThrows) {
|
|
+ throw new IllegalArgumentException("cannot build");
|
|
+ }
|
|
+ return commitSigner.isPresent() || chainId != CHAIN ? Optional.empty() : Optional.of(messageAt(height));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Optional<Address> commitSealSigner() {
|
|
+ return commitSigner;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Address signed(final Sealed p) {
|
|
+ return SignedData.create(p, ALG.sign(Bytes32.wrap(p.hashForSignature().getBytes()), foreign)).getAuthor();
|
|
+ }
|
|
+
|
|
+ private static Sealed prepare(final long height, final Optional<FalconSeal> seal) {
|
|
+ return new Sealed(height, seal, Optional.empty(), false);
|
|
+ }
|
|
+
|
|
+ /** A seal of index {@code index} that verifies over the message of {@code signedHeight}. */
|
|
+ private static Optional<FalconSeal> good(final int index, final long signedHeight) {
|
|
+ return Optional.of(new FalconSeal(index, sigFor(index, messageAt(signedHeight))));
|
|
+ }
|
|
+
|
|
+ @BeforeEach
|
|
+ public void arm() throws IOException {
|
|
+ final JsonNode v;
|
|
+ try (InputStream in = getClass().getResourceAsStream("/aere/registry-v3/ok-epoch-a.json")) {
|
|
+ assertThat(in).isNotNull();
|
|
+ v = new ObjectMapper().readTree(in);
|
|
+ }
|
|
+ final PqRegistryV3.Registry epoch =
|
|
+ PqRegistryV3.load(
|
|
+ v.get("manifest"), v.get("chainId").asLong(),
|
|
+ List.of("falcon-512", "slh-dsa-sha2-128s"), null, true);
|
|
+ for (final PqRegistryV3.Row r : epoch.rows()) {
|
|
+ id.add(Address.wrap(Bytes.wrap(r.id())));
|
|
+ ecdsa.add(Address.wrap(Bytes.wrap(r.ecdsaAddress())));
|
|
+ }
|
|
+ hId = epoch.bindHeight();
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(hId, epoch);
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(hId, epochs, hId));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHfinTheAuthorIsTheIdOfAVerifiedSealWhateverKeySignedTheEnvelope() {
|
|
+ final long hFin = hId + 100;
|
|
+ AerePqFinality.install(hFin, CHAIN, V);
|
|
+ final Address foreignAddr = Util.publicKeyToAddress(foreign.getPublicKey());
|
|
+ assertThat(id).doesNotContain(foreignAddr);
|
|
+ for (int i = 0; i < id.size(); i++) {
|
|
+ assertThat(signed(prepare(hFin, good(i, hFin)))).as("index %s at H_fin", i).isEqualTo(id.get(i));
|
|
+ assertThat(signed(prepare(hFin + 500, good(i, hFin + 500)))).isEqualTo(id.get(i));
|
|
+ }
|
|
+ // one block below H_fin the envelope's signer is still the author: a foreign key authors nothing of the set
|
|
+ assertThat(signed(prepare(hFin - 1, good(0, hFin - 1)))).isEqualTo(foreignAddr);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHfinASealThatDoesNotVerifyAuthorsNothing() {
|
|
+ final long hFin = hId + 100;
|
|
+ AerePqFinality.install(hFin, CHAIN, V);
|
|
+ // the fixture can express the defect: the same index with its own seal IS an author
|
|
+ assertThat(signed(prepare(hFin, good(0, hFin)))).isEqualTo(id.get(0));
|
|
+ // index 0 carrying index 1's seal
|
|
+ assertThat(signed(prepare(hFin, Optional.of(new FalconSeal(0, sigFor(1, messageAt(hFin)))))))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ // index 0's seal over another height's message
|
|
+ assertThat(signed(prepare(hFin, good(0, hFin + 1)))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ // any other bytes
|
|
+ assertThat(signed(prepare(hFin, Optional.of(new FalconSeal(0, Bytes.of(1, 2, 3))))))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ // no seal, an index outside the epoch, a negative index, a message that cannot be built
|
|
+ assertThat(signed(prepare(hFin, Optional.empty()))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(signed(prepare(hFin, good(id.size(), hFin)))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(signed(prepare(hFin, good(-1, hFin)))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(signed(new Sealed(hFin, good(0, hFin), Optional.empty(), true)))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHfinACommitsAuthorIsItsIndexOnlyWhenThatIsTheCommitSealSigner() {
|
|
+ final long hFin = hId + 100;
|
|
+ AerePqFinality.install(hFin, CHAIN, V);
|
|
+ final Optional<FalconSeal> anySeal = Optional.of(new FalconSeal(0, Bytes.of(9)));
|
|
+ assertThat(signed(new Sealed(hFin, anySeal, Optional.of(ecdsa.get(0)), false))).isEqualTo(id.get(0));
|
|
+ assertThat(signed(new Sealed(hFin, anySeal, Optional.of(ecdsa.get(1)), false)))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(
|
|
+ signed(
|
|
+ new Sealed(
|
|
+ hFin, anySeal, Optional.of(Util.publicKeyToAddress(foreign.getPublicKey())), false)))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(signed(new Sealed(hFin, Optional.empty(), Optional.of(ecdsa.get(0)), false)))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void unsetHfinLeavesTheEcdsaSignerAsTheAuthorAndHfinNeedsKeysFromV3AndAChain() {
|
|
+ final Address foreignAddr = Util.publicKeyToAddress(foreign.getPublicKey());
|
|
+ assertThat(signed(prepare(hId + 100, good(0, hId + 100)))).isEqualTo(foreignAddr);
|
|
+ // H_fin below H_k, without a chain id, or without keys read from the v3 epochs refuses to arm
|
|
+ assertThatThrownBy(() -> AerePqFinality.install(hId - 1, CHAIN, V))
|
|
+ .isInstanceOf(IllegalStateException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-FIN-01");
|
|
+ assertThatThrownBy(() -> AerePqFinality.install(hId + 100, 0, V))
|
|
+ .isInstanceOf(IllegalStateException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-FIN-01");
|
|
+ AerePqIdentity.uninstall();
|
|
+ assertThatThrownBy(() -> AerePqFinality.install(hId + 100, CHAIN, V))
|
|
+ .isInstanceOf(IllegalStateException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-FIN-01");
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTagsTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTagsTest.java
|
|
new file mode 100755
|
|
index 0000000000..f171b392e0
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqFinalityTagsTest.java
|
|
@@ -0,0 +1,235 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.ArgumentMatchers.anyLong;
|
|
+import static org.mockito.Mockito.mock;
|
|
+import static org.mockito.Mockito.never;
|
|
+import static org.mockito.Mockito.times;
|
|
+import static org.mockito.Mockito.verify;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
|
|
+import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.plugin.data.AddedBlockContext.EventType;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.OptionalInt;
|
|
+import java.util.Set;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-412 Rule B1: finalized/safe follow the last certified anchor's parent, monotonically, and a
|
|
+ * forged between-anchor block can never be reported final. Anchors every 32 from 96 (K=3); the
|
|
+ * certificate predicate is a set of heights that "carry" one, so a planted defect in the rule (an
|
|
+ * anchor without certificate moving the tag, a lower height moving it back, a non-anchor moving it)
|
|
+ * turns exactly one of these red.
|
|
+ */
|
|
+class AerePqFinalityTagsTest {
|
|
+
|
|
+ private static final long ANCHOR_BLOCK = 96L;
|
|
+ private static final int INTERVAL = 32;
|
|
+
|
|
+ private PqAnchorConfig config;
|
|
+ private MutableBlockchain blockchain;
|
|
+ private final Map<Long, BlockHeader> byNumber = new HashMap<>();
|
|
+ private final Map<Hash, BlockHeader> byHash = new HashMap<>();
|
|
+ private final Set<Long> certified = new HashSet<>();
|
|
+
|
|
+ @BeforeEach
|
|
+ void setUp() {
|
|
+ config =
|
|
+ new PqAnchorConfig(2800L, ANCHOR_BLOCK, Map.of(ANCHOR_BLOCK, 3), OptionalInt.empty(), false)
|
|
+ .withAnchorInterval(OptionalInt.of(INTERVAL));
|
|
+ blockchain = mock(MutableBlockchain.class);
|
|
+ // a linear chain 0..200 with deterministic hashes; header(n).parentHash == hash(header(n-1))
|
|
+ Hash prev = Hash.ZERO;
|
|
+ for (long n = 0; n <= 200; n++) {
|
|
+ final BlockHeader h = new BlockHeaderTestFixture().number(n).parentHash(prev).buildHeader();
|
|
+ byNumber.put(n, h);
|
|
+ byHash.put(h.getHash(), h);
|
|
+ prev = h.getHash();
|
|
+ }
|
|
+ when(blockchain.getBlockHeader(anyLong())).thenAnswer(i -> Optional.ofNullable(byNumber.get(i.getArgument(0, Long.class))));
|
|
+ when(blockchain.getBlockHeader(any(Hash.class))).thenAnswer(i -> Optional.ofNullable(byHash.get(i.getArgument(0, Hash.class))));
|
|
+ }
|
|
+
|
|
+ private AerePqFinalityTags tagsWithHead(final long head) {
|
|
+ when(blockchain.getChainHeadHeader()).thenReturn(byNumber.get(head));
|
|
+ return AerePqFinalityTags.install(config, blockchain, h -> certified.contains(h.getNumber()));
|
|
+ }
|
|
+
|
|
+ private BlockAddedEvent headAdvanced(final long n) {
|
|
+ final BlockAddedEvent e = mock(BlockAddedEvent.class);
|
|
+ when(e.isNewCanonicalHead()).thenReturn(true);
|
|
+ when(e.getHeader()).thenReturn(byNumber.get(n));
|
|
+ when(e.getEventType()).thenReturn(EventType.HEAD_ADVANCED);
|
|
+ return e;
|
|
+ }
|
|
+
|
|
+ private BlockAddedEvent reorgTo(final long n, final long commonAncestor) {
|
|
+ final BlockAddedEvent e = mock(BlockAddedEvent.class);
|
|
+ when(e.isNewCanonicalHead()).thenReturn(true);
|
|
+ when(e.getHeader()).thenReturn(byNumber.get(n));
|
|
+ when(e.getEventType()).thenReturn(EventType.CHAIN_REORG);
|
|
+ when(e.getCommonAncestorHash()).thenReturn(byNumber.get(commonAncestor).getHash());
|
|
+ return e;
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theConfigurationUnderTestHasAnchorsEveryThirtyTwoFromNinetySix() {
|
|
+ assertThat(config.anchorAppliesAt(96)).isTrue();
|
|
+ assertThat(config.anchorAppliesAt(128)).isTrue();
|
|
+ assertThat(config.anchorAppliesAt(129)).isFalse();
|
|
+ assertThat(config.anchorAppliesAt(95)).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void startupScanFinalizesTheParentOfTheLastCertifiedAnchorBelowTheHead() {
|
|
+ certified.add(96L);
|
|
+ certified.add(128L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(140);
|
|
+ verify(blockchain, times(1)).setFinalized(byNumber.get(127L).getHash());
|
|
+ verify(blockchain, times(1)).setSafeBlock(byNumber.get(127L).getHash());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(127L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void startupWithNoCertifiedAnchorInTwoIntervalsSetsNothing() {
|
|
+ final AerePqFinalityTags tags = tagsWithHead(140); // 96 and 128 are anchor heights, none certified
|
|
+ verify(blockchain, never()).setFinalized(any());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(-1L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aCertifiedAnchorAtTheHeadFinalizesItsParent() {
|
|
+ certified.add(96L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(100); // finalized 95
|
|
+ certified.add(128L);
|
|
+ tags.onBlockAdded(headAdvanced(128));
|
|
+ verify(blockchain).setFinalized(byNumber.get(127L).getHash());
|
|
+ verify(blockchain).setSafeBlock(byNumber.get(127L).getHash());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(127L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aBetweenAnchorHeadNeverMovesTheTags_thisIsWhatKeepsAForgedTailOutOfFinalized() {
|
|
+ certified.add(96L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(100);
|
|
+ for (long n = 101; n < 128; n++) {
|
|
+ certified.add(n); // even if a between-anchor header somehow "carried" a certificate
|
|
+ tags.onBlockAdded(headAdvanced(n));
|
|
+ }
|
|
+ verify(blockchain, times(1)).setFinalized(any()); // only the startup one (95)
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(95L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void anAnchorHeightWithoutACertificateDoesNotMoveTheTags() {
|
|
+ certified.add(96L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(100);
|
|
+ tags.onBlockAdded(headAdvanced(128)); // 128 not certified
|
|
+ verify(blockchain, times(1)).setFinalized(any());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(95L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theTagsAreMonotonic_aLowerCertifiedAnchorNeverMovesThemBack() {
|
|
+ certified.add(96L);
|
|
+ certified.add(128L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(140); // finalized 127
|
|
+ tags.onBlockAdded(headAdvanced(96)); // certified, but lower
|
|
+ verify(blockchain, times(1)).setFinalized(any());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(127L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aReorgBelowTheFinalizedBlockIsNotFollowedBackwards() {
|
|
+ certified.add(96L);
|
|
+ certified.add(128L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(140); // finalized 127
|
|
+ tags.onBlockAdded(reorgTo(130, 100)); // common ancestor 100 < 127: logged, not moved
|
|
+ verify(blockchain, times(1)).setFinalized(any());
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(127L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aNonCanonicalEventIsIgnored() {
|
|
+ certified.add(96L);
|
|
+ certified.add(128L);
|
|
+ final AerePqFinalityTags tags = tagsWithHead(100); // finalized 95
|
|
+ final BlockAddedEvent fork = mock(BlockAddedEvent.class);
|
|
+ when(fork.isNewCanonicalHead()).thenReturn(false);
|
|
+ when(fork.getHeader()).thenReturn(byNumber.get(128L));
|
|
+ tags.onBlockAdded(fork);
|
|
+ assertThat(tags.finalizedNumber()).isEqualTo(95L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void headersAreLinkedByParentHashInTheFixture() {
|
|
+ assertThat(byNumber.get(128L).getParentHash()).isEqualTo(byNumber.get(127L).getHash());
|
|
+ assertThat(byNumber.get(127L).getHash().size()).isEqualTo(32);
|
|
+ }
|
|
+
|
|
+ // --- the certificate predicate: the controller feeds carriesCertificate(decode(header)) into install(),
|
|
+ // so it decides which anchors move the tags. On a stage-5 chain the certificate is the v2 (hybrid) list
|
|
+ // and getFalconSeals() is empty; a predicate that read only the v1 list never fired (rep28098 rehearsal,
|
|
+ // 2026-09-26). These three cases are the control that both fields are read.
|
|
+
|
|
+ private static BftExtraData extraWith(final List<FalconSeal> v1, final List<SchemeSeal> v2) {
|
|
+ return new BftExtraData(
|
|
+ Bytes.EMPTY, Collections.emptyList(), Optional.empty(), 0, Collections.emptyList(), v1, v2);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void carriesCertificate_trueForAV1FalconList() {
|
|
+ assertThat(
|
|
+ AerePqFinalityTags.carriesCertificate(
|
|
+ extraWith(List.of(new FalconSeal(0, Bytes.of(1, 2, 3))), Collections.emptyList())))
|
|
+ .isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void carriesCertificate_trueForAV2HybridCertificate_thisIsTheStage5AnchorThatWasBeingMissed() {
|
|
+ assertThat(
|
|
+ AerePqFinalityTags.carriesCertificate(
|
|
+ extraWith(
|
|
+ Collections.emptyList(),
|
|
+ List.of(new SchemeSeal((byte) 1, 0, Bytes.of(1, 2, 3))))))
|
|
+ .isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void carriesCertificate_falseWhenNeitherListIsPresent() {
|
|
+ assertThat(
|
|
+ AerePqFinalityTags.carriesCertificate(
|
|
+ extraWith(Collections.emptyList(), Collections.emptyList())))
|
|
+ .isFalse();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentityTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentityTest.java
|
|
new file mode 100644
|
|
index 0000000000..a375f42609
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/AerePqIdentityTest.java
|
|
@@ -0,0 +1,135 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: probes of the identity translation (AerePqIdentity), on the registry v3
|
|
+ * conformance vector ok-epoch-a (three rows, each with its ecdsa link, row 0 with a transport).
|
|
+ *
|
|
+ * What must hold, each with its negative: disarmed, every function is the identity (the build that
|
|
+ * carries the class and is never configured is byte for byte the old one); armed, an address becomes
|
|
+ * its id exactly from H_id and not one block earlier; an address without a row stays itself (so its
|
|
+ * message is simply not in the set); the set after H_id - 1 becomes the sorted ids and a member
|
|
+ * without a row REFUSES instead of being dropped; the local node is recognised in both forms and only
|
|
+ * its own; ids reach peers through their transport, and an id with no transport means "every peer".
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.InputStream;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collection;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class AerePqIdentityTest {
|
|
+
|
|
+ private static final long H_ID = 1500;
|
|
+ private PqRegistryV3.Registry epoch;
|
|
+ private final List<Address> addr = new ArrayList<>();
|
|
+ private final List<Address> id = new ArrayList<>();
|
|
+
|
|
+ @BeforeEach
|
|
+ public void armOnTheVector() throws IOException {
|
|
+ final JsonNode v;
|
|
+ try (InputStream in = getClass().getResourceAsStream("/aere/registry-v3/ok-epoch-a.json")) {
|
|
+ assertThat(in).isNotNull();
|
|
+ v = new ObjectMapper().readTree(in);
|
|
+ }
|
|
+ epoch =
|
|
+ PqRegistryV3.load(
|
|
+ v.get("manifest"), v.get("chainId").asLong(),
|
|
+ List.of("falcon-512", "slh-dsa-sha2-128s"), null, true);
|
|
+ for (final PqRegistryV3.Row r : epoch.rows()) {
|
|
+ addr.add(Address.wrap(Bytes.wrap(r.ecdsaAddress())));
|
|
+ id.add(Address.wrap(Bytes.wrap(r.id())));
|
|
+ }
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(epoch.bindHeight(), epoch);
|
|
+ AerePqIdentity.uninstall();
|
|
+ assertThat(epoch.bindHeight()).isLessThanOrEqualTo(H_ID);
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void disarmedEverythingIsTheIdentity() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ assertThat(AerePqIdentity.author(addr.get(0), H_ID + 10)).isEqualTo(addr.get(0));
|
|
+ final Collection<Address> set = new java.util.TreeSet<>(addr);
|
|
+ assertThat(AerePqIdentity.translateSetAfter(set, H_ID - 1)).isSameAs(set);
|
|
+ assertThat(AerePqIdentity.isLocal(id.get(0), addr.get(0))).isFalse();
|
|
+ assertThat(AerePqIdentity.transportTargets(addr)).contains(addr);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void anAddressBecomesItsIdExactlyFromHid() {
|
|
+ assertThat(AerePqIdentity.author(addr.get(1), H_ID - 1)).isEqualTo(addr.get(1));
|
|
+ assertThat(AerePqIdentity.author(addr.get(1), H_ID)).isEqualTo(id.get(1));
|
|
+ assertThat(AerePqIdentity.author(addr.get(2), H_ID + 1000)).isEqualTo(id.get(2));
|
|
+ // an address the registry does not link stays itself: its message is then not in the set
|
|
+ final Address stranger = Address.fromHexString("0x00000000000000000000000000000000000000aa");
|
|
+ assertThat(AerePqIdentity.author(stranger, H_ID + 5)).isEqualTo(stranger);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theSetAfterHidMinusOneBecomesTheSortedIdsAndNowhereElse() {
|
|
+ final Collection<Address> set = new java.util.TreeSet<>(addr);
|
|
+ assertThat(AerePqIdentity.translateSetAfter(set, H_ID - 2)).isSameAs(set);
|
|
+ assertThat(AerePqIdentity.translateSetAfter(set, H_ID)).isSameAs(set);
|
|
+ final Collection<Address> t = AerePqIdentity.translateSetAfter(set, H_ID - 1);
|
|
+ assertThat(t).containsExactlyElementsOf(new java.util.TreeSet<>(id));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aMemberWithoutARowRefusesInsteadOfBeingDropped() {
|
|
+ final Collection<Address> set = new java.util.TreeSet<>(addr);
|
|
+ set.add(Address.fromHexString("0x00000000000000000000000000000000000000bb"));
|
|
+ assertThatThrownBy(() -> AerePqIdentity.translateSetAfter(set, H_ID - 1))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class)
|
|
+ .hasMessageContaining("has no row");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theLocalNodeIsRecognisedInBothFormsAndOnlyItsOwn() {
|
|
+ assertThat(AerePqIdentity.isLocal(addr.get(0), addr.get(0))).isTrue();
|
|
+ assertThat(AerePqIdentity.isLocal(id.get(0), addr.get(0))).isTrue();
|
|
+ assertThat(AerePqIdentity.isLocal(id.get(1), addr.get(0))).isFalse();
|
|
+ assertThat(AerePqIdentity.local(addr.get(0), H_ID - 1)).isEqualTo(addr.get(0));
|
|
+ assertThat(AerePqIdentity.local(addr.get(0), H_ID)).isEqualTo(id.get(0));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void idsReachPeersThroughTheirTransportOrEveryPeer() {
|
|
+ final byte[] t0 = epoch.rows().get(0).transport();
|
|
+ assertThat(t0).isNotNull();
|
|
+ assertThat(AerePqIdentity.transportTargets(List.of(id.get(0))))
|
|
+ .contains(List.of(Address.wrap(Bytes.wrap(t0))));
|
|
+ assertThat(epoch.rows().get(1).transport()).isNull();
|
|
+ assertThat(AerePqIdentity.transportTargets(List.of(id.get(0), id.get(1)))).isEqualTo(Optional.empty());
|
|
+ // below H_id the recipients are addresses and go out as before
|
|
+ assertThat(AerePqIdentity.transportTargets(addr)).contains(addr);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void anIdentityHeightWithNoEpochAtOrBelowItRefusesToArm() {
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(epoch.bindHeight(), epoch);
|
|
+ assertThatThrownBy(
|
|
+ () -> AerePqIdentity.install(new AerePqIdentity.Config(epoch.bindHeight() - 1, epochs)))
|
|
+ .isInstanceOf(AerePqIdentity.IdentityException.class);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducerTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducerTest.java
|
|
index 5569abeb7b..6dfa922ba4 100755
|
|
--- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducerTest.java
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSealProducerTest.java
|
|
@@ -75,40 +75,69 @@ class HybridSealProducerTest {
|
|
@Test
|
|
void theGateAloneSuppressesEmissionEvenWhenTheScheduleDemandsIt() {
|
|
final HybridSealProducer poartaInchisa =
|
|
new HybridSealProducer(
|
|
H_HIBRID + 100,
|
|
orar,
|
|
INDEX,
|
|
Map.of(SealSchemes.SLH_DSA_128S.id(), slh.privateKey()));
|
|
assertThat(poartaInchisa.sealsFor(H_HIBRID, MESSAGE)).isEmpty();
|
|
assertThat(poartaInchisa.sealsFor(H_HIBRID + 100, MESSAGE)).hasSize(1);
|
|
}
|
|
|
|
@Test
|
|
void atTheHybridStepTheExtraSealIsProduced() {
|
|
final List<SchemeSeal> seals = producator().sealsFor(H_HIBRID, MESSAGE);
|
|
assertThat(seals).hasSize(1);
|
|
assertThat(seals.get(0).getSchemeWireId()).isEqualTo(SealSchemes.SLH_DSA_128S.wireId());
|
|
assertThat(seals.get(0).getValidatorIndex()).isEqualTo(INDEX);
|
|
}
|
|
|
|
+ // ------------------------------------------- intervale per schema (AIP-22 treapta 2)
|
|
+
|
|
+ /**
|
|
+ * With SLH-DSA on the 128 grid and the anchor grids counted from H0 = 64, the producer signs the
|
|
+ * SLH-DSA seal only at the parent of an anchor on that grid; at the parent of a Falcon-only
|
|
+ * anchor (32 grid) it emits nothing, although the key is there and the gate is open. The two
|
|
+ * heights differ in nothing but the grid, which is the only thing this proof is about.
|
|
+ */
|
|
+ @Test
|
|
+ void theSlhDsaSealIsProducedOnlyAtParentsOfAnchorsOnItsOwnGrid() {
|
|
+ final long h0 = 64L;
|
|
+ final PqSchemeSchedule cuIntervale =
|
|
+ PqSchemeSchedule.parse(
|
|
+ "0:" + SealSchemes.FALCON_512.id() + "/32+" + SealSchemes.SLH_DSA_128S.id() + "/128");
|
|
+ final HybridSealProducer p =
|
|
+ new HybridSealProducer(
|
|
+ H_ATASARE, cuIntervale, INDEX, Map.of(SealSchemes.SLH_DSA_128S.id(), slh.privateKey()), h0);
|
|
+ final long ancoraHibrida = h0 + 128L * 10; // 1344: pe grila 128
|
|
+ final long ancoraDoarFalcon = ancoraHibrida + 32L; // 1376: pe grila 32, nu pe 128
|
|
+ assertThat(p.sealsFor(ancoraHibrida - 1, MESSAGE)).hasSize(1);
|
|
+ assertThat(p.sealsFor(ancoraDoarFalcon - 1, MESSAGE)).isEmpty();
|
|
+ // the negative control of the grid origin: the same heights read against another origin flip
|
|
+ final HybridSealProducer altaOrigine =
|
|
+ new HybridSealProducer(
|
|
+ H_ATASARE, cuIntervale, INDEX, Map.of(SealSchemes.SLH_DSA_128S.id(), slh.privateKey()), h0 + 32);
|
|
+ assertThat(altaOrigine.sealsFor(ancoraHibrida - 1, MESSAGE)).isEmpty();
|
|
+ assertThat(altaOrigine.sealsFor(ancoraDoarFalcon - 1, MESSAGE)).hasSize(1);
|
|
+ }
|
|
+
|
|
// ---------------------------------------------------------------- jumatatea de certificat
|
|
|
|
@Test
|
|
void aMissingKeyEmitsNothingAtAllRatherThanAStubCertificate() {
|
|
final HybridSealProducer withoutKey =
|
|
new HybridSealProducer(H_ATASARE, orar, INDEX, Map.of());
|
|
assertThat(withoutKey.sealsFor(H_HIBRID, MESSAGE)).isEmpty();
|
|
}
|
|
|
|
@Test
|
|
void aNullMessageIsRefusedWithoutThrowing() {
|
|
assertThat(producator().sealsFor(H_HIBRID, null)).isEmpty();
|
|
}
|
|
|
|
// ---------------------------------------------------------------- dus-intorsul cheii
|
|
|
|
@Test
|
|
void theSlhDsaPrivateKeySurvivesSerializationAndStillSigns() {
|
|
final byte[] encoded =
|
|
SealSchemes.SLH_DSA_128S.serializePrivateKey(slh.privateKey()).orElseThrow();
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSignerRegistryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSignerRegistryTest.java
|
|
index 87bca049e7..e2e7be5948 100755
|
|
--- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSignerRegistryTest.java
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/HybridSignerRegistryTest.java
|
|
@@ -117,64 +117,64 @@ class HybridSignerRegistryTest {
|
|
p.setProperty(
|
|
"7.key." + FALCON,
|
|
Bytes.wrap(SealSchemes.FALCON_512.generate(random).publicRegistryForm()).toHexString());
|
|
assertThatThrownBy(() -> HybridSignerRegistry.fromProperties(p, "test"))
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
.hasMessageContaining("beyond count");
|
|
}
|
|
|
|
@Test
|
|
void wrongFormatVersionRefuses() {
|
|
final Properties p = sanatos();
|
|
p.setProperty("formatVersion", "hybrid-9");
|
|
assertThatThrownBy(() -> HybridSignerRegistry.fromProperties(p, "test"))
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
.hasMessageContaining("hybrid-1");
|
|
}
|
|
|
|
@Test
|
|
void unrecognisedEntryRefuses() {
|
|
final Properties p = sanatos();
|
|
- p.setProperty("1.cheie", "0x1234"); // aproape corect, dar nu e nici addr nici key.<schema>
|
|
+ p.setProperty("1.cheie", "0x1234"); // almost right, but it is neither addr nor key.<scheme>
|
|
assertThatThrownBy(() -> HybridSignerRegistry.fromProperties(p, "test"))
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
.hasMessageContaining("unrecognised");
|
|
}
|
|
|
|
// ------------------------------------------------------------------ the canonical hash
|
|
|
|
@Test
|
|
void hashIsDeterministicAndMovesWithEveryBoundThing() {
|
|
final Properties p = sanatos();
|
|
final HybridSignerRegistry a = HybridSignerRegistry.fromProperties(p, "a");
|
|
final HybridSignerRegistry b = HybridSignerRegistry.fromProperties(p, "b");
|
|
assertThat(a.canonicalHash()).isEqualTo(b.canonicalHash()); // determinist
|
|
|
|
- // schimb O cheie: hash-ul se misca
|
|
+ // change ONE key: the hash moves
|
|
final Properties altKey = sanatos();
|
|
altKey.setProperty(
|
|
"2.key." + SLHDSA,
|
|
Bytes.wrap(SealSchemes.SLH_DSA_128S.generate(random).publicRegistryForm()).toHexString());
|
|
assertThat(HybridSignerRegistry.fromProperties(altKey, "c").canonicalHash())
|
|
.isNotEqualTo(a.canonicalHash());
|
|
|
|
- // scot o schema de la un validator: hash-ul se misca
|
|
+ // remove one scheme from a validator: the hash moves
|
|
final Properties altScheme = sanatos();
|
|
altScheme.remove("2.key." + SLHDSA);
|
|
assertThat(HybridSignerRegistry.fromProperties(altScheme, "d").canonicalHash())
|
|
.isNotEqualTo(a.canonicalHash());
|
|
|
|
// alt chainId: hash-ul se misca
|
|
final Properties altChain = sanatos();
|
|
altChain.setProperty("chainId", "2801");
|
|
assertThat(HybridSignerRegistry.fromProperties(altChain, "e").canonicalHash())
|
|
.isNotEqualTo(a.canonicalHash());
|
|
}
|
|
|
|
@Test
|
|
void hashDomainCanNeverCollideWithTheFalconOnlyRegistryFamily() {
|
|
// the domain is part of the preimage; if someone aligned it with the old family, a hybrid
|
|
// registry could pass itself off as the genesis-bound v1 registry. The constant is
|
|
// verified here so it cannot drift silently.
|
|
assertThat(HybridSignerRegistry.HASH_DOMAIN).isEqualTo("AERE-PQ-HYBRID-REGISTRY-1");
|
|
assertThat(HybridSignerRegistry.HASH_DOMAIN).isNotEqualTo(PqRegistryHash.DOMAIN_V1);
|
|
assertThat(HybridSignerRegistry.HASH_DOMAIN).isNotEqualTo(PqRegistryHash.DOMAIN_V2);
|
|
@@ -183,41 +183,41 @@ class HybridSignerRegistryTest {
|
|
// --------------------------------------------- the registry + the v2 certificate, together
|
|
|
|
@Test
|
|
void endToEndCertificateVerifiesAgainstRegistryKeysPerScheme() {
|
|
final byte[] message = "commit hash stand-in, 32 bytes!!".getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
|
// build the registry and KEEP the private test handles so I can sign
|
|
final Properties p = new Properties();
|
|
p.setProperty("formatVersion", "hybrid-1");
|
|
p.setProperty("chainId", "2800");
|
|
p.setProperty("count", "2");
|
|
final SealScheme.GeneratedPair f0 = SealSchemes.FALCON_512.generate(random);
|
|
final SealScheme.GeneratedPair s0 = SealSchemes.SLH_DSA_128S.generate(random);
|
|
final SealScheme.GeneratedPair f1 = SealSchemes.FALCON_512.generate(random);
|
|
p.setProperty("0.addr", "0x" + "aa".repeat(20));
|
|
p.setProperty("1.addr", "0x" + "bb".repeat(20));
|
|
p.setProperty("0.key." + FALCON, Bytes.wrap(f0.publicRegistryForm()).toHexString());
|
|
p.setProperty("0.key." + SLHDSA, Bytes.wrap(s0.publicRegistryForm()).toHexString());
|
|
p.setProperty("1.key." + FALCON, Bytes.wrap(f1.publicRegistryForm()).toHexString());
|
|
final HybridSignerRegistry reg = HybridSignerRegistry.fromProperties(p, "test");
|
|
|
|
- // certificatul hibrid: validatorul 0 cu amandoua schemele, 1 doar Falcon
|
|
+ // the hybrid certificate: validator 0 with both schemes, 1 with Falcon only
|
|
final java.util.List<SchemeSeal> cert =
|
|
java.util.List.of(
|
|
new SchemeSeal((byte) 0x01, 0, Bytes.wrap(
|
|
SealSchemes.FALCON_512.sign(f0.privateKey(), message).orElseThrow())),
|
|
new SchemeSeal((byte) 0x02, 0, Bytes.wrap(
|
|
SealSchemes.SLH_DSA_128S.sign(s0.privateKey(), message).orElseThrow())),
|
|
new SchemeSeal((byte) 0x01, 1, Bytes.wrap(
|
|
SealSchemes.FALCON_512.sign(f1.privateKey(), message).orElseThrow())));
|
|
|
|
// round-trip through the v2 format, then EACH seal against ITS OWN key from the registry
|
|
for (final SchemeSeal seal : PqAnchorV2.decode(PqAnchorV2.encode(cert))) {
|
|
final SealScheme scheme = SealSchemes.byWireId(seal.getSchemeWireId()).orElseThrow();
|
|
final byte[] key = reg.publicKey(seal.getValidatorIndex(), scheme.id()).orElseThrow();
|
|
assertThat(scheme.verifyRaw(key, message, seal.getSignature().toArray()))
|
|
.as("sigiliul %s contra cheii lui din registru", seal)
|
|
.isTrue();
|
|
}
|
|
// the per-scheme threshold, on the same certificate: 2 Falcon validators, 1 SLH-DSA
|
|
assertThat(PqAnchorV2.distinctValidatorsWith(cert, (byte) 0x01)).isEqualTo(2);
|
|
assertThat(PqAnchorV2.distinctValidatorsWith(cert, (byte) 0x02)).isEqualTo(1);
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapseTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapseTest.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 038d862876..2bd1894938
|
|
--- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapseTest.java
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorLapseTest.java
|
|
@@ -76,121 +76,121 @@ public class PqAnchorLapseTest {
|
|
}
|
|
|
|
@Test
|
|
public void theStatedSpansAgreeWithTheBounds() {
|
|
// 36, not 37: (13,268,944 - 13,267,824) / 32 + 1 = 36. And 19,425 for the second range. The
|
|
// span is carried in each entry so the two cannot drift apart in silence; this asserts the
|
|
// arithmetic from the outside as well.
|
|
for (final PqAnchorLapse.Window window : PqAnchorLapse.windows()) {
|
|
assertThat((window.lastBlock() - window.firstBlock()) % PqAnchorLapse.ANCHOR_SPACING).isZero();
|
|
assertThat((window.lastBlock() - window.firstBlock()) / PqAnchorLapse.ANCHOR_SPACING + 1L)
|
|
.isEqualTo(window.anchorHeights());
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// isDisarmed: TRUE only in the first range, and deliberately FALSE in the second.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void isDisarmedIsTrueOnlyWhereNothingWasInForce() {
|
|
- assertThat(PqAnchorLapse.isDisarmed(DISARMED_FIRST)).isTrue();
|
|
- assertThat(PqAnchorLapse.isDisarmed(DISARMED_LAST)).isTrue();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, DISARMED_FIRST)).isTrue();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, DISARMED_LAST)).isTrue();
|
|
|
|
// The neighbouring anchor heights, both measured to carry a digest, stay under the strict rules.
|
|
- assertThat(PqAnchorLapse.isDisarmed(LAST_ENFORCED_BEFORE)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(DISARMED_FIRST - 1L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(DISARMED_LAST + 1L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, LAST_ENFORCED_BEFORE)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, DISARMED_FIRST - 1L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, DISARMED_LAST + 1L)).isFalse();
|
|
|
|
// And FALSE across the whole second range: there the digest and the ordering did hold, and a
|
|
// relaxation that leaked into it would throw away the binding on 19,425 anchor heights.
|
|
- assertThat(PqAnchorLapse.isDisarmed(LOWERED_FIRST)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(13_500_016L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(LOWERED_LAST)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(FIRST_FULLY_ENFORCED_AFTER)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, 13_500_016L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, LOWERED_LAST)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, FIRST_FULLY_ENFORCED_AFTER)).isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void everyAnchorHeightOfTheDisarmedRangeIsCovered() {
|
|
long covered = 0L;
|
|
for (long height = DISARMED_FIRST;
|
|
height <= DISARMED_LAST;
|
|
height += PqAnchorLapse.ANCHOR_SPACING) {
|
|
- assertThat(PqAnchorLapse.isDisarmed(height))
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, height))
|
|
.describedAs("anchor height %d of the disarmed range", height)
|
|
.isTrue();
|
|
covered++;
|
|
}
|
|
assertThat(covered).isEqualTo(36L);
|
|
|
|
// The rest of the chain is untouched.
|
|
- assertThat(PqAnchorLapse.isDisarmed(0L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(13_014_000L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(13_000_000L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(14_077_000L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(Long.MAX_VALUE)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, 0L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, 13_014_000L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, 13_000_000L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, 14_077_000L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, Long.MAX_VALUE)).isFalse();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// historicMinSeals: the threshold that was really in force, and only where it was lower.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void historicMinSealsAnswersOnlyInsideTheLoweredRange() {
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOWERED_FIRST)).hasValue(1);
|
|
- assertThat(PqAnchorLapse.historicMinSeals(13_500_016L)).hasValue(1);
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOWERED_LAST)).hasValue(1);
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST)).hasValue(1);
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, 13_500_016L)).hasValue(1);
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOWERED_LAST)).hasValue(1);
|
|
|
|
// One anchor step past the end and the configured schedule applies again, unchanged. This is
|
|
// the assertion that stops the lowered threshold from becoming permanent.
|
|
- assertThat(PqAnchorLapse.historicMinSeals(FIRST_FULLY_ENFORCED_AFTER)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOWERED_LAST + 1L)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOWERED_FIRST - 1L)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LAST_ENFORCED_BEFORE)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(14_077_000L)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(Long.MAX_VALUE)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, FIRST_FULLY_ENFORCED_AFTER)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOWERED_LAST + 1L)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST - 1L)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LAST_ENFORCED_BEFORE)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, 14_077_000L)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, Long.MAX_VALUE)).isEmpty();
|
|
|
|
// And it does NOT answer inside the disarmed range: there the rules are skipped whole, so a
|
|
// threshold would be a second, contradictory way of saying the same thing.
|
|
- assertThat(PqAnchorLapse.historicMinSeals(DISARMED_FIRST)).isEmpty();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(DISARMED_LAST)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, DISARMED_FIRST)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, DISARMED_LAST)).isEmpty();
|
|
}
|
|
|
|
@Test
|
|
public void theFloorInsideTheLoweredRangeIsOneAndNotZero() {
|
|
// Measured: 2,926 of the 19,425 anchor heights in that range carry fewer seals than the
|
|
// schedule asks, the counts seen are 1 and 2, and NOT ONE carries zero. A floor of zero would
|
|
// therefore accept an empty certificate at a height where a certificate was in fact required,
|
|
// which is weaker than the history needs.
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOWERED_FIRST)).hasValue(1);
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST)).hasValue(1);
|
|
assertThat(PqAnchorLapse.windows().get(1).effectiveMinSeals()).isPositive();
|
|
}
|
|
|
|
@Test
|
|
public void windowCoveringNamesTheRangeOrNothing() {
|
|
- assertThat(PqAnchorLapse.windowCovering(DISARMED_FIRST)).isPresent();
|
|
- assertThat(PqAnchorLapse.windowCovering(DISARMED_FIRST).get().lastBlock())
|
|
+ assertThat(PqAnchorLapse.windowCovering(PqAnchorLapse.CHAIN_ID, DISARMED_FIRST)).isPresent();
|
|
+ assertThat(PqAnchorLapse.windowCovering(PqAnchorLapse.CHAIN_ID, DISARMED_FIRST).get().lastBlock())
|
|
.isEqualTo(DISARMED_LAST);
|
|
- assertThat(PqAnchorLapse.windowCovering(LOWERED_FIRST)).isPresent();
|
|
- assertThat(PqAnchorLapse.windowCovering(LOWERED_FIRST).get().relaxation())
|
|
+ assertThat(PqAnchorLapse.windowCovering(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST)).isPresent();
|
|
+ assertThat(PqAnchorLapse.windowCovering(PqAnchorLapse.CHAIN_ID, LOWERED_FIRST).get().relaxation())
|
|
.isEqualTo(PqAnchorLapse.Relaxation.THRESHOLD_ONLY);
|
|
- assertThat(PqAnchorLapse.windowCovering(FIRST_FULLY_ENFORCED_AFTER)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.windowCovering(PqAnchorLapse.CHAIN_ID, FIRST_FULLY_ENFORCED_AFTER)).isEmpty();
|
|
assertThat(PqAnchorLapse.earliestAffectedBlock()).contains(DISARMED_FIRST);
|
|
}
|
|
|
|
@Test
|
|
public void theDisarmedRangeIsTheSameOBJECTTheOrderingExceptionUses() {
|
|
// A second copy of these bounds anywhere else is a value that diverges. PqAnchor used to carry
|
|
// them as its own literals; it now derives them, and this is the assertion that says so.
|
|
assertThat(PqAnchor.UNORDERED_WINDOW_FIRST).isEqualTo(DISARMED_FIRST);
|
|
assertThat(PqAnchor.UNORDERED_WINDOW_LAST).isEqualTo(DISARMED_LAST);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// The self-checks can say no. A guard that has never refused anything cannot be believed.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void aRangeThatContradictsItselfIsRefusedRatherThanAccepted() {
|
|
assertThatThrownBy(
|
|
() ->
|
|
new PqAnchorLapse.Window(
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorTest.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 5bea4d37e3..aabecee7c2
|
|
--- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorTest.java
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqAnchorTest.java
|
|
@@ -162,78 +162,78 @@ public class PqAnchorTest {
|
|
// Attack A4: the same index twice to inflate k. Unrepresentable, not filtered afterwards.
|
|
assertThat(PqAnchor.hasStrictlyIncreasingIndices(Arrays.asList(seal(2), seal(2)))).isFalse();
|
|
assertThat(
|
|
PqAnchor.hasStrictlyIncreasingIndices(
|
|
Arrays.asList(new FalconSeal(2, signatureFor(2, 0)), new FalconSeal(2, signatureFor(2, 1)))))
|
|
.isFalse();
|
|
assertThat(PqAnchor.hasStrictlyIncreasingIndices(List.of(new FalconSeal(-1, Bytes.of(1)))))
|
|
.isFalse();
|
|
assertThat(PqAnchor.hasStrictlyIncreasingIndices(List.of(new FalconSeal(1, null)))).isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void historicalUnorderedWindowIsAcceptedAndOnlyThere() {
|
|
// The 36 canonical headers written unsorted during the 2026-08-10 interruption. Two real index
|
|
// sequences, decoded off the public endpoint on 2026-08-11: block 13,267,824 lists 2, 6, 1 and
|
|
// block 13,268,944 lists 5, 6, 1, 0.
|
|
final List<FalconSeal> real1 = Arrays.asList(seal(2), seal(6), seal(1));
|
|
final List<FalconSeal> real2 = Arrays.asList(seal(5), seal(6), seal(1), seal(0));
|
|
|
|
// Inside the window: accepted, at both edges and in the middle.
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real1, PqAnchor.UNORDERED_WINDOW_FIRST)).isTrue();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real2, PqAnchor.UNORDERED_WINDOW_LAST)).isTrue();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real1, PqAnchor.UNORDERED_WINDOW_FIRST + 32L)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real1, PqAnchor.UNORDERED_WINDOW_FIRST)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real2, PqAnchor.UNORDERED_WINDOW_LAST)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real1, PqAnchor.UNORDERED_WINDOW_FIRST + 32L)).isTrue();
|
|
|
|
// NEGATIVE CONTROL, and it is the whole point: one block on either side of the window and the
|
|
// very same certificate is rejected. If these two ever pass, the exception has stopped being an
|
|
// exception and has become the rule.
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real1, PqAnchor.UNORDERED_WINDOW_FIRST - 1L)).isFalse();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real1, PqAnchor.UNORDERED_WINDOW_LAST + 1L)).isFalse();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real2, 1L)).isFalse();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(real2, Long.MAX_VALUE)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real1, PqAnchor.UNORDERED_WINDOW_FIRST - 1L)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real1, PqAnchor.UNORDERED_WINDOW_LAST + 1L)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real2, 1L)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, real2, Long.MAX_VALUE)).isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void historicalWindowDoesNotRelaxDistinctness() {
|
|
// Attack A4 inside the window: repeating one seal to inflate k. Sortedness is relaxed there,
|
|
// distinctness is NOT, at any height. A certificate that repeats an index is still
|
|
// unrepresentable, which is the only part of the ordering rule that an attacker cares about.
|
|
final List<FalconSeal> repetat =
|
|
Arrays.asList(new FalconSeal(2, signatureFor(2, 0)), new FalconSeal(2, signatureFor(2, 1)));
|
|
- assertThat(PqAnchor.hasAcceptableIndices(repetat, PqAnchor.UNORDERED_WINDOW_FIRST)).isFalse();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(repetat, PqAnchor.UNORDERED_WINDOW_LAST)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, repetat, PqAnchor.UNORDERED_WINDOW_FIRST)).isFalse();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, repetat, PqAnchor.UNORDERED_WINDOW_LAST)).isFalse();
|
|
|
|
// Negative indices and null signatures stay rejected inside the window too.
|
|
assertThat(
|
|
- PqAnchor.hasAcceptableIndices(
|
|
+ PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID,
|
|
List.of(new FalconSeal(-1, Bytes.of(1))), PqAnchor.UNORDERED_WINDOW_FIRST))
|
|
.isFalse();
|
|
assertThat(
|
|
- PqAnchor.hasAcceptableIndices(
|
|
+ PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID,
|
|
List.of(new FalconSeal(1, null)), PqAnchor.UNORDERED_WINDOW_FIRST))
|
|
.isFalse();
|
|
|
|
// And a sorted certificate is accepted everywhere, window or not: the exception only ever adds.
|
|
final List<FalconSeal> sortat = Arrays.asList(seal(0), seal(3), seal(6));
|
|
- assertThat(PqAnchor.hasAcceptableIndices(sortat, 1L)).isTrue();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(sortat, PqAnchor.UNORDERED_WINDOW_FIRST)).isTrue();
|
|
- assertThat(PqAnchor.hasAcceptableIndices(sortat, Long.MAX_VALUE)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, sortat, 1L)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, sortat, PqAnchor.UNORDERED_WINDOW_FIRST)).isTrue();
|
|
+ assertThat(PqAnchor.hasAcceptableIndices(PqAnchorLapse.CHAIN_ID, sortat, Long.MAX_VALUE)).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void historicalWindowIsClosedAndAnchorAligned() {
|
|
// The window cannot grow: it is bounded above by a measured constant. And both bounds must sit on
|
|
// the 32-block anchor spacing, because only anchor heights carry certificates. A window whose
|
|
// bounds are off the spacing would be evidence that the measurement, not the chain, was wrong.
|
|
assertThat(PqAnchor.UNORDERED_WINDOW_LAST).isGreaterThan(PqAnchor.UNORDERED_WINDOW_FIRST);
|
|
assertThat((PqAnchor.UNORDERED_WINDOW_LAST - PqAnchor.UNORDERED_WINDOW_FIRST) % 32L).isZero();
|
|
// 36 anchor headers, measured contiguous on 2026-08-11.
|
|
assertThat((PqAnchor.UNORDERED_WINDOW_LAST - PqAnchor.UNORDERED_WINDOW_FIRST) / 32L + 1L)
|
|
.isEqualTo(36L);
|
|
}
|
|
|
|
@Test
|
|
public void sortedByIndexOrdersAscending() {
|
|
final List<FalconSeal> sorted = PqAnchor.sortedByIndex(Arrays.asList(seal(5), seal(1), seal(3)));
|
|
assertThat(sorted.stream().map(FalconSeal::getValidatorIndex)).containsExactly(1, 3, 5);
|
|
assertThat(PqAnchor.hasStrictlyIncreasingIndices(sorted)).isTrue();
|
|
}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3Test.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3Test.java
|
|
new file mode 100644
|
|
index 0000000000..e5538e1c61
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqRegistryV3Test.java
|
|
@@ -0,0 +1,509 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: probes of the v3 registry, and the writer of its conformance vectors.
|
|
+ *
|
|
+ * TWO MODES. With the environment variable AERE_REG3_VECTORS_OUT set to a directory, the vector
|
|
+ * writer generates PROBA keys (its helpers are package-visible since 2026-09-23: AereLocalKeysV3Test builds its own epochs with
|
|
+ * private keys it holds) (Falcon-512, SLH-DSA-SHA2-128s, secp256k1), builds two epochs and one
|
|
+ * negative vector per refusal code, and writes them as JSON; each negative differs from a valid
|
|
+ * manifest in ONE field (the lesson of AIP-20: a negative that differs in two places measures which
|
|
+ * check the validator reaches first, not the one it names), and where a field feeds a signed
|
|
+ * message the signatures are re-made over the changed field so that only the named rule can fail.
|
|
+ * Without the variable, every test reads the checked-in vectors from test resources
|
|
+ * (aere/registry-v3/) and requires the outcome each vector names: "ok" with the stated registry hash
|
|
+ * and row hashes, or the exact refusal code. The same files are read by the Nethermind port and by
|
|
+ * the public JS tool, which is what makes them conformance vectors and not just fixtures.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.bft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+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.ethereum.core.Util;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.InputStream;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.security.SecureRandom;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Iterator;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.Map;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import com.fasterxml.jackson.databind.SerializationFeature;
|
|
+import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
+import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
|
+
|
|
+public class PqRegistryV3Test {
|
|
+
|
|
+ private static final ObjectMapper M =
|
|
+ new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
|
+ private static final String RES = "/aere/registry-v3/";
|
|
+ private static final List<String> VECTORS =
|
|
+ List.of(
|
|
+ "ok-epoch-a", "ok-epoch-b-rotation", "n01-format", "n02-chain", "n03-extra-field",
|
|
+ "n05-unknown-scheme", "n06-required-scheme", "n07-falcon-header", "n08-pop",
|
|
+ "n09-id-derivation", "n10-duplicate-id", "n11-duplicate-key", "n12-rotation-one-key",
|
|
+ "n12b-rotation-wrong-key", "n13-rotation-unchanged", "n14-ecdsa-wrong-key",
|
|
+ "n14b-ecdsa-missing", "n15-transport", "n16-declared-hash");
|
|
+
|
|
+ // ------------------------------------------------------------------------------------------
|
|
+ // The conformance vectors
|
|
+ // ------------------------------------------------------------------------------------------
|
|
+
|
|
+ @Test
|
|
+ public void everyVectorHasTheOutcomeItNames() throws IOException {
|
|
+ int ok = 0;
|
|
+ int refused = 0;
|
|
+ for (final String name : VECTORS) {
|
|
+ final JsonNode v = vector(name);
|
|
+ final PqRegistryV3.Registry prev =
|
|
+ v.hasNonNull("previous")
|
|
+ ? loadVector(vector(v.get("previous").asText()), null)
|
|
+ : null;
|
|
+ final String expect = v.get("expect").asText();
|
|
+ if ("ok".equals(expect)) {
|
|
+ final PqRegistryV3.Registry r = loadVector(v, prev);
|
|
+ assertThat(r.hash().toHexString()).as(name).isEqualTo(v.get("registryHash").asText());
|
|
+ final ArrayNode rh = (ArrayNode) v.get("rowHashes");
|
|
+ assertThat(r.rowHashes()).as(name).hasSize(rh.size());
|
|
+ for (int i = 0; i < rh.size(); i++) {
|
|
+ assertThat(r.rowHashes().get(i).toHexString()).as(name + " row " + i)
|
|
+ .isEqualTo(rh.get(i).asText());
|
|
+ }
|
|
+ ok++;
|
|
+ } else {
|
|
+ final PqRegistryV3.Registry prevF = prev;
|
|
+ assertThatThrownBy(() -> loadVector(v, prevF))
|
|
+ .as(name)
|
|
+ .isInstanceOf(PqRegistryV3.RegistryV3Exception.class)
|
|
+ .hasMessageStartingWith(expect + ":");
|
|
+ refused++;
|
|
+ }
|
|
+ }
|
|
+ assertThat(ok).isEqualTo(2);
|
|
+ assertThat(refused).isEqualTo(VECTORS.size() - 2);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void merkleProofsVerifyForEveryRowAndNotOneRowPastTheEnd() throws IOException {
|
|
+ final JsonNode v = vector("ok-epoch-a");
|
|
+ final PqRegistryV3.Registry r = loadVector(v, null);
|
|
+ for (int i = 0; i < r.count(); i++) {
|
|
+ final List<Bytes32> p = PqRegistryV3.merkleProof(r.rowHashes(), i);
|
|
+ assertThat(PqRegistryV3.verifyMerkleProof(r.rowHashes().get(i), i, r.count(), p, r.root()))
|
|
+ .as("row " + i)
|
|
+ .isTrue();
|
|
+ }
|
|
+ // three rows: the last leaf is paired with itself, so its path also "proves" index 3 unless the
|
|
+ // count bound refuses it - that refusal is the whole point of the bound
|
|
+ final int last = r.count() - 1;
|
|
+ final List<Bytes32> p = PqRegistryV3.merkleProof(r.rowHashes(), last);
|
|
+ assertThat(r.count() % 2).isEqualTo(1);
|
|
+ assertThat(
|
|
+ PqRegistryV3.verifyMerkleProof(r.rowHashes().get(last), last + 1, r.count(), p, r.root()))
|
|
+ .isFalse();
|
|
+ // and a leaf that is not a row never verifies
|
|
+ assertThat(
|
|
+ PqRegistryV3.verifyMerkleProof(
|
|
+ Bytes32.fromHexStringLenient("0x01"), 0, r.count(),
|
|
+ PqRegistryV3.merkleProof(r.rowHashes(), 0), r.root()))
|
|
+ .isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theIdIsTheAip20SenderDerivationOfTheFalconKey() throws IOException {
|
|
+ final JsonNode v = vector("ok-epoch-a");
|
|
+ final PqRegistryV3.Registry r = loadVector(v, null);
|
|
+ for (final PqRegistryV3.Row row : r.rows()) {
|
|
+ final byte[] pk = row.key("falcon-512").orElseThrow().publicKey();
|
|
+ assertThat(pk).hasSize(897);
|
|
+ assertThat(pk[0]).isEqualTo((byte) 0x09);
|
|
+ assertThat(PqRegistryV3.idOf(pk)).isEqualTo(row.id());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theRegistryHashCommitsToChainHeightAndCount() throws IOException {
|
|
+ final JsonNode v = vector("ok-epoch-a");
|
|
+ final PqRegistryV3.Registry r = loadVector(v, null);
|
|
+ final Bytes32 h = PqRegistryV3.registryHash(r.chainId(), r.bindHeight(), r.count(), r.root());
|
|
+ assertThat(h).isEqualTo(r.hash());
|
|
+ assertThat(PqRegistryV3.registryHash(r.chainId() + 1, r.bindHeight(), r.count(), r.root()))
|
|
+ .isNotEqualTo(h);
|
|
+ assertThat(PqRegistryV3.registryHash(r.chainId(), r.bindHeight() + 1, r.count(), r.root()))
|
|
+ .isNotEqualTo(h);
|
|
+ assertThat(PqRegistryV3.registryHash(r.chainId(), r.bindHeight(), r.count() + 1, r.root()))
|
|
+ .isNotEqualTo(h);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void thePinnedHashIsCompared() throws IOException {
|
|
+ final JsonNode v = vector("ok-epoch-a");
|
|
+ final Bytes32 good = Bytes32.fromHexString(v.get("registryHash").asText());
|
|
+ final PqRegistryV3.Registry r =
|
|
+ PqRegistryV3.loadPinned(
|
|
+ v.get("manifest"), v.get("chainId").asLong(), required(v), null,
|
|
+ v.get("ecdsaRequired").asBoolean(), good);
|
|
+ assertThat(r.hash()).isEqualTo(good);
|
|
+ assertThatThrownBy(
|
|
+ () ->
|
|
+ PqRegistryV3.loadPinned(
|
|
+ v.get("manifest"), v.get("chainId").asLong(), required(v), null,
|
|
+ v.get("ecdsaRequired").asBoolean(), Bytes32.ZERO))
|
|
+ .isInstanceOf(PqRegistryV3.RegistryV3Exception.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-REG3-16:");
|
|
+ }
|
|
+
|
|
+ private static PqRegistryV3.Registry loadVector(final JsonNode v, final PqRegistryV3.Registry prev) {
|
|
+ return PqRegistryV3.load(
|
|
+ v.get("manifest"), v.get("chainId").asLong(), required(v), prev,
|
|
+ v.get("ecdsaRequired").asBoolean());
|
|
+ }
|
|
+
|
|
+ private static List<String> required(final JsonNode v) {
|
|
+ final List<String> out = new ArrayList<>();
|
|
+ v.get("requiredSchemes").forEach(n -> out.add(n.asText()));
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ private static JsonNode vector(final String name) throws IOException {
|
|
+ try (InputStream in = PqRegistryV3Test.class.getResourceAsStream(RES + name + ".json")) {
|
|
+ assertThat(in).as("vector " + name + " is on the test classpath").isNotNull();
|
|
+ return M.readTree(in);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // ------------------------------------------------------------------------------------------
|
|
+ // The vector writer (runs only with AERE_REG3_VECTORS_OUT)
|
|
+ // ------------------------------------------------------------------------------------------
|
|
+
|
|
+ static final long CHAIN = 28001;
|
|
+ private static final SecureRandom RNG = SecureRandomProvider.createSecureRandom();
|
|
+ private static final SignatureAlgorithm EC = SignatureAlgorithmFactory.getInstance();
|
|
+
|
|
+ /** One validator's PROBA keys. */
|
|
+ record Proba(
|
|
+ SealScheme.GeneratedPair falcon, SealScheme.GeneratedPair slh, KeyPair ecdsa, byte[] node) {
|
|
+ byte[] falconStd() {
|
|
+ final byte[] h = falcon.publicRegistryForm();
|
|
+ final byte[] s = new byte[897];
|
|
+ s[0] = 0x09;
|
|
+ System.arraycopy(h, 0, s, 1, 896);
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ byte[] address() {
|
|
+ return Util.publicKeyToAddress(ecdsa.getPublicKey()).getBytes().toArrayUnsafe();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static Proba proba() {
|
|
+ final KeyPair node = EC.generateKeyPair();
|
|
+ return new Proba(
|
|
+ SealSchemes.FALCON_512.generate(RNG),
|
|
+ SealSchemes.SLH_DSA_128S.generate(RNG),
|
|
+ EC.generateKeyPair(),
|
|
+ Util.publicKeyToAddress(node.getPublicKey()).getBytes().toArrayUnsafe());
|
|
+ }
|
|
+
|
|
+ /** A row under construction: keys (scheme id to pair) with the id they are filed under. */
|
|
+ record Draft(byte[] id, Map<String, SealScheme.GeneratedPair> keys, Proba owner) {}
|
|
+
|
|
+ static ObjectNode rowJson(
|
|
+ final long bind, final int count, final int index, final Draft d, final boolean ecdsa,
|
|
+ final boolean transport) {
|
|
+ final ObjectNode row = M.createObjectNode();
|
|
+ row.put("id", hx(d.id()));
|
|
+ final ObjectNode keys = row.putObject("keys");
|
|
+ final ObjectNode pop = row.putObject("pop");
|
|
+ for (final Map.Entry<String, SealScheme.GeneratedPair> e : d.keys().entrySet()) {
|
|
+ final SealScheme s = SealSchemes.byId(e.getKey()).orElseThrow();
|
|
+ final byte[] std = standard(s, e.getValue());
|
|
+ keys.put(e.getKey(), hx(std));
|
|
+ final Bytes32 msg = PqRegistryV3.popMessage(CHAIN, bind, count, index, d.id(), s.wireId(), std);
|
|
+ pop.put(e.getKey(), hx(s.sign(e.getValue().privateKey(), msg.toArrayUnsafe()).orElseThrow()));
|
|
+ }
|
|
+ if (transport) {
|
|
+ row.putObject("transport").put("secp256k1Address", hx(d.owner().node()));
|
|
+ }
|
|
+ if (ecdsa) {
|
|
+ claim(row, bind, count, index, d.owner().ecdsa());
|
|
+ }
|
|
+ return row;
|
|
+ }
|
|
+
|
|
+ /** (Re)computes the ecdsa claim of a row from its current JSON, with the given key. */
|
|
+ private static void claim(
|
|
+ final ObjectNode row, final long bind, final int count, final int index, final KeyPair kp) {
|
|
+ final Bytes32 rh = rowHashOf(row, bind, count, index);
|
|
+ final Bytes32 d = PqRegistryV3.claimDigest(CHAIN, rh);
|
|
+ final ObjectNode ec = row.putObject("ecdsa");
|
|
+ ec.put("addr", hx(Util.publicKeyToAddress(kp.getPublicKey()).getBytes().toArrayUnsafe()));
|
|
+ ec.put("claim", hx(EC.sign(d, kp).encodedBytes().toArrayUnsafe()));
|
|
+ }
|
|
+
|
|
+ /** The row hash of a row as written in JSON (reusing the loader's own parser via a 1-row load
|
|
+ * is impossible here, so the pre-image is rebuilt from the JSON fields). */
|
|
+ private static Bytes32 rowHashOf(final ObjectNode row, final long bind, final int count, final int index) {
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ final Iterator<Map.Entry<String, JsonNode>> it = row.get("keys").fields();
|
|
+ while (it.hasNext()) {
|
|
+ final Map.Entry<String, JsonNode> e = it.next();
|
|
+ final SealScheme s = SealSchemes.byId(e.getKey()).orElseThrow();
|
|
+ keys.put(
|
|
+ s.wireId() & 0xff,
|
|
+ new PqRegistryV3.Key(
|
|
+ s, Bytes.fromHexString(e.getValue().asText()).toArrayUnsafe(),
|
|
+ Bytes.fromHexString(row.get("pop").get(e.getKey()).asText()).toArrayUnsafe()));
|
|
+ }
|
|
+ final byte[] transport =
|
|
+ row.has("transport")
|
|
+ ? Bytes.fromHexString(row.get("transport").get("secp256k1Address").asText()).toArrayUnsafe()
|
|
+ : null;
|
|
+ final PqRegistryV3.Row r =
|
|
+ new PqRegistryV3.Row(
|
|
+ index, Bytes.fromHexString(row.get("id").asText()).toArrayUnsafe(), keys, transport,
|
|
+ Map.of(), null, null);
|
|
+ return PqRegistryV3.rowHash(CHAIN, bind, count, r);
|
|
+ }
|
|
+
|
|
+ private static byte[] standard(final SealScheme s, final SealScheme.GeneratedPair p) {
|
|
+ if (s == SealSchemes.FALCON_512) {
|
|
+ final byte[] h = p.publicRegistryForm();
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(h, 0, std, 1, 896);
|
|
+ return std;
|
|
+ }
|
|
+ return p.publicRegistryForm();
|
|
+ }
|
|
+
|
|
+ static ObjectNode manifest(final long bind, final List<ObjectNode> rows) {
|
|
+ final ObjectNode m = M.createObjectNode();
|
|
+ m.put("formatVersion", 3);
|
|
+ m.put("chainId", CHAIN);
|
|
+ m.put("bindHeight", bind);
|
|
+ m.put("count", rows.size());
|
|
+ for (int i = 0; i < rows.size(); i++) {
|
|
+ m.set(Integer.toString(i), rows.get(i));
|
|
+ }
|
|
+ return m;
|
|
+ }
|
|
+
|
|
+ private static ObjectNode wrap(
|
|
+ final String description, final ObjectNode manifest, final boolean ecdsaRequired,
|
|
+ final String previous, final String expect) {
|
|
+ final ObjectNode v = M.createObjectNode();
|
|
+ v.put("description", description);
|
|
+ v.put("chainId", CHAIN);
|
|
+ final ArrayNode req = v.putArray("requiredSchemes");
|
|
+ req.add("falcon-512");
|
|
+ req.add("slh-dsa-sha2-128s");
|
|
+ v.put("ecdsaRequired", ecdsaRequired);
|
|
+ if (previous == null) {
|
|
+ v.putNull("previous");
|
|
+ } else {
|
|
+ v.put("previous", previous);
|
|
+ }
|
|
+ v.put("expect", expect);
|
|
+ v.set("manifest", manifest);
|
|
+ return v;
|
|
+ }
|
|
+
|
|
+ static Map<String, SealScheme.GeneratedPair> both(final Proba p) {
|
|
+ final Map<String, SealScheme.GeneratedPair> m = new java.util.LinkedHashMap<>();
|
|
+ m.put("falcon-512", p.falcon());
|
|
+ m.put("slh-dsa-sha2-128s", p.slh());
|
|
+ return m;
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @EnabledIfEnvironmentVariable(named = "AERE_REG3_VECTORS_OUT", matches = ".+")
|
|
+ public void writeTheConformanceVectors() throws IOException {
|
|
+ final Path out = Path.of(System.getenv("AERE_REG3_VECTORS_OUT"));
|
|
+ Files.createDirectories(out);
|
|
+ final Proba v0 = proba();
|
|
+ final Proba v1 = proba();
|
|
+ final Proba v2 = proba();
|
|
+ final Proba v3 = proba();
|
|
+ final long bindA = 1000;
|
|
+ final long bindB = 2000;
|
|
+ final Draft d0 = new Draft(PqRegistryV3.idOf(v0.falconStd()), both(v0), v0);
|
|
+ final Draft d1 = new Draft(PqRegistryV3.idOf(v1.falconStd()), both(v1), v1);
|
|
+ final Draft d2 = new Draft(PqRegistryV3.idOf(v2.falconStd()), both(v2), v2);
|
|
+
|
|
+ // epoch A: three rows, the switch epoch (ecdsa on every row), transport on row 0
|
|
+ final List<ObjectNode> a = new ArrayList<>();
|
|
+ a.add(rowJson(bindA, 3, 0, d0, true, true));
|
|
+ a.add(rowJson(bindA, 3, 1, d1, true, false));
|
|
+ a.add(rowJson(bindA, 3, 2, d2, true, false));
|
|
+ final ObjectNode ma = manifest(bindA, a);
|
|
+ final ObjectNode okA = wrap("epoch A: 3 rows, falcon-512 + slh-dsa-sha2-128s, the switch epoch", ma, true, null, "ok");
|
|
+ final PqRegistryV3.Registry ra = PqRegistryV3.load(ma, CHAIN, List.of("falcon-512", "slh-dsa-sha2-128s"), null, true);
|
|
+ addHashes(okA, ra);
|
|
+ write(out, "ok-epoch-a", okA);
|
|
+
|
|
+ // epoch B: row 1 ROTATES both keys (keeps its id), row 2 unchanged, a new validator joins, v0 leaves
|
|
+ final Proba v1b = proba();
|
|
+ final Draft d1b = new Draft(d1.id(), both(v1b), v1);
|
|
+ final Draft d3 = new Draft(PqRegistryV3.idOf(v3.falconStd()), both(v3), v3);
|
|
+ final List<ObjectNode> b = new ArrayList<>();
|
|
+ b.add(rowJson(bindB, 3, 0, d2, false, false));
|
|
+ final ObjectNode r1b = rowJson(bindB, 3, 1, d1b, false, false);
|
|
+ rotate(r1b, bindB, 3, 1, List.of(v1.falcon(), v1.slh()));
|
|
+ b.add(r1b);
|
|
+ b.add(rowJson(bindB, 3, 2, d3, false, false));
|
|
+ final ObjectNode mb = manifest(bindB, b);
|
|
+ final ObjectNode okB = wrap("epoch B after A: index 1 rotates both keys under its id, index 0 unchanged (moved), a new id joins", mb, false, "ok-epoch-a", "ok");
|
|
+ final PqRegistryV3.Registry rb = PqRegistryV3.load(mb, CHAIN, List.of("falcon-512", "slh-dsa-sha2-128s"), ra, false);
|
|
+ addHashes(okB, rb);
|
|
+ write(out, "ok-epoch-b-rotation", okB);
|
|
+
|
|
+ // negatives on epoch A, one field each
|
|
+ ObjectNode m = ma.deepCopy();
|
|
+ m.put("formatVersion", 2);
|
|
+ write(out, "n01-format", wrap("formatVersion 2", m, true, null, "AERE-PQC-REG3-01"));
|
|
+ m = ma.deepCopy();
|
|
+ m.put("chainId", 2800);
|
|
+ write(out, "n02-chain", wrap("chainId of another chain", m, true, null, "AERE-PQC-REG3-02"));
|
|
+ m = ma.deepCopy();
|
|
+ m.put("3", M.createObjectNode());
|
|
+ write(out, "n03-extra-field", wrap("a row \"3\" beyond count 3", m, true, null, "AERE-PQC-REG3-03"));
|
|
+ m = ma.deepCopy();
|
|
+ ((ObjectNode) m.get("1").get("keys")).put("ml-dsa-65", "0x00");
|
|
+ ((ObjectNode) m.get("1").get("pop")).put("ml-dsa-65", "0x00");
|
|
+ write(out, "n05-unknown-scheme", wrap("a key of a scheme this build does not know", m, true, null, "AERE-PQC-REG3-05"));
|
|
+ // n06: row 2 without its SLH-DSA key; pop and claim re-made so only the missing scheme can fail
|
|
+ {
|
|
+ final Map<String, SealScheme.GeneratedPair> onlyF = new java.util.LinkedHashMap<>();
|
|
+ onlyF.put("falcon-512", v2.falcon());
|
|
+ final List<ObjectNode> x = new ArrayList<>(a);
|
|
+ x.set(2, rowJson(bindA, 3, 2, new Draft(d2.id(), onlyF, v2), true, false));
|
|
+ write(out, "n06-required-scheme", wrap("row 2 carries no slh-dsa key", manifest(bindA, x), true, null, "AERE-PQC-REG3-06"));
|
|
+ }
|
|
+ m = ma.deepCopy();
|
|
+ final String fk = m.get("0").get("keys").get("falcon-512").asText();
|
|
+ ((ObjectNode) m.get("0").get("keys")).put("falcon-512", "0x0a" + fk.substring(4));
|
|
+ write(out, "n07-falcon-header", wrap("row 0 falcon key with header 0x0a instead of 0x09", m, true, null, "AERE-PQC-REG3-07"));
|
|
+ m = ma.deepCopy();
|
|
+ ((ObjectNode) m.get("1").get("pop")).put("falcon-512", m.get("0").get("pop").get("falcon-512").asText());
|
|
+ write(out, "n08-pop", wrap("row 1 carries row 0's falcon possession proof", m, true, null, "AERE-PQC-REG3-08"));
|
|
+ // n09: row 1 filed under an id that is not its derivation; every proof re-made over that id
|
|
+ {
|
|
+ final byte[] wrongId = new byte[20];
|
|
+ RNG.nextBytes(wrongId);
|
|
+ final List<ObjectNode> x = new ArrayList<>(a);
|
|
+ x.set(1, rowJson(bindA, 3, 1, new Draft(wrongId, both(v1), v1), true, false));
|
|
+ write(out, "n09-id-derivation", wrap("row 1 id is not keccak(0x50||0x20||falcon)[12:]", manifest(bindA, x), true, null, "AERE-PQC-REG3-09"));
|
|
+ }
|
|
+ // n10: row 2 filed under row 1's id; proofs re-made
|
|
+ {
|
|
+ final List<ObjectNode> x = new ArrayList<>(a);
|
|
+ x.set(2, rowJson(bindA, 3, 2, new Draft(d1.id(), both(v2), v2), true, false));
|
|
+ write(out, "n10-duplicate-id", wrap("row 2 carries row 1's id", manifest(bindA, x), true, null, "AERE-PQC-REG3-10"));
|
|
+ }
|
|
+ // n11: row 2 carries row 1's SLH-DSA key (its proof made by that key, over row 2)
|
|
+ {
|
|
+ final Map<String, SealScheme.GeneratedPair> k = new java.util.LinkedHashMap<>();
|
|
+ k.put("falcon-512", v2.falcon());
|
|
+ k.put("slh-dsa-sha2-128s", v1.slh());
|
|
+ final List<ObjectNode> x = new ArrayList<>(a);
|
|
+ x.set(2, rowJson(bindA, 3, 2, new Draft(d2.id(), k, v2), true, false));
|
|
+ write(out, "n11-duplicate-key", wrap("row 2 carries row 1's slh-dsa key", manifest(bindA, x), true, null, "AERE-PQC-REG3-11"));
|
|
+ }
|
|
+ // n15: transport of 19 bytes (claim re-made over the row as written is impossible: the loader
|
|
+ // refuses the field before hashing, which is the point)
|
|
+ m = ma.deepCopy();
|
|
+ ((ObjectNode) m.get("0").get("transport")).put("secp256k1Address", "0x" + "11".repeat(19));
|
|
+ write(out, "n15-transport", wrap("row 0 transport is 19 bytes", m, true, null, "AERE-PQC-REG3-15"));
|
|
+ // n14: row 1's claim made by row 2's classical key; n14b: row 1 without the link in the switch epoch
|
|
+ {
|
|
+ final ObjectNode x1 = a.get(1).deepCopy();
|
|
+ claim(x1, bindA, 3, 1, v2.ecdsa());
|
|
+ ((ObjectNode) x1.get("ecdsa")).put("addr", hx(v1.address()));
|
|
+ final List<ObjectNode> x = new ArrayList<>(a);
|
|
+ x.set(1, x1);
|
|
+ write(out, "n14-ecdsa-wrong-key", wrap("row 1 claim signed by another validator's key", manifest(bindA, x), true, null, "AERE-PQC-REG3-14"));
|
|
+ final ObjectNode y1 = a.get(1).deepCopy();
|
|
+ y1.remove("ecdsa");
|
|
+ final List<ObjectNode> y = new ArrayList<>(a);
|
|
+ y.set(1, y1);
|
|
+ write(out, "n14b-ecdsa-missing", wrap("row 1 has no ecdsa link in the switch epoch", manifest(bindA, y), true, null, "AERE-PQC-REG3-14"));
|
|
+ }
|
|
+ m = ma.deepCopy();
|
|
+ m.put("registryHash", "0x" + "00".repeat(32));
|
|
+ write(out, "n16-declared-hash", wrap("the file declares a registry hash it does not have", m, true, null, "AERE-PQC-REG3-16"));
|
|
+
|
|
+ // negatives on epoch B
|
|
+ {
|
|
+ final ObjectNode x1 = rowJson(bindB, 3, 1, d1b, false, false);
|
|
+ rotate(x1, bindB, 3, 1, List.of(v1.falcon()));
|
|
+ final List<ObjectNode> x = new ArrayList<>(b);
|
|
+ x.set(1, x1);
|
|
+ write(out, "n12-rotation-one-key", wrap("index 1 rotates with the old falcon key only (slh missing)", manifest(bindB, x), false, "ok-epoch-a", "AERE-PQC-REG3-12"));
|
|
+ final ObjectNode z1 = rowJson(bindB, 3, 1, d1b, false, false);
|
|
+ rotate(z1, bindB, 3, 1, List.of(v3.falcon(), v1.slh()));
|
|
+ final List<ObjectNode> z = new ArrayList<>(b);
|
|
+ z.set(1, z1);
|
|
+ write(out, "n12b-rotation-wrong-key", wrap("index 1 rotation's falcon signature is by another validator's key", manifest(bindB, z), false, "ok-epoch-a", "AERE-PQC-REG3-12"));
|
|
+ final ObjectNode u0 = rowJson(bindB, 3, 0, d2, false, false);
|
|
+ rotate(u0, bindB, 3, 0, List.of(v2.falcon(), v2.slh()));
|
|
+ final List<ObjectNode> u = new ArrayList<>(b);
|
|
+ u.set(0, u0);
|
|
+ write(out, "n13-rotation-unchanged", wrap("index 0 did not change its keys and carries a rotation", manifest(bindB, u), false, "ok-epoch-a", "AERE-PQC-REG3-13"));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** Adds rotation signatures over the row's current hash, one per given old key, in scheme order. */
|
|
+ static void rotate(
|
|
+ final ObjectNode row, final long bind, final int count, final int index,
|
|
+ final List<SealScheme.GeneratedPair> oldKeys) {
|
|
+ final Bytes32 msg = PqRegistryV3.rotateMessage(rowHashOf(row, bind, count, index));
|
|
+ final ObjectNode rot = row.putObject("rotation");
|
|
+ final String[] names = {"falcon-512", "slh-dsa-sha2-128s"};
|
|
+ for (int i = 0; i < oldKeys.size(); i++) {
|
|
+ final SealScheme s = SealSchemes.byId(names[i]).orElseThrow();
|
|
+ rot.put(names[i], hx(s.sign(oldKeys.get(i).privateKey(), msg.toArrayUnsafe()).orElseThrow()));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void addHashes(final ObjectNode v, final PqRegistryV3.Registry r) {
|
|
+ v.put("registryHash", r.hash().toHexString());
|
|
+ v.put("root", r.root().toHexString());
|
|
+ final ArrayNode rh = v.putArray("rowHashes");
|
|
+ r.rowHashes().forEach(h -> rh.add(h.toHexString()));
|
|
+ final ObjectNode proofs = v.putObject("merkleProofs");
|
|
+ for (int i = 0; i < r.count(); i++) {
|
|
+ final ArrayNode p = proofs.putArray(Integer.toString(i));
|
|
+ PqRegistryV3.merkleProof(r.rowHashes(), i).forEach(h -> p.add(h.toHexString()));
|
|
+ }
|
|
+ final ArrayNode ids = v.putArray("ids");
|
|
+ r.rows().forEach(row -> ids.add(hx(row.id())));
|
|
+ }
|
|
+
|
|
+ private static void write(final Path dir, final String name, final JsonNode v) throws IOException {
|
|
+ Files.writeString(dir.resolve(name + ".json"), M.writeValueAsString(v) + "\n", StandardCharsets.UTF_8);
|
|
+ }
|
|
+
|
|
+ private static String hx(final byte[] b) {
|
|
+ final StringBuilder sb = new StringBuilder("0x");
|
|
+ for (final byte x : b) {
|
|
+ sb.append(String.format(Locale.ROOT, "%02x", x & 0xff));
|
|
+ }
|
|
+ return sb.toString();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqSchemeScheduleTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqSchemeScheduleTest.java
|
|
index 41e03e825e..41f03ceda2 100755
|
|
--- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqSchemeScheduleTest.java
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/PqSchemeScheduleTest.java
|
|
@@ -60,68 +60,120 @@ class PqSchemeScheduleTest {
|
|
.isInstanceOf(IllegalArgumentException.class);
|
|
assertThatThrownBy(() -> PqSchemeSchedule.parse("100:"))
|
|
.isInstanceOf(IllegalArgumentException.class);
|
|
assertThatThrownBy(() -> PqSchemeSchedule.parse("100:falcon-512+falcon-512"))
|
|
.isInstanceOf(IllegalArgumentException.class)
|
|
.hasMessageContaining("repeats");
|
|
assertThatThrownBy(() -> PqSchemeSchedule.parse("-5:falcon-512"))
|
|
.isInstanceOf(IllegalArgumentException.class);
|
|
}
|
|
|
|
// ------------------------------------------------------------- poarta de armare (D-147)
|
|
|
|
private HybridSignerRegistry registruCuAcoperire(final int falconi, final int slhuri) {
|
|
final Properties p = new Properties();
|
|
final int count = Math.max(falconi, Math.max(slhuri, 1));
|
|
p.setProperty("formatVersion", "hybrid-1");
|
|
p.setProperty("chainId", "2800");
|
|
p.setProperty("count", String.valueOf(count));
|
|
for (int i = 0; i < count; i++) {
|
|
p.setProperty(i + ".addr", "0x" + String.format("%040x", 0xB0 + i));
|
|
- // fiecare index primeste macar o cheie; acoperirea per schema e controlata mai jos
|
|
+ // every index gets at least one key; per-scheme coverage is controlled below
|
|
if (i < falconi) {
|
|
p.setProperty(i + ".key." + FALCON,
|
|
Bytes.wrap(SealSchemes.FALCON_512.generate(random).publicRegistryForm()).toHexString());
|
|
}
|
|
if (i < slhuri) {
|
|
p.setProperty(i + ".key." + SLHDSA,
|
|
Bytes.wrap(SealSchemes.SLH_DSA_128S.generate(random).publicRegistryForm()).toHexString());
|
|
}
|
|
if (i >= falconi && i >= slhuri) {
|
|
p.setProperty(i + ".key." + FALCON,
|
|
Bytes.wrap(SealSchemes.FALCON_512.generate(random).publicRegistryForm()).toHexString());
|
|
}
|
|
}
|
|
return HybridSignerRegistry.fromProperties(p, "test");
|
|
}
|
|
|
|
@Test
|
|
void armabilityGateWalksTheWholeScheduleNotJustTheFirstStep() {
|
|
// the registry: 3 validators with Falcon, only 1 with SLH-DSA
|
|
final HybridSignerRegistry reg = registruCuAcoperire(3, 1);
|
|
- // treapta PERICULOASA e ULTIMA: hibridul cere SLH-DSA cu acoperire 1 < K=3
|
|
+ // the DANGEROUS step is the LAST: the hybrid requires SLH-DSA with coverage 1 < K=3
|
|
final PqSchemeSchedule orar =
|
|
PqSchemeSchedule.parse("100:falcon-512,999999:falcon-512+slh-dsa-128s");
|
|
final var refusal = orar.firstUnsatisfied(reg, 3);
|
|
assertThat(refusal).isPresent();
|
|
assertThat(refusal.get()).contains("999999").contains(SLHDSA).contains("covers only 1");
|
|
}
|
|
|
|
@Test
|
|
void armabilityPassesWhenEverySchemeHasCoverage() {
|
|
final HybridSignerRegistry reg = registruCuAcoperire(3, 3);
|
|
final PqSchemeSchedule orar =
|
|
PqSchemeSchedule.parse("100:falcon-512,200:falcon-512+slh-dsa-128s");
|
|
assertThat(orar.firstUnsatisfied(reg, 3)).isEmpty();
|
|
// and the same gate's negative control: an impossible threshold must refuse
|
|
assertThat(orar.firstUnsatisfied(reg, 4)).isPresent();
|
|
}
|
|
|
|
+ // ------------------------------------------------- intervale per schema (AIP-22 treapta 2)
|
|
+
|
|
+ private static final String SLHDSA_CANONIC = "slh-dsa-sha2-128s";
|
|
+
|
|
+ @Test
|
|
+ void perSchemeIntervalsParseAndOnlyBiteOnTheirOwnGrid() {
|
|
+ // Falcon every 32nd block, SLH-DSA only every 128th, grids counted from H0=64
|
|
+ final PqSchemeSchedule orar =
|
|
+ PqSchemeSchedule.parse("1000:" + FALCON + "/32+" + SLHDSA_CANONIC + "/128");
|
|
+ assertThat(orar.hasIntervals()).isTrue();
|
|
+ // schemesAt ramane setul intreg: cheile si armabilitatea privesc toate schemele
|
|
+ assertThat(orar.schemesAt(1000)).containsExactlyInAnyOrder(FALCON, SLHDSA_CANONIC);
|
|
+ // 64 + 32k but not 64 + 128k: Falcon only
|
|
+ assertThat(orar.schemesRequiredForAnchor(1056, 64)).containsExactly(FALCON); // 1056-64 = 992 = 31*32
|
|
+ assertThat(orar.schemesRequiredForAnchor(1120, 64)).containsExactly(FALCON); // 1056 = 33*32, not a multiple of 128
|
|
+ // 64 + 128k: amandoua
|
|
+ assertThat(orar.schemesRequiredForAnchor(1216, 64)).containsExactlyInAnyOrder(FALCON, SLHDSA_CANONIC); // 1152 = 9*128
|
|
+ // sub prima treapta (parintele 999 e sub 1000): nimic
|
|
+ assertThat(orar.schemesRequiredForAnchor(1000, 64)).isEmpty();
|
|
+ // at the boundary: the step is read at the PARENT (1000), the anchor is 1001... which is not on the 32 grid from 64
|
|
+ assertThat(orar.schemesRequiredForAnchor(1001, 64)).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void withoutIntervalsEveryNamedSchemeIsRequiredAtEveryAnchorExactlyAsBefore() {
|
|
+ final PqSchemeSchedule orar = PqSchemeSchedule.parse("100:" + FALCON + "+" + SLHDSA);
|
|
+ assertThat(orar.hasIntervals()).isFalse();
|
|
+ for (final long h : new long[] {101, 133, 200, 999_999}) {
|
|
+ assertThat(orar.schemesRequiredForAnchor(h, 64)).isEqualTo(orar.schemesAt(h - 1));
|
|
+ }
|
|
+ // and a scheme WITHOUT an interval next to one WITH: the first at every anchor, the second on its grid
|
|
+ final PqSchemeSchedule mixt = PqSchemeSchedule.parse("100:" + FALCON + "+" + SLHDSA_CANONIC + "/128");
|
|
+ assertThat(mixt.schemesRequiredForAnchor(96 + 32, 96)).containsExactly(FALCON);
|
|
+ assertThat(mixt.schemesRequiredForAnchor(96 + 128, 96)).containsExactlyInAnyOrder(FALCON, SLHDSA_CANONIC);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void intervalsThatCannotLandOnAnchorsRefuseTheWholeSchedule() {
|
|
+ assertThatThrownBy(() -> PqSchemeSchedule.parse("100:" + FALCON + "/0"))
|
|
+ .isInstanceOf(IllegalArgumentException.class)
|
|
+ .hasMessageContaining("positive multiple");
|
|
+ assertThatThrownBy(() -> PqSchemeSchedule.parse("100:" + FALCON + "/48"))
|
|
+ .isInstanceOf(IllegalArgumentException.class)
|
|
+ .hasMessageContaining("48");
|
|
+ assertThatThrownBy(() -> PqSchemeSchedule.parse("100:" + FALCON + "/abc"))
|
|
+ .isInstanceOf(IllegalArgumentException.class)
|
|
+ .hasMessageContaining("not a number");
|
|
+ assertThatThrownBy(() -> PqSchemeSchedule.parse("100:" + FALCON + "/32+" + FALCON + "/64"))
|
|
+ .isInstanceOf(IllegalArgumentException.class)
|
|
+ .hasMessageContaining("repeats");
|
|
+ }
|
|
+
|
|
@Test
|
|
void beforeTheFirstStepMeansLegacyNotSomeDefaultScheme() {
|
|
final PqSchemeSchedule orar = PqSchemeSchedule.parse("500:falcon-512");
|
|
assertThat(orar.schemesAt(0)).isEmpty();
|
|
assertThat(orar.schemesAt(499)).isEmpty();
|
|
assertThat(orar.steps()).hasSize(1);
|
|
assertThat(orar.steps().get(0).schemeIds()).isEqualTo(Set.of(FALCON));
|
|
}
|
|
}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SlhDsaParallelSigningTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SlhDsaParallelSigningTest.java
|
|
new file mode 100755
|
|
index 0000000000..d4f0726a0f
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/slhdsa/SlhDsaParallelSigningTest.java
|
|
@@ -0,0 +1,137 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.common.bft.slhdsa;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assumptions.assumeThat;
|
|
+
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
|
+import org.bouncycastle.crypto.params.ParametersWithRandom;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * D-337 (2026-09-26): the parallel SLH-DSA signer must be the SAME signature as the Bouncy Castle
|
|
+ * original, bit for bit, and must actually be the path taken. Otherwise the anchor certificate would
|
|
+ * carry a different SLH-DSA seal than the second client and the public verifier expect, or the
|
|
+ * speed-up would be claimed while the sequential code still ran. Pinned: deterministic signing over
|
|
+ * several keys and message lengths equals the original; every signature ran exactly 1 + 2D tasks on
|
|
+ * the pool; the kill switch falls back to the original code with the same bytes and no task; and a
|
|
+ * randomised signature from the parallel path verifies under the original.
|
|
+ */
|
|
+class SlhDsaParallelSigningTest {
|
|
+
|
|
+ private static final org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters ORIGINAL =
|
|
+ org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters.sha2_128s;
|
|
+
|
|
+ private static AsymmetricCipherKeyPair keyPair() {
|
|
+ final SLHDSAKeyPairGenerator gen = new SLHDSAKeyPairGenerator();
|
|
+ gen.init(
|
|
+ new SLHDSAKeyGenerationParameters(
|
|
+ SecureRandomProvider.createSecureRandom(), SLHDSAParameters.sha2_128s));
|
|
+ return gen.generateKeyPair();
|
|
+ }
|
|
+
|
|
+ private static org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner original(
|
|
+ final AsymmetricCipherKeyPair kp, final boolean forSigning) {
|
|
+ final org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner s =
|
|
+ new org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner();
|
|
+ if (forSigning) {
|
|
+ s.init(
|
|
+ true,
|
|
+ new org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters(
|
|
+ ORIGINAL, ((SLHDSAPrivateKeyParameters) kp.getPrivate()).getEncoded()));
|
|
+ } else {
|
|
+ s.init(
|
|
+ false,
|
|
+ new org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters(
|
|
+ ORIGINAL, ((SLHDSAPublicKeyParameters) kp.getPublic()).getEncoded()));
|
|
+ }
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ private static byte[] ours(final AsymmetricCipherKeyPair kp, final byte[] msg) {
|
|
+ final SLHDSASigner s = new SLHDSASigner();
|
|
+ s.init(true, kp.getPrivate());
|
|
+ return s.generateSignature(msg);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void parallelSignaturesAreBitIdenticalToTheOriginalAndTakeTheParallelPath() throws Exception {
|
|
+ assumeThat(ParallelSigning.enabled()).as("needs more than one core").isTrue();
|
|
+ final int perSignature = ParallelSigning.tasksPerSignature(SLHDSAParameters.sha2_128s);
|
|
+ assertThat(perSignature).isEqualTo(15); // FORS + two halves of each of the 7 hypertree layers
|
|
+ final byte[][] messages = {
|
|
+ new byte[0],
|
|
+ "a".getBytes(StandardCharsets.UTF_8),
|
|
+ new byte[32],
|
|
+ "anchor parent 20333167 on chain 2800, a longer message".getBytes(StandardCharsets.UTF_8)
|
|
+ };
|
|
+ int signatures = 0;
|
|
+ for (int key = 0; key < 3; key++) {
|
|
+ final AsymmetricCipherKeyPair kp = keyPair();
|
|
+ for (final byte[] msg : messages) {
|
|
+ final int before = ParallelSigning.tasksRun();
|
|
+ final byte[] fast = ours(kp, msg);
|
|
+ final int ran = ParallelSigning.tasksRun() - before;
|
|
+ assertThat(ran).as("tasks run on the pool for one signature").isEqualTo(perSignature);
|
|
+ assertThat(fast).hasSize(7856);
|
|
+ assertThat(fast).isEqualTo(original(kp, true).generateSignature(msg));
|
|
+ assertThat(original(kp, false).verifySignature(msg, fast)).isTrue();
|
|
+ signatures++;
|
|
+ }
|
|
+ }
|
|
+ assertThat(signatures).isEqualTo(12);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theKillSwitchRunsTheOriginalCodeWithTheSameBytes() throws Exception {
|
|
+ final AsymmetricCipherKeyPair kp = keyPair();
|
|
+ final byte[] msg = "kill switch".getBytes(StandardCharsets.UTF_8);
|
|
+ final String before = System.getProperty(ParallelSigning.SWITCH_PROPERTY);
|
|
+ System.setProperty(ParallelSigning.SWITCH_PROPERTY, "false");
|
|
+ try {
|
|
+ assertThat(ParallelSigning.enabled()).isFalse();
|
|
+ final int tasksBefore = ParallelSigning.tasksRun();
|
|
+ final byte[] sig = ours(kp, msg);
|
|
+ assertThat(ParallelSigning.tasksRun()).as("no task on the pool").isEqualTo(tasksBefore);
|
|
+ assertThat(sig).isEqualTo(original(kp, true).generateSignature(msg));
|
|
+ } finally {
|
|
+ if (before == null) {
|
|
+ System.clearProperty(ParallelSigning.SWITCH_PROPERTY);
|
|
+ } else {
|
|
+ System.setProperty(ParallelSigning.SWITCH_PROPERTY, before);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aRandomisedParallelSignatureVerifiesUnderTheOriginalAndATamperedOneDoesNot()
|
|
+ throws Exception {
|
|
+ assumeThat(ParallelSigning.enabled()).as("needs more than one core").isTrue();
|
|
+ final AsymmetricCipherKeyPair kp = keyPair();
|
|
+ final byte[] msg = "randomised".getBytes(StandardCharsets.UTF_8);
|
|
+ final SLHDSASigner s = new SLHDSASigner();
|
|
+ s.init(true, new ParametersWithRandom(kp.getPrivate(), SecureRandomProvider.createSecureRandom()));
|
|
+ final int before = ParallelSigning.tasksRun();
|
|
+ final byte[] sig = s.generateSignature(msg);
|
|
+ assertThat(ParallelSigning.tasksRun() - before).isEqualTo(15);
|
|
+ assertThat(original(kp, false).verifySignature(msg, sig)).isTrue();
|
|
+ final byte[] bad = sig.clone();
|
|
+ bad[4000] ^= 0x01;
|
|
+ assertThat(original(kp, false).verifySignature(msg, bad)).isFalse();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyIdentityTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyIdentityTest.java
|
|
new file mode 100644
|
|
index 0000000000..44a80d34f2
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/validator/blockbased/VoteTallyIdentityTest.java
|
|
@@ -0,0 +1,75 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the ONE place the validator set changes form. After block H_id - 1 the vote
|
|
+ * tally holds the sorted post-quantum ids of the same members and open votes on addresses are gone;
|
|
+ * at every other block (and disarmed) the tally is untouched.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.common.validator.blockbased;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.validator.ValidatorVote;
|
|
+import org.hyperledger.besu.consensus.common.validator.VoteType;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.io.InputStream;
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.TreeMap;
|
|
+import java.util.TreeSet;
|
|
+
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class VoteTallyIdentityTest {
|
|
+
|
|
+ private static final long H_ID = 1500;
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theTallyTurnsIntoIdsAfterHidMinusOneAndDropsOpenVotes() throws Exception {
|
|
+ final JsonNode v;
|
|
+ try (InputStream in = getClass().getResourceAsStream("/aere/registry-v3/ok-epoch-a.json")) {
|
|
+ v = new ObjectMapper().readTree(in);
|
|
+ }
|
|
+ final PqRegistryV3.Registry epoch =
|
|
+ PqRegistryV3.load(v.get("manifest"), v.get("chainId").asLong(),
|
|
+ List.of("falcon-512", "slh-dsa-sha2-128s"), null, true);
|
|
+ final List<Address> addr = new ArrayList<>();
|
|
+ final List<Address> id = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : epoch.rows()) {
|
|
+ addr.add(Address.wrap(Bytes.wrap(r.ecdsaAddress())));
|
|
+ id.add(Address.wrap(Bytes.wrap(r.id())));
|
|
+ }
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(epoch.bindHeight(), epoch);
|
|
+
|
|
+ // disarmed: nothing happens at any block
|
|
+ final VoteTally before = new VoteTally(addr);
|
|
+ before.translateToIds(H_ID - 1);
|
|
+ assertThat(before.getValidators()).containsExactlyElementsOf(new TreeSet<>(addr));
|
|
+
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs));
|
|
+ final VoteTally t = new VoteTally(addr);
|
|
+ final Address newcomer = Address.fromHexString("0x00000000000000000000000000000000000000cc");
|
|
+ t.addVote(new ValidatorVote(VoteType.ADD, addr.get(0), newcomer));
|
|
+ t.translateToIds(H_ID - 2);
|
|
+ assertThat(t.getValidators()).containsExactlyElementsOf(new TreeSet<>(addr));
|
|
+ t.translateToIds(H_ID - 1);
|
|
+ assertThat(t.getValidators()).containsExactlyElementsOf(new TreeSet<>(id));
|
|
+ // the open vote on an address is gone: two more votes for the newcomer would have reached the
|
|
+ // majority of three with it; after the switch they do not
|
|
+ t.addVote(new ValidatorVote(VoteType.ADD, id.get(1), newcomer));
|
|
+ assertThat(t.getValidators()).doesNotContain(newcomer);
|
|
+ t.translateToIds(H_ID);
|
|
+ assertThat(t.getValidators()).hasSize(3);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n01-format.json b/consensus/common/src/test/resources/aere/registry-v3/n01-format.json
|
|
new file mode 100644
|
|
index 0000000000..24631f15c0
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n01-format.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "formatVersion 2",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-01",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 2,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n02-chain.json b/consensus/common/src/test/resources/aere/registry-v3/n02-chain.json
|
|
new file mode 100644
|
|
index 0000000000..9bca0b7f72
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n02-chain.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "chainId of another chain",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-02",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 2800,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n03-extra-field.json b/consensus/common/src/test/resources/aere/registry-v3/n03-extra-field.json
|
|
new file mode 100644
|
|
index 0000000000..ef96f09515
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n03-extra-field.json
|
|
@@ -0,0 +1,63 @@
|
|
+{
|
|
+ "description" : "a row \"3\" beyond count 3",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-03",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ },
|
|
+ "3" : { }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n05-unknown-scheme.json b/consensus/common/src/test/resources/aere/registry-v3/n05-unknown-scheme.json
|
|
new file mode 100644
|
|
index 0000000000..1ebe53acad
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n05-unknown-scheme.json
|
|
@@ -0,0 +1,64 @@
|
|
+{
|
|
+ "description" : "a key of a scheme this build does not know",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-05",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7",
|
|
+ "ml-dsa-65" : "0x00"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad",
|
|
+ "ml-dsa-65" : "0x00"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n06-required-scheme.json b/consensus/common/src/test/resources/aere/registry-v3/n06-required-scheme.json
|
|
new file mode 100644
|
|
index 0000000000..af77e69fab
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n06-required-scheme.json
|
|
@@ -0,0 +1,60 @@
|
|
+{
|
|
+ "description" : "row 2 carries no slh-dsa key",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-06",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39883a85bf19c4c6226ed184055922f5d874d232c6c5b4df688d7bc238a8f67c4e03e4747c85bda6563341e70b135e469907a1d3e727489e05f7ec8a668ebb8583fa6a118448a6668cc5bfea74d54f5b38a2e7f8714acc751678730c0d3fe735e8c5b7f02abf9315f778e0c8cec1bbb6aabb918dcc9c99febba4e3c3e3ccd5069799964ea34437aacfd7a44946125d107ee1e11643dd4df6be35899e64b6bbaef2b1953e5bbe21abc3411a494157f6797070f9122eed64924218259599ae69c2d7941e67729bcca3ca32eb2e0915f3a786ce88b25d30019f134bfa81b6475cfe74d9422ebd3481ae35e4d052ae0d68a77a14d67d9e409bcc6eca46b6c71b9b946ba06e70b64a3b9eca1ea338a7e521246d017e2107aab0d5e1a693ac713edb76280dc3076375a0cdcb586f712500dcf9f0b6b2846714fd2e2511fc7c5f0dea79fe5ba22962cf01b4203deca1fe5b5259c3db98604ca7424db15708ea0d0cebcbe0f828a3a9863931785231fff9788d3b0e6c52220927583539240efebcd9781eebb634b72549d24be2ab6cad7da8366ce61e0665314dbc06a907a63f3d744533659364adb9b5cb6cb59903a66ce97b03e88f43ead94607e88532ee2b96af40bd2b8360bddf18dcd9fe732608541e74ea6a3e14121f468a92649acb9650efec47b3e4d1a7d784a8b0c7323cdfe7f2390ad61f49c67e2093c707b8cba1af39294fb6c86fdff3b645e25df27adb7970e2825e0a4f61bd35f9fbb53b33d7cd7b9a699c7ee11959f11b2972a91e2f92129a3055d846945731c6c705b4fe7ed6372f952b57fa7ef5b214cf6125059f23845655caf4ef1ee351d4baa9eaa5a72de4cb36847e787eda3ed6338bd7cf92025db415df395f22363db33974cd203b583339bee8b99dbabe3fbc8e6ecb76f333278d08"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x4732138455fd4f975bdd2fa3b9b2d5717315b78648f8325cca9d350bc460a20c14ed099ecb4e29c7d37c715e76c3df0fc30462e41b0055c29b4b9285e46c434d00"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n07-falcon-header.json b/consensus/common/src/test/resources/aere/registry-v3/n07-falcon-header.json
|
|
new file mode 100644
|
|
index 0000000000..3bb2585b28
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n07-falcon-header.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 0 falcon key with header 0x0a instead of 0x09",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-07",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x0a501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n08-pop.json b/consensus/common/src/test/resources/aere/registry-v3/n08-pop.json
|
|
new file mode 100644
|
|
index 0000000000..128c8d19e8
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n08-pop.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 1 carries row 0's falcon possession proof",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-08",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n09-id-derivation.json b/consensus/common/src/test/resources/aere/registry-v3/n09-id-derivation.json
|
|
new file mode 100644
|
|
index 0000000000..b1c2c8ddf6
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n09-id-derivation.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 1 id is not keccak(0x50||0x20||falcon)[12:]",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-09",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x86f21da7cc9a47f4030f45bc704fad2154b45bb9",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39f3424cc32c4c2bdb8e81d8e158b4b51a163f5c389e440e053666da13d90b2c55ce9034afb919a85ce9dbfea3f4ad217f67759764f5f6f59e6b8bee9bef8cd431f341653d4678ccacc60919ac21672f44c5bc161f6f9d9bd056f41be829666814d847c3f931db1b78a3c8ee17929542e9ccfbf40f5e78c1a29804d337a672adbc0ea63e0367acc6b2e702b295bc31c6a52547afce023b4177750fd5f929dc99076dc0ca2e9258c5c2bca3c3893ca9a00d963e3aecc3dbd9bdad2120a95a670068daa7504392cda930266cc41ac29a1d8805c0d0cfc75606f4f9b5587d6d1b97b626ec5bb7e8dd2f48f2706f64e76ea08845f45055a6a0b5eb5f7eadd19ac36ae12a12cf2ef58e2c8f43359845b51fdfc523ccebfad1b4ada4d14f4de5da0313cd309872608b44b190cdcd45f09f4ad5940d85d8083e3319c19bfe227d6d8df56152aaf11cbbed2330afc689f3a4dcaeb4a57f0537edd510cde7704d343dc54dc65db05316b95ca44aeeaf06ef5ca2abce8fed3095b35cff2b6afbf5e47e672671aa73ec92b9d37301d8488bb2ac71b28dd64eed637a56acf24c6f9d34bfe58d9645e18b0cc939a748f04a396746f3158601d95fbbfd7c8904932a0eef057843d44f6a01ec297b9dbd5712ca4ff83022270279ad1164a623876a75983c3ef7a7de6449dcaf697bd023d728ddab54fee05b5d4d8f3755a74a3507ba96c2e3617f78645a33a8a4c5f0869c9e212c09394e5c03d3bf631bcbe4394d4da8dddd7369df38b9ec83cedec3f03475914390361cb5522e9d1df381be267af77bb7e1b8ea9ac4679dd4c360153f96688c35a8d4fe12db57b2fd895c5327b98a1024898f50708501c58a4551c55db5d86db3ecc4ad28dde6ee8d0eaa0b7350a7dd4c4b2cb3252b5b3499a5b44b9a333c80",
|
|
+ "slh-dsa-sha2-128s" : "0xc7c85a7c49c8c259c3166dce0f1f2155457e792c84764ce212d277586195859b6144ea3b90735555fd7e96eda0a2b052e80e4f20968de14d33ab27bbd1d1b83ded17b9f69ca31ecb4a32e6449ced6433ffcb6b8bb933c59c09fca37a16fdad554067ae6315da891ae10e8e706f711a3a938c6c1a06d6d81e0fc5351e0b2f534821ff1161201697558e561743ee8c356b0ebd165573a162457de3acc60a2f3c299e59b04f0a28b944afe344ab8981486b4f84327980cc2634b990ac26fbfe2a2def151f21c9031797d2a683faa342035e35cbd6e63621ba78291d6cbc5d490eaec4b683c831a2a3b9e3b7f56f6700ce9e8f536177b9deec6dbaaea4709454cf791c7175149190fd61ee615e59b896272f7f03008a4ba435d3690806c9798827a5c02f4e9d6cce8de388465a98794b4180e7c4224fda72659aab19aacbce0e0c5cd0a4b86169b15939418adabffd03c9d269cbd16a1ae4350eada6edaebd686c70a8e50059529c19e1b7c4a3e9a1d8dc336c12a948b48525fc58e8aa831b775c9049ef47c9665468f67af5c6a877f7831b9367015059ee1f39f42494f6718cf5fb7f53e6c85e59a7a1c14c6b63bae82bd446d39681e556d7f4ca876b3a1115eb1c901f243b6dfd47f5ea7e956978aac47e6cc0e4aba4d26de8ad159274974f70765ab04b88837322f22f3f8ccb9fc8616fbe6dec1fea6aabd395a9c0efd22d43f57f920daf9b1e7d3cc7822c7d696be96ade2979caba15bef0da98531e0cb92924910c5ff57f918431d15cb8b84c3e862c940675f0992d447aee93188848e61215b8d70e787c0f2166c367592f305d5f625ce2f824927b9c626a365227095e1beffe2da3f00c651e821f9182e736f3e01fb05aa994705f19355c87ae7bf02e1905680960408899e7a05098c9fe82100dddd51602e6b1e341dccfc4c29190a798192972d7101ab6c86141f88ee3ff59481331072e4b0a0085000a7d93f3f46e3308a00a8bdce9dc9952a0cfabb98b564580d5ba1fb14f02592b17d5be74aba69b30871f8949764e01019c760f1ea2a979104243cef01e64f7f26ade55770c1226db30e6b7f0ca5e9d4bec189a2b88e20518b579c94b51c0e45749c7aa64feebba7acefdbe4e2c305736a6118f237b5f84fdb2adc315d3b6c33ccc5d56b4b25cac9953dd6d1f4ca03d97ae0f624565251b3b97e5073e988aadd4b1803bccea1a0f07423d00f805645c5b5c7227939d55ac9d9aaf1813877ef1ef420703d63521ca5e2561da45532a131790ae3130b96bcfb5419c8ed886823173c80ff92e7a3efaf6e80682b67f63108395c35d896423bd4d9195f3c186da8de257ff0927bcd1c33a95effe0dd33776af45bbc4be1611cb5868005e6927f0bd9fdd39682b9f3ffd062b5e4e5bbc9354e8e2d9b4db2afb198ec0c5450c43d5eb09c38c7896efe0e129c286445977e3be9496868ed3df248f9c77a3c0b455f37ab3972b28936526e611c7c8052e0ce28be6167b838684fa2a41682a4a15bda1084c8668dfa606287980af5457646682f04aa62a0d836d8417faf52ec1c4434aed5519491bb07d27042a056b782b7bd7d4ba8f4afd9e54f63188b49edaabe72fb7acbf767f83416d3ba90efa9995fcb1d7c89a01d1ca9e2b9d9bf77f809fc5fcb5ff916991e94040f242d2e1d35f3822c46c720d8a4b283409e55dc1ceff3d7dd3e64329e75b295ea492ca819332f0c21a07097b2d14200b2055bc923af6b4d6c6fd1d2b4337966c2fd781308b8beca6fb6f14a81fe689ac6b568f7f86b60b7a811a34b7dfa6d61a1e4caa2b7bbf2c19e0c41165309e38e3b55f3b09bf22d98fd5f91bd3f68b1c08fa83d003e962863b56cb24544db5d25989284c154221419b7de8bf02486b57c00fc51a1cd462275539c9850cc5e170351a9d63a27971d1830e4229d18dad2cab73dafd73950c8d41aa046bc355ef892da8aef82dcc85667453da46868e23f647dcff6299f349972ed8bfed7690c26b8277f8975664e2fd30bba65b90723e52315ee80bceeb6234f42497bb1936ae03dc7de1b1d62b0fba152fc742dee4ada7981698936ba45ed7619c6a1c90a9d7d2de176a54e2fed25ce0e4f204cd6f3a8d94ff34eeebe9af8a97d7e6baea00ab7006ce259e523cdeb32404ed38073b04e23e70e335f0c6ecfae71d80136d8d4b4ed3f213ad71514b0d4e79f4564b894eab00d5f401287d4d2be7763131847a7051d1c3f399ee1def1375f0b32475725343a37c279c4caf06978a53594110dd581f7820361ea9110458414682963092c241b10db7c89b364a71f4c576d9808f47f2eeacd124d081543ab4b9433dbafe8e90a8077c2024e47b1109bda4a61ded707e89cd60cff05e4aa7394cb4bd01f4abc8d7253682814bc3ffe3c3599a80ca2cfd80a0026e2c9341f9bbcb3de905f33a45bb4341ae88b462434516d640802b73272d25aaeb5bd03d6e72109a23369fbe99b2bce745ede6b0dd7b91705e9139ef77ac2bc0ae58518214383a0286b98219392178f79517ea14b986a05182ce744956107207ea9c5c2d793f83522ee9937bb2cf2e2839a06a6fc813ae065acd91dbc6aebdda4d144519e29293fe6c03def2e4fc6c8dd82eab21bb4e752576c6c3e9e10f9561383ab8fb056dddc870ba7e43067a8083b703ac3b7bdd9895c369c7d543dcc2b3d57e5bd1e25fea5581397eea7b5fc87dd73ae2279a13122f1cfffe93875a075fd71e5d2e600d310a898c79b901c21a2f887d76b9c863129f8550bc909e401eac2eadb17ced4f2e42585620a95a80c375dae577fe2271901b225c29da22145be6bc1d15159733d29504f21d4b61493902e5d3ad7e9868841e3d9097063caffd1aab5f6e8dfd95250a42878169e0371a3b9f9efde9e5215e02ffcc8609ed56c01c2d8a2b55a3283e9ce93b9b10930fd6080f40ccf098674cf2291fa1a58a00ee97ed553578a4129f906c1279fcac25ae1c149c7e7a2f0d445a31113584b481dfa6a915f3189dfaf10745a1f76d554830eeb8834ded30dde668809de0d570451f84ad457719c77b50fd6f8d60c03999e0b99cdeff0443527c5613bc89b066c97fdc2cd4a96c1fc84ca558f706fc0567b05d1b691a819870127c8fea456602610272c7d023df1476bfcc60cbc0d44f6e6d2e93c8c14d1bf1c71f1dd2bb3253b6f62a4ba9c84eb1a7d15a09a899a4d563b778511a67af7c2d5d90ebc2bf8a46d1ce14d05281591a8c5c866559535bf6467b1b7caf6d847ba520526083b1d56561650e3be0aaf44251190f0f0d0624a789754dedb7088c4b66dd7c144d873ae8c510e1673fd52c12d0c0253b38e395de07fa36d6ae61d23fc3035ca708ef3f3913061477856a22647b022dedf89896c117c1b85338783f72334951e8451aba87a4111cd7a6f04bcf8ecfb113d2e27e4eb50bb0232003673c7600c5a4242cef139fc14e0b532bc80a64c51b0e8767f6432236c0582abca2b2f1d443f2048684a1f8af6fe360a8dc0ed0760660bfeb4852fc807df06a58482de1affd3d517496020fab2f2b37fd445f5cddec391440d0b890c4453e42b5eeb87f9a5de41b64c5d38356884a8766d6ecdf800bb1636143e0985d01368081127681c06add07c2ce4f6e0633f35e23d49ffcf08f770312649710839b9e17118afe60aaeb1442ceae9f496669e8bd1e84885e39bc1ba934134bed0bef28902b69e851600945b7a96808b5039181e990154a17825570e2b273490c52e1817977a9f3b21700b10f74a80cb15e795377dc0b252ac9889480c7888cfdafc28b247c719fe579ea08cd93fec1d7debfdffe80ac4505ffa1a717468849c6f6bea9d6b835c37a17c768c9db73315a50a09e832bdb2c1de657e75e6dc6f5a7225d676dfa4119dff5c1d3d6a82ff1d345d1e90d43bf4f8afc0103da3c1984261b1922503d86379753e9e5d63ca9c6bf75ceba231276eac4823a1a87790fc242aba218c2fcfec4ccdbe1de393008ef6f44101c41aeebe372663c5687c280a2252adf1f9970587c03cf8130dd906a4551c24fb8957e12e511d38cf0a14e2cddba0887be829eac0755797bc18ce4e7f2150701bdaa3ebc97e201289bb7a0d103cc7adf54652dbf1fb2c3569e80c74c8a3748105fc272cb4c89dbd99c41cef171abb0209cbb1be8f9faac8452ee32d009abacc60b8b75d0acead3ead7385aec2a879983460b3f3cc59400eeaf9c60a41775bf759aceaf899a13f715845e7cec0227369073c94511a184e0c3db3e246981a1d24c7e62befa4df3cd0a0850c6a4e099bb3daa120e053a899e176bc092acfb1780cbe90a995b25b3b1fed31623d7e68378f676a07ee701fa19334fa83fce3fea5f1b3d3c3f5887e74fe6e48153670ae27ad84fa7ed88cc22f6b1ef393bb4cee3fa63c195a6ffe20d6c3f82ec03b81373c6b352c5bd3c66636f57c823c4aedb29d8024414c258c723f3b8e6657d8d08b812cca6af68fdb92bbab15733d1dd31fc58a2016a5c4fa03fb0653f910d6dd1a87cb28533b3508fa5db1e3612d1e2b319daf372e0b775a6a0328859a2d4e6d89ce5b3263c68009c3cedab1a79e61a66ced75495834b87c444268c86c309f61f41a2484394891a46a7e16fcd5622581b83569f281ccf599d5f045671e666a6036bf2b65cc793f3794fd829052303a64b0363177672228c359dac45163058c5d2742d2dd86771794777548754ee49f3d4651f292ea30ec7cf3e8c5b74db15923991015d2f18de70f79a73169c6a4fc5819e9fdca7b3d7a4720d0d1de141c91d6e946c25556cf4d272b9c2ca25ef7d4f028ac2cc1bdc4fa1d579f87ce31d514c2ae5b3072c483d274d984eda9f6450a4f4bc47b05fa75d9f6a3152027315aeca879d2f6a27a342cc9a2a2109fa73fbea16aea9c25294c9276d84fed450cfed38f34a3daf82d11c22e9554140f32cc16e3fe737fb403c3b9e44f6f3ad417e6c3cceb76e104f184382955a5e87860c455458df5d8f8aa44af9571dc47fb337c83db67a6eed4a9a41b912a6d99ef15ef9672ebd91bb62037e46cf91f68fade2eeeb5fcfdf4b86f6d816df1489bad34bbdf99ddcf7f18d1062e05d8f14cf41f7aaabe22768a123703a96d561e01a693df984a7c719d603a32d8f45de4441e04e208ccb15adc9813ded7e9197a9adc6da6f16147da196aeaf9404a8e6c8395a2705da81c9f3e75aa9b0798e35250299c250e4e4540b4e3ffa1191292eb44160779bfdf10feaaabd081fe975486c458e5abf97aa45e26cce18fc749aa200460a54cc2293647aadaabe70fb01c7b3670700a419025949ef9f7677594b85d0837977640156acf48678afa477a242145a1c8fcea198d1b6a0f296568dff2b8dbb8b79d5151c68f9b7a9b8c5f9ba9275dad04de3dd7563c71ee0d62e3c068745ffa79b42085862c30eafeb806408786e491ed2dc80afe93879d50117063aa16024ff79aa6cb15d19d5affe5b0c5d19d53c48e1185f50e1c49c34d872895ada2bc63e71be3f578384171a4faefc33062e1c5b8afbebef3931f33864e6a6f180e2fbf24cf70bf1f9114ab6c3e360a9766243ae7e24a5a1e9ea130745a4f17007c16ed3d0b2a3aad226a0312c968c0ee2aef7203af3cb5f8388e1c723b8d3f1118672daf87d1e8652c8b2aa59fbdd56cc98200f3eac2ab2d95961e1cbc3b7a7d1f89786d73be0823aa7df818482def88c7cc1041d53f11cd4c6223c7988aed51002f20eacd2e9655fce66a5daa5349500c9d083680a4f282c337bbcd957d47e2f7451c41018d156720f135ddc641c8569dc8a9cf77528e1c9a74bd2796cdadd67b42901ac0951377e5b2210d2f48b2d4322fe200d4834713b17ea5e38bd6f518b401c53a6d0d60d3691dc895843a7419c6960301e49c6b263f9b31c797ba2294a3a7b3968a13bf0bdb085b357244ffaa8c20da84be65b9d1a3ad287662d8b99a14899fcc21f423f739440bb0bfd51e3ac3196a69a3b145eaaa0e5d1a205e6168a5bfa92181e7e7bc8b6fcafb1edc5837f619736bbb8d74976b07161a0206dbc0a28baf0dfd259485c3a02bb5c0e5191514fdd8bf09d1006940bdde987454af348b9b9e5ac70a981f9f560c5e213073c6fefb674d482b037657d79cc284f33fa37f7e3e854da6f4f2acceb8b946e7af85770d8cf797c88d8c710ba552139749a256b5d34d4d2d7dfde90c4db2ea791b6a02b9882a18da502ebb22f2ca33de1bbab158cff5604586915f018d852338ecf4fc6037cb9a54f237cefcec458fee8e35693d7d369bfd6c8b6a328af535d7e174173fb9c0205b56cfb97330b19a9ef51dcdd5bdc1d7f4d3525334ac963c9af3253354bfef26e5e1a76244bb8bec800eeecec7698eb024591c84aa1c0fa83b1936773998e37c241171511bf9f4a419be8e65c3f619d25e04384de8f7977ab98feb8ca915f724fab36ff48e36cde7df3a27528584e6f89de3ecc28f19290113781d41d1d18f6970a1ff5b24490daccf30012accf94de3620c2e90b3bc107fc13196e002b4c7beeb0ef0349af18aeac3a40ddd7c6c83d0729f7ab8109d18f2d999fa0a6e34268c96515046c9d2cb7732ad95282837f826ad3c2ac8e3ea1e4dd7391fcc76baf9c3ee7402448d5921f9654cd000466c302827a274c041a58eae83b0c89f1b05b0e72710b4cfbe78c20c35f87096d54cd53dd16057a48bcdaa0c3d29d4bfd8c1d275563862ad46fdfb9482c16b42a084b4e566539e31a3d71265e2aad2875f526b6422e69d4770bb594006069814a12c7a91f4ce4eb96bf607f8034c1dcddfe63e7c3d24c35f4aea46e1d9fbeacd471a21837efe0d72f9463f95eae3720316b3c1fe4de540b1b50b3a462e5bf9a2a948fcd93a5cc343c22d535d46a28aa78eaa5a9899acac5165e0ffe5ca431f535e1445dcf55cc9836323a324d7e9d9131564753f1a1717fabc4f37631b99a48b409e7d55b09793c145431cc0d22267cef81cee5bb984ebc771cdcd7fa87514734854ef98997f9e8e4fdc6799f399e8c5e2300f70998166217e8a5e3e981f726d373a317821c82509f4fc043d967edc5cf236b156f7ce452abfaf08702e2020f747f23d0cea8abfad05a6745bd6c96f93f073cf10bd23f15fd35c60c65972efa01e2d506e32276813523045fe404567905e25f4d185069402d43efe34d52d3027bd03ac9be5e0e253dc0bede7f6a3cb758b1d0e272078ea6d74d255f69ac64a92e8a10ab63b56aeffc12d77e8f482fa2befff52b78e2f2d2b2d7647eecac8daf8adbbcbae213141723c0b82506568c8ace99a6d1881dad8cfcc1ba5d802f739dcab913d563fc27e3980ec2f73ab67516ad50fcaf25fd273fcc860742cfd6df7c382af54a49b88a93919a1764d0d5784bf14d9f4e70556d2681d66f3a20d4374aeae1e3a8f39b430ee096e6da798714cc7aad2635b387f9ec61808d45f14fe5d386bd34836e40cdf7ff34200e4564043274076ad36e31acf26d3f44b3456ac7d57339dce14323c00bf8974c73f7b509c62b3abb8aa331d0a673995aad271194e5a9fb0f142226a6d4effb0e7f6563541c7a3bcc95267c255fa118c24b2b054e5bcfdb95fa8ab86bfe9d3317d405ab3cd37b79b2256f9c4b94807a0e141007a001936b510a5372bd5bca125e924bbfad8e3336f10253196ac8b4a7e7fdd6cc3e483cd862e0c6c6d594aed8462ac51b83de7dd5a4e840423be98df6b1a114accb3fd74dbf904ed900e0fd216704e6ed754c0d720a220f32c3422c341cf5eae6589645c65be7704db6c7a43c558506129155637c41f2007e1c2c41e3c132131364e863b9824861c81306f6d20fca430c1029d57c00826b66aa7eac954bfe189733220c00af05fed6093cee3e907b9cd2c2af7ddb3aaa818b6b168a16ce4bfcea932749f061c222fe6eb611e7efc04e9eac547ab14e6dfaad3f7c06ef3aedee6022434566e1921206a45b5dd0650dc91ce611203ccf8dd681ad9eb6907a7a19e52c61b4b2808e64e4ed89933d3dde4d7231730d8b840ab49b3f66977f2d1002a753b42db089e56b2823359becd78b1034a25d99198fc3902acf7393ceb0003327f6c18bd034c18cb6e63a1dfcf34ac2fe2d10af83c7330bf1d9398e0ddd692a7825f9c5a4de0805039d8b4176d16c7ce11a067595b86f019efa07d13ec489981b3f486f692ad112ad80779e0e8b341817e4631fb24f7696800a8e9c42eba1a40bccc8cf48d6d8a2d4f059d2a63bacb2f338232c90e5eb52fd4f8b303ca88b7aadc04174d76f6441d603cf44d3edc643c1d38c998b58902c01cdf97ddc86f029ace8adf0404c3dd922d64eba76248b894513952c9590421083b10f9b98a1ea57992b547b41360caeee4deee0fddf0d86ad6d6259000b22c92826444b9537f62b93234133b82800ca517a91dbc6e16473e798fdbfe780495225ee2930a59dc942a8e35da7c3ad410bf053619463d247349cc2037e8fa579c2f93bf857253d4da9e2f4023ca2b14ba9f0aad93d1a7609bda79d9877ac81493b68a571276873976563d1251b0c22c684ae9223dbcecedc3d94de456121428a82912364433951c8eeafbc4574f5a00b81428194cda9707e3744ff79699809037b460dc604d2153e06170764cd5be276c535a6b8942feab4dcebf49f41d533e58b59e1de21f0e528c6f868fd3a220b36e24cbdf1af8a89608da5de874ea3b57d14424712edd570325844a1624a1853ee4ad74aff09ab375d4ae7b8e431c1d5d63d3e7ee51c4d22e73652eea838329fb4bebe3ad92ce7152bc3a7660432483502ff6e392ca0d4772292a988aa002946e4e3a061c9a121ffa27e8032d60f58cdf4e79dace6bd36c10a09b4a298d3b8a76bc414bbf56e88b171a1774e04cfcd6a866ed8cb1ac4a263b66458f530de14171e9cbf85105b892bf7b450938483082d8989aa3582a3909bca5c03639d6045d072087ec38b0bc7b9fa024be7144383d669e2e35915d0fdc01d581346bb0e5d8b47760738f772e08df0bee8b5c8b575c2b4b0b3de1d1f5fd260b54c0959d2fc5c7241444ffe0bdea0fe520d60a7e54b51686f40cf6773e3e4287bb88fc5f0f869632764196c5ffe3b5a3c66cb15d44d945b992a4bb84f617bc6ac90ad040765a59ec312bd0b95ab823a5874c4ba4f9865c883a9cc493d7b4e5e09992dcb998be63007eb1d675cd294da94a8a1504e6668b45dbfd3aef4fb08e9c737f7bc1434afd489f490313ac9c719dbfce1e88d8ab5c99ee542c9ae97ce13023bd041875503cd7c9e6d8784f64bdbdef2da7d682617fef77416ffef3eda866c38c8e91570398ee3168b7f834d2c960f54aaf2f80f6021b7eaf8182303b4ed9bd4eaf5049750e29203a45b7518878e3e0a9d2674b53881a722a246317c4fb472231af1dfa2a945574c60c507db33f6edc54a19219e5d5f60dc2c6fd81726b6735542afaa228988f5bb4a22ecac6279212eb4790f551451b1bc68a43a7f29a08766946bafa5b678782e027ed4d2255f4c93d753fddfea84b1e41f5c444dae8dfd3664a8d708a20ef2b549aeebb4423b80ba61ef617ce10ab702d4799f3c40fd37490f5677ee8784f6dc1dba9e731ec6e4768db926748f962be373e4ceca3f399148ef249b28699e9f4f584d4b66ce4e64ff6f50938a80a2cff992321577b2fa29455cbcbf97bf4effc227c79b023a0b836da9be9425b68d258c800b44e3acd4c8de445f1fadb1f5c7f005c44e6466199f2d67ddd0c660dbe014d8562fe6892dec8d2ca3d16413845c424a015fb3d3f47abb236db04c429fc988c2c220bffe2e442fe50c7be1114dec77b7a7d172346aa9982c93a33d321668027fe11f9dfb5deba429920966f92619d443f722066ace9e3304f9b8340b069e8de27363bd12202836ad9ef1dd99d94918e92a75dbeedd4b7a6c307e6a9c0489788976f330806a7fad424076d2b3c79e3319a2001871a204abda1210af00d3380c863063d576377a562bcaf0978929b3e0c805aa4fdc51365f5ca95ef1a0cef3229c642b6b9501b5765159ef34efbaeedbdfa7a3a9f075b411c8ebc0b82de72515ad02b39a30c23aa68be4530137ba8bff7e341c788092887cc9c1def3a9ef754ff324501c5cd3cbfdd635dca123bcac7093a767e25caab6cee7bf10fefce0a2084e2e040f8aa489698282c906bbde1869e7d605dd5d9bf8691863d007a6c97adcc727179b5ac7c4c23ffb9b3b70e6108cf95c51f2d37e8f65360b40216bbd05467d7edeb9f63a9fc45daeef5f2fbed0a0a7b0dd8b84d8a3d07041b576e20cdd3780fddbc1a3ef9cc8ab5f5c50227e8dd2303a9dd1d24b7b7d96de315100a7762c48f5aab88ee853eab14d6444be1605b91c5a4c50c3a4d6e921a7a51acf631194d60c5a73249a899880f57874d3986468c64e894c73c13df92047a48bc5720cc6be4fb06738679a82a4b6e5d41cdc5dbc3661073281076d73c0b86177b6a0a61160e92dd68efc9900ca45e59c9139a62c08a603aa7cf431caa68ab3acf69efd51619684ec79d07727cef9ecb8e1a093dc2d7e110234f413ff77cae5260135de14d5609c86339dc58e0f1b26043650dea0bd6c7f1501a3e1f224c940eefba7bc42ab4e8ff8c35e6889d141826eabd2d3d6b86e8ac54d462c26a2b04543a63448939a632978940b1c025892d844b0734499e55079fab745a152dc2afc87c7dd175c12c113c0596d7889458101326e1666e63e79b2c0bcd0b5fee7285bdda22d6afe424fc344773ceb5339d046ae2b0dab8116286bd8475af7f22c02099b839c48b8b138dea653f3c57bc0ad6684bcd75163eeb9796ccf3f4fd9414b3cd778b8640a4d4d459350e6908708466cca5bacad3f3c06cb6be8528e27d0a9652019cc1cb947a1e486cb612e320e4d309d60aa6eb6e6521cf8ba9ea67333c8803b9c6561d87e1cbb377b2a0d97bf6469957c3e4d06e64b2420050ecd1856a86a99fc3a34cf106d5963d65207a2d35e2bee30edf947994407ec912d8d80bf8397a9660ac69ea906e6cd4d0a82cd099bcdea5c22cb94ccd2b1173cbc59ea0fbc8719a60314ecd535326f0dc45253d370c5a1e7dce7a2d1457dbf59eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xf4c9b39d82d4240ebea3a6fc6d3eb294fcef05bcfd4a817656372bb43494b58c39911c689115a8c27dcd3cc6628c885779213612cfba7e4e57b7f5dff61d117001"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n10-duplicate-id.json b/consensus/common/src/test/resources/aere/registry-v3/n10-duplicate-id.json
|
|
new file mode 100644
|
|
index 0000000000..91961390e5
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n10-duplicate-id.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 2 carries row 1's id",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-10",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf9c9de83a646dc7f78f23792e596dd3ada0989a9b24524300fe109992fd619014ed6842cc68ec0ccb505132b51c98f72a718aaba11c1ee761c787e3cc4d96bcb4cd4dbf865773b2c71f75d0ae3384b1cfc259c9d36b50765c9ca23adfc5e91c8208d833193279876f96f4610d8d462a6595a82daaa451f396c996bc5366bce0cd446300f238f1f30c639b4d1162de28c58e8a7214cc52d394f8302678b1fde127beb8733c340db994b12ba951bb637635fda6fb3ea8c62b78f4591fc328721dfcd2397e2699afcb37472d396ff48799ceb9faf3bd4af4616eb75c9fdfd888658f04bd1343eb767c740ecc541f1b95469a6c7499684dbaa3c0ce74afa5f316f56d0628cef994f474e6712c51ed108cb00845f9c5e4e1f4d1ef151babab5877a8cbbbbb8ebc8a0c3966bca7ebb3f59255f7b0765f31d0c1fdce9e617e5eadeb94ca65aab2b8789dfe757cccc7b3bcb5010a64b33dd3d7462e7467951f84305e1ca379076439bc897b77944e1b83d1cfee4a3438aed40ac744a1c0bfb39230a8312e7dcfcd40c0aef08ad6b7096fdc288abfaf5e97a308396e919cda9471843187025be38ce75241e9bb9e68cb3f0123ea83d2650a771b7f95b8eee9abba4910a1a5d0ab5c7d0b33105fa6a7306ff62642bac6a35b5f4611739ede89d9728d3acb3c278f37e0a3783c4c7db9a3b73ce468ed62d8794476f6d1ece9c9817d93d491e135b534ce4a84ea3d53040f77883ab055d9ce645ad2c455355a755ad0a1a5d24fb4fd348d1188d909211248b75a65b8cd44cde264f18c3a437ec8358d14b4b5d18a14096b41d16b0c296b37539981cc655bde421de16e7935c3d1966f153608f2b85ae8ba599558f48f366d0a537562017a411bdb83cce350120174480e1fdf1d3dcca8562c21cb932d5c58b1b3dfc0",
|
|
+ "slh-dsa-sha2-128s" : "0xc9de54d901b6fa6bd74f85ba38a2858f64f2826854beff593d80632adc63afecc9e035ba1eca4fe543400ba56b8d83986910002cf9bf630b2bfd3c67a47210d9bcb1276c5888813a81a016f54c8bc2bcba88f7ae12c7506053273e289837cf9f3299de2d9b9ca7a73d6314a297a6dbde9cb7f38b9c0b67cc824bb4ed03c62087188c6b0116d62be4a49b2087a8150b882512565a1c45ef316c27adbfced543002ac88a304a9cecbfd1acfb9d1a46037cbd4cff2832deb574aa2295109fbb79e8e95f53ec31524e9de3e29117403453b82638acc1bc54f781ad9de9e8fc50b398cc11f4ba59ee8c8d7395961f3f75e4867fdc9abf4e3b53b799befa69ac1473a2b178f709906240ff4c0bd4b65c3ac488106c4eb880e1af47dc92d20cd2aebddb78c8151b8a685db9743295bedbad090cc443de04d58894d1dfe1d7d8e08e8d1df1b4847ea7be835993804c0c60754e42486b8566e1b3b3e47bfa262e752197fc95e611f4015b1b94369608982d5ca8cb9faaaf6ac001e48f02cf5f18118e999de2ffd557cc7ca02aaea2a96f6b0fc5229bb497f6842b7a007a8c3572c77e1b5a87a9585bc34b41678832381e051bab823d8a37f1e1dc09fba0c8815c1c9d3fc360c6d70fb19a7675e7b97e9e5046a7bf7e23e463e0ff38eaf10e9dc466145413df96010e96b058499c27686c4d4918743229d3214c3636b351ca421d9fc4505d139e0f60c7226f01d59cc7e0db46fa80dd1267dadc064bbe960f91a8d06007db6f32f33fab0626020a979fdfc9cd72f317108dc29ce26e8e8681ba1a75131a045ee58fef714671d03dc99f53903835e5020497087aa41f2c3076f2077a442d9a9d4b18bf8c1eb0229637fe03f13519127ef8b5013cb8a38d8ecec5c87357737bf857aad26c69d8d6e20cd5883d7df0cd674a63f7d98720f80ab8f0ddf99b6cc8bb279578cdb4ffaf3c5536ebf29ed45f932cea5100404789368965a47350ea672eb34e59744279fd94a233d72c98c731ef729c0ab7e3b9dce92ba9ab5cdccbb9f194e7a05652aa4fc239406ba6692cee5b1dba9674626d376bdd72e89f52019026333a46b7b437088f9c5c372f2efc8f4417e07678e87bb1970e9eba6d5518bd186e03b5d9ca2643d1214708e180169580ab2a59469fc170826c13e329d2d8bacf3b892405a2db21664557ff6161f2ca2439b0d10e1bfbbae0fdd01e567a78b6e016fb19575a5e26d5568ee3657bd49172c23bcda3e0fc94c458d622fe314e1cbaa8b20cc63cc7da1409a624c581ee0d665f199f24b52c3ea31abb954d86c7aacd79d1709cd90105352ec18f435e9066e722f116a912aa92b9f6a91dd1e092a08d5e9d3cbaf77555005815850182f595bed56f645f4da24f7f654e5393d765e2723632f5e05b48bf2bcb82a88ebe21c2078a72b3ea97fcf01f80b017c7b05dd788f0504b157802e9ea7061b8a81b5df14e72428fa13a19b7dfa3ba8fadc6ddd19821a380fb2bb41f5ba61bc6782c4fce6d683f82b56a55048e418bce0356003ce8be9e827e3367ba56bf17f7a3531d07635d7dd2c2ac0515fdb99b371f9e7b93bf28af94f9fa752936f8c302fe9c5a0753c25617184450ba98634b7b3040307fe7af9d30e138803f2d50f9a4db048ef049f488473e598e6707db264048f931775947e481e9c2b012fe5aa05889acbec05e98783d39b65e39373b0dc59a24f6517ee4a17989e053659896b914c3f7af77633fda0f2a06eafc72eca0f7c5d5b8163cf65cd91761584267b6fd666689d7f6a141b52aa58fc31f64fb5c04c65453ba6262dcbb1d8afcf8432b21beb1d5e10753710c9bfbee37eb3dc0a566d83a2fd5d94906bf9d811e51dc3583f3379ddab34347586eed0c64195bf97450a22bd0740954251cdd3a9c63375215652343b2f2a5bf05b022b1ee722b9c9e3d60cb54ec7d3ca81639ff611fe2c2a754e75cc1f445f66a0098d642cb36e1b199863050b334b751bddc152da95e1b32aa49da80fe90841bf9dd02be330dc0bd033f864d227d5db104374d1c551d57de3da82bad013be5e779b42028c1173c52f7cc31a310853a7ce782ba1f3444107a728fe7263580757d2b86f2adb8a648e2ed1902ec15ce0644abe6a1c8f9211d2a97d22899f7da63b4f5b960a30bafb814a928e814f996dc8d63327c79ed8cc57e4e9332ae200a0249d78ef4333ce97c524ed07d357a2142e8fd3d29884acbaede1aca34891414d066d15b254a087998acffd99698f51b5860961fabfbede5ea33d73182140f38de7ccac5911ff7c5e72d6a83268330aa62487ae26ad1a0f9e9b63036c44489742c9b52cf99a6aeb32927a96e4b80468807efefe2399883c8438d76cb727077662b3116883c784f6c479b2d3c2a77ba19301654426ca1c6a6bcd4ed2df1ae383e89dcf16c06c26fee5c15df697c963610720e76c92ed7644814f087ad4c9384a486060fb8918c14a5f3af270e649c4fb6671712ab85534066070757fea8856297af0b4686291ea6592d3c13624cb81e1f870823ad232fec874cdaa0b63c49ec7e8d25ad1c2d6cb2b1d227ac689091b852383818419bd24c3635625e0523b335b87e0e56a08b1e7486983b1b5e473e5a019493dc07a4e0c73ced0b8dd56bd6f7124216b0c8fb1e74d3dd9be21833723242e3578446bd949717e1360144785320ce79acd274a5074ab695c45d9eb49b889b841ea1605b300a1adda0f18770291cf3780a38b50073c393bfa9e721ffba89dd0a3e84c795799f2d2ba2f70041a13e34dd1de43e550f7ba92496eabce75c91e023450aa37dca806ca9a30cd899fb332d0cf3b479e21bc47572a51b5acf7e181667237c25bd4239c2479a59b47c9c32046889b35394433c30cb96c78226b53ea89a8f07754320ad2237129b4a60164dbe0c21ae7cf53b1dd26231ffed917139a6f8783b3eebbb542b938d7969f007458655d2224cc761f61d41ba0a2ee356847c886ead864802027d58c82ff58cc56395bb1e3c623deaf76e6dc322e9109f91b1ebf35e196da1400cfeaeab77b1c6ef8f8330b4969628b1ebd23f1f8f39e557925367d6102ad8f34e908f782a4e6ddc9e14f540f4ade4d630296e412237e77baf745ec093547de84d0604afd7841c5ffea36be213f3bd08d5ebcee65d1108e3d4907ab0aa491f01e155d1e9419ed5549c17ad24032b79091f4bee3392b2ac3aef0f6090b9234e8edc2883f7b872fe74a422a8bdb790b375abe105b07041a05d96a37f3131c5b907b49fd80bca05159d0922a0b8a1518ca549777b7b8f11ef677fe7fe0995cc83690a4370bde93ddca9a6243acec7d5974d2b47f6712fa3dfde07523ad59a6c945d354b9105a363cb4b3f2d380ef5c66f7b67ae50b4d9a524c4694ab33bd2e93fdd0e423b81e955a0aa52bcb0471f2ff7aa8969c44092839ffab230977cb29b81f44d7c56ea5e2841709898da2b0b6a58e40052480ed40beb2c360f1ff3cc10cecbab23777085ae9c2f416fe8f7474a183d9e01e1eb706220b058688ecc650d9e5c69364eb6a755a9bcca5d9177cc48ea5ee39840ec5489252c5713b730234b59a9bcfebd86b7e9212593ea6a7dff5d99e5f26c486567d2f272c1d97c1e69e5847fa0deaab1c8781f48431ef9767c955ce4fbf2829d562be985951d3257511798b74bdb2f5284087c0195ce3b85f6125b16a0001e8c0b10481ee63be97c15f50b0a97b418bd743afd499a6f1107c2d4af18aa7539c33ac19b6794058825d08666e7ad937d4e10b94fbb012749ddbb3819e98c4a9a9cab016103aa0550a17f7eee535207447f228b5dbcfcbf3752de79bc92a3e9ef2b269dfeba7b1265dd29a3e7096eec1b284426f83c9fdfe630d9da9093bcbcf45180d7ce97fafcf1fb53ff559f53d445e96294c91ec0cbdf8c0d34df645bb1a737356fa8138f03748fefbbae40d25eb39a938870f0ab65e46fceed858e78b2d297da91ee56a7046c3bdfd65116a6afc28c0ed4e26b73ef75ea1383698f9a6de23def22d6e38adbdcc7dbb65f7d4aa92edfa61c5e29806898f3de6d756354d5e5d2dae0e6839eacc7eb8684b7b67ddd2ae084235740bcd8c645ae324065e482ed8fb9e857fca3beb4a82f34b89ac6be1029e034a64787a04eab41d001e5a4916a9b7d994250c1e5f32eab646dac9ca463c2d8b9f0b755dd50b5a077db8f4875000461c677f44289eaee145d52cb591cb139f761c64246ed90a306f7667f7587dadcb5c6274e47eb9acfb12f893dd3852763f30f801daf184a506cb5fa070138643db566bcd962f22d1d32c383a8204675040b887cebe61933526e673115ccfe4e636170569787c119c53a6fd2b0924283958a1450ab2113a69cdd8f99e83a1fd0cb96595cfed5ad3dad843d8538cab3c977314a3f230e358625c63801765196979eae49341d02cca3b8aa5185d73faea75623804edb27722211413d6059ff78fe12c448678ac636dae9ad2565317f5eb83575483f17b5e86f2f32be1306821ceeab3eab2ab7908db00785d506ca5c64a7add4c738ff8f6051873c05351f6eec9fd303d1986fa1a0149b524c9cfd5e834806c66b3f0ca81124e9a6970b83a64af256bd9c574a5eefb4bb66ff9b967b7ebe5d10a106f8d9135b12ee040a99ff20d61f9fb62eb0ddf676a15d29a179ee1c7f83cdc26fd0645d49dfae18422321b0070260dc5e66f8ca76dbe4ce4943a15963c2e565dbaaa1adf4477a7163c8bba558ed1a372e47f84164ee2d3110ad80dd3e608131fa11e920e701c29863980205865344827b61d63c342daad9bb52d1aab4c53b732c0cb1359ad7f1b0a60c3cefa7ddc0f420a5c59f124d1c6c4bdb8ce2cb3e591cdc16166c497782c9c4261aece4f2cf638741c34e913e08f701622c112e9942a11900a7e6373a50cdd3dcd283a4f994f4e8ac7e7ab6fcf414d87d8664bd4b1fc8051596fe09572488f0485a6e63904a46213a82caf4a57f03af2f29cd50c72b2f203daaaa641e03f45ea92182faea719acc5219e6868ba59fda61d32b644600aa18c2677813813f1fbc6b4d5526b516b8cd3b798fb5aee5cdce41dd421ecdd6f3a13c9f8ec69ca0779faefe0afaeb37e6e0cd9127fb3a3600b5db3d2737b44d7c3fac76a1549a7d55df1b4bef3fdf64fe9a094edd84706bc20b630c7680961f500679da9f279a9e20b71c1a200ef06b7ed79177f48e830fd58e3300916c946f61b1845233224cf65d49806d73d4b30297826ec2174f63d8625b4023c9d0c13a924172bb0ea55299b9156c2c517a5e91f089df07747377f490f7b2d1cbbadee76a8e97ba1af0cae68ffb9f140f05c1115fc8928457d0f9ccf186d8c6d07ec6c6a7c7d95460fa24c80e073fc50199cb9ac66d1bd2fa5378dd37160da7657815d81338b718bb88d3881e6ac34eec9794d345e401022d9aa62f76052b79cce25a13cdaf1c8dde90b6b28bb4eefd06de47b606f22eac990484f6be859b3a79db4b70b8837c8b46f48b14a795e073c908a1ecb60558a2eed052095611d5f601806992faf4893f0e9e155a4a396df455610842b1eb3a773d1401288b76bf8b3a0bb1767b858e7cf33a6f59950af0a7eef6ad03525611eaca985889a575cc96038233553bb3421ad82f0dc9050afd08d39701fdb708c71147f4f5e9f4e85966f98666d63d81481e63a27e105d8b81d852734cb2c46250b5d90f008a6af80dbaa0e12494525710a9ba32c245de59d79417fffd9d4475aa5f6580a5c3095021e391fecb3395d1b4d37d4aa0ebbbafb03646a220486e7dcd1ea471979592e992aa45fd4b361aa7fbb263c9e49235baf23daef532be753f9bb231cbf3ca3d31d5b55f0ef3bb9ae616ebf3e760b1d04b5e066552d12bf60dd970809e38b8617826138dacbf1375ef828fa6e01eee2eb1dc6a5979e5f9a8e795af0102cbedb7c51c9c550a8128f3d780c6dbfb1740a556e3fbfcc2a8f0c510bde87f6ed03540fe7cadd5bd256af56065f764ee22c0980561afc392dfb6b0c7d520b4d4aa0666567ddab5d5aa0cb039cbe65343ec1e776bb8e0e69999886eb19ead813f69ca515a758474a31494e1e611c0cad2d91abb68c69914232ecaac0cad8fb0af8b4c18e460bba6139198bab41b405afbaafbfd95e4ccbe69ad6fc4b05b68423d4e49f7d313d9fe593dd472cba497a07a86b77d057c9ef26d101dee907588b6b443e0bd65918cc1db642b082848b7757245ac19466c6dcaff1235baf1ace182235394ea01c516f776cc1c80a6c4a1305b31aa52fc7179e97dad1c0d79f81dd7905ebf305b296393aecfc67f6f9d28a7dce5f74d53b0a9acce05320f53c7788437ce863ba196f3881a0bb19edb4355e772a5539d9b23b2a631ee31d55c5a28d3410dbe7e340dd0b6b6c171be399f5a6930f1dbef0e850204b2faa99516cf19899c93d1ef1e2fafc20c5f74642ce6b1035db9597507f43f754fbf32f3e598115b451377bddec28fc19f8410e48413fa9b6d227f323bb2a71fb7e984bb8cdcabbed3151b2cf19e8997fee8fa20f80e5eb5edc71cfa38b0093f957cebaa569be1a1d29b4ac9c4cb5d8e4a2cf36909ba9a1ac5cbdf41c2595a86d9b33524eb25b1f93e0d4a787f68923917e2c9942f776d3163cf791618eae20df41e3af5f9704d2d586b6f6e4347f032ac981726c95ba72c60a38570885e97198d3f9a3cf8637032de5f35f851a0a3c775452f3265a8b0f567a9925dfc0854b2ade20e0b28f7b878bec3c4c170df454dcdc641f32638ea7766d6d1bce6ab4a99ec169d69673f79449bba8a00e6842bc25be10ebbdffc0d74a0f5bcc8e7ffdd743f3232db2eb10e75417bf8ecc672f5e1b158171993540e2b1f7505c81a4978463d45af571e013b4619181028d63b51f73a9e325ebc79398c865b876202185a3860ab98fbe00cd4e385cb4ea5b262f43b2d6524ba0c8cdc24b7fd9a377a8e798281a4e2eff177a871f0aa41159066c89fdcd0bbb89eb42635f6e360148b25e590422a623e0f6a042629effadf969bbe82398bce9fa1297e26976aa39ed5f3c157985656bdad1149054c1a01f385cb6f3cabc2c534730d9174e53ef9157059ff5156b2a01ac71f01ce8869b0e192c3897935dd59356c95751e4119205558db2f040694a57a9a67aa7dbfe9f62d4cd1aa43ede69222884bb88cd74d91c09eee6f6fb96e1ac0b31f7dc29b58a6487c996a2dc1f6af396ab1c60e8c287cbb03a273889661a0f80aaf7d67e2d2ce5e29e64e2ec60c605803bf28e394d4a611af48d5ae920589d3958285f4287c0f56209de0e46a99bc2b184fecc292a0da8351790f8c029ca2eaec8f195efe1a4b2534b98674116e1fce19e625785b857393a92543e4f276024d9c4053f12985ebb40f2d6d7ab22b128f34e4a7e8f26ec138bf62d75aefbb5d1efa4d36578ef3c7d2af3f9990bc8c0a368ad184d6ba36be7a8dba125491e610ed0aa5ef19809afeec4ddaeaea2853a927081f92e58797d581e8e6f6fe73da8d50c13d37b5241000a92e3224c75f228007f3acb2c38ee8d633e1a587379f497e7b93fec2cbc7286827ad0c98ed961ad526407d97c5ffb17d108d345cb6b0d45abf90fca99610c7ff291dd9347bdb94e56555a9610afc3ad27042113ccd9f1561d9fb8441685fd9be44fbb0f2323ed1adf7285c8e65667aa4f8ebf6bd8599f13efa5a3ab2a9ca97e6963cec0c10023674d623f8d25507a47b24f9a0c491087f84613cdae0a1ce438d832a3464d96d1e75fe473359369a1f46871fe097f46a0047a290ff3a4f8200dc7c1e5ced78e3fad8b7470a1f8768d631450ca9ac8b379b65a141143a9e10daf38a246e21b290895a4d903c2e47f039c1d6070128860d3b531c8e46ab617ae34ecb3429169c72e3f134e26ce56e7d4e1669535f25f521b1a5e3a179e9d8a16688b101e91021aa80f9988026c3e92ada1f2411f2965b00616df0fb9fad76c7dd40f36e0778b6ae3046bf61298da63f6039df8aaad0e86e830e83bd85462590f77c7f9f5ad87ca72da678c36d175d23e7df017681549e103628dd0fb47d507a1e0df822006b6278f5c2787c18427919be5a0abf49a98faf159b07eca7dd08be113b053b811b8da734538205d792e7b21904ef90162da6484cabda74302a1aab4db7bbd23bff51810702b2642b3d964f50f234a657608c2464121d4a33000eca4b30ac9357e81310817e1a2de8485487c2a7342259aa3b4260001180df6b0290a8739c0a9d296c3db5cbae8b8e1f3138a4f1fe3e67eceaae13f88da7e86f471740adecefb267089392b2e798614edfa66fdfbe45236cf6189d2b5538df56e635144054cf4f4d9347cc02ab214305be94f1632c02d0110ee5292d6e5755b9a837ead7ad1db8dc71ae91bfad768e7f34ef53bf6b90b7713a3d1f0d4cc0b6df3db1936ab7306d6020eafeed31d7627476d94bd6765a1110969852bdc630c490ddc03879ea1416dce21a2f364f2551fe2383d121e54c568f8bd480ab2fcbe9df0b8790daec4e146f6daf939f5860c8f3c77ef7c4530381de716adc36a7ac284d8dd7ba86241b910e838869c59f5c72431181fb37f8dbdb1d5aee402697823bdd6992449f437bded25af21eecee30bceb02f807cf77afbee810f95a6be473aef683ab1a2ab7ecea32834a44009fa8ae3efa66d5553dd8fb97900468020fddd2d519d66da1f453ac1a6e8c29c34ce9aaf8bbd5a2c59f8e7dfd057a258bf5eda4aa364396145d7e21a63138a01fce8fd7eb259deea64ee92181bbe01de69e7ae060f312b2230bb948aae99cc814692abb6488ed25cc28e8c62f3ad5081b0ac4acc7992e233c9008a1687fc843fe9c0352016ddedd624b060eb62957094f423332fc72c6162628b27f83300c188e53aa078d827aab56b885cfed3ef50ae5543f884bb2d860a051e6d369e3e6b2d30b7abbd9e9564bb123955f1d31e13181e963f346f558fcae1f26fb81c90be77464d63064656ee9edc0d08cee1c2797557f90dd46c8e0dc852f4a11119025b346e1c35e735dd739f4ce869c7583c0819ee748371799d3292c5eebfeef3542a08abf79db73945878520594fd1e79f1d57a22cf288025c9990c0801190ff54be4df7ad92c86e886ef08d81645ef92e93f666216f9c3a95358227f505f3c586f5fcc5e417d8847b91079c5fbd2b3289ccad9c08f4be5b9e04577d9b768da2d7b192d4217f14a8fe31869921f8cf899c744d1857f7e66fbf09aad0206261db64e8285d86cf5050a591c6ed0cacb138637423b7bf44a735300c8d31d4ff434b10a6ea142595ac0a3e1cc51d87728a56ba78943407909866638164ccb2c2fb241d5b7943e76dba3f29192ad5d3aba4027448ea99708b81a06a15feb3909325c38841f0bd904c51ad383b55eedc282b7350435f75f2e3aa691fa8e24f0318c4055137de195ba0432772ac70a2cd0cd0819b55170c610862cee136143f8e467bb14c9a548c0f46166b75bd0541749b3fc486ed02f774556edd410f0600bbc784ce32f1732d58607867ee583e584b70df8b276e98a72a09873668124fe3b09c403fa6b3d30087a64d551da4d373a9fa4256f0f2dafd254c14696a0c4dc1f2de33c67ec3051cb606c5dd37c9ed8d03299d7198d6d1b8232d2ea7e0cbb8b8a3acf144d110a04420286f8b538569be5672f3c6b93d8343f1f9927d72cc64733450d188b8e82b9b30187f68751bd3579e4d035965f4d337a600a5304669e27207ba5f80e5ba68932749174018fcaac4b5e39cbb79dd0cea07f2a3da996ed69b5d728992c67025c69f7a3ac5f419cfd267ab72cc91596215ccab718b4db8706bfcede4aad669c91b42537991cc508282c9d4a8c2c15003bdb810716a02f3f08215dbb3204178e10179373b822107de5e3637ad23463efdc6b18c6a5ec7363794c971cbe338b9db08f69af2912b9d45be8396a7f726d78e6e85f7b4341c3b35403ab399a7181c4b33a9975a1c4d07ce6c5a8f8b9f614d4638db39eb05eed248b63b45440af6d790fed26d77183581bd7129e7e03d61108d81f590385f2c413835a11b57729f6fff470b56e78f54a2d73a2d104f4994299543d8783482c2aa218a31bfe3cb2e68aa6cdbf2dfc9b75f7c55e3005979196c4aada77490aad5c52c2493ba4b08cff6b17c0614c4673f902809512770539c7ade6ba2cd43cdf9c668310bed149f467c0d44ebbb76a23a8fb28fe7fc2e1000ea5e8c5e61dff237be9f0c2ee0fab29114dc07b229a93a2ff02bc7077eeecf087f3716fcd69e64ed9b5d9b78b8b159384d51bc43d64415da2a4f29410459603a4cf6a6735bbdca3650fd15aff192a785a3ccab7f3a4df74a02d724d36d4e98e243256e6361c50f4b9839e0e73bab1ab3cfe3f8e2a1a94a7734644c2e0077c9c12614db21f024ecbb048c15cde54859e93e73ba07df2b11eef7d7ad9485d9a8dc674645510547b6f0d586f7beb8c2b1991b4e9794730fcd31cfff08743f41c82f1bfd11f01f10af1c2a8b7d4e5a586016f5b523abdd11d1bc77d9b678920fbd73c406db701c27020f910fb63dc59ed44ef7de5676346989152da54b0073228e439c32d1ac85e667ce2392278ea1d528bb9828287ed1ac64c91413a2d849fcb56e5f08a070487730e25bf566529a1f7e4ceb037e10fbae016713069bd81e874950f6ba5c1b2f4eb26d04aed24a1e64ee0eef339f13c5c55cc229da57c86f676103c10d20e5da578cde3f2bc71acf2ab1afab32df621cdc451eca58cd86c9f55c8fe41d056a581a446bfac3acde068e930583e0fd43c51f8a36677d23436e48c5306795d745aa3c1679893b9223bebfdde35beed183de0b663d9099eed1edb3b7b1ca9eadd7d5b73421ffdc59ee0a3dac1688546fb42e78db833cdd1706d8bcc91f3eb0c66ae5834361cf78f8122b95e48e5b8149b46ca8e0338205965182150ff69e0f7f129b725779e9c7cd83782da6e6a7f97d596480369866899684068e051fb98e5ce562b05992e27a1358d3ac495300f21f474e7ad94f8c0958c8c7ae4801e39ffbac70c4ec3fdfbdc13ceb919aba3822b1c0311b115c861290fc333c32aa74f38f7ee4c1fbc3f1ddff350c7393a48dcceb1e9ca"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0xdc947bf1571de4970daa8a731a94015700b880a4b5f0bb1a06f50a8fdf3282452d45e3f3052db6e09410480b99bafb7d0f887de669c896b4547efc64ef20446d01"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n11-duplicate-key.json b/consensus/common/src/test/resources/aere/registry-v3/n11-duplicate-key.json
|
|
new file mode 100644
|
|
index 0000000000..d1e7730e74
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n11-duplicate-key.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 2 carries row 1's slh-dsa key",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-11",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3974a283855c2660f08a7de343c0ebb15dbe2963c3dd6e5167a9214aaf91483e511ba80e41ed58933631744da49a2aa9406f729496c3858c21128715719736ef2ef8a6f766308f834b9a8bdf37a9acce248e95d78e5acfbc0c40e8af2c52a0f018e3a9dbe0f7198c809efc71d5ddca55115c7076687a2fa34e3ed98c2d53697344d5892c3704416d11775492e393d93f8ceebbc8bf00ea6f8fb413e4481299a74232e53bb08efc4634e812a67b11f3c66f394c2c82857791aa912bb7960160921dc630444beb693164b57834519e33682542cd8b47f22a5562a0bcbe046512c38fd4909becd1c896d6d5cb96c3dfa413c32e98945cfb85f8a246899f6ca2a619530383d665583c5cae30bf4734da866f323c96a6725116ded3b79c527b9ecbc166753829b966fd75c454935fab98e7cbcccb2385011099d6762c320493e2d57aa50d85a9358b5a34ea74258ddca98c22c3255beba5306f3668c3a1bfda3a7da93ea9c27ec42b502647f0de2097cde4b34c9daeb5c5534ca0f0cf12f0d1dd4d8605d15bcd02d58c6e6e51a5436fbad2d6597ae2dbe7e090c8c3928ba75384bd09997e3f512e03ab81d4b24a4ea71b0ad1d5f5f16f72950046618c0198df20ded31541aec2bc0c8a1b38936a595eb7e30b8322942d24c6b138cfa9939647c65bfe7642ce716aa7db44689ab54b2badc8184641a0753f36cd32ed95f8467345df6e99274c5ab0f9725378035b2592346733283310f168b0e14e423baa6c917d2cefdb2075a48d0584785e03b2e8213bfb314acb11fe66b297c16e86abf390244e2b2885bafb7641ba86e20649f4bf4612f936319034554df58d71f0e7296dfc6f74c0bc0f5ac9869705173429b149fe47bdb29c27194262d94f62e49b6bb3e0f5d054760dd3d4e31f685d8e766be0ab0c",
|
|
+ "slh-dsa-sha2-128s" : "0x81709f7b1144f9f5dff017c8404c3a0d6915874e412f3a49100aa094998baf781b3813554da2507c6dac69721c353bde08d7916e70cbcb85c8aebac92c41a420bb72e3239d878ef704089319f11ed02fcc081216bd69c01d5c9f1b2df5c8124941a08e0b5bb0e001eb357a9c1eedf78ab65e1a0d3c37bde0b04ad42f051f13eb690960cb1f0918f3e2c6bb8d0268d5b152426bec82cc9df9c0859effcbcc4bdc9861b188d5f58a39f756dad13384b1d715df24d5ae8d6d867a14093417621892954b0b003623ec7effc1740d1022d752626472742b914ab7bf77131a5372d452901bdc13e7478525067812025da47f43ed6fea5e28a627b5dabed2dab313bb0ef2575c9c1cb4678e3465533086f11976c7210ae58968ec5c72646fa52cd54f61fc0d0f22ee45e69e21e25ef06feba51083454ff55a8fdc25f9b77a8348a9e0b7e7d9652914bab0446d10e3d449b656d27bc2d2349d559fb5c7e893216ad6b05cc5d3107125072f9495c0b72d03c0137ba0bb402dfdff6a5f3a94096885b9b2aa63c012cccc2f10496d9d5de2a044c730600c2f1bef829cdd8128f26bb0995ce91a54e3ab3cc24b03b482e4cd342aeff77defa4e1390149b04659e5d46fef266474aa89a81db88bbc7867f80424efac9a3145df2b44b8a70b10c748a9858e77189fa85dbb0cda5c1a4db3c1a585ce3da4241d404e4926a4ff5776357e32d806b632270cbef14615aed54ffe8ded20de50301364b46bad87c0b00f6f895a8d41671ca473ff978ca5c23851df6af08167916c5eb0f85eed0daca0c8cce14a307974924a44c458f7993a2d6fcef3e1935c943bd2b96038a525cb801d25a337526107a5e8406e1ba5d5907593af3d702d63bc7a4e966652cf6816da5c2dd3ace68f5cc554794affd42d4c64d022b54c9ce32802142f98c742e1ec7cd18c8079a215ea6106ddc76a79705db9f574a45be1a0f5d1bfa91274f1d560180b346c58ed068c2147b172af30c3b85f3aca5a4370a5b94142364d21bfe28de8012e252f75b69aedb4e41053e11f055805991cf93a60defc865fc3a1318418982feb7f7bc24eb22eec05a0023e56a72705ba4623c3c9187ee71502c86897d82d1e6c962ba97646db58756bd1cd934814d26ddd7ac0d13ae74c0654c1a55bef9eb7474f18ea1e18776f1eeae615085cbf7c7cc807708062a47320ae195cb20e7952f2d357a9c134adff063a276c6fb08d7e9a435ae0071a76256f2e6f043f1ef26a57f8f7d92de7e81c3c46c26015ad3aec2b8d789e9eb6e3800e3cb4000b2ce19ad80193db8916bcc3c22c78060f61dbce94f05da69df9cd7fdc56b746de15c3eec4ff7b194207cb6e467ecb518db510031abb9e36683d4e6d16d9f03386c017855425361f027498e82c0432b315a643ea873bd9c82a60a699547cc65247bd573760f3d63191cd813d2dc4eac926fe93ad981239bb9b5f1decab35d805e85ac312f17e2d925de220e3e34a98a92948e2c5f7c8bd7967bdf26d602ce474ddd799941ae8729b14dcab428d80222960f710de03792a21f8598a798a2f4154fce79e7b405be5f2c5f50c096eadb91c09ad8b97173f1be97125955d8b86ced4c525877f6a4727b9137bf351cac869eaa68264d3f348f6abbe7399d42c8d9f892d8ee47750ee02e7904b0611d46d5cdbee450765839a99304493d8979088b2e16f663c16196201059ee02328d1716311dd921be932440dadcc3b00d1aa4f57bebae2c3769429db44709e91ee8bd244adac252a0a56b29846b24fc0a6d81c14d766f4f3a40e07f2e76be8b408cc4d380a44d9ae009248c033ca792cbdb3b7aa7a5c8b01ccf950456787a3ac0dc915747cb81ff17bb986bf30841f9c7f515cd506a0fb87a9dd8558ff6b028be9d7b87fd449519d1cf1e8dfd7a93594645b635c469bc1a64a6429d59a3f46d495390730f4614db293757b71e8a8c6339678190a1817f3fc4a770b7f60aac2f36757bfe4fc7e6305ae6d2c3fabbf239807079bee138c209b8e7919c6d28c89d2c95e229ffd15d0faa70c0ac77210327e0c49d6d3819fc0d6bfe25f4369685c12c9662d45b464c5e5c241a26127de1ef6afdebe372e9ecdd3d1a94066eef2bf33e1cb870986e0d27970c4decb8b5718bb0711fdea5ae35445c54f67b42c8317426ba4a2a2f3fe5bdf67f92b4acf8d729a68c1362fe91ce613e490793910653814efa47a7db6177338e832eb363bfc4c7942e3c8d06cb5984080cf8f0acaf8551f18ab36621fa6d4ef6973f5a927690e1e5b3eb538f3a6118280cad37ca9ea7cfa7e5a24b5ee01fc98b07bb02741f7f20e135c2e20253e41c8265c115894ae33d0f18f294822ce5a4b2d1895bde7ec205c548c52f3a33520277ddac099cc9fd654174ac3a9380a3cf246c74dc3e847a4f4c178a79024804ac1be3405dd5e1b4f1e5097d7dc8e49c5f6646d56b4e6b70fbb7a6bfa2a42b389ab0a67750f2fff0e1caf18c7d46e05a245c3a45357dd97699eb40559916fe67953f702cbb6603303f37d6305cc6405b7f39c05ad63d162a91f032e245b3cc6b40f483cf5a5bef09f31eacb3effbfd0fba965ac8896e16d3c17646fa7bb722517eb7fbdb7849683d8e082901209cdcc51a9fdd19442267acf93752935f4e981973f7c9137a0dde8f241cd44f4188eaff6bd1c770f89370d457e3aaa1017545ee9913c8e821f998e562b7ea72aafa9d3983352c42e3224ff6a1134149e6c0972f3f5b9e798524ab5d7c956067d10d9197035d02823e800aeeccd830ea228734d503036f0eb3427517ef5270328773c8c19fb10bffd8b78dff1c62812ba24bc9bafbccbb1563754f803196797612e983c0e529d4731cd1b8c4f325b9110241a49d2a142b07b03af9c8c0f21e6c7560d0ed0d7b7fb76959dd1a02ce9af31a452947404d355d19093e4061524e6aebbcf8012ee88680a5ab4337a3e204517cfcf02e5f0b7dd17d56daf171ce910d1da62a8baff52b3c432270eb31ea000948c77087f9a16d2eb5ab0a60113891900ebf3a4fd50f5fe6492b03b301454312cb33100e8f7171cab291fb5c2abc7289ab390616364b35ed7cd8fcf9336053c3e6dfdd4bac5ed2a3f951bd24b599e97d417fd8d3d75c473a3fd39d60cfc60cc1643dc3c9fee812802992ecba7fef5b83a8f835c3605aaac5dc6b1a30b8ab2d3f7cf0021ff17de965e98945e65d6ff8608081b9cae901f8db3f5f4795e1943b500e2d5c751e3c3dcf6e133e3f03108f89b507346daa4e793b1644a63df3cf165b842ce72b6b82c4d2b34cd049d74f464d602de8e1a17a1126aa881bdd1e46494aaf18ca7d2771214f24810a2491a1bd5340a66e422b5caa0d99af2536f7b0d61e050c448fbf95cbfdcde26c011b4b5cbe0ed14706ab310e8494c6b7de256a1084a8efc7e7c46425c48fc11669e3c59ab4275a17b97385fd6abe772eab55ba80485b23c07c994e997e7792420d164d2f56ca81d23af5e330ceeb9a98326b102fd7c4928c1aebc07d85232f73283df607215c5399232397c27da072c00a4d9b889a5335425c8402c174c4a82e46bb47e44582c887efb8018858decec4827a1a8e0e51acf554dc925a759ed729eb218a770be9ebd40152ae05e8bcab0306280bf2e441c30c3e85cbff7c4dd80569081bc11b1bf4e901ce1771c5f9562a2b5f3e78f04a831ebe744d1f14471701ed243ea474b03448e4b894c1528298c9090102d69518c58c49bd37e9d09b272a0506917c0d010c1d552924a89b5e5085ea08050088e3bcc6683d277c112ad254a93bf6d593e161a0f2dba3acebf175d34e179e3d4affa9a67c7abe77fe741f86d3614f69d78d5424f06c5aa592604e5e17b325811734494e9e08bc3182384b21c8f9b89ab416125f29b7c5492e04007e7d257efe01006b9e0d9d2a5ad7037286c3fa95ca29f26cc8067aed4a6b09885af4700bea93c8f3971d617b04dafb53f2cf349a38c7ff5ac491f0a3de1c62b24234867985a190a07ddb16ae34c67a28bf24f3e62d5aaa70b96866e5eb545098ce5b4b2ee3ecac0ea8a364c8a1eaf2f9c15c4a2f3f8126339123693555c7bc64e506a98b4b9f0d77308e33f71c6a3dcfc2bcf7d331d889db6210788427878c93fea18fc3ee7e9c5c416fa3125630096529e90175f8246f906372825ff87c433af9fa60ddbbe54a44238278c3b2439b6b572dfbfced008765d1dbc05f9e5abdb01d98d14e748628c3ce197162cb2a293b9d7cf7b5775ab52a43a31d25fecac96f0daa371958f226c963abea16f280292e45375c6a4caf980cd84abca8f280c31e6355561b06b90b98efcb7ae86ffb1b4c2fb829c7bfc02d63b146a07af6b2c70dd3fea0d7e3b2189492051f825dd318dd586b88b0f69bb4adadcfcddb616ac24b2a6ebbff7dc4042b6b02872c8c16374b96bd5f2adcdfc75e94c743eb0bc4abcd1cdb028d840c8c89b69b5b917057e4f6b90055e6f903d8f023cea016dc706ee89f2f654324cbafb03b0b4f7016b0fec4319a19596e226bb1d6cafe41cd0ae4f1ad9b54163814ed2cbf1a6008964c1a6d8115734d960c0b978ef26fe911dcd1ab83db34d1f8a5e5288bdea20dad9f5e4364986ef95ddaa1bf75a37fe30ce3075c93652e746f49d0981b5d631fdc15baf0069d57bdfc28a27413d04884aa306f2c9db7fe288b6056d9b9c132a95a13401f17d924bb7b7ad44dfc6b371a77b0a23ce40045472812690ae34b0ee6bf7056200971dde6a133acbdd586dfb91df14d181093110b22d3e13c06adb9e5eddc6838a14ed6683beab5910fece340572b3109c9d09b4dab95f2aaa5c286cbcd9a413ff5b0765bb0c912dbc717dd13c7fe46b05dc0417ee6fc81b011074783b61f7feecfce6f8f4cc87bbd988430bc3ee68c9d06d843c1d51ad1f37a40c73d448786eecafaac7fd84e028d746f6b0689ee61e93f0d436eee6466f1bfa0ab0288a080a817eb31c59106217efd5ba43620401db5042e4b0ea0ce39f9450decf2d4d69937ac08b0ac9f538f3795d24da9c12f8e781961d1183edad10fea48279972760486a470a640966e091c7ad8c1bf435fe15978613e188b4bc5e0ed8afa0961909928d35cbebc8284110956964880a664196a355102b21e4930f4cbc74aaba3000838a3e84182a486f8f94a223369adbdd3060a424e0eaf79e97a5158289f513176c8d583143d612c7bb951c040bf71a4f9797463385bb9a8934885fcd3b5cd28a8296fbd16e9eefb600d5e9f0f1e61a35f202eed5042da1cc4631b9546cbd27b0b31a8a764bc4950f3bc2b725983e29d43344ddc394b7d531f1a3f8c299ba9b9672abe9dce3244aee6eaca69ba7357a046dbedfe0ca3ac137cc4c68c9582921a801df2c10f4a62c5ee6837d93e90c346eb9424e027177b6af5d676734295adcdf9ff1fe239b7d8ec5defba43a365927fa6d055375d23132e2e945f33cb0edd3c0e519c039b489a4bb5eb4b619c6d80cf40fb87598acc9164b748824c409573b2d80880dd8ed6f67f715178c52a6c4d27f6f8b7b183c25740c6a81d22c1d88a9b13d44feee20cdf900f39ad1086c53a2e853d9c8c9e987d5b151459f921782710002c602fc94c7639cda910268ebe823d752a2954289933f99bb6f2d5eb22b615392ac4a6e5921beb51a0af757cea3ea56d913faa1ab71a0601a0664d3beb4e6a7b0716ba6bf5e720662376d3a71516833840359a73a1a868d9da700d47651efc3490b0340226d8cc6afd5ff6fd1f684120ca9c444bf19fd7f55a159e06bdd202855e2824311994eca4a206478fc7e1e29fec619506e43ba77feb8c159f067b55a47a2d0fce452f0f61b2a746fdb7ad963e0c74fc06243b650496f3ea72ca06f36813befad7c20008d2fcb3eb4db2799a70e6cfd30d499b16154d86a1f1714e8f02827e367be7c06464eb8fb0f75293ff2aa2a8a04577043b60b2a41492de40a235b69bc6006e45fc651301fc300acfce3494c18710fab004601cec07a08d86b466c6e0c9f156a647a9787dc26c483cb589d2f1622b31caa07f32a2a878d9806ba3dee087949d8ccb3506a3110fe717de36cc41c74046deb937f878086c04279e16135a4f6a8c824af7883b3e22958d9aafd26f0ac57e2421e2722799d5638a2f42311a1f93869b972f6bb5f23e7b0fcfc8d15b4b5b29eed5fefd8a8e33d8bafa4765e08a1f00ce21487a5d4801b221db87e9635d63035209bb6e3d5c1835184689dfcb34f3864ab8f409777f3d335501c48da98d6d6bac1b683645c9e6ca9a0ee0e7dc57572b0051b23a5a51b113c64e89fe256dfd6143d9ff487030e6d48d8b0288ceee6a1c66b9a04dcb94a8e02f46954271d55d75ed61f22ce4583cf1899c0b00d8ec509d20eb1bf3663f44ad40f2d2f462a45c81322e3b5786a6a5318c9f1ba9606ee75f119ef398822765f548f268f17a831dbd5f20aa018e0e90ac6dbe4c353b03c8814e3823b4fddc513ce201d987ee7691f682ddce6fe19ec530ee5a48cf4a14de58bea44ef9dc2d6dcd9e78068ccc55789b8cda917d2321441280a86feb3a99d965cf894930607e61e3aff981c86c635718dba067f2ee9967d2200e453ca6fb7399e31e6edb5c71828c1e9afbbb4d2527d4308ad3926bf9dd9bf21d0a09e604b5382168d420f7038bdca5183b3130121260c20f71a79ab839ba47cb00451811a3e4575700e0a9a33c9a5007ec15e29548e6753c4674c48a7c940e2452aad50b2de471d7df174597c2be8790fa532919752b4e25aa3cf7ac5d24ce3c7dc29bb9593e0a6ba3d15ae7eb25b962ad7070aa0b0ee6f5752d2ba75a6667809d336b10fcc64b076a1dfea563dc16a15bf81956222387ebb529f59671928b0363e48df63cb753ba4acfc7d47c1ca52717d7f39e165b8028e6b4534ff532d50ea6c4e53e2edcc3f030168c9f643237286d4f4d79e6d0c574826d04432267b3e83b6d14550a5c3486d6c4f9664901bb7ba5c8eeeb71f9ad7564551d4fc2cb2a9887b4b67ca8bb47bbfb267a0fef98e0065689f3cf846ea8079fc7a4946c4775d47db01fb42242461b90d8ca064de876cceb1c81acfb3b0ae1df7884f22ac23e294d1db4a34f51cc78266c2fec31e4e302776ae004c186f935c6b4ea0848fb535a53a192f4d7cae2519cda8e329257864569aa89d95104cae0605e671601b513d3fde5287059e51e133b57fe822cbb3ec8cb211104ca8eabbdca781c331d6c6cbfde5d1e07a7e4480b9bc899ff81172bed01a17764cb4903b4b1dca91bf9766f5a017cc2cfb80b568169bfff2a0faec60c68bcb23466011d98e153423aca4084870817381a156803b032d0cecdda83df8cf3b1ffdce232cebebcfcfa3334066d4967726e10d1f422303c97d8ce863d3706846b8c3d611131817ad117edd929f228924644daa9127383c5b5dc7c86415f7a71ce3defe42c585954711d85e505d7da236e3f89e2732a5f1138a3228225572252a57d2a264f708f59ce667817426ed200e12138900520280887e4ceb1e5b35c4491b42c82dccbad0e892773e99f7e33344bc03885b55e812089c70e3cf2d224ce08b767a38c30c5dc0b83a8272a94d499d7796e9d5baf2511f5ff74a5c4af5943c0c450ecff4ffb7b466196894b2da7833df08979ffc7a8414960da90d02a64e266fcd1570b5666608ae345e9009abc0a3765eecc1bb4340525b53f145b99efcfc148f6134f61e99d7968c06241b5f8628f793f58b26085ee9df53403ebdd4f93278be4f108c3e13b5d34998fc375bcef2e31bf99d7b3fa653c472c11deba26ece9e6c2f9376847bf167a7d98518dd90f586bc77db402efb7e7a8eabbfa1facb0401793db5de20b4f4b2c4579017b2ed826d1f09a297819d735918a23de4eb7383a21bb90f18fd996e2f04bc7f207d175cffe2c332f2fa0e7e80e4383fc8f584d725126f382025da0fede837f5fe4dc647ded43c7530c1777c2c5ca2091123673b49fcc248ddb72bde28d557f919d0ffe93354ee68d854e9c5823620161e616190fa0d3a32f1d106c576d8a38dd64df3fb03e3d0fef034fe09b438d1fe8800bf5094f184e29d736e94d0bfb410cae39500e253b6c973ebd24c2950270d85f2aa71408440e487618d53fa0a1521de9e3e24cf7bab8b43e4a464bfe1fdbb0bfbd443d3ff45dbcaf761ffea019f1d835e945a7e06ed09e945fe3278fc3d3154d418c0cbc82612d3dcfb029aa807087324c6b46b60ae25d061878df415153064f83e3ef6da2b2149785e41805e5be0b96f61d315c5defe936a649d5bee68cf92f831e651e0f588dc4d86c48f36d5ccae935d40e8b0cfe6acb65ab535715bfa87a3763c4bdca155f7e1e1ce65dea089d7866a4b212e488223918c60049263a776c3a934af1edd04859edd1d393df0adb67c455a56575b44eafddebf6feb70910c720cd771cd1c09866f493731e8cef9484180b0ef67dfc579e21cd55641bda6981b1d5d3e2b664327044fb3de9c9b05fee297328e54eabfbe9917f3cd5ed9855f9c93ecaab0ea8a9497e7e1bf35322cafef0ca95a117b62261aae081191d67ad7a915f0fed459e4d27e944d8ebec31fd6d2062956f5c833b2a4ccb30814dd91b5a8efe9c152e1f5e68f41ff48e925ed9a0a78b33b43373a64d9c87ab2ad01b3807f38e72d8adc21808d831a888def2895e6e7acf1527483ed2dfe065172fade7750604a7ee62200c486d9144369a2fe72bfaaea3d7e3981e124819aed1c36f0dc9ce6f5b36bd4c5018493dc91d1e078bcb6dd0c96e46f83739ccc7cb7c9f2dc88edbd988df1ef4fe58d640667922e9a49d83da004db34488d09aab0cba8e2ac141648ec4cbfe90853aa3b94f7055522f3ff8c83a25e671456c977e0183d6e9d56da437dc8d60efe9f6f8bbc094b0f79c754612574ee8901eedfcc90d2981ff578a48856ebc35150acbf0538df7cc5f5a5d620ca47bcdae52cdef2952d8486bf23d903c400374ef6bd1dd9f4c1760d3824104c1f37cb7811cebcd6d18b58d9ae580d781dfd3f47b6b1f43fa8d98d7315fdc844cd40a6a3d9c3e55b4e655ddbcbbfada63ce0c7c2f174021ca80df9d692ee2ec6c68df4b20ccaa4305a95ee90b42dfe8cebf6a504a6ed504525a1d63053809f6e38b334013acdc899e842f02f703963ef760997199784fe9e426d31524af130e15e350d16355cb69985cb6989017a4872c10b252a940916414ea9bc84105560801ac77c7f400132b5a192365c1da6025ed7668f889aedf4ac2a664afe2620ac881dc072fd5edeb87b0f2ffc1c0fcb27ae9a62835292f0b51611de58f2b3260675a11998de1e3bf626b7d0b033c8f148779c54d9524e420268e949fa1884d56eaf0bafa33ac12829fc3d556082f5644a8f3a53c4e6181fa9831a404832180f06152ce01ed24682bcffe60026956883b050a4c43d33cdf8dc56318bd76021318c2427bd19eb600badc4038c5bf760d461543b36de718e4e91a0850ad2f8ea82c265842f614e99d70b385fec917dbdee81b227cd0adc0a5f4db5c4d268271fb739154420bcbb2ba33303d9f939da5d3f2803f5dbd2e02becc683b1c5f825b2a2c7332e4bd3fb9b41d4b07532c2de5772cec38f5e2ddf6f9926f2cd2c63f752d06a407723ff1ad4c3e0d11565a414de52c7e8c46bd913f9e2c0a53c2f731ce5851b1a14ed968a3fbbb9e8a55b93aecdf2868dc81d6c77a8fc9ddfd3ff43799034e7eee170b2fa9b0e7ab5076c35e5f3db3da00100d0712d05a8789af1eccaf37443408634659bb67f51a93057b14118021197c77ccb096f09a5102dbd64af86fc10a6a4699c8fa0aaab6a7f2ca63e95d7d950128056d3cfd76d6ad7404190430ef77803b4cc477d2d2ea5403cfc306ce3ec547d79f1c5f41547981629360f40158bc7c27215804ebd4f42bd8defb920da7d60b15c5a3641aa4f56dc54a14da0fcf7c1c5f238272fd75d70ceed15847a33564845685944035d55488c95d9113b148d434714eb4dcea337daf0b1dad4ad5926c5cac406bece6826b4f335b1b02d0538a32276a1df31b5c378f83f248a4398ac18a06a136375711a8935443471f44758dfa462c24ce9169182eff1698475a064c697b56510cf2dfc77023596304fbedfa865a2127f54a3fce0c2a8400bdf3e106b49edd53dc2f4414fd3af6d62ead68af57a88216546731edc26c0717b804df554ba3ec5d7cc39bb68613d99c6ac4e50df2720e151b37bb1f01843af17540ede0cfcfcc744871e2869f776c78ceb04398a7c9222d76cf7469852c825f53ada2e39c521df4240ca70129ef2d123f3f6efa138808386237d1b3b5a4dafd4429d143fe92205329f2062331f775867311970038cbde439ce6fc5425dd713cc4ea1bb5d0e36e97b75c031b138a3170a89d7107e795a0e052f56d3731fca334977d11e6e0aaba784f4366740649d28e01b9a47d26aff23cd6eee2b3a0e57a9cb8a8a9fbbb81a608a6444f9941f77757e52727166ee1bdef8c621a6d27e776f62b24eda9d1e1aae160280f011fdcbc45f995681b56b500a967de5a765c8f6f80336421e96e90cd251344e9d84f83cbf09176e29dcd15365f8892130bda24975b70df3717504a007a8d64bac7b2644931375a56df1e76fb3554c87cf6a674baf1293462a8140981fc7ccba0cd3cfe3c002ba9d443da991464dc27c85e6c599ed8f3eae56ca1a8aca810eec0472318fa7734535036292b870229e44fa3c6bcd79e2d72930b8da76f54b627dfe2b572db5946e49e482a128e6ab5b4cacf1a8480f4b2a89d889d22110bd44c3823e4359d9b21edb5dfcd65c968b17d2a56729f7bc9591fb5423a51d3173b1cab3de487564619eb4975af7d1882374c8c1f3652c433cae0001796b37098d62f9f5c8660d855d106388c38a7175fd503bb092e1dd3fbe9da79c977588f62dcab26b414620c25b6b50a649988fb6f177c66df6f6bec3e9e2c491e00be0641974a86fa730929869cac672a45c497cf7fdfb23fd2d4b9bff2551d98587af13867fb17fdb1e77d95b286539260631bc800bd27f3cf3f6904d81d4cb8a19a924af0dc45253d370c5a1e7dce7a2d1457dbf59eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x85bb15dd7f350a7178cc3b8ea7601c890a82b052c1aef38b249e5455de31d592531031bce1f03b71782bfc6293d7a146f84b834ce5da977efd1c1eae03c0312701"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n12-rotation-one-key.json b/consensus/common/src/test/resources/aere/registry-v3/n12-rotation-one-key.json
|
|
new file mode 100644
|
|
index 0000000000..898f5b344c
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n12-rotation-one-key.json
|
|
@@ -0,0 +1,50 @@
|
|
+{
|
|
+ "description" : "index 1 rotates with the old falcon key only (slh missing)",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : false,
|
|
+ "previous" : "ok-epoch-a",
|
|
+ "expect" : "AERE-PQC-REG3-12",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 2000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x391de378d9ee4e1d810e6ce145b1819f1b73dab7f6dc2468fa65d1ddc8e2a7e6fd8f185f8945700a938cc0c5afd87bda48c1b8167c3e6607ac864bb2b194a368c33cf8ab6a5eebb9a704d4160b068184264c2e59c4f82b9b4eaa9197c3ba5289c429e0f4c548769279daade1286d354212b1ba2ea4818c974c17770dbb59b65b3b9f891c826721f51a7ce14f94e2ef4cab868cf852ed9bfb17cd33ebdc4d688d6ba12c74aed2c8104d117574642af25e9bc91ba3fdabfdf1ed13c6e59fa1a0a4388925d2254195c666a6c235174a73125790bbdbed463617757fcc17cfd32da7c7f89e755f051aaee186665d9de393a82508d15f88db0271495c959bda6651a81a04dfc2103364f95f5464effde48f3b7ea80af9c1bbee99c9d39b0627984f09ccc6a4c888d121ca34e56760b1c3178e48607325676c484f4d666681f0d2454f7fdc59cca37136c5c06e746987e6a116728f8b0ae1ae9a32efdfcc956fefa55577ac670bc3d66016391bbb833d97f91d3a78696370a6f05efbd77cd50d4697c3df5699277eb1cafc1883776d9ecc72a763e5b65dbdd184efb9696cf58360e73f2d4db5e8bc6ad65bbbe7a8a994f5073fb4b12ad9b5196c450e27a53d8ca231f670966a238a6223b47d90990b1f6796f93eae971d4939d99dfea29d4ba2e3feffb97c0b27d6b6d2ee10751e75c658b44ee71abe9230f74a0d7f232329b165f5b2a3e584dfedaafa9ab477c0c516b6553c58797421f8d1e9236f992b61963c108752b1c43278a9b910926b396292fba67211e9a16b88aa9bab7b6b6db29f30ab5b7ef1568d46a010e8a27144a5e958022be5cf6bf4305f14e10781323acca3bb1d6b567d3fe5f652661dfc54d71ed9e3969289c29bff0c8972899993505cde2fca11c821d9280abfd5c20d4fb53380",
|
|
+ "slh-dsa-sha2-128s" : "0xee44a0de25b75a42e32080200c89b82e2f89551d44da272720c816fb144aa42ca29cc7a0045d97c82676d36286a9f1bf4d5b9e44b6855d90f25e03e3370cccc7665f3c7fdeb6f9565b76745a7652f70b7cb18989582559b81160fa32c7db7915f14c657ca37224955d174cc69de41774e4ac576f362306f3383733b322f8b333d9d0dee44d80e36a86491bfb7441a3c66809bc600399ac9788b4d7796604d4ec423c40dc1a6fb2b02db9a0d35072cb5aa617ef769006c504052596186ac0d504561c815617067f669b29757aed1de7a03c9c0410fb8b040dac268aa95232533eef1f69cc0100b33c9726d55af73b5d608b501b0470c4e9340b68251fc645bca481dc2d375de626580faa7b7faba8f8a596f795481cac23240854839a1100cd92a6410291ccd40cfdf1f70981c568b32904a0ad649de41b32299dd5a8bf50c35e5dbbd474c258946881b49e335e01c72ab6654741e657bcc5109fbda7297999cb4b272302739ee07cff0d1c9ef454a5dc5403cb7c170337336f94d56f6ccf563af44bcc8382de301720076a7ac1edc1ad95dba129760d7e9cd4df609bb8f7b389e7ab1e85e1b54fa5e3f2163afd7e24c5e5eb61a9e8e79dccefaed30f5fae83bdbd8a1673b36ce894891720b476652a26401e7890af9199bfc74fd0aeb6622fed8e488b8151a6c51a11bd808702f945ae9f9a016bdd94f45279d4765bb376df7fed5506b52b74c867c087c3386f74b130cacd7bcb4e832b697b50c796fa8fe4881c3f994820799417885af464f4f1a85989e5e3b54c3bd878a7ab054bd08c1ad850c96f3c0105380323908fdc94771609b10e489a8445f751f75a9b617cb1aec4460be2b53920e52f7d85096065fecbc6f19daae458f657dfc894758f3d9a6519fb4276e16b38aaeebcefba89a7686546901c57a29b95266d7ab87155a854ba9b269ac94a279e9c4bb38e6a4928cf6fdc3984b4363cc44e0e3cd7a7edf08388b9ecd5a04c55ac26b98f98cda79cd3f402caba28360899cca559be68d7a825022f9010e65f9a6564fcd0ec1cc4c0f4029086c90288fa83656cf2ca2cf30d5c423342cd15b9197905e9ab30a9d147aa2599abae71070e40058f0787ae39f39d6e5c1a8184b2cb3b1e6e45c40c61d46af8490cc9af6422a439f16adfe93a3cbe88f63df5eb8fcde9ea111ca96ea7be416d030500f2c7cf967dcaa4d3ed76a613b2bcc034ed3aa84f35556e7a65a8798825b576236798318034204f041dc59a9f9c407d34c2ca2d77470700ed6442cea5282ee99ceb71c6bf074423dc0785a39b89b062f89231af868812777536d0b144212d5b4b6fc7b87ea04fcd6f94438704f985b746a13dd519c57260f87150db4dc483b664944b9e805197df797be099940fed468b1e214ae99a68e99c6b5cf3d30fdbb1b3cc009ea58958eb4c4a7b7bad6b34fcea2a87eeafda01dca5223458affe54422ca70ef541ca8437171943d5bcdb70eca8de02b93098653160cae52f4d72fe5a6a7ad51c6465388f0362e6e72a3c96b9cad2248e8d9a2cdf89747444c7e51e2f89eb19daac76da37180e4133e0dcab15fc72c7bb90c1024d03eb2e630fc6d2537a101961b388e32ca5019a626b5a23914b06e7822905a5e3c21369b69fa63fc9f43cf7ecb6749c668c7a940b82f88c71802ce6e3c68b5c10c9249ba356bb3bb0539b581a8bd6ca141e5dc2b5932251746c1fc1c3da475581f3e3717f5d905f5ff3c83f1523f57cb750dabae0404beb55aba1105b995268906131835718cd43240bae9aecb30c794a8b186436cf752179b1de65b2a87917147612e3c95288a3e816238b3fccccae1da8041b4f784ddcb3d37ef3f019ef997bd8a4e172d397106a5adebb166c5f565016bb1c5f7f1a0cbb5bb22cd642fa4390ea640c04a968fb5a49ef929df1cafbb69c124ea58b31bf066be388d7b6d4c52409581da785d6447fd72b54949e4c1ad08fa64b520f2b8df83bbfa417952b87fbf802652a65df0d388ea32dfcab3227f645b6b28b66087819b4339ad171a48760e2bf90f1a01184389e23e7df583eab7c2dce385bb7a4d60ae5573966f916bb84aaec6cafe710f839b103532f9a7a556bfa116a05480386ddefa2858ac7ebdb58664a0e633a53e1685d71d5aad11f5eeb3d9ae30ab120fb88f96f383bb86917b72e02768f071ffca7e3fc2ac79846a36f6bd72c58aff03f9e87fdbeb65c8ce5976255227778cfa40ce0eee943b66a382e172abc814ebbcb0bf49efa75f87ef8621d227224b7be51b73a928c23a8937570e1a046bf1fd4c6993a9c14e552915953776265f78882ac8302f70900f9d612d2e7b7dad88cdedcdce7e615baf89ef249d6d535f92a2ec90a7435785f4d0c7a75812b875ec22e638f4af1705cc362ecf52c67900c888d068dc6f72a161013c30dcaa49cbf25c56e8937aa4897451061dcc7579ca99a25348e76ff121983444553419e820a3d1a41744f4227dca054c454a6497e0762155e2a06d17acb44ea55f54e4d6d2e1631a63d9494cf69c38ba66deb9d95c0ee01950dff8e6a5d1c46fececc7027997b8ec626f8405ae99ac20600898fd7fc422e6cd3f774b4009f371ce38e1f089ec93ec0a48d6bfb90ee79c3bcff321eeea33a44022ab910458984b75c5089cec0d8beec20c4c39311b991154fac7c0461b7d667488dc9f0f5497cf66166782e2dfb69a71031fd0251918e4c1243aa4dfb9fc2b6123b4f02f436c0f8737a6663af2b99fbd22c6af539ca9389bfb4e55da2c9ad42521ca6978f71991f53fc8cb227e228a62f3e22d7c3eca8ecee260e55084ad3ace0d6379d5eaf82bf6d3b69c4e74fade4210114d95b41a4c004858119a9a9b178d5a0cc97386bfed0dc6edbac5281c2842951a0c4d7da10207523973c676b8e6887a087c1c2f156970cc6db9cbd3c8ec1c9c1bec41fcbfdb4e8929b67e6c1939bb990ee2cfec3197b4ce824d25a7b4c765945e85ff2b096037adc4dd763b87850fb39aa98f1d395c9353ae3b5b53842a7056c011fb690e856401fc6f67b1c0a5414fc229284e74c230ced260d4fafc5fad153a5154d35c3bf9c559239ce18ca9810a1254a0a6c2960a53d838431447739261dc3b055a0b115914af263ac9fce2b512884620451156c40cd84b7bb2d449aad243a8aea3859412476ddbb5eb73028bfc6b2a942839e363262f94795aa45f6579680997d6acd7a8c8daeace08362fcd420f2f8a96801c002361b942493cc5ae79884eddee989af9832d55319ec033956660c5f11b9fbff9f1410a18c0e9a38e9261bdd13bc392a18a3df97aa33e7f59c125f88d78c86058f3c7e9a9d3b37bdb1e05d90375de0090b418de3ca761560f079a6ddf328e72cd89dcb63c9dd0357ec736782696241e2095aa6107a8bf7bbcde26d5d14533f28ddad7fe1b3f0c181c0e6d55204f6ce79cfc557cfb2d54cd2f33adf17a837243b51705bca7ad8cc452e5340732e678274f9eb532bfea122cfd2959b2499ad25a18db7dc387e976f8b5510821cfff778be799b80505cf38ab1ba6b01561ff81ef17f7735a1ed6a319a7f571daf92afb7490fc17064ccb6a8453ae6e66a2afdcded0c7359461278c49d342df84c43a0607b7327853db675e4c9ca95c52ae013461ca0763d157ac992e219a6683a547c32374631b53138676f50ae0d30588fb25de808e1d9efd5fb9485192428477c2f64fcaa862761c7f5505cc650910224400e2a2db13fbea0b0cc358d163c6d4a8e6296e4c9554078a55f23e60de9bea12ac199cd19b97babe61b2a3b853860b4441ae8dcd85d59695393816c64bfc074e945452080e15bcf6776cbb6b251c13be63932702468679b2bd7e1693a1d910e1b62be91e177a8dec8e4d7642e88e513e3a871ca502854ab0fb7fb8a099d0e0dfd73064012051af337abc78bbbc6fa2dc7169ebfde2d40167048d78f12cb5e7c130a2137a0b26922553f43aefdcdcec55bdbee0fa752a4787ea9d1c75d1bcd9d28135515a0ecfa9735901a0eb89f915d036e21263f90606f65e62f6e5c8237db14d570612611b3ceb4d026ac13f473e5706cd7975c95d49734253757f9c1e6aca9261cd2b95722098c5f7c74daa6c926ea4867ab54e4605a15bbf7ab94348d9b45c31a1fbdc7f420cccce25abb4249cf413008a01e53296318414dfac822cdc0bfc4298273f65cda3fcd61236e255dedd879fbf20b8c4843e27ef413c7a1ce2c714c88358091abccd7fed337a7d4f725ffbf7856ea4694113d605b1ff7b2bdbaf60f7abf7d43eebb1e82f4b6b7f3f8fc23ae27b09f78a7a3b324c7790431c800293e08fed2fa49aafe8f5670d4e6bff4cf6e7924993d6e18ad87699da99a2f2ca9f3c7b44b3b61dcfa5f041f7a6df94131b8e5c04069678541c87872daeb2943902afa6ff4798e45a75659568a02471afde44f8e116fff4eb7c16053a7aa370bcddbf5229c231ef8f2e642c1a88f90e0a309d24a3ab28d3adc176665e522cf5bda0285baca5bf2a0fb4c0fefff3b8ea1522c9ef29342ea57eb4f16d69bcf948d66247ed2f2cc4e567476f736d170c98398ac7c0d158f294ff33ec8d2794ec1929c57ee6d7f46da8e40337a2b380717227ed82eb13a14d129069e98cdd65bc34472fe1a52dfa7e466e559705c53d73d97239e38bbd600aaab107ced36fe7d8ef2387a05d8548a48a684fdf02b984022aeb28e8c5eccd1941ae19d2cb12a31de296b4fd1409266c43118848962e9e59a41054a52bf2f20b09eb4e77cca72df70cdc4d712d5c0313ddf9ec8df2d901145341b3ccfcbed77288ce3e4afc677ad8681c746eca02e7f7538d0108b68a922a21d6a8c2cfd67d8849ff5779de1c00588133309d4158d1738e508a1a2ba3351a46fd3f86339d66b1244bc2788de3fc60144d03c08b0ef08914088f9ce947d2b230ffb9ce176a4bd45b0c8b100e17ec7829eb1ce10b1a514b5e33d4f40792f0a300a4c3ba7a912db8e19cb72ee02ae8ddafc2caf116df905640d0cb65cd0c61d38e0a9741d3dc2b7677e8ec051d329183c954ff9c0c2d8771182d5550a742ba8147ec6571bde519c2f57f10aeb1c8900f8324f017f3b1dad92fb0d19a76de75c0c7cb67d079c8bc0bd7355fa25752d5d00ab00f9ab332aa23aaf8b5cfa4d2723b2020c9e494208c61a76e18c9a583172d6ddf544a327c931e8b908830e46f184998fc0d34ebe767e4f5d06f99804759c7e2b76a8baa302d6950f90194b0cc694a0d351374cd028ba6b0414377a850ca2f209d13cb7daf43d14f606a0e549ce14189023fc7b45e2b095a3f45930a72296eced3e2da24bf237959c0b966bb88a3a9818932b1cd41e8ee002df515ec94901902b2e67545dae53e08810b99dade7b579b847a6570211687a62a56dcb324bb442c4fc22f9d85e54b3f939937daba84c86fcc36c83ca87de70fc7f4afed335e8f9aae027e854e3a022a053c3b22be3617240f1355be9af3f4c8e9481005cbef07bf1380ddc012412c31b221275b56c3ad52cb2f7a9b340526e6128416025d4fe497f2d502070653d36f924420c0844b5560a8728e4a3be8b1ce67a1541c00e97aef9c808bd77af5aa280690d98f5ec218bf5c9d135d85069405b82c221d834b8285402f481b7d51ecdca91c4c2b27c12f486d382e0c14ec23c2bdf33ea8ff693af551fbe55e46bd84f335a68646bd092f914da4954c57201d7e812f4974a553f043ace9c6ce2c609cb4d90dc1ceacd5d610cf4723024538cfedc1bb22c9663ac541f89f97b37d2e1b4d8073ada1596e684b94e74c2c2f0087251f1eaa6789ece436b2940d3285f297cb7482aa9b8c47118a0b1d2031fc311689828b64855bc17306529e4b0a3326438b42698dd4e2e0c2f624aa510a2363583cbac47fbf9974925d81af9534d0ccb41e2b445eb19569d703cd8ace661139fa344a5e097290c233114370831d4710676f7e93889ed533454928333655b06ac5ae67f301f2b7944d769892ed76374a1f3861c8624b2a302df1a2f1a60d41e61379ab3681d8eee152c251e1b7b0806aab2f287338b752918cb989d864e9acaa92944f5194f8eba19a18a025157d2c3988163baf8b7ca9060edc2227ade8e05348d86d18f9eb633e4f06ee346e4c2912ed1c763a75fd1baf32cffd0c856ff9b44f1470136c0a8ae0b88175a7e7f993d8469cc8ac3f643aa7db36992cc97011be0a42ff1df8aa7cd82e260e05fdd67304644335b386c7825858a438c51b63f877af005f7d95202b54a2130a1f652ff7addfb798daf4415572376fdd910cd099066e8d2fe251a907e41bb950e960fe5116f4a4fc6037273250569b41ac07002ecf3b4b63f8b853f9693badd2e8bff695266095f4b2f38ee4d60428a45e7586d9d47c01c12c5e18d1ca9afedca6f03384567ddc730fb8fed27516eb7c54135cc7447af831f0c37727997ab2b01fdbc5e12c112aa987e95cf5aaaf44be14bf4882f49cd84894d555655d17aff21f077b2cca1ff0922afbcbf4781145cfb87df585e6af1955db04843a763fa735d33b3df836585c5894e5125d500673d5e4d0bdf6708d8d28c80298a9bb47c7430ae8ec52285a4c14371b3f8ac1e21306b34bcb0c1e3aa7a8dc8955cd9cac32a0f69d0fa0aab30abcbeb2c21d655ccdbae1c2040faedfc7a5ef29cd5d9227908335ebd257ae8c410b1916b9a5bf0e72902c2bcf701a18c1fe13695a8435b0d0129f3db883f428acea8b7f274a629865f1849d4c263a1536421875ffacf058f0128f0d012fd60f2b3fa6b71fbb96f3e1e33faa09b1d20b0919018e91a6bd9595e9c16d4fa6665c4d0adbd77a59cbbbd587029a4f306c887277a7a27748a6f289edfa16c7e4042fc81355b85a994cc6784f5fde054f188b9775836594abd82c1309a66db4388ad49f60794d8c8e1fe279f8965312a1e23c2956427bd6e289e55ec728f66c36526d40aed7c44e5352fa3e2b5d27bdc1f7b3bfc4f095d002bc8e7b2df2032daea9bd3e0bed2733e7ba13c6d8b45c492becabbef0e8c62c257480faaf6aefede888ce1546046f04ce7e06936cbda44c5f33c71c07b53fb3ac7a72c3770838471aace69f7ea454d2980fb5462173aaade7964b888606741270f92bc18950284d013b692bad63ec3726d8f6596788a032eee6eba08eecc836202b06ca43fcdb062e65f8ec91f7400963bbb8094de4b4e1042e040e81130a3ff037e1b7e947b0c3e8b7ab5b539f8570ec2cf08971a1bf0d4f3e8311b5c625b7d032fe2e0603ac1a4824432b4c7bb5afa190afa30c36f168d196fc89015aff8229fd4b299206e8183897229e95ba06324edc1a9ac81aad786d5c9d38c87c48fc6159934a8532489f06e1aa314a057d91c0f7218861ec241dfccce63d60bfa624652795229fff21cf5ca61ce05ea0ad6a1763173675377d1f2427564e397683428fbcc4b97495735d075f84b289b73389a1fece959f9d9b4932f4d33a0907202c650ccf65327d24cc24922d0d675fb59621e2bcd2eb31ed1ec5fddc96593d4f936ad42731a50f164e404b93920283bf9fa43f8be5878d18e07cb8813914508532625f71d02a615bf47018e3b3efed72d17e0c974d33df18ae70e3a4a743ac3c955d1c366bc94d789c90a8b3771969210c7f0c4b9b12f9fedca5d2b71b6c04e7024a0a5e3d0d3c7d30cf568a659cc17309b223399b39ee5efd0cdec3a34b0735df8d7e0bafa40a8aefd742b3e0157fc89d113af5fcb0cd136a9cfb82acce406054aeda30b83ade59cb6771c366c86b5d9b016a74f220a967b83254db3e24d3e1f5d5e23b21354420dfca6bd8454575c6b0e528744f44ff8e1b9679b084d083b9ebeff09df273a476332dfa172cb98c79ecbf3ae4a722c25be71a3b206d848f56b02fd04bd32ff959e6931bf6cba042f9fde027d832632cc40d4320166f9644296d2dcc845491ed780cb609c0432408d08dddc70fa2d52884df47a55a8a3e706a24ac6ceb375a894636e1ac121040561ef486ffeebed3c5336d123dc05a5cf221b9e895f6d3ffb24b3674039d50fec114d3648d6dcf4fbc0b503658672d675c4ac64dac4db4615d011e82bcabd9573fe9e2af224103f99c4e6e5acd2196f1eb2260fb4aa61c298f99c20c4ac1c9e70a9a9e28db441c3adf2f2b3a00ca3f1398b5a112126fc3f0e2d11d40db36d0aa47d59cf8ece36df8daa854509e546295bebf92465f32a7edae6af4218b49781034329c22ce9e87258216b4a901b823a227e46f2938df336d3fe03fdbff4efc7b8ff8142b4bb60592abe508675d04081e5eee99468971fd49989eddf4648d3948266b08133b8c22ce3523757821a05f254cf5691848b1532655e85fece5eb186e87fea61936fa63aa047b5cb77c08aeeb2991c26619139b951ba4c2ed487703a6123c9c16d7b6cd3a17ad108fbb7c79fc3706f654be77a6cd8a5213d3976b1a4527144e788b712f37cbfd5f4ea5aa5fcc0f91b98d74ddcacb83fb33e039e1b88811a2138743ffc0dc5eae46c688f48c0be92a7094f92c2d4bae0c1dd95d40ffa113f27b8fd1808178be0c3bf77b677df2a17c9443fb6023c9e43c48614fd7d09a904e7a064125f8b7671fbb7529169138feed4bf3e6c215947efbf44fdb5eb1e3a5700fc8bcd1cf2a393ed438e68b607a1061e6cbd46a0b4f30fb4a492e786c5cc6d4f80542d64d0d271308ba072deaf7b1ff1c5200a2bb24c68aa2a5cd07052ee5760e0ede484e0a9c482cc74ab564654787e1698bef1386fe446106af25cf2fd950a78f4b521d547c83b6e4b6ef652444af342e90bb5761ea0dbf6b8c315996ed3d3a1a9d1e5f2b75ab18d0bcc87ee639299a248406d9deefecbb6883fe81ad12f20d80fc9b3c8962cd84e5da215b96bd457d5146aeb36d08185b2ee021fef7fdd43d0555c0fd16e7b66d1f534ae0b87f6299fc3b8e70236f39c91601564a5c2b3abce248ecd5450096e65df8b69de8b5cd963127f207f0df538f990bf29ff0c2930ab8b378b86d2619b150ab4dde82469e40e9e6e503182882b03442f92cf7449fc2c4b2f7ab91cf5ec57b8b0ebc18b27ad9125da57b6c139edbe7495defc73d68e71019b2b808a1ecb89fde58ed9dfce8b17e072170983e3dc3551149108582b95b2e4bd9552faff0bc7fd13dc0130f62a967761928dd62c9cae970ee447842a15baac31a280b443390bfefb7d4115e8d1c6458e1920485985635b75bf84b6af5226dd9b36c94bcd1a5f3ed99fc3e5adc6f3c4a592d2eaecce02d0e5ae97e6c4c7e101d4138e526fe3f090123c6df8596505b4d28c1be9e0c3f83dd4ac07946617eb553f7688f6724c8d8d34281a8c094740170280cec80b61b07eadb2c63427690ce73233f18593537e07266a71523688e6fdd36943d015c1bde058ebf5fcd12ea00e6b41565d062722941ca346b5949078421cf1f32fd38ce1be52fd65f2e9862bc5c57b45f33581eb72d387f0c212d68f85baf7e42058e41966429b0189da4eb4e58c1104e59d34eb0678a1385c38289210ac86f77cf8bef670b9ed04414875a29c27b79bc97e7febc40c39cc8e201ca56b25cd8c96f1a37ff688fd5d55cf5232d216283169b51cb41c631ca323056f2e8f74d5178a83b3bf43cfbbbb40f2680f338a89b294d4b611b0f275cc60e99bfcf270cb761c1c2a6773503a3c0e03b2a858d0cb5f81b032012bb0e15add080cecf19bedadc4d0c7e9d81fa75b97e7ca5e1c9eec88bcd10afc0d8e48f83aee498633bb260d731e0f900a9b0ae3f0d6e57346b8d3d8019bf079b4f909b6dce5718052416de8b61e9ef317ecf2faec5a64c0ce4bd5aa72b79360ff9b58d4a5f3e0648000d90a947933b0fe71d81ebaa96cd4c54c5d42b941e73423efb1f6626767f0e6dde52cd8796b0db31cedaad75b4ff72b83e0e9ece164c4f4dac170cca65e42db8b7ead0fa6e2f0b2d9576c79d1d73aa4b7ce4b954958dea381a65d4287bb1e02b7b88b33b2f1872d92ec6bf79fbb726aa436434fc7f2e79f0ff8bf243e19c08f680a5012c3c3d0501abb46026c420e485166fff457412a075086266b854aeaf5ac3a300ff5501bfd7ae96ebe56a5df5b7abb5fe2d9bf7ffc0005b6aae9dca8380a66c8c14e884f9f3338346ef1daad62042d09cd774b43016b0339aa208c5d6c2f7373797202ffe680edce71d684030e5841edd57cacb0cd596c63515a1b992de113fd2c8330840915d3409f608c8d43601f09dddeda6c504352e4d8ed932d8b5076a557fa2d87914ccbb0fed61c1f4d9950be0900b2212a82abcc4d9f4466d1f5469939c1e35dcd2d124623e2e1aa2dbe90ce09b958edc4e60d7e7502ed16a8a1d08dfcef84eed8a93d6940441ad41e493ec09abce869a8de0a778fd8df55cd1d9d7f053a72314e786088abdf968a3b1d1427e52427c2313182f51b5556466960017468a35ed2594280ad8493a5d3503ee4c479fd4c8db0141fb6b77331b46fb228f94e213ad372c09ebfc8bbcc79eb074162b4694b7bfb8444a4938a80747d2c15879e28e3cf44a8ac2ef8c5d9f93e9cb42f81cf88035dab96b6c078bceb4fb9cf293dc964b0cc9b722a84f3423bd4fbc57ad1f68a8166e86da595fb3b7a4dd87190dc65756e0f7750b68e3f605def2821619fb4fada9cfd1c41343dd4f5424a1911ca709ca745962a484d981db73a23a85c046a3eb73cb48b085d3286738e689437cd4976cbd3e2c5a4a4e385b3aadd09b08859bcf5506164db33d414caee679c65069543f1db8b242dc424af5a45bcb5ef9b939ce94e4dfe56ca25702d7912c38dc44d94670d90109ab685ccd59988bb7e932ffebc882b7dab274065578c041591d481501797b4039da17684a7242622f4390544b05023d3902949d348a44d9ff421d04a55395cb4248c7cb0f13b697f1423be1342d31fa9b85aab70c16bc62eae5660256d2472dc908768ccb7ff02cc84ffc6059752499711338e41d37f8751d84eec47a51c7daaa273e19c523d3d97ee5f71571def6f7268f24afaae71eafc84986eb8a0bdd50fa553c815939a4b56380b22b650fbb989b525d2862c5d420c83509b5c76b1a9a2105b45c2182331ce72e8f1804efee93b1929338f"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a89834aba90aa88f605981578667395d730a408f3d112231997200c28865ec37a4a1f044c8817949cfc8a4fd9028832fc406f1bb919789f2099629c2c8d6bd128de4f51c02a73c49dbf17883ef90a9dbc0350aa67e024a893e555b4f989780a45320af4858421346445f66aa86e4954c0bce0debc896f21bc960e4fbd4eebed93e943a40387210ecda652c36b6da73570500adae1a2a03284dc47f1e370570a07007d8c5a64089e81e2c4d45eb6ca01530884070d46f4605ffe139457d5155c8e9ce8f201715ce7b9d18755304ddb6871551498985ab400cdc4349c6b5ed10b76b425e70376e39a6167622eb5d4b7cbd932aeeaca53b3e28ea06c44780b01684e66eed712559543cea677f1d9807e2ad0312c42e43d399302a0c4c506da7cba37000c3ecd10b58922889e5c8d31a9882ab8ae4b69d3d3d3abc6450881e9b79d9e2ac51085f61ddcfde73e57c1784a6a766ee2bc434d4973a9667c1c8e00eba0c544a36c593a764f519de83251ec48fb45a63e00ad4aaf01d1a295eda0eb95b27fc364c33e3482f4e5256cd622242840d0630194316033219c3051258f548a23c08d205a7b15199ba8d6507565d06a1f20db367183d56d9dcfd2e12c36bed83d239ddbda9efe8507451542942033282bce486f002a215c2ef599a6619247888a81782b005acb3d550988c1f22c6b186038bbfe1c583d165588e00c7f0f7e462a778e6a8126be71ee0dae7b5cfc6145aa6e65c8c136d34f7b45252652995898150cbf177f47ca8d16b583ce5b0e809567c08b99c06095c879b4d945b13c8a62429966347946b606dd78803a3c8113a431761dc868ba2e2541c66b39f30ee21b0ee3fba5eee922d56f49ea60c25a1094381908a69b351e325357d9b4b9e2d040d8be7795891ad46a334a057b0aebdb2e5a9cd760b02c774f60df240e05ed3708840b1663cb435adf9929c138b9fd15461d86328d5895d8778ada79d9b567386a6302b67b4b99a37f4362dea36fa2fa1f1ee2f4f8293b131c57595468aa5ba62a03dfadc9784c8190559887603c4b50b7487e795285705f07f90d8a9ca50e4abf0905d7487f04549132cb3a62ac2e490d6d5bfde20568290b693681218426fa0458eb356b198b41bc60505afdf7219ce5959124e4d1a56ba63345f91ab39afd970997895689c8397c023b1c8b774f92f0e5940c764abe3bd609a0d50a98dfe291e1677e6232896ccdea3d047f35c558daa130ff53cc66aa03ca5687a2006cb7c8c3f",
|
|
+ "slh-dsa-sha2-128s" : "0x3345627b00d77c13ce3ebdd12964c45d0bec4dcaea60b64fbf6cbe7b897b8136"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x398665ef3725ef330b6f53d5f76d657e97169314a4005b2a0d60feba61548a5feeb57b8c985312bebf8466f329bb42c76e604d7555168cd6f373a22b3827f043a3224851071f9ecb55386243392eba25baf906f8c035eeac71c9c523b5968d7df4cc7dfa52e4919bce0f474a9cb04fbc698260e4d37114ecf919434117cc9a0e7befce3559125d60c2a0e93a9dcef72ee54c47d0dd657b45dbfff4b586cf5b9e4c33ec8dc53632040766a2df13ccbbe6a649df9649bab629a6a5a3cd33b53fe7e20ae515aad9db894e75ffc44f786ea2b054c75e560a31e46c29308451fad294989d91c0883125430fc439d648d49e9457b546884e2a471dcd7df66ac42565c017fcee3190a09cdcadba95e836bd292f83f9b2c4ea08fdf6ba44d856a6c375bde9083bbf2b6d89e32a19427a4613a38351f448dbad1da609a551259582d8c843a0c89d5b3b9f85b24fc469896e8b9683abee444ef7288c98561f4657f236e9142de5e7a98960ef4d35576fcae78e9e6ef5dd28a19435c79b9f37b71dd85c070ead1d4c7695b763bbe8d689c566e22a224902a24418548b227be8736d8cb98c2cc20a3042759e43935409ece39c96f7eb90516b73efe4732597e7c088e9185eacd08f094b4311c2c8f4cb770b7a7b5fd526ac44111b72a50a0b7fa36c2c9bab7d4ec39286bf509bcb08ea221fab495fd050b2a83b1bdc308405088144f649162aaef2d71f94db507628ad673152c29b05fb1aa3d1a68a867b6472347a54845549f7cbec83328f8c71f1d862195edd15164d7652078d8d4f5c0d2419948d13d204d3d4f998f336621b7479c526ccb629abf3b0e3a0eee6ab363ee7936117e4ad8445a124ec2215298f2b38ac95c5d3402f3c9c1f0d34b4e0d7dc9c95dde6f18c1b59676615cec25c340522153a75767c560e6f7d80",
|
|
+ "slh-dsa-sha2-128s" : "0x6e16547734391aae71d29745c3ac8cdfbc98f07ad9a8470650f0a0085883ff970643e21b67d6ffe83653a99f2198f821cc080dd7f0cd1a612ab5c6f18d9903ecce34a5cdf069ac66483448219c06b131b377900b999f9aecf637713feedd8c7d4beb03ee11bb297bf4a97959ac5c85c0c83b48147fa9a3be7543ce1050394e83ed745f9ec0c555328d3786da46acac3074c0611667ce5bb4613436dac210c2e9cb186e9540d7d43ceed7f278363811083368d50f6d258a46a32c8df5d62c42c4f6f34c627076169428e646774dd6dfe6924e2240e720fd4d53dee8f880c782862de1ff96fc5204a17625ca008781cb120f74caa37a36dd20136567c05e8e7723a2e21569f065d4fc631811ed0b2d9bb67d2c82b755d14cdeaccb797f207427d572419360af1c443fa68064a653b1e21a2b83fbd93e38c7cfa5046eda9b86c68f3855c61cee9f799ba02e611a1b7df6a15fdc4b4b09e51b3b5e1101d0dc90a213cfa0522e93808fc4ab3d8cef74d279b98069988f6b8c6b4c8d3d62fe2a5a62f1a7fb0fbac7fb36529dd85416a330f35a7e4e161757a83282ad50ddf92c6096cc1fe071952dae4540e0c9d0507d4b61ad34751ce17fdf2e99c3e54cb523d3ffe2cbe8a5c58b84bdde119175e9599df6b2666a7721e246305457cdb5ff5ab4ec9d04bca439d59989253bbfd9a91cb10a9fac3134d85ef28f1e4d4f884aa195216a4811be7617c0d6004c7833088851fb7758aa5aac838ddc5e3a51d122fbb03b0b5d0a3593b2b97eb69c2266eb236bcf3134414536ff36895bb081e9fdd2e5a9f9ba71310af0fa126eddac07ca67020ddd4caafc9b102afd4d0bcae2a957bd65d0a15762b98f4dc7b548cfb463ae10ec3da3b5a4e9976b8f05405904aff74d3d536f9a321b41e0c1d5e4fdbbf61b42d868602e112b53552b8199a6618723e5638273822fe0afc5e6fe068d117bd5af3a1c1e8bb4ea9ae639674b51a523d19f950629a76e9a52c673dd153915863d0ad166d357f8d23b85010aa0b8263de0f253a0ec29b0973af15e4419d965164b5fc6a0e782716d86bfeedfabf4d9705e7093373819a814a45b245cdd13a667b31f1724b5cbffe3b5ed3087118715a0ee68af333bf26f1ac1ff13eaad6a5edd5e760e89518e24a982af4f44386c6d92db7a2229bc9c4df23274cb0f10d348f2373a79f55ee05e3dcb256df464c5f3e54ab790f1fdc585cbacd93c775e50bd02f451b69972728bdce813b46742ebe9e45d45c8bc23d4b298b5956e03b48c0a11c602ccdebace8f92e2521cb346f291717cc1881b0fe3a2e23d4ac694b7f1cd296b32b7f2f139877a129079a524d7e3c4f9c36b5836346a6944c49967796d8564ac8d2ed5e804a14c655ef235fcac5a8cf0372f7df952af0de7e4319089b54ea3f718b539a9bca631ea0bcc9259c64626d252245d541d90179364072b081d70da0a7e561ba2902e8ce864a398dccf55a4f583df7b6f6ad6738813eef6815f8f67936b7b842ed7dcc48808156d236d70a9ecba41994bc0296c3a236f2772c747db6ad62723c4457bf8a2e526f306d8012e04adcff0015a88167d199029ecbd333a6ea35f5b9dc2eaf11a14fd09b35bb2842a4e610da4afef15f332d5d1e82c7b0b452b7564eb45193af060595975d496ee59151e3c0f1545ef2694eeb1a2e38d4e008c0943c8e7f181a258c35e5068df39376aad6ef356e0010303d9a0dbcab91dc708b8e9482f50aa18f88f45864d539dc0818148149aa259eeb270a474b0a117de91b6834672a5cb4b5fb7c2ea0ea7e3bc9884163887986aff1cd89c49a6ca417dff067da528dd33dcd1f7db96ed50820bd72dc41984ed5c767478b79d8f61cb7b417893a3a4451129525a915b1e999086e6db74ef627534015206953ed3a5e2bbc5c629b00f3f3b22a37519426c20b2a10c60087ea32fe606d81c6457a02bdcadd8d56360dbd278ced2d4cb9af64af4ec77989475882f3c1c0b9f9e0b6528b9834e34024dbbd64dc19fab35f3bfda66c086f4c0ff06a29e9fe881340d1c0719ef568e3f8f683282b963005e93620c01de327adc0af4ea7f968fa987cb8f38350ebbb3b91192ebb009f9fa85657e06cca6f71edd3d0dbcfafcc11b908cfc38a08ba288910fcb14f97746ac20ff6e6c43eb099d09a717ac03f5e0600f0bb611d6972626999f5661e048476aa999c83e3f476e77e7ae09c6fb7c343a196e1846ef061be75fd8b662932fdd2c7d8784c6e498d4d828c910eca00ac199957fb44d572d4bd2c599fa6c7c2a166d96aaf4959c561d1e9dacf502f76b050c836194fe1897d54a017944a973f49b2ea59b66c24d18f13048e093e83af249854da9fd6b4974b4db3e8e65684b3b6a0a11d942ad5bb667460dd98ab54319cc2ab704a7a57c1583b8289477f5557d2da684aecf66eec3a54da742e2d24a6935ffc4f439d4a8abc21921087df93da2bbdc3a0f61729b397faf12bfe59c85a6af75c9f4ce4af19239840b57c3a4ead6096f2910da23bdfd02ee4f3676897f475d625d0e9a9cc930116bb2327232dacbd0ff32cfaa40aed89024b9ccfacdb76bae77a87b569582442ad2230c8fb3e0dca3937dea5685c46aff9ae6e16438e0e9ea8ba299936a42d68967926edeb3ef955d95c5a0b74a13edd280bdcb462dfc2d82e7ec89377edf6760450e1ebc61f035fff661173de5fc80dc66b8e3d38c67f4ef8c25c2c5626dd2875e10d870f12b3f36f749eaa0c82e94b2f30686cda1da606e0c815a35fe6fd671915483e1b2b48fab000ae560dca0119be7a0a3dfb347ef95c7fcd9a78e76911cb5bd438a7e96562e437e32eb399782a9498ac992716bd9f3d7d4e35a1f1821f9008f547d171ce2b69b007b5e377a3244092396acf958932616bc5cb95059762f48468a94f9f897736b11bec2ce0af9ebaed9add43bf5c262106a96083ad967b7fcb127012b1b37970a6be14cd9088f6ea927a66a76c35e1320452848bf7496fadbc613b2e122e55634f0491397ee5d211d780971998244f303802d7630837d05f3dcc588d8ca32e02f16d2297aa577576ea5c1b90d6d330a18444dba772d7aa94d0bf2000d598a069d03e7873f114cab9174af2f28e257ef2c0e44925da7ccb593d6183fdd37a1abfd7107ce02c655e7966286b72d65394f312d72505803bd53621a08100a041210cb912d5aef260b84e39faa7b5d8a539b6392b32ce6287e1a619804677b3f69ac46fbec010e726f3eb3458433e68e6417ee375dc70c2b2ee16b2cd9b228d6a46f92ba66a8c5b08cbd284dd759478c9f690c5e1e16d6332b5a0b9aeee43ac8ce3eb0c3eb6940b61a65bf7c3348d8dd15302b8b7bf6b6257e074d0af3eda088f7c22e6778c8cfef1f15d9f86c76a4b05c9afa228bc4f116ee8adb959b4ed9afb2307f2252b10baa436795028629d05277ea2722ffc14d9a5fd56e6cd6f0ba218675df025e50586e46429f1c6028e305d22b5479dd045d98a93fa30de08bec1576ea692bfe6b657b4be65578fa2dfcc197212643ec9a1a8de5971c07023abd8767c528025281f9854145e3d9c47e01bd37dc3a35b76639e4716465b862b705ebaf674a64313641de333828d75c16d4f6ebc4193fc2c92e5a3373fc79dcdd8505a8ea7ef8be6ffcecbb2e80017b6fe401e49193ab31e67a56e8163cce767abc393608e7485f41983ce27b9b1de1a0281f237d685d401641f860f8f11d10805fbf0c7125deaf583458787c6f2850b0cc8c62053e069df241192c6af9018158c27e30574a9025af5af73bd956bc008efe84b31fd9a49c110b803947fc939faeb773cd3c33d1b6a96fca0c079f2eeb4e3ff768bbe1cbada9ad22c2d97928389e5f7145a346931e4138d66319f0154cdf3b28cc9bc04139f92e421efb522d0639f02935e228d6eacf3ccf0356b32c163dff6b597d51b64a13c8c93f60f150f445271489db644665ed1208c025b35dcebe82e73034561704c602d1b24e04c08e4ca8fab21c5136b6d4b7af05cf8ed62961b4bc1c2883154116a0ca8933e36042eb98d851be695d8c4de2c2530372c606c93bab254d6b00e59fdaaec98c56415da26ea8449061e12bd22743a1a0e0e1e117a4a9448d75b3a9dfe6f213460ca639632d404af60c764d91405391137ab9ec4e8519d11e3dcae18dfad0404ce14ea4dd36dc3ee24b7a15709410818ed0a42091a01ed9b7f39f7c87d60d2b3dcbba880001a519fb7de152ec06c73d35c08b3e375b9186752931b6108a4b84189fe07a7165e18357a94962dc2761f4eff0df829427646d2210b55915be710e2a1bb413df2055e7aa0b0b9a4067d35881f22c08e61b587a59ef82ed4df267afbcd4c62f22435167f2d7a4a939eaf28a6f1903c8c046b2d7719b7134834cd56964ba860e60ebb6fbf4605a11b52aac2d595cf3b6533fe2452b65dfa0fff71aff39124a88e3e02977d6063a8370f98e3cb8c80f35260a8541b9584b1d2bcb315b394d7641ca56539b4ca8bd9e4fbc594b0a3bf1ed678be2f9a18d31d610b55ee175514738717d47e4821150a799ebce655d0c75228c2160aa1936dd42f9923de2ac97d0dc3ea062d41d5beffdd1d69672b73490d6a5e14a655228bc39ffc8f1e862fd39dc950dfe648e0ff87807e543d02c40411ddfc6c1f8eed733750557c9f68d830c83af737c9d8c3ff0d23987a8e09e6293d707940eef4cc838365775046af35dd26acfbb4264a9ab84818a71c5a13d8e615c5675656671e5fc2e91b682e91eca76ebfeb1c09334e962496f583affefc56dc144873c79d4df77da394845fa29ff348007c8ee7f23f2944c121ee3177879e6938eb043a0abb75991b3e789571e3eff009cf089acee93612e97be85e1cd83da9ff5006c14151afa67fddbd9262667f98df52dfded25f28b36fa32ec662cd5a6b0f844030dbe1c87e9e2d435fca1a81045b8de5b8ccc411a839064bfd133731f55ee2ed2ee727d9382d130ced8a48942ea295bcf75fc74e24204b808956bfc171392f18554764aa80e75a539941d90a4afbce1f981f0c35bcfc78330ecf3d416d0683c7682cbca066a10c43273a0f85495cb4916ec0eee9952431a11717cadc95c7626436953fdd5fbfbf9ffe329159d1bd79499807796d75c458c3e3914d1f73f656e9fa273244615710c3eee84553a7ca0250e97a0b8895695bf86408d2f3cb2fbffffd62c8583af5b25b7e2a38e266c9623429f8d80ab8fdda6774df598f966b86ac228639af66cd0e3ee7ad7714b4ecb42876c31eb2608fab0c6ee26e97fca305aceeee80bbe22cb5e9819322aedff05cdb78b1fb3060ef18ce0385ae0fe6803b414aaf0b340eef94a7517e5cc3df4bd273f92120b8ce73281cab96821ddaab08b41b97708dbc7d0edc49cb362759905ce8d42743f83a0d75878596c4c5ca878b7aae6fee6ca7b20f2ee60ea773499a781b958f4353ceb078e5c04b0fef3e0112dd0e3a7ef19e4c63a202fdcb8ea56d15b2fb0deee4198a19c9aa59c1ef2b3de73f291445c248779eb5fc76953137adce5dff20f2198cc9e729be4adf385e0f25f67f68c04b4cc26987c133b987f477d89977621b8313d6d18a5ff6a76c73ed608f5e4adb860e2e8a6cdf237d4871a98f0c448668bb42f29ccad560fc1e571f8abb3c75665a65a212fe9d2c1c48eae9b92bd0a8b7b3d2fef99ffaf7942f5834533a592423d2cd66aa793e85bc8351876946a1e49e13ee374609932ec1af8d4d3f52e00f783368aa2bba882cc91c5fc6eeb657f3682dca8e9d63f319df3bd1cf52c511f600a6c815e4ad59426d9e1f32831dc5d8b0673c7c58e8bc1601d241bcb76c1306ddd5aea847dc903f376bc4d8e73a55f0a5ad331f57bee70533b29e6b8493d9f11ce4f27f9605f693c05487bd43882ebe8a1090a95abcfc186d74a3708ce3351ce7226183a21c08497dcf52727b7de08ad6a970b2c9f314bc7b33995ffc77a9a36ab46c7a05f61315d18b3f2217703be5753b4ee1670eba3af00e90a94664039aac93e89dcaa59d4566bf286f33c740feb763d0a385855f4410052c52abcfc972298ce03ddcb2e65dca251afbbb75c516ba77001dcaad8470f61e3391c1c68b1b7dfac9e50d53d2ad12876ba96419b39d7f94fd88b58ac1c123790bca733b12dadec6922384c6f3b7284334bed918acc06ecac7674428d56496e9d2e8f0175b3c7e384218380b6d59dc93541ac0a7419eb0ced7ca8c12a487fef9ea50280b7f7067a8855e784362e85703f6b848ddcd4bd31293baecda021fcaa7198b27d37900ac192d71de4e5124089bc1c8234fc455fe71171fc44494395b323fe3575ac720af5cff428326cca56ceb0c47e20e1432018a769f467405f5a8b71e15e0bd32f027640212d893678ec6fa16e5c00bf5c0eaf2de0333126ebba6b2306211cbc731a6baa8fc5a64a30141a8bde237c217161e384af3355b4a253d35766a55cc69be97abead95dc2ccdb4d243f64aa6d74330cbb2fc9fffa79fb6b6baf99e5ba9abd7966efc1586e72bd25f6563fbe125abec67f24e3510bcaa34c49499811ad2425c25593ff362c90c5c4fb3c4c45a4c63c46cae8cb1759ff2d82ac2726b60b4f094b6344191f3828c78d369956b7a28f650f63260c2dcdfa66d1df4731866efa6a335281d1cf2ce3635eb4294c8b2e1d4b7ced7b4b58a10d693e9f5a269b9d3451198735697af3a7b4b630b835e3b56e252f71f9aa6dcdfddfae13668bbbe3538d5aca766dbab6655c4aa906e0106640d21c30f1a241f4f5dedd526e8f579848f1b64808afb54bd2737a18d9a0e4a078705847b59a1ca4b2b554d03304daedca50726cd23326a6507393b2dff27921b5d7d322cb9901e0efce9bfd95039bb3bf6a99282f9dfb1e90289e986a657b3aa212cec6e611423eb3e4523f4723302b1b4ea5db2cc3fe3a7f0f3add38eaf228a6f0c02b9237e4078b438c01a0856d64053427af9f84eb04f022fd12986287b48cde73554b014f75a04d01f7d3fc6285347be643ce214b72c911e6c5360909ec590ffec8b4395fe271e97af852edd3801ccf04d3ed6684c66c67278cf331ac7c9b748e2dff377cafc7fc6732352245aabc9f5f25cc29d8f7f211a88a7aac750e488ad0304b7907bb063e29fccb16dd7ca0b78fc3962046a83f9c7138d49df3b765df47829e5f56e5155dba194d5128648b92e4f5c11bdc9232725faea4b87d6d940b9bd7cead9462736c7ef605336c40c9a053a000ac390b6340dc85a6905d35dc83c2d13786d233952ca8777b5981b761376f4ce2c5bec0587c2b28aecf39371b8899d227dd58c054aea7257dcfd838c32d6053362842a0baee7f967b6a4f5e1cac240896a8ec8fabbc4a551a55e674dc8cede1b9cee3874ff9fd3b91db433a12e78904aa3ec84d57a0169f1719297b467c46b278f671f74b8bb3c2c0cc2a093cf93439c1267e3be38b12e9b5881c27ab47bb01397c6470b80174ede3df34ee51ac116bad6fba58f8b8e2c7e0d1dde184460a5bce9e1d853d11ac017001fccfd5b767afb69691844e8327d39660c06b8916e918f5587f5abcd0f0bc45328ac01b1ace66405ed6c7a5080f5795f2ba0c0d9e5d05f462d89aaa230f240fa47c5c0de0b2099e93ae8c0f94a45f0513ce2797cddccb5216bad88333f6fec5805e0b9474a18ff562e78dfe325c1a6bb3648b41595690cab5ca9805eaa8e13526d036f4233f8181aa8efc76e14031d343bd5d9023fd6cd6b32947e173807883b6a964d398d3fdf9f34a44bc5fe41c5d72ffe5fedaa13fa1da68e19656ed70771529cfe822fc694be1445c79a041eff9753cf47a48ebe9f2c9f1546117b97a1c2bd6e375b957fe38cfcbb29f8eb726f18bc6131b1e27316064980e35d95fd913583b9735c6bfb03ec86e935024e60679a61d972b4aa296189fbc268552acb6cd890c68e50e325719d2f2c99b8105bc92fb582eafc1d618b4e88070e6d8df4924a1780f63ee216c0e937073725353b0c97acae72ebe521fb05fa78a4d6ecb7ba2b860190b6a5c340c83249919c26466c9cf4a9b774fc823141f65196df32edddad59fb05ba24738d81734004c42a7f92f5234b7f4fc0d605b032b08eda4cdfa3b03a3b805ecf5e4ad667a8cf399efb3c1d6822d9d5bb5eece6e08a515cd75c4485537eed6cbd55efb0a3d393d2cdcf44846f0c27cf6a664c70dbd54fd56b20bcc482de2eba84163375b1bccd43da63467557828b791dfb0a976628206e26e9eb10f1e9b9fc34571cc1a38f54909a1ee0b097e0f22f3ca58b56c631708e9baa52d7eb551bd327a6e0014fe98f04d7b0544fadc06c16a5652ea16b6c92a014bdeb2c070843152847293a0a925cf3c22bc9ac23464919ba6340cf233990690c94601876bc30bd5283f97cfdee757caee7b7b41fc265fb2ca9751e3b523e8498d665151d1c67624a084571f6c29973e624703d2e87f1ae5a5e0dbeeb96f46698223e063d10d85fd13fa0deb3891359844ad5e8100036d9b70b3b7831ae78c927a5e2c2ec62992cc424894ccd6f064e9ac307e6a2dd092deed179cf60b4bdc6c56c32a538d477d7917f7203f898659104ad5aab3e520a9f21d9c01b581cc968a68a77648cd95f66b5a1eb1b9d60b0a73c2eb05873f279c4ce43409853df2c8db254fd5b63af900c764ad4a0aeb4641e1a4e4089967e83603cef0317d06d1b990354c11b17c83c2a78cb9152615b9eed33e20f61a83179748ed4044a65edf285b155d41c735a883a481fa07c4941865b86d3cbd54c345d7933e32daa90a1291211191e0a3a5015f0f60d2ff07782606c164485aa469bc97f74dbf1345ea631bacb972be00547074759fab2b98a78cc43b7e4fee587e40e23d9f8ecaf03337d47d27bce633ccd97c0b18509afe35d54b1761a4ecbff6c44dba5402f3111eb671183b5e6bdcd69398056b980c35628f03214e0cb4ee5364e51de27843ad6c24b1e972889d54ed2a31d74000c32fc90b3c96dc3761c9649305c5f5e75f5b5ab7eaee213dbdda1039d4f3f450c77e6434752b74a55c42c98719836fd91fceb27be449d65c89a823218e882b987277622ce62fd0b46130760f10be6b49ec57e25cf6584a99433cedb1ecb1ce25cbf5e2b6eb716c12064f2cc45f4989c4c1b6c1ebd390c44195a16da16340d3a8588754ae676a990df1eaf04336b3252a5177ca3b3b2afd8e7555e92be6f6d7e64bea52c8d25adce3c580b5731574729107afe0e1025e6da2f2b05d6cc223778ac7de1202566098d43d0e4db6df8d242b57353cbadc0711030c6612cb92a9f9685c88856a0739e61d08c8fc5864fb9d8f41b27b43152ec15b3307e2c6f20e00254984e6284763acc977d9e16ffd4ca8be3ba7a289e3c5863371c132b8300f59d50f9efd344d1cf51c5ac64f29210740be2dfb720397941e2ba939e31c9ed563a674628b6ec3c8983be01e41eca61f869b920bf08db3255cc04a1f459653a4a3c204e6ec5496af1984f5e47caf56993bce1124bbfdb5d7081895a96170241307f000ed22ba92d5f5d920ab39d3ad1e288abb76ec3acbda6a7779be4c65e99bc7d7d5aa57d08ca1774e0fb146cd3a894beac12715bf322febeb256518addf26df507db3c79cb2883e6bb1e4716e185026cd760c76038d52a2e0695d76b3bf9da7df9f4dea5323f7dddc8ea1a0031851928e354e703651f7a21df505a4e7f9f7a8a398582aaa9f504510c0bc6f9af8942601bb3a6df3faf2e97c9df28268e1dd466857d413fa0bab4ff017f12554dd317455d6c716f9449c5273ffc959f147d7e0da0c2eab432b83f96f7d2de7b1ebc41eaf2128f8eb8f9c09c7b3fb4e95bb3424b216232406b81abd4c0afe11835a8425304376b08a4442c6eb0e88a51bc67a49b143bb35416c9ce613538483c091bf181d322efe10b2204aa0f0e01507a7cb809cb54b5cca5f44c20da32b2b7ec52098e53de672795b68a44ba667bccac558210307ac27bc5c203a2e6a264e7cf3028cb4ed41e29bc46985c1440187155b8bd737fbf9480749d62481d805463d75ec17c7ba83c60cc7020fe4b110ab1a248f6fbfda3e5b8a688a280f87a53ea7154311951c2001a7894eee171a64cba9b19a21e09540dc5ba85b1b2880efc39c8886dee72e64f045d00d99a90ffc81fc957ee65b7bb93e113717e7e7a275814404198f9e9d33f45335908f1ae917e0322b3d12c3d298ee814d22f8a57304faa93c18a14fdf53f05499239b66498512a6856ea194705521857a1724bc2925ba34f0e2707c84ee234c3436b4d3ab46cab863a28a011236e564ddbab3d49baf77be49ff2f5f2ca75252971a421aa2d4975aeacedba6cd3629efef8b2322b516c60ecca2541112b59d73b88177cd3be06163a463306cac2c0c1b11f84ab9b2fb6ab776bf0dc0fcb381975e4c1a0198b41bf6c1587bf6ca7272d8c722a581bce4494be5431cc5e3038ec33d843b9049b018fffa03cb3ff58e5da6bd6d49ffa6f776a5c4fee3cb258c4bf92e5e4079e38437f321e0c29d608cf5f69129e705e66a7036d67d43fd4a2919271fe07052fd30c049b793d2af0dec2431ea687077cb7a7a5badc21fcb0c2ac10bb37247207596d33d1c2232fc2a225acb9f30be7fe6da19514def9b595929c1c0c4b146099bcd980356b601ed0701299ca1a5547d62badd0475bc76fe51d0565b95b52a801f14e1f1ca62526cf8931f0706e3a478d20ce7eb1b1088454beac15277a72c90dd95f6146f961e41caccb2cddb2cd0680760731bb6db221944eab186425b0c2caedd840be5a2575d8dfd5810c4db5403d4491304130bbc564cb578d814d952706570e56641e8ce6232a2d4b18941c35301cd5c29211237c274dfb1aae379e25efdf827ff6e41cade1d57ed229a6ba76bf98de6592e5ae3ffcd481b53071e452a0b25f12919003474bf4ad2f36138d3d7c23c89b5b41a25c3622bf1dab6762cfa86a5bdeb6f2baa9cb3ea7dfdf9bdc700f4062ce8fdf477a17088bb2bf654e2eb9ab943472dadd73e3b63a4fdcf90fffa98983130e16d512b54aa0d4acbb1604d00fb2adc4a88e87d466237ee7b0fb33e5f384656a8759143db4c377e2cd264259"
|
|
+ },
|
|
+ "rotation" : {
|
|
+ "falcon-512" : "0x39aa8af7d097a0c1c179367796790d2e6f01dc80a2936d8f1db4a57f4cf4e17e29e341b1a07806c8dee46b3fdfa567968dbfb21e510f4d269afdfbcf6df5dd60a9be3d28abfe2633d4db26f751cc26188b4ed2cac9b3a7b02b7db9574797b3fbed1a94786c57f50dd59ab32e213769521ec5926519e22a5084f7508f197eddabb3ba3a85a192187649eb4ace6b4decc0a3ae576aa6bba0c9052e2e8eb044b3874f8a66faadd717a0833791dc67f6670ee2e916f46b7dddfdcd1f0e138ab8a93dcb4b69626b5eaabbb08f61d0af2765d7e0d8e5500d460a76d2ec9dd4590b340f3f4e559393a13d88aa12501c5313ae58d1a5f52621b2940243de4ff00b4cc32d42921c5ca12246e2f0ed14b4623dfaaff4a2eea3477e3d0e2bbfe0a42f96fc468184388c8b70da9769c49113371c252748a02a789b00e41e2ae202e3c873bae8fbdf1cc9a706e58bcdbfd764272f3585185a4c8f1ea541394d55808a9db4670ab55fb32cab28e52d0b2e793398cfdccc3fdfc72059d36dd73e66c886e68b6d7a78d13f07a79283e088440d789dcf13db64a24b30bfdddf225d6c3324afa0dec9decf4d15906363383a910d446d996ad2b1b6d8de68ca7e07d5df59b8c679d089a2a81f723f3ad06fab71daa1ec8c45712c3342cda4ac84ffc58e35ccfc9cbf498f899c542d6525c8d6bce984dd25379edd7b4488a19c8717cfa1bde4a90cf7573fc06fe39eecc96a73f1d2be1c98c2e3cc590a48b56eb76b5cc6a5d9f7649aa69b9913b48e46e654c625ace3f116aa65b6e8c333af67755e5552a8d11c733e5e921085716977e65fbd1aa4aa4d0f0552815f5c63708d12acec91deff083c594af671bf90320a5f1078540631a1aa681b8ea44322cf7aa0c99ec7816f6e261f3821b58599faea28cded6bd3c600da40"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0x41f547a71d1404f147606491f3b96e49f67d4658",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09b3f618864123704b78a9552a0b068f395444870c2cbd5d741a0c565554bc2785a691ff502d6ed0e14c925eaa24c075d20949d12f369848e178d50b085e87c9b251f68b61ec506435bf5b53a49d299409f54e906daed0c1a25a63563090f6660380321e786311b492bd7ff684a2650bec34d5bdf071c49f5a050415b2c3579b2994fbaa9a97b7f24a30e7e8bba68145196e0424471de31775aeca732dad506b16ad4f61a325136a6664f439e60687e764a009db3218f706785b98b154a625c168fa2ac541b8dce39682172b95e19424b98ba985622b2a23d8db2d46a7230bcb667372a924aa4d1a9e9cc1a8dc1ae11fe88081d74d857bf63e9814a08c9ce059a4b1ccab23a2fba765086b15bcba135d0937a064b90663ec69ab521746600610bec0a6b3c705277f90d588a00e908dd075059de6c52fe05fd8fa8ba1b3c2cf151cc810225db79aae0328b8ea1e92fc67b7bde405a1442128023128a5f7089722b954f15597ebba3aa3b55ae947be1e659be52af04c3205492387b51e72746a904ff13ae41964281ebd81783528269ccd6d2a7845d790fe4cda8ee58d93de3a3ca28bc4e6e18e812c313452a4468049a86ae39d5fe156fa2a43d29161bc911d515f4cb6b625f4679e37d5b55064a16c3e48a7f3ae10a09d9ab7f0ea4dfa2fba9da412af1978720fc47185c7ae16474833c8d278dca65b822c5526bd4da67c0700166cba95e3d23691e6e1e86ea4e560cddd59af18a689c4dc2b6dc0e114f2a84754498a8e299ac17a12fd199d1fd8d5c31b0a40ef4b2fc9627d16ec11241fddb4fee6c652d0119f7d60e852decd3489cdfb75c10a18f562154e542614427ee7cb0e96b99d74eb9585223760bac37de51697d86403ac877f823451d8c60e84188a8fa6804c3a8298f223169c4c61fe443434a76d6a51ccc1d06df3b962fdba9e27d7723a8390f4672d66dc2f756263ab928d9d14f6d550acb286647ed6dfb091c462cf4756194ebac9c94bdf7ae4ac7b5093ab9cb94455dad8ab15b134d31947df478a1aca5e28e98020dfdb6d4ab750911bb2690104b9606e78c8659c2f511bfa3254d32e65aab180ebb74f9848700a8cba3a1a546b77678a17716f232e57b204157761161670bf654f182a14bbbb1c16b14b652127241167e898e097b6270b062f0607a50bb040868768a24312a8da316dbc547237ace3a160b7835c805061f8f2723386929835251945908058905f625cd9a91eea83c0f693523128c68613038e",
|
|
+ "slh-dsa-sha2-128s" : "0x9fc24e59b10d63d59b6c448f79d029745c4f27a31903ad2a6f6fdd09b3abebb1"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39916580739423a110970dbfa8b6f06ebfe827b6503b1629f4008d64024e63c71af7a932f3f29cbf08eae4cca92f36f670de2f3a0a461999f431bd5da16b868d2230d6403158010384f0f98d2b95936e0a132f5b86f5d11e32ecf3cf206ab9d26c1cb7fc93ea3468109a59163b15391795b76ce450813b28d28510767270c1c474632bd6eab70174350d329d0039ef8fa6739b2f665fff021cf669156e3797da72e5913d08c94a48a16d12b5ad7e521b730bef92d7cc277a92b3e4c9f9cfff7cb3896f93dbd495637c2a47835f2afde4222c8dd36d4d6d9cb419b5b5563bcc1a61b640e70bf2c4bed6599c5ec50643fa302c227ae56adc3d4b044926f4bc4b26d58d0d0778e2b8ec5e18b5cb9ecb6d7a26808962082bea23a932afefd0d483a9952f98ea11b629b0ad74c367e09cc016b817b624547ed8fdf360a8a06acf7b5f0d3c92448d9f7e9453a4e29222611490a7188dcd0a8568b67d333228454cd9cb99fdc9d6d945a64d8d96348120295b8f2ea9e95f92d9dddfa2a91b6ea2c44de7b605db8e3e1019dbe5cb464e0b211713cdcc32ef3631caccb48b6b0c968492a5f1288e99ada3a4d8287b5c9f46236b4b3fcfa55135f1ee4b13e3d6765866a316d8cb3ce80d67a518ee974976172f91eff1cf973631ade2a2b81134c39d0f3c72bf4fe546a7bc7d3f1142aaae3f5b4e8f3932d9b516ff1cfd827e7395d576d96cff52f00e76abe5ba3f1f0887fb064ee11096e52d441d1b4dc7a69462acb7296c489f498c456b2336f2f112391bd7e545629697bd096ab373a34147643199222b8f1b05a95bba5877aeed29c43bddecbc814a6f2bb38d1dde30c352e06f19bf52717236488848599eaa1ef17873681e91064430aa2f4a23445fac0a8c8231c8cd7c27f928ca0ebf7ab08feb53",
|
|
+ "slh-dsa-sha2-128s" : "0xe922917f6a5d9d49338e445586f4b3bfcdd92b89a013edba38e598aad56f8d10875fa62dddbce6c66865eb7d14067931d640a3b7c5dc448bf7cb6309943c2f0930c78c03fad2cdfa1c21689c6f621bfb1cba1968dd28e66ceb6cd5cd4f10b8797a53a8ad54e93febced4dc1c48fc4bf768b85a811866f86f004fdc340628ccf44b295fb5310898614b6a0341a2456b94930d086ee75f67bb935e62c739fb87407975f78f372ec11c0bf8bce5144abbb2678711850174134e6e5acc3b87f14022d158a57dcc7916a8e75341488af6b1d9c0af90bf2ea86440fd1b8001d7fdb8ecb8cf392498e41f8be5c7aaa81841aba7422c45fcc0caadd52d36d1d56cd02d027b6ed9d122ab3d53597507079bd9fb476105b12e3406c1873a8bf6a5b9479b5cab9c370b79425b1bc7616e2f1f66a398c2e38f7a9ff1077918fb3f7e65f025d4feb8b13397460a753b1999b3d351c5b77ece3751686c02db0ea4ff23727527cdaf038ff060a09689a13fb7dc902cb82844b11f8092625272d8888090e60cb1040b6cc5b0ceb6854a7fa769a77523e7a718a1a9cf56b94be12fe8fc4d319b335757c6b4807e17e9ffdbb486d9910404e675648d069c55e96894c7b2ab17d91aff88f44ad609142ea3747117596c98831338c616cea7439b1754390604188018818a5fd2cac7522b2df5e42c14e77b7383744234da5fe1a02a60e18a178751eb9c0212cd847317d64dabe4407c4a4d2ccb6965eb33699c37c733d42e66f92b01cf8b0ba2c8d737711439de358756ab4ba374e7359f8ec5838f531c984e2903026acbce89ff2935855ba5e5f3d85c82bfc3975ba3d4a9721ffaab1182035bb7526f062466895c5900f854fb52f5913591828cef55cd07d70c5805327cccb9822860f32a8e8f78806e39d36ea7be59186da6ab5f1739b6716323b9379446ce6e50345cfc9b769162ba96929e2cf0693b77a558e5386945fe5c6410a2594805695a4cb602fb25993a0359753f4ecea67d0a1045a80054664a5f589dd823d11b1e440813b3bf141f119c38f9595c1eec85ce74fd0cd69ab783ff7adf32746d3c4db1153df20ca1ff94acfcf3c8ece27b9a7819f7751028435730771a0d7eee4d5a05627e9577de7a1c0d16400a81c6d93fe48990d8d4eb942233b6e81f2606c228423d52fa012ba6de7c24ef446f32ba1e1bee5ab78e79f40ddc3f8279277735564901682f03ffbae6176aa8c2dc6871cdea56cb875f25c88d955ad2e5f560fa25acb5d2130327aff86a324aaa721874c4276667404738fffa534f26e4e0dd67a9d0e5d447c2868af3f5b93dad621f528509fa6c3d2b9a391275396d3db6487ef219bf42088433b79d34ce793f024380319f1a0017c0cf821d998871fd35d2da47b774f6c6664e54090d74d087fa43ca622417314ac0a7f2d23da0e9be5242191b9096ab0e200bcee276a787ecb770a60f975c2935f24600869822ce96462d97f34c23eaa50b443a504670923b260e1698eb12a76a094b9a8b9bc2fb07c38b03b495a70e4976d05477ee88b58e2d66729a91f0fc003e56236c5285869a6eba073b36efdac3999ca0b91408282f83b179629bebabd5355381c4435bb173598ce3496dd8616eba46505a64d29a166b51b1033cafccc0c6cce63afe4f2dff7a2cc62a909853b14b40c418d3a180a922b02243637700c87bd0268e3ba09730a2e2e20065a7310d8cb86ae6b2174454ee4c01fc86c0441cbc51f1801a021da1f1fa4ba6cc0e8e35a11a0e55a4aec60d5c98330ea1822991083deb2a80efaf382d29cd0b04fc2b3289e024814281aad94ffde1a837da103a0022b23f223e63b852ce8bb89d50271b29b5dd805edf1f4339bed98ad4e4fa42cd726f3f70c7c434035cd9180a02ac954a1173c2694f0cd59942291c34a8071803a69552d71b8191c4299add494d05e838803e5e9de4e5a2d7b0f8b4a221ce677b5b365e57284f4b74c973c72a565422b2233a5b3770cf28645a18ce1bf7cd0e726566c382d801e655829a7c5e2aa149217075014492b80533bad2c8013c382aae26cf4dc39a6eace929903894f85c8e97e4be1df2bbd53fc780c46ed384e01fb40c515e88bcbeb2005df6c152f0d169a90ce3a43c2c3469a85a456991996f6e9ffab555233598f767b38307fab61336a8d57c1f6753749d46e1b3032532a5ef11082cb30e12bb6b292d0f37806e6208d4bbb7c7cba1b3b410ec1d29dd35af7d38ba79059999992088f06b587bd9570ad0a1e2352a6133a50a3a45da27fcf63cb7c6fa98e6d3d3d7987447fc596edd9a157d72d0bb60441935481c54f9c163b985c708ea1dc510f35f9aa8768e73843ba5e8621912f43383365f534f3ceef986e90664123079f7355e5a5193b0ca1bce0443e01adc00f18f8f07a9038cfbc672494715221c0b8c5dadf7a66875ad67300e5fd662ae7b4281f2df29aa0f5b7f9f70fd3180d7875aaf784eb3da36f9fd8abfcbf2f156392cd196ab952669a531bf941b48b7d2850cb8a66addeeb1447d89daac2079094bd4163d9e0d8ed52e9a93e31a7d4f5d2afc4b7d2c0b988d41c3e247237363dc05dd16d49d159005b42ab9def7290a51beb7811e9f4fb9961a7af09fd4f291f797f8eeb05bf76884ca340af07f62f587dfcbadb344c1b350960686aeecf772f59d3f5c9f6c01240667d1fa5c3d84dae1f0dc9562543e4636d81a3f0407bc29127bf4b4527d0f6d7815a941fb53e6527d5940739bd369786e710f6b0f69b05b2e0c49bfa51411319b9f7b172fc11d901e41ec54887a0fe5748b1d2403d23ed5494b96639126c1d3fde11d85c8c717fe8b01319a9668b109e2d34a6ef5911aeb31c88b71c32a6723b0ad2a28b2d8c75087a546550b0971dde64d3cd69434914d5544a8828c6e7775cc802fd71e467e0327d692cba302f681fdf0c7425ee580c413d1a3904974e55e7ddb19de793541a7a4310e50990744b4655e72b4eb5a3a8c5fcc09a545198c6475dd26a43338753855ae4dbd845d3122b16063b9d4f1170b0fb1eddbe15bf6a0f935565ea46bbbd6c00491a9ea8288822dbfe8788aec3eb3e5e42140fe3cdf16328587b736242c2aa85828dc84352bea3c6d985ac48437bd72f12adc7fc08d03371992547b91a3061c9f9bc6c32a8555df262c14dba813ae8e2f9c732bf7360b1e94498f5a1248ca4a0c020e381d8c25f4924f91bf0c649207b1314bc0088d2f15f662a2594962596ea66c036677c451e77f051cf9c5f6b83ada58109f68b415af541dff5d6cba732a938ef4d425243a3571f475af0a456a7ea5afc7c78fa195780b270ee1f4d69fca7c93087e103595af8757afa5dd23ed17bd723c1edf8701a1b4bcb2102ab2aaef2df7cf485370d310651f6e897cd2d687375d29c7f101aed941cbbbc12ac7ad60c3147e41fffafb766e548f0e96bc911f38a6d1864277c170fae28e4b06fee1d1925923432bbe28e41f8cc19271f68196bf4724278f8492a6d5c0826e03d8dc1232c0efe5c7598b71be7d6c468ccb1077d7c8bd4630bfa4a108d58d5498e40584f6ab690e27ec8152c1c39bb70ccf7c5f2c33e48af63d536d9e7ba90db931783a9cccc05c22dbfd90f84f75d139aa22b1246a15534f1521ecb9031ff0686c39b728fcf6e0323cda56b641561a88c6f78cb1d880d102d26b20213d03af41c91ba6924a0ae17a92fdb375492fa0b514ce2fe88fb95d72e5b1b11bff99d1b0ea0832a0d3472b5880b3ddef0bc0891833adec1f7797f86fc549b22df2a0a59390a900e588cdd2405e5afea987db98554585c85fa2428cababff59c17713cfb100084192cee9f4ee3855163ce76fc59ebd4b23766b0ca7c2d59754ca42ebe3c997cc4cdcfc2ef455d3afd488474b4da2a6ba278c196616f995c4398710c291efccbe36bb724bff2d097095f440f79917229a6fce31dbd89e58696c4571dce1e535adf5e1b0942fb5d59a13f7fb4eb17647e83e587acc50d920db2951bb48e1495256e10a62a8d43d3cb7719c54c24f546ce4937e2ba7b1911f5684068c365398e41f7153cb1e2b9ac014bb7395a36efff14ee94373dd128d725dd6ae6af408a5da12ee540fd8d2264b24cc7fffdb2859ce5227ec3c3d5e0bae49b5f495a39e5d6b3baf7c967b21a55e3528fb0bda0e9f2a3cdc37904005a76b07d044ce439a345f5ab69a3db8c711d478288df2d4776d53ccfbf49a06d0d0332814d34053c98ee3464bbf46309b763114ddf1073100c34466cbf3414b4bc7b8ee73c44d76c46435c0354a71fba7d8ba8b0248f867cee79a4beacb5dee9c45577e5b423582fd261b6164de192e98aaabb47179a6fff8827221a70c77df46d01357bf27392d4dfe3b8e24abe9854d3109b533edab16f495eaae07562dfb4428cefbffd748f144329f7653931a9f65a3b024bf19d2fe04764d53730df662469a19c4bd966dc925b1ac52d9094ff7dd7268697468135000a8766d8292f9079f9bb5601193df637f8192812a9a97f604015ec15c89fee9f700509cd745da588a86c7c756bc84745c593bcb7c7d9d34bea98d505a57b31a90833e3d1e154c3b686d5d8a20375111bfc6964bdf2f815e160754b56c59fec8fa533cca9e21d4f688ed94cdab427f9e179fd308856ab7f7206d13d65cace5f8d65c8b95270559a7d33c76c81794ec38d75e2b3f9ebd1351e07da0540e3981d447558d6c21ce6b0c32bf61a3f554cae9edac7a92e2e25965037830c57f30a021953d91c8349b94181ca8c3bec9f33327caa08e437e542d4cd9742ea16801aae94e19442030e8c95bd4f23d88ae9a1f1cfe4a80b046f2e54885c54572a215f17bf8359db4edc830c48941153bdff79a6777a67a9ca0ee3c5d2e4497871f4797974c1d932fa3417b909ca5b29dfb315bf1590829f1cfad84b9e068213b8a6e9171c1c41757e262d371b7073d1b90fde5bdbafab76426f486581bf52fb2a53df2fdd0a6d5065afa6148606a3dd311b155dc0dcaf9f741a50d105053225f1c223ad0fd8af47d27db808cd32f733fcc8e2655523fd36a906c6e6a1d6eba56311424458b446bc1b77b866af76be210b9a417e87903a1ba2e431c176a82cc5a71a4ddf29350efa6dd8d1707d3884b31b9b52bc876b6599f40b077c43d815d2e02ba043505abe7ecd7dcf73818ceb77a09ea4e582616f4af11133a80429edc9a434f3cd2b41192edad842b433ee7936fa5c7680023f0727f4337c53912fdf6fc7e6d5c0dda2e0a8722d5b0565ddd8f9349815bf38e8615b5c7ae35622d7feb7907e6423c8aa7bdf57355c0353da377977e180b88ecb1faaeee2d7142f342263e636eb99c78af9cd0ef0314d9b57fe1176bf8b13c221b5a05c1f876194ac26c35b0ddd91a2130276ac402314367d99c2e300a33073c06dc18cdf5361908d58a9553268c6d0ba19ef6f6d0bfbf2b1e2f5d284c74695189d8a3236e927d9598a4be253d0492f98015851be3693b0c1b3c4a73a95ea57c20699240887d501db5d3525e787dd1a583c2a831a9b59886c873b8ea5dcec376ff37fdabfa21b74b3968008dfd9784fec35696779217b4f5507ea15852f751af31243dbf857d66cdbfb2e290b52f67312fe5d93bdba25b1b7dfb0f3488974a7ff0e437cea09d0baaba7bbd2506fcd182cf0dabe7c262a823fa1dcfe00bfaf7cb5f54283763a45134dfabe9927fecacd648ef767fdce12d570693ca6aa10c74c41761f64f31139f3aabbabefe6c7bd79a6a3334cb465f4203604c0288c49db25bd25c6c4c113e09fbd65c0f271f4a373294831c33f7b2ef392e4a4b91a3973d38473b9f3a485cdb04b7f75a833e2c0461c6f27e6d8f518d3a4366ea3bf37f43e4408f00c4c72ca8d0a9fdbf1ac7fc9fed47e8a3f3f33ebcbac25fc2e70bd39a85519181383597ccc3503e597a734c98e98a15be8bf4b37330f585ea138e5a2e4104ec1cb6f5a23df7ad83751c32432033f072e8ee3cdeaae4e7de98f9e58633bcdceab69ff60004cfdf51b54e9a33232e1df86ca9708811a69b8759e5b2daf57eaa8f1f74ae6aedfd9106c105a6cd715b66f561c0a0500a501a9f3d50a0b5540ec96d24fa5f6157f5465d413b204a224e2b752a49322a90aa340e4422e60a449cab5b6106135ad34ae309ada87ce9a99cab959f6c2502b2da99d8ef296884f4255fa88f38908e4294f799afbf3d664900c5230ebbec54328167495caa99942c13e834da5c488f2dcbbe4d2448eea2657a2f82a91a53d09b2b5445de8c8c8ede11f028e067620f2ad83be80d19f3b9a9f3b81bc8a405c233b2b17ce8ee5e0ef05847aeb36f219817d735faf6092d13569cbf069696bcbc50cb50cbef921f8fe76775f1034e73bf04431b696eae4943efd78ef6c19436c76ab389825e57b23f4529fb848233833afa418d85a92fc865e634357071bc415da56078f44bfe306d3b00574c04b2e94d6b801d5e3bc03686d1bb27dc2753112b2c22a43610a4dbe1e78c9f4f6f2b4ca3ccbddc2ce0e78fa34cac5935bf0867bf14f40648c805876e61fa841292ef2d2d53ecc00319a6df0bb6347dc865e39d9da574ad93f9cc910a9eb920986d5e6b331cb29b45ff32ddbc9e09b71eef73c8673307d6684a34ce85ff3a4208741b205d31011555b17b7c5effc210ad9309468a007d76983011b88c818eaeb3d3815a02d76f735433192f1bc99a6c7dbb57e107caf9e986248ebcb2e9c28279ea1e19a8f8027bd6f8728c9aed0b974322254e686526cd9ee0c6720de4eac01cd83e5705570c249856ebd7ec76cddd98cc096fb93db8ed86a5aa0736c36d978c09b915f7b9290cc255ea1a4b355888fb96e506cba34683c6a890c77d92fb01bba6b69f91efb3e4313111dafc3a189db063195bb650e0cf353dd975fb5c286f86b8f7d982ca5f74a78fa0fa3d693980be09298bd41c4ef38874ddb95e928494b9e345525b00e4760a1d6a4d54675e39b1d955e20a58f3ee65ffd1e249eb3558ba348a2be114f396c422c57314ce6df0ae9406dc6bd0bf5f1db49f012a03834b3314dec7839860867033643aa7dab3fe17ee025812ad2c05484abd0bdeb67043be2a57533d294aa03f24ec8afae512537343eaa16b07eabbbd2cf6755261ee473dc457ec36775102e1c8150248e4e51dcaa6abb7753920bd5247ccf6dcfed9dde98c9f37938d1c824fce116f39f0d67ab9c1fbc79e034e8bee6f79715433d485edc70e5c098ef7bcf2972171da06cd2f19cde8f824e0f2bbcd816f7eb87b7bdad659a900f36df708d3446d8e412b92142d8414f3a0508d106473e809a0831953e2064c655519a8f22fd0c517df7ac44d72a0e7b6fb697b188133fdea4d16e51c6da3109f7cec1a43fdf47957a35f4651454ae04da9e9d5a1668f46cbc58422c38fdf204f4e9c0df3b1f0ed2e14d0e008bed642353ede25a5c25684e7d593eee9d14b3a5a81429b30895ff5d1f7f4a124d2fc9bc1eda61e8e4bd73b57ef1a168cdfb1ce1d70955567a3d949bab203c379e3676932f96c04ddd0271a6afa0bd55988134de26bf5d6c725c09e04aaa03d393a82805a366e0d98e4b65bf45e05ce45f4dbdc1f8ec052102df08f5852630b706dcde9a3efebca3852e85cbd7fb6e6e00b4bb397004db1602b7f8c0dd365eb2d946d00eacf0ecedae83d26555a1bef8be88eee9de9f9811074151f0cc747f36d45ea7290d53c18fa8ce73f77f54226e5b1719a9bc911c9d7565693836edeaa6cdb7b2e2f9cc8c86b7c207cc14c261793df6c4c623355db04d5eac01c011677d26b764e9048bff8d76e2b6bdf792c57e044eea4307f5a3a62900df3f57ae88577644e2121134d61bbf3100fedf83371438b7854d06340ffc00383a0a4789a6a85062aaad3761dbb3c77e61c5926b0488f711a77735dce429b6e028373dd341fa2db5394867242331168665b4d7fc4ef96b12a571b8b25d44fb0de64b9820734e5647821a038428d67dbe95885526c3f2b8064e8baa5144b7fabbbf5a133c4b8d7a2f950a4fb69f9cdb37ac28cf0421894f0b771f80db988e25fb4ba9991664c93116bab82ba808693d583a2b697fd2b5eb673f954255da410df58231eb7c89b8257c5a68ca0306d088638b2faecbe3cacbbf77725e1685aa81d965f1ef663f1e474eceecbd52943c2e4e0456b52aa0c7758cd2fe67f3132176113a16dc9bd11d6dc03ee643fe8bd6677f2ec0ea754ab499e00ced482d78147ecb2f91d3154e03b57dfad4e4cdab98e134a609a7512a5a0e7c3c4adc9db444238e0fc3c3586b389d8d090ca46222a9533672eabe4fabcf61beaeb59c507f2941ced1ee4cd2afefee5aebeb354ec33cb85c9695426126f016929b471b9cc07dd6ff787fc2d682cc1e80657bd656acfb865dc91d6b032785cdd7a1d66d4d5463e142b6f028e8fb5bd6c621109e7022818b39197f85fd6ad4785efe48c4509e9a537f10d4fc9d23f275fb9e684c2f827868c9ff3baca8faa59903c829bbe1992541d15d538e64329e886ade0c5517cbab3b15fdb4e82506e27f449e268b488de32fd036fcf80f6c97505a5f33e4d3a004772a8970a3fe54049513cbc57131ffca1c82918a81bcb879b8f48d4300b11cd90069912ec9e59d10b6bebbc24ba1061c62a8762156df586a4aa758f13cab5ab59a3b1ef7d038c68920eb0a3c8a673c27b6fb80e5e8741b3b7fedff0c068a83e72373da07c8d73abbd9fa0084bdc92866917b546dbf7a6304f04b18d9bcebe2b4bcf5ac7ec526abb4a52a19094c8c231668d063c5558bdef0436ac418f42c5f41f2df996d19d48f8bec412de05a6a3b079e5b6ac1be0773814acc3d20166874ef64a6cf27f7fc72e0232031ddef1a6a4ac9897a86605550dd635c995626fe985aaabdd937bafe3e2a4082f0fc875ba7ea963a8e5987ad400423967bba1c0e369263ddf16fefc88901be069fc617ba6dca90608cd4a9d86476f8cbb41fc8197a9ee6fb331aae55959d107bef29b4f6f064651964999fb8dc904b8193dc7582fd47b0b0fb912f1c0c3838dd489c374ba5ea614cc80d4d196291c4a54989ae628dff5beb61612353ea0cdfd75962ab057bac887ce7f5df01861c769b88c7e1682f0ec6f7cea63598c3e6f41093d845db95377654fc56702a4110810917521ffada7432b7b16a64699e6a955a4273fe9220976f8b1ae9ea79678a3a74344a44c32454e7bbbae9a1fc440811693f66d63663c84bf847e0a2e8299fb0a6413194231a666a2efe5ae1c41db1cf12dbd8d58408cbeb1a9507b5b09ebf416f712b0040f8300dc5188e673c5ab1f13156718031f25cd5156beb8e77e95b48f42d1361da25a94cf1bb4a2a5c41f8da5c3f6a30c00e7d0323f7bc14583fe20815f468928fb69a480673b6c775b2d1af6a176abe5f6c679aae41ee1d5c89439a798823b65ef718515ceed5a7ec87eff54479a9afb48d0fcdb9a240e946719598512220d2afb20840e3680689cbbbf096e7d7505d1d854faacf024935a672278c5dfad333373015b11571b2a7329a0d2fa792d838ba3fcbe5303f84cc6d0454b89cf740bb0f83b79c98b38fa17dca42c5d57d8e86cbe16d46c4c0caad1f55ac4a399d9755067b642299b6b023e47ef74343b9d856545a51907f86034397dc1cdeb0856ea9fa753ba82c5f7e44e4423684f1b03ec59e5cdd96c03dbb1421e89bb0d1dd570309d92519e2b90fc83ece91ec6b13134cad1272f0fb1092a21e0066cc0a783e566167b52856fa6ef12aca963dde340e94f04980279f67a1eaec339d0656c09a3fe91a2b1885f1c09e831471ebe78f2af2efa1fe5821034ae172082de7cf5fd8599f7c575311d35248f2b0e6342cf7ac4bbcd19942a74ae9a9ea3ef5641f70ad1746406ad9bc24a1a3ed17dfda75ad54fb920ee9c92b792b76d42cec2c22fd1bb0f7acfa398d82b5f016f2943dfb44ca1d96b2a54ceb7595837379d62feac76dfa610a82ec947047176aa74fa8d58aef3d34e79768ba7b213a8c44c6e9739f05eb197148b2d2f3c5a1dbf0d4ddc4ae2bf0eeb93d2d4d0990c2c21ae34300a3139ccb5cf216b4031f5be4fc61b137a952fd516e45236dc791b692910a09a600fce9c14ce9e429ef1ae3ae737ebe9921d10522a4507d0794fde66f639189cca95923c51f97cfde4d57c718b6e0ee709227fef69a95a229ab54a4ba9d858115ac04dd0a594ee8fba7d29a23d8df53c131dbd6f7f47c6ec482cb2da38e98a8bb51a2878950877408f0892199ae4e94c4c8eeb614eeac1435b2947ba67c30ff52ff4c958eefd318814a17f53c8ae691d3fd91ea8196bd82d4af9fa216e32636d6535d5c68f579d3066654f2cc067873fea5d56f9676800892f210363fc790086a778fb721854a0abf9a2403ac6de964c2eee9011a44cc0d66ced8bb0634cb986a12b0d5d875db0f26f008555f7ff57f42a441250dc5d13dc5342ef36c288127d46b4a2cd85e5189877003589579aa787c46843e47666be2ca6e8aa84e065ec77f0f77e5cee75785e2358a5e1fd7d540ba1d36052964d7a5de9d1598cb71b238c6a6f2a4b6c72d8c5b0a4c2f17342747dcfb2bf7bc52256fa21741e1f8e7c2b749005ef240296ff9935f75e943c2e725e9f54636c3466450a49eadcc6f330558f2146426fe6786f4ac6fed1943d616474f7665e8ecc2612479eac464c8313066de5fb652beb42ee17c0d9eac4496b5a732c3df31d90e24ffa8eacb12b72dc1d393d0880959e0ce9db8141ae1490bb12af9bb2d12da5809a348714024d7beb73dbdeb4d7adcb68c59ada159fd1855ddfaa33e0b985d7bc3f509e64ee52b5057656295dc669939c45d89a07f03c0062e20e309a0388725c993f74cfbb8db38b85f13bae8b27a4da755398f228d79eba2ad5101d80c75eebee608dae268dac0c3a1c63e311fd82cddb78f06fd576314ffbee8ed598818894fffa54b56e7a7be5c20ac553d106609f4bc757acfe7b116f695fa4ac3ac93bd0de4bf87aa6aca5535e467298aa934c11143bbf39c464db663b97ad416b6501daa12fa8d9aaa31334851f36f654356467cf4f42fcf0c4cb239c2acf7c7938c0760a6a8f953e75471881c59293285241f7b73e4b3dd5"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n12b-rotation-wrong-key.json b/consensus/common/src/test/resources/aere/registry-v3/n12b-rotation-wrong-key.json
|
|
new file mode 100644
|
|
index 0000000000..531040d2c4
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n12b-rotation-wrong-key.json
|
|
@@ -0,0 +1,51 @@
|
|
+{
|
|
+ "description" : "index 1 rotation's falcon signature is by another validator's key",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : false,
|
|
+ "previous" : "ok-epoch-a",
|
|
+ "expect" : "AERE-PQC-REG3-12",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 2000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x391de378d9ee4e1d810e6ce145b1819f1b73dab7f6dc2468fa65d1ddc8e2a7e6fd8f185f8945700a938cc0c5afd87bda48c1b8167c3e6607ac864bb2b194a368c33cf8ab6a5eebb9a704d4160b068184264c2e59c4f82b9b4eaa9197c3ba5289c429e0f4c548769279daade1286d354212b1ba2ea4818c974c17770dbb59b65b3b9f891c826721f51a7ce14f94e2ef4cab868cf852ed9bfb17cd33ebdc4d688d6ba12c74aed2c8104d117574642af25e9bc91ba3fdabfdf1ed13c6e59fa1a0a4388925d2254195c666a6c235174a73125790bbdbed463617757fcc17cfd32da7c7f89e755f051aaee186665d9de393a82508d15f88db0271495c959bda6651a81a04dfc2103364f95f5464effde48f3b7ea80af9c1bbee99c9d39b0627984f09ccc6a4c888d121ca34e56760b1c3178e48607325676c484f4d666681f0d2454f7fdc59cca37136c5c06e746987e6a116728f8b0ae1ae9a32efdfcc956fefa55577ac670bc3d66016391bbb833d97f91d3a78696370a6f05efbd77cd50d4697c3df5699277eb1cafc1883776d9ecc72a763e5b65dbdd184efb9696cf58360e73f2d4db5e8bc6ad65bbbe7a8a994f5073fb4b12ad9b5196c450e27a53d8ca231f670966a238a6223b47d90990b1f6796f93eae971d4939d99dfea29d4ba2e3feffb97c0b27d6b6d2ee10751e75c658b44ee71abe9230f74a0d7f232329b165f5b2a3e584dfedaafa9ab477c0c516b6553c58797421f8d1e9236f992b61963c108752b1c43278a9b910926b396292fba67211e9a16b88aa9bab7b6b6db29f30ab5b7ef1568d46a010e8a27144a5e958022be5cf6bf4305f14e10781323acca3bb1d6b567d3fe5f652661dfc54d71ed9e3969289c29bff0c8972899993505cde2fca11c821d9280abfd5c20d4fb53380",
|
|
+ "slh-dsa-sha2-128s" : "0xee44a0de25b75a42e32080200c89b82e2f89551d44da272720c816fb144aa42ca29cc7a0045d97c82676d36286a9f1bf4d5b9e44b6855d90f25e03e3370cccc7665f3c7fdeb6f9565b76745a7652f70b7cb18989582559b81160fa32c7db7915f14c657ca37224955d174cc69de41774e4ac576f362306f3383733b322f8b333d9d0dee44d80e36a86491bfb7441a3c66809bc600399ac9788b4d7796604d4ec423c40dc1a6fb2b02db9a0d35072cb5aa617ef769006c504052596186ac0d504561c815617067f669b29757aed1de7a03c9c0410fb8b040dac268aa95232533eef1f69cc0100b33c9726d55af73b5d608b501b0470c4e9340b68251fc645bca481dc2d375de626580faa7b7faba8f8a596f795481cac23240854839a1100cd92a6410291ccd40cfdf1f70981c568b32904a0ad649de41b32299dd5a8bf50c35e5dbbd474c258946881b49e335e01c72ab6654741e657bcc5109fbda7297999cb4b272302739ee07cff0d1c9ef454a5dc5403cb7c170337336f94d56f6ccf563af44bcc8382de301720076a7ac1edc1ad95dba129760d7e9cd4df609bb8f7b389e7ab1e85e1b54fa5e3f2163afd7e24c5e5eb61a9e8e79dccefaed30f5fae83bdbd8a1673b36ce894891720b476652a26401e7890af9199bfc74fd0aeb6622fed8e488b8151a6c51a11bd808702f945ae9f9a016bdd94f45279d4765bb376df7fed5506b52b74c867c087c3386f74b130cacd7bcb4e832b697b50c796fa8fe4881c3f994820799417885af464f4f1a85989e5e3b54c3bd878a7ab054bd08c1ad850c96f3c0105380323908fdc94771609b10e489a8445f751f75a9b617cb1aec4460be2b53920e52f7d85096065fecbc6f19daae458f657dfc894758f3d9a6519fb4276e16b38aaeebcefba89a7686546901c57a29b95266d7ab87155a854ba9b269ac94a279e9c4bb38e6a4928cf6fdc3984b4363cc44e0e3cd7a7edf08388b9ecd5a04c55ac26b98f98cda79cd3f402caba28360899cca559be68d7a825022f9010e65f9a6564fcd0ec1cc4c0f4029086c90288fa83656cf2ca2cf30d5c423342cd15b9197905e9ab30a9d147aa2599abae71070e40058f0787ae39f39d6e5c1a8184b2cb3b1e6e45c40c61d46af8490cc9af6422a439f16adfe93a3cbe88f63df5eb8fcde9ea111ca96ea7be416d030500f2c7cf967dcaa4d3ed76a613b2bcc034ed3aa84f35556e7a65a8798825b576236798318034204f041dc59a9f9c407d34c2ca2d77470700ed6442cea5282ee99ceb71c6bf074423dc0785a39b89b062f89231af868812777536d0b144212d5b4b6fc7b87ea04fcd6f94438704f985b746a13dd519c57260f87150db4dc483b664944b9e805197df797be099940fed468b1e214ae99a68e99c6b5cf3d30fdbb1b3cc009ea58958eb4c4a7b7bad6b34fcea2a87eeafda01dca5223458affe54422ca70ef541ca8437171943d5bcdb70eca8de02b93098653160cae52f4d72fe5a6a7ad51c6465388f0362e6e72a3c96b9cad2248e8d9a2cdf89747444c7e51e2f89eb19daac76da37180e4133e0dcab15fc72c7bb90c1024d03eb2e630fc6d2537a101961b388e32ca5019a626b5a23914b06e7822905a5e3c21369b69fa63fc9f43cf7ecb6749c668c7a940b82f88c71802ce6e3c68b5c10c9249ba356bb3bb0539b581a8bd6ca141e5dc2b5932251746c1fc1c3da475581f3e3717f5d905f5ff3c83f1523f57cb750dabae0404beb55aba1105b995268906131835718cd43240bae9aecb30c794a8b186436cf752179b1de65b2a87917147612e3c95288a3e816238b3fccccae1da8041b4f784ddcb3d37ef3f019ef997bd8a4e172d397106a5adebb166c5f565016bb1c5f7f1a0cbb5bb22cd642fa4390ea640c04a968fb5a49ef929df1cafbb69c124ea58b31bf066be388d7b6d4c52409581da785d6447fd72b54949e4c1ad08fa64b520f2b8df83bbfa417952b87fbf802652a65df0d388ea32dfcab3227f645b6b28b66087819b4339ad171a48760e2bf90f1a01184389e23e7df583eab7c2dce385bb7a4d60ae5573966f916bb84aaec6cafe710f839b103532f9a7a556bfa116a05480386ddefa2858ac7ebdb58664a0e633a53e1685d71d5aad11f5eeb3d9ae30ab120fb88f96f383bb86917b72e02768f071ffca7e3fc2ac79846a36f6bd72c58aff03f9e87fdbeb65c8ce5976255227778cfa40ce0eee943b66a382e172abc814ebbcb0bf49efa75f87ef8621d227224b7be51b73a928c23a8937570e1a046bf1fd4c6993a9c14e552915953776265f78882ac8302f70900f9d612d2e7b7dad88cdedcdce7e615baf89ef249d6d535f92a2ec90a7435785f4d0c7a75812b875ec22e638f4af1705cc362ecf52c67900c888d068dc6f72a161013c30dcaa49cbf25c56e8937aa4897451061dcc7579ca99a25348e76ff121983444553419e820a3d1a41744f4227dca054c454a6497e0762155e2a06d17acb44ea55f54e4d6d2e1631a63d9494cf69c38ba66deb9d95c0ee01950dff8e6a5d1c46fececc7027997b8ec626f8405ae99ac20600898fd7fc422e6cd3f774b4009f371ce38e1f089ec93ec0a48d6bfb90ee79c3bcff321eeea33a44022ab910458984b75c5089cec0d8beec20c4c39311b991154fac7c0461b7d667488dc9f0f5497cf66166782e2dfb69a71031fd0251918e4c1243aa4dfb9fc2b6123b4f02f436c0f8737a6663af2b99fbd22c6af539ca9389bfb4e55da2c9ad42521ca6978f71991f53fc8cb227e228a62f3e22d7c3eca8ecee260e55084ad3ace0d6379d5eaf82bf6d3b69c4e74fade4210114d95b41a4c004858119a9a9b178d5a0cc97386bfed0dc6edbac5281c2842951a0c4d7da10207523973c676b8e6887a087c1c2f156970cc6db9cbd3c8ec1c9c1bec41fcbfdb4e8929b67e6c1939bb990ee2cfec3197b4ce824d25a7b4c765945e85ff2b096037adc4dd763b87850fb39aa98f1d395c9353ae3b5b53842a7056c011fb690e856401fc6f67b1c0a5414fc229284e74c230ced260d4fafc5fad153a5154d35c3bf9c559239ce18ca9810a1254a0a6c2960a53d838431447739261dc3b055a0b115914af263ac9fce2b512884620451156c40cd84b7bb2d449aad243a8aea3859412476ddbb5eb73028bfc6b2a942839e363262f94795aa45f6579680997d6acd7a8c8daeace08362fcd420f2f8a96801c002361b942493cc5ae79884eddee989af9832d55319ec033956660c5f11b9fbff9f1410a18c0e9a38e9261bdd13bc392a18a3df97aa33e7f59c125f88d78c86058f3c7e9a9d3b37bdb1e05d90375de0090b418de3ca761560f079a6ddf328e72cd89dcb63c9dd0357ec736782696241e2095aa6107a8bf7bbcde26d5d14533f28ddad7fe1b3f0c181c0e6d55204f6ce79cfc557cfb2d54cd2f33adf17a837243b51705bca7ad8cc452e5340732e678274f9eb532bfea122cfd2959b2499ad25a18db7dc387e976f8b5510821cfff778be799b80505cf38ab1ba6b01561ff81ef17f7735a1ed6a319a7f571daf92afb7490fc17064ccb6a8453ae6e66a2afdcded0c7359461278c49d342df84c43a0607b7327853db675e4c9ca95c52ae013461ca0763d157ac992e219a6683a547c32374631b53138676f50ae0d30588fb25de808e1d9efd5fb9485192428477c2f64fcaa862761c7f5505cc650910224400e2a2db13fbea0b0cc358d163c6d4a8e6296e4c9554078a55f23e60de9bea12ac199cd19b97babe61b2a3b853860b4441ae8dcd85d59695393816c64bfc074e945452080e15bcf6776cbb6b251c13be63932702468679b2bd7e1693a1d910e1b62be91e177a8dec8e4d7642e88e513e3a871ca502854ab0fb7fb8a099d0e0dfd73064012051af337abc78bbbc6fa2dc7169ebfde2d40167048d78f12cb5e7c130a2137a0b26922553f43aefdcdcec55bdbee0fa752a4787ea9d1c75d1bcd9d28135515a0ecfa9735901a0eb89f915d036e21263f90606f65e62f6e5c8237db14d570612611b3ceb4d026ac13f473e5706cd7975c95d49734253757f9c1e6aca9261cd2b95722098c5f7c74daa6c926ea4867ab54e4605a15bbf7ab94348d9b45c31a1fbdc7f420cccce25abb4249cf413008a01e53296318414dfac822cdc0bfc4298273f65cda3fcd61236e255dedd879fbf20b8c4843e27ef413c7a1ce2c714c88358091abccd7fed337a7d4f725ffbf7856ea4694113d605b1ff7b2bdbaf60f7abf7d43eebb1e82f4b6b7f3f8fc23ae27b09f78a7a3b324c7790431c800293e08fed2fa49aafe8f5670d4e6bff4cf6e7924993d6e18ad87699da99a2f2ca9f3c7b44b3b61dcfa5f041f7a6df94131b8e5c04069678541c87872daeb2943902afa6ff4798e45a75659568a02471afde44f8e116fff4eb7c16053a7aa370bcddbf5229c231ef8f2e642c1a88f90e0a309d24a3ab28d3adc176665e522cf5bda0285baca5bf2a0fb4c0fefff3b8ea1522c9ef29342ea57eb4f16d69bcf948d66247ed2f2cc4e567476f736d170c98398ac7c0d158f294ff33ec8d2794ec1929c57ee6d7f46da8e40337a2b380717227ed82eb13a14d129069e98cdd65bc34472fe1a52dfa7e466e559705c53d73d97239e38bbd600aaab107ced36fe7d8ef2387a05d8548a48a684fdf02b984022aeb28e8c5eccd1941ae19d2cb12a31de296b4fd1409266c43118848962e9e59a41054a52bf2f20b09eb4e77cca72df70cdc4d712d5c0313ddf9ec8df2d901145341b3ccfcbed77288ce3e4afc677ad8681c746eca02e7f7538d0108b68a922a21d6a8c2cfd67d8849ff5779de1c00588133309d4158d1738e508a1a2ba3351a46fd3f86339d66b1244bc2788de3fc60144d03c08b0ef08914088f9ce947d2b230ffb9ce176a4bd45b0c8b100e17ec7829eb1ce10b1a514b5e33d4f40792f0a300a4c3ba7a912db8e19cb72ee02ae8ddafc2caf116df905640d0cb65cd0c61d38e0a9741d3dc2b7677e8ec051d329183c954ff9c0c2d8771182d5550a742ba8147ec6571bde519c2f57f10aeb1c8900f8324f017f3b1dad92fb0d19a76de75c0c7cb67d079c8bc0bd7355fa25752d5d00ab00f9ab332aa23aaf8b5cfa4d2723b2020c9e494208c61a76e18c9a583172d6ddf544a327c931e8b908830e46f184998fc0d34ebe767e4f5d06f99804759c7e2b76a8baa302d6950f90194b0cc694a0d351374cd028ba6b0414377a850ca2f209d13cb7daf43d14f606a0e549ce14189023fc7b45e2b095a3f45930a72296eced3e2da24bf237959c0b966bb88a3a9818932b1cd41e8ee002df515ec94901902b2e67545dae53e08810b99dade7b579b847a6570211687a62a56dcb324bb442c4fc22f9d85e54b3f939937daba84c86fcc36c83ca87de70fc7f4afed335e8f9aae027e854e3a022a053c3b22be3617240f1355be9af3f4c8e9481005cbef07bf1380ddc012412c31b221275b56c3ad52cb2f7a9b340526e6128416025d4fe497f2d502070653d36f924420c0844b5560a8728e4a3be8b1ce67a1541c00e97aef9c808bd77af5aa280690d98f5ec218bf5c9d135d85069405b82c221d834b8285402f481b7d51ecdca91c4c2b27c12f486d382e0c14ec23c2bdf33ea8ff693af551fbe55e46bd84f335a68646bd092f914da4954c57201d7e812f4974a553f043ace9c6ce2c609cb4d90dc1ceacd5d610cf4723024538cfedc1bb22c9663ac541f89f97b37d2e1b4d8073ada1596e684b94e74c2c2f0087251f1eaa6789ece436b2940d3285f297cb7482aa9b8c47118a0b1d2031fc311689828b64855bc17306529e4b0a3326438b42698dd4e2e0c2f624aa510a2363583cbac47fbf9974925d81af9534d0ccb41e2b445eb19569d703cd8ace661139fa344a5e097290c233114370831d4710676f7e93889ed533454928333655b06ac5ae67f301f2b7944d769892ed76374a1f3861c8624b2a302df1a2f1a60d41e61379ab3681d8eee152c251e1b7b0806aab2f287338b752918cb989d864e9acaa92944f5194f8eba19a18a025157d2c3988163baf8b7ca9060edc2227ade8e05348d86d18f9eb633e4f06ee346e4c2912ed1c763a75fd1baf32cffd0c856ff9b44f1470136c0a8ae0b88175a7e7f993d8469cc8ac3f643aa7db36992cc97011be0a42ff1df8aa7cd82e260e05fdd67304644335b386c7825858a438c51b63f877af005f7d95202b54a2130a1f652ff7addfb798daf4415572376fdd910cd099066e8d2fe251a907e41bb950e960fe5116f4a4fc6037273250569b41ac07002ecf3b4b63f8b853f9693badd2e8bff695266095f4b2f38ee4d60428a45e7586d9d47c01c12c5e18d1ca9afedca6f03384567ddc730fb8fed27516eb7c54135cc7447af831f0c37727997ab2b01fdbc5e12c112aa987e95cf5aaaf44be14bf4882f49cd84894d555655d17aff21f077b2cca1ff0922afbcbf4781145cfb87df585e6af1955db04843a763fa735d33b3df836585c5894e5125d500673d5e4d0bdf6708d8d28c80298a9bb47c7430ae8ec52285a4c14371b3f8ac1e21306b34bcb0c1e3aa7a8dc8955cd9cac32a0f69d0fa0aab30abcbeb2c21d655ccdbae1c2040faedfc7a5ef29cd5d9227908335ebd257ae8c410b1916b9a5bf0e72902c2bcf701a18c1fe13695a8435b0d0129f3db883f428acea8b7f274a629865f1849d4c263a1536421875ffacf058f0128f0d012fd60f2b3fa6b71fbb96f3e1e33faa09b1d20b0919018e91a6bd9595e9c16d4fa6665c4d0adbd77a59cbbbd587029a4f306c887277a7a27748a6f289edfa16c7e4042fc81355b85a994cc6784f5fde054f188b9775836594abd82c1309a66db4388ad49f60794d8c8e1fe279f8965312a1e23c2956427bd6e289e55ec728f66c36526d40aed7c44e5352fa3e2b5d27bdc1f7b3bfc4f095d002bc8e7b2df2032daea9bd3e0bed2733e7ba13c6d8b45c492becabbef0e8c62c257480faaf6aefede888ce1546046f04ce7e06936cbda44c5f33c71c07b53fb3ac7a72c3770838471aace69f7ea454d2980fb5462173aaade7964b888606741270f92bc18950284d013b692bad63ec3726d8f6596788a032eee6eba08eecc836202b06ca43fcdb062e65f8ec91f7400963bbb8094de4b4e1042e040e81130a3ff037e1b7e947b0c3e8b7ab5b539f8570ec2cf08971a1bf0d4f3e8311b5c625b7d032fe2e0603ac1a4824432b4c7bb5afa190afa30c36f168d196fc89015aff8229fd4b299206e8183897229e95ba06324edc1a9ac81aad786d5c9d38c87c48fc6159934a8532489f06e1aa314a057d91c0f7218861ec241dfccce63d60bfa624652795229fff21cf5ca61ce05ea0ad6a1763173675377d1f2427564e397683428fbcc4b97495735d075f84b289b73389a1fece959f9d9b4932f4d33a0907202c650ccf65327d24cc24922d0d675fb59621e2bcd2eb31ed1ec5fddc96593d4f936ad42731a50f164e404b93920283bf9fa43f8be5878d18e07cb8813914508532625f71d02a615bf47018e3b3efed72d17e0c974d33df18ae70e3a4a743ac3c955d1c366bc94d789c90a8b3771969210c7f0c4b9b12f9fedca5d2b71b6c04e7024a0a5e3d0d3c7d30cf568a659cc17309b223399b39ee5efd0cdec3a34b0735df8d7e0bafa40a8aefd742b3e0157fc89d113af5fcb0cd136a9cfb82acce406054aeda30b83ade59cb6771c366c86b5d9b016a74f220a967b83254db3e24d3e1f5d5e23b21354420dfca6bd8454575c6b0e528744f44ff8e1b9679b084d083b9ebeff09df273a476332dfa172cb98c79ecbf3ae4a722c25be71a3b206d848f56b02fd04bd32ff959e6931bf6cba042f9fde027d832632cc40d4320166f9644296d2dcc845491ed780cb609c0432408d08dddc70fa2d52884df47a55a8a3e706a24ac6ceb375a894636e1ac121040561ef486ffeebed3c5336d123dc05a5cf221b9e895f6d3ffb24b3674039d50fec114d3648d6dcf4fbc0b503658672d675c4ac64dac4db4615d011e82bcabd9573fe9e2af224103f99c4e6e5acd2196f1eb2260fb4aa61c298f99c20c4ac1c9e70a9a9e28db441c3adf2f2b3a00ca3f1398b5a112126fc3f0e2d11d40db36d0aa47d59cf8ece36df8daa854509e546295bebf92465f32a7edae6af4218b49781034329c22ce9e87258216b4a901b823a227e46f2938df336d3fe03fdbff4efc7b8ff8142b4bb60592abe508675d04081e5eee99468971fd49989eddf4648d3948266b08133b8c22ce3523757821a05f254cf5691848b1532655e85fece5eb186e87fea61936fa63aa047b5cb77c08aeeb2991c26619139b951ba4c2ed487703a6123c9c16d7b6cd3a17ad108fbb7c79fc3706f654be77a6cd8a5213d3976b1a4527144e788b712f37cbfd5f4ea5aa5fcc0f91b98d74ddcacb83fb33e039e1b88811a2138743ffc0dc5eae46c688f48c0be92a7094f92c2d4bae0c1dd95d40ffa113f27b8fd1808178be0c3bf77b677df2a17c9443fb6023c9e43c48614fd7d09a904e7a064125f8b7671fbb7529169138feed4bf3e6c215947efbf44fdb5eb1e3a5700fc8bcd1cf2a393ed438e68b607a1061e6cbd46a0b4f30fb4a492e786c5cc6d4f80542d64d0d271308ba072deaf7b1ff1c5200a2bb24c68aa2a5cd07052ee5760e0ede484e0a9c482cc74ab564654787e1698bef1386fe446106af25cf2fd950a78f4b521d547c83b6e4b6ef652444af342e90bb5761ea0dbf6b8c315996ed3d3a1a9d1e5f2b75ab18d0bcc87ee639299a248406d9deefecbb6883fe81ad12f20d80fc9b3c8962cd84e5da215b96bd457d5146aeb36d08185b2ee021fef7fdd43d0555c0fd16e7b66d1f534ae0b87f6299fc3b8e70236f39c91601564a5c2b3abce248ecd5450096e65df8b69de8b5cd963127f207f0df538f990bf29ff0c2930ab8b378b86d2619b150ab4dde82469e40e9e6e503182882b03442f92cf7449fc2c4b2f7ab91cf5ec57b8b0ebc18b27ad9125da57b6c139edbe7495defc73d68e71019b2b808a1ecb89fde58ed9dfce8b17e072170983e3dc3551149108582b95b2e4bd9552faff0bc7fd13dc0130f62a967761928dd62c9cae970ee447842a15baac31a280b443390bfefb7d4115e8d1c6458e1920485985635b75bf84b6af5226dd9b36c94bcd1a5f3ed99fc3e5adc6f3c4a592d2eaecce02d0e5ae97e6c4c7e101d4138e526fe3f090123c6df8596505b4d28c1be9e0c3f83dd4ac07946617eb553f7688f6724c8d8d34281a8c094740170280cec80b61b07eadb2c63427690ce73233f18593537e07266a71523688e6fdd36943d015c1bde058ebf5fcd12ea00e6b41565d062722941ca346b5949078421cf1f32fd38ce1be52fd65f2e9862bc5c57b45f33581eb72d387f0c212d68f85baf7e42058e41966429b0189da4eb4e58c1104e59d34eb0678a1385c38289210ac86f77cf8bef670b9ed04414875a29c27b79bc97e7febc40c39cc8e201ca56b25cd8c96f1a37ff688fd5d55cf5232d216283169b51cb41c631ca323056f2e8f74d5178a83b3bf43cfbbbb40f2680f338a89b294d4b611b0f275cc60e99bfcf270cb761c1c2a6773503a3c0e03b2a858d0cb5f81b032012bb0e15add080cecf19bedadc4d0c7e9d81fa75b97e7ca5e1c9eec88bcd10afc0d8e48f83aee498633bb260d731e0f900a9b0ae3f0d6e57346b8d3d8019bf079b4f909b6dce5718052416de8b61e9ef317ecf2faec5a64c0ce4bd5aa72b79360ff9b58d4a5f3e0648000d90a947933b0fe71d81ebaa96cd4c54c5d42b941e73423efb1f6626767f0e6dde52cd8796b0db31cedaad75b4ff72b83e0e9ece164c4f4dac170cca65e42db8b7ead0fa6e2f0b2d9576c79d1d73aa4b7ce4b954958dea381a65d4287bb1e02b7b88b33b2f1872d92ec6bf79fbb726aa436434fc7f2e79f0ff8bf243e19c08f680a5012c3c3d0501abb46026c420e485166fff457412a075086266b854aeaf5ac3a300ff5501bfd7ae96ebe56a5df5b7abb5fe2d9bf7ffc0005b6aae9dca8380a66c8c14e884f9f3338346ef1daad62042d09cd774b43016b0339aa208c5d6c2f7373797202ffe680edce71d684030e5841edd57cacb0cd596c63515a1b992de113fd2c8330840915d3409f608c8d43601f09dddeda6c504352e4d8ed932d8b5076a557fa2d87914ccbb0fed61c1f4d9950be0900b2212a82abcc4d9f4466d1f5469939c1e35dcd2d124623e2e1aa2dbe90ce09b958edc4e60d7e7502ed16a8a1d08dfcef84eed8a93d6940441ad41e493ec09abce869a8de0a778fd8df55cd1d9d7f053a72314e786088abdf968a3b1d1427e52427c2313182f51b5556466960017468a35ed2594280ad8493a5d3503ee4c479fd4c8db0141fb6b77331b46fb228f94e213ad372c09ebfc8bbcc79eb074162b4694b7bfb8444a4938a80747d2c15879e28e3cf44a8ac2ef8c5d9f93e9cb42f81cf88035dab96b6c078bceb4fb9cf293dc964b0cc9b722a84f3423bd4fbc57ad1f68a8166e86da595fb3b7a4dd87190dc65756e0f7750b68e3f605def2821619fb4fada9cfd1c41343dd4f5424a1911ca709ca745962a484d981db73a23a85c046a3eb73cb48b085d3286738e689437cd4976cbd3e2c5a4a4e385b3aadd09b08859bcf5506164db33d414caee679c65069543f1db8b242dc424af5a45bcb5ef9b939ce94e4dfe56ca25702d7912c38dc44d94670d90109ab685ccd59988bb7e932ffebc882b7dab274065578c041591d481501797b4039da17684a7242622f4390544b05023d3902949d348a44d9ff421d04a55395cb4248c7cb0f13b697f1423be1342d31fa9b85aab70c16bc62eae5660256d2472dc908768ccb7ff02cc84ffc6059752499711338e41d37f8751d84eec47a51c7daaa273e19c523d3d97ee5f71571def6f7268f24afaae71eafc84986eb8a0bdd50fa553c815939a4b56380b22b650fbb989b525d2862c5d420c83509b5c76b1a9a2105b45c2182331ce72e8f1804efee93b1929338f"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a89834aba90aa88f605981578667395d730a408f3d112231997200c28865ec37a4a1f044c8817949cfc8a4fd9028832fc406f1bb919789f2099629c2c8d6bd128de4f51c02a73c49dbf17883ef90a9dbc0350aa67e024a893e555b4f989780a45320af4858421346445f66aa86e4954c0bce0debc896f21bc960e4fbd4eebed93e943a40387210ecda652c36b6da73570500adae1a2a03284dc47f1e370570a07007d8c5a64089e81e2c4d45eb6ca01530884070d46f4605ffe139457d5155c8e9ce8f201715ce7b9d18755304ddb6871551498985ab400cdc4349c6b5ed10b76b425e70376e39a6167622eb5d4b7cbd932aeeaca53b3e28ea06c44780b01684e66eed712559543cea677f1d9807e2ad0312c42e43d399302a0c4c506da7cba37000c3ecd10b58922889e5c8d31a9882ab8ae4b69d3d3d3abc6450881e9b79d9e2ac51085f61ddcfde73e57c1784a6a766ee2bc434d4973a9667c1c8e00eba0c544a36c593a764f519de83251ec48fb45a63e00ad4aaf01d1a295eda0eb95b27fc364c33e3482f4e5256cd622242840d0630194316033219c3051258f548a23c08d205a7b15199ba8d6507565d06a1f20db367183d56d9dcfd2e12c36bed83d239ddbda9efe8507451542942033282bce486f002a215c2ef599a6619247888a81782b005acb3d550988c1f22c6b186038bbfe1c583d165588e00c7f0f7e462a778e6a8126be71ee0dae7b5cfc6145aa6e65c8c136d34f7b45252652995898150cbf177f47ca8d16b583ce5b0e809567c08b99c06095c879b4d945b13c8a62429966347946b606dd78803a3c8113a431761dc868ba2e2541c66b39f30ee21b0ee3fba5eee922d56f49ea60c25a1094381908a69b351e325357d9b4b9e2d040d8be7795891ad46a334a057b0aebdb2e5a9cd760b02c774f60df240e05ed3708840b1663cb435adf9929c138b9fd15461d86328d5895d8778ada79d9b567386a6302b67b4b99a37f4362dea36fa2fa1f1ee2f4f8293b131c57595468aa5ba62a03dfadc9784c8190559887603c4b50b7487e795285705f07f90d8a9ca50e4abf0905d7487f04549132cb3a62ac2e490d6d5bfde20568290b693681218426fa0458eb356b198b41bc60505afdf7219ce5959124e4d1a56ba63345f91ab39afd970997895689c8397c023b1c8b774f92f0e5940c764abe3bd609a0d50a98dfe291e1677e6232896ccdea3d047f35c558daa130ff53cc66aa03ca5687a2006cb7c8c3f",
|
|
+ "slh-dsa-sha2-128s" : "0x3345627b00d77c13ce3ebdd12964c45d0bec4dcaea60b64fbf6cbe7b897b8136"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3906b14ccdbed5db7be47d08798522129164ea6ddb3dbb9b03435bc210adcf65b7be2eee34a0cff0abae6e8bf68b57594952e3a11d308d4a3b2182afc92b4d835f3f14b6009266ca17121aea6fb139793642168f298e631fa26d8be5e945fd77b159e4589311d7a98b2e964f1a158586f37f47cd3567ff0ab62df6c29ad5ded1a3715b8d96c342d0a51db423bb09171f45b2a90a7abef2056a5972af54ad8c4a1f9033c85a2eb17bf392c7867a4bd2b5035944b7a5dca5273e8d3a7a9cfc64c698047b2edec90dbc6f43d471550ecb03ff4e63529d7dae0e72efd9fe4c2fc5d7fd30d77b4679a1eeaa9b035331756f788ffc9489f38c77ef47338d6bbdd84bdc371534d5e60ff5ee2a49f329865e04610f9de2f5f420f51a3e0c84f7a92ff53fd99837278e17f4a66991f2f3a2199776331543d6b7c262c4287c45276c47ab38fa9e2de9a32185731f4ee6b1b6c7f71f7eab59a5a7fb54b92488431ee74a7d10841755548064b8496f12c669bd96499f7a20323973fe61b2ec8be9ae47618d927381a6f6fe57f89a13094c76305cadee5e737b58c41d837724edad2b5fa4250b066acf7e45cfb589d7e2c79d9f2a7cf928dd1a57930f8abdc1d64cc7ce84aa1082b1f1e46cf52a3366c1c3fc158fcb27f3f81cb94ccb6ef6ade8ca8a87f258e77f3308b123a8b11749b1919bed8cb77891e55eb79b41bf1c8a936ab2298a956cffd24ccbad08e8b63508dd1596374ee283c53ab056ff3ba7956ddfcc6f68c5f0b1b1248fe76aa3a346b64ce6e015cc3e2dfd5de75d0870419c8a4c172d964ebb587ddda7a5828f4fd13308bb6315e83d28c86959ed21ad635a07a22095238cb9c9a690d26ddf67e4592342bef6929482d529b037ed542d4cb4374b819b611bf69d3dd52e2a3635053244077d0220",
|
|
+ "slh-dsa-sha2-128s" : "0x6e16547734391aae71d29745c3ac8cdfbc98f07ad9a8470650f0a0085883ff970643e21b67d6ffe83653a99f2198f821cc080dd7f0cd1a612ab5c6f18d9903ecce34a5cdf069ac66483448219c06b131b377900b999f9aecf637713feedd8c7d4beb03ee11bb297bf4a97959ac5c85c0c83b48147fa9a3be7543ce1050394e83ed745f9ec0c555328d3786da46acac3074c0611667ce5bb4613436dac210c2e9cb186e9540d7d43ceed7f278363811083368d50f6d258a46a32c8df5d62c42c4f6f34c627076169428e646774dd6dfe6924e2240e720fd4d53dee8f880c782862de1ff96fc5204a17625ca008781cb120f74caa37a36dd20136567c05e8e7723a2e21569f065d4fc631811ed0b2d9bb67d2c82b755d14cdeaccb797f207427d572419360af1c443fa68064a653b1e21a2b83fbd93e38c7cfa5046eda9b86c68f3855c61cee9f799ba02e611a1b7df6a15fdc4b4b09e51b3b5e1101d0dc90a213cfa0522e93808fc4ab3d8cef74d279b98069988f6b8c6b4c8d3d62fe2a5a62f1a7fb0fbac7fb36529dd85416a330f35a7e4e161757a83282ad50ddf92c6096cc1fe071952dae4540e0c9d0507d4b61ad34751ce17fdf2e99c3e54cb523d3ffe2cbe8a5c58b84bdde119175e9599df6b2666a7721e246305457cdb5ff5ab4ec9d04bca439d59989253bbfd9a91cb10a9fac3134d85ef28f1e4d4f884aa195216a4811be7617c0d6004c7833088851fb7758aa5aac838ddc5e3a51d122fbb03b0b5d0a3593b2b97eb69c2266eb236bcf3134414536ff36895bb081e9fdd2e5a9f9ba71310af0fa126eddac07ca67020ddd4caafc9b102afd4d0bcae2a957bd65d0a15762b98f4dc7b548cfb463ae10ec3da3b5a4e9976b8f05405904aff74d3d536f9a321b41e0c1d5e4fdbbf61b42d868602e112b53552b8199a6618723e5638273822fe0afc5e6fe068d117bd5af3a1c1e8bb4ea9ae639674b51a523d19f950629a76e9a52c673dd153915863d0ad166d357f8d23b85010aa0b8263de0f253a0ec29b0973af15e4419d965164b5fc6a0e782716d86bfeedfabf4d9705e7093373819a814a45b245cdd13a667b31f1724b5cbffe3b5ed3087118715a0ee68af333bf26f1ac1ff13eaad6a5edd5e760e89518e24a982af4f44386c6d92db7a2229bc9c4df23274cb0f10d348f2373a79f55ee05e3dcb256df464c5f3e54ab790f1fdc585cbacd93c775e50bd02f451b69972728bdce813b46742ebe9e45d45c8bc23d4b298b5956e03b48c0a11c602ccdebace8f92e2521cb346f291717cc1881b0fe3a2e23d4ac694b7f1cd296b32b7f2f139877a129079a524d7e3c4f9c36b5836346a6944c49967796d8564ac8d2ed5e804a14c655ef235fcac5a8cf0372f7df952af0de7e4319089b54ea3f718b539a9bca631ea0bcc9259c64626d252245d541d90179364072b081d70da0a7e561ba2902e8ce864a398dccf55a4f583df7b6f6ad6738813eef6815f8f67936b7b842ed7dcc48808156d236d70a9ecba41994bc0296c3a236f2772c747db6ad62723c4457bf8a2e526f306d8012e04adcff0015a88167d199029ecbd333a6ea35f5b9dc2eaf11a14fd09b35bb2842a4e610da4afef15f332d5d1e82c7b0b452b7564eb45193af060595975d496ee59151e3c0f1545ef2694eeb1a2e38d4e008c0943c8e7f181a258c35e5068df39376aad6ef356e0010303d9a0dbcab91dc708b8e9482f50aa18f88f45864d539dc0818148149aa259eeb270a474b0a117de91b6834672a5cb4b5fb7c2ea0ea7e3bc9884163887986aff1cd89c49a6ca417dff067da528dd33dcd1f7db96ed50820bd72dc41984ed5c767478b79d8f61cb7b417893a3a4451129525a915b1e999086e6db74ef627534015206953ed3a5e2bbc5c629b00f3f3b22a37519426c20b2a10c60087ea32fe606d81c6457a02bdcadd8d56360dbd278ced2d4cb9af64af4ec77989475882f3c1c0b9f9e0b6528b9834e34024dbbd64dc19fab35f3bfda66c086f4c0ff06a29e9fe881340d1c0719ef568e3f8f683282b963005e93620c01de327adc0af4ea7f968fa987cb8f38350ebbb3b91192ebb009f9fa85657e06cca6f71edd3d0dbcfafcc11b908cfc38a08ba288910fcb14f97746ac20ff6e6c43eb099d09a717ac03f5e0600f0bb611d6972626999f5661e048476aa999c83e3f476e77e7ae09c6fb7c343a196e1846ef061be75fd8b662932fdd2c7d8784c6e498d4d828c910eca00ac199957fb44d572d4bd2c599fa6c7c2a166d96aaf4959c561d1e9dacf502f76b050c836194fe1897d54a017944a973f49b2ea59b66c24d18f13048e093e83af249854da9fd6b4974b4db3e8e65684b3b6a0a11d942ad5bb667460dd98ab54319cc2ab704a7a57c1583b8289477f5557d2da684aecf66eec3a54da742e2d24a6935ffc4f439d4a8abc21921087df93da2bbdc3a0f61729b397faf12bfe59c85a6af75c9f4ce4af19239840b57c3a4ead6096f2910da23bdfd02ee4f3676897f475d625d0e9a9cc930116bb2327232dacbd0ff32cfaa40aed89024b9ccfacdb76bae77a87b569582442ad2230c8fb3e0dca3937dea5685c46aff9ae6e16438e0e9ea8ba299936a42d68967926edeb3ef955d95c5a0b74a13edd280bdcb462dfc2d82e7ec89377edf6760450e1ebc61f035fff661173de5fc80dc66b8e3d38c67f4ef8c25c2c5626dd2875e10d870f12b3f36f749eaa0c82e94b2f30686cda1da606e0c815a35fe6fd671915483e1b2b48fab000ae560dca0119be7a0a3dfb347ef95c7fcd9a78e76911cb5bd438a7e96562e437e32eb399782a9498ac992716bd9f3d7d4e35a1f1821f9008f547d171ce2b69b007b5e377a3244092396acf958932616bc5cb95059762f48468a94f9f897736b11bec2ce0af9ebaed9add43bf5c262106a96083ad967b7fcb127012b1b37970a6be14cd9088f6ea927a66a76c35e1320452848bf7496fadbc613b2e122e55634f0491397ee5d211d780971998244f303802d7630837d05f3dcc588d8ca32e02f16d2297aa577576ea5c1b90d6d330a18444dba772d7aa94d0bf2000d598a069d03e7873f114cab9174af2f28e257ef2c0e44925da7ccb593d6183fdd37a1abfd7107ce02c655e7966286b72d65394f312d72505803bd53621a08100a041210cb912d5aef260b84e39faa7b5d8a539b6392b32ce6287e1a619804677b3f69ac46fbec010e726f3eb3458433e68e6417ee375dc70c2b2ee16b2cd9b228d6a46f92ba66a8c5b08cbd284dd759478c9f690c5e1e16d6332b5a0b9aeee43ac8ce3eb0c3eb6940b61a65bf7c3348d8dd15302b8b7bf6b6257e074d0af3eda088f7c22e6778c8cfef1f15d9f86c76a4b05c9afa228bc4f116ee8adb959b4ed9afb2307f2252b10baa436795028629d05277ea2722ffc14d9a5fd56e6cd6f0ba218675df025e50586e46429f1c6028e305d22b5479dd045d98a93fa30de08bec1576ea692bfe6b657b4be65578fa2dfcc197212643ec9a1a8de5971c07023abd8767c528025281f9854145e3d9c47e01bd37dc3a35b76639e4716465b862b705ebaf674a64313641de333828d75c16d4f6ebc4193fc2c92e5a3373fc79dcdd8505a8ea7ef8be6ffcecbb2e80017b6fe401e49193ab31e67a56e8163cce767abc393608e7485f41983ce27b9b1de1a0281f237d685d401641f860f8f11d10805fbf0c7125deaf583458787c6f2850b0cc8c62053e069df241192c6af9018158c27e30574a9025af5af73bd956bc008efe84b31fd9a49c110b803947fc939faeb773cd3c33d1b6a96fca0c079f2eeb4e3ff768bbe1cbada9ad22c2d97928389e5f7145a346931e4138d66319f0154cdf3b28cc9bc04139f92e421efb522d0639f02935e228d6eacf3ccf0356b32c163dff6b597d51b64a13c8c93f60f150f445271489db644665ed1208c025b35dcebe82e73034561704c602d1b24e04c08e4ca8fab21c5136b6d4b7af05cf8ed62961b4bc1c2883154116a0ca8933e36042eb98d851be695d8c4de2c2530372c606c93bab254d6b00e59fdaaec98c56415da26ea8449061e12bd22743a1a0e0e1e117a4a9448d75b3a9dfe6f213460ca639632d404af60c764d91405391137ab9ec4e8519d11e3dcae18dfad0404ce14ea4dd36dc3ee24b7a15709410818ed0a42091a01ed9b7f39f7c87d60d2b3dcbba880001a519fb7de152ec06c73d35c08b3e375b9186752931b6108a4b84189fe07a7165e18357a94962dc2761f4eff0df829427646d2210b55915be710e2a1bb413df2055e7aa0b0b9a4067d35881f22c08e61b587a59ef82ed4df267afbcd4c62f22435167f2d7a4a939eaf28a6f1903c8c046b2d7719b7134834cd56964ba860e60ebb6fbf4605a11b52aac2d595cf3b6533fe2452b65dfa0fff71aff39124a88e3e02977d6063a8370f98e3cb8c80f35260a8541b9584b1d2bcb315b394d7641ca56539b4ca8bd9e4fbc594b0a3bf1ed678be2f9a18d31d610b55ee175514738717d47e4821150a799ebce655d0c75228c2160aa1936dd42f9923de2ac97d0dc3ea062d41d5beffdd1d69672b73490d6a5e14a655228bc39ffc8f1e862fd39dc950dfe648e0ff87807e543d02c40411ddfc6c1f8eed733750557c9f68d830c83af737c9d8c3ff0d23987a8e09e6293d707940eef4cc838365775046af35dd26acfbb4264a9ab84818a71c5a13d8e615c5675656671e5fc2e91b682e91eca76ebfeb1c09334e962496f583affefc56dc144873c79d4df77da394845fa29ff348007c8ee7f23f2944c121ee3177879e6938eb043a0abb75991b3e789571e3eff009cf089acee93612e97be85e1cd83da9ff5006c14151afa67fddbd9262667f98df52dfded25f28b36fa32ec662cd5a6b0f844030dbe1c87e9e2d435fca1a81045b8de5b8ccc411a839064bfd133731f55ee2ed2ee727d9382d130ced8a48942ea295bcf75fc74e24204b808956bfc171392f18554764aa80e75a539941d90a4afbce1f981f0c35bcfc78330ecf3d416d0683c7682cbca066a10c43273a0f85495cb4916ec0eee9952431a11717cadc95c7626436953fdd5fbfbf9ffe329159d1bd79499807796d75c458c3e3914d1f73f656e9fa273244615710c3eee84553a7ca0250e97a0b8895695bf86408d2f3cb2fbffffd62c8583af5b25b7e2a38e266c9623429f8d80ab8fdda6774df598f966b86ac228639af66cd0e3ee7ad7714b4ecb42876c31eb2608fab0c6ee26e97fca305aceeee80bbe22cb5e9819322aedff05cdb78b1fb3060ef18ce0385ae0fe6803b414aaf0b340eef94a7517e5cc3df4bd273f92120b8ce73281cab96821ddaab08b41b97708dbc7d0edc49cb362759905ce8d42743f83a0d75878596c4c5ca878b7aae6fee6ca7b20f2ee60ea773499a781b958f4353ceb078e5c04b0fef3e0112dd0e3a7ef19e4c63a202fdcb8ea56d15b2fb0deee4198a19c9aa59c1ef2b3de73f291445c248779eb5fc76953137adce5dff20f2198cc9e729be4adf385e0f25f67f68c04b4cc26987c133b987f477d89977621b8313d6d18a5ff6a76c73ed608f5e4adb860e2e8a6cdf237d4871a98f0c448668bb42f29ccad560fc1e571f8abb3c75665a65a212fe9d2c1c48eae9b92bd0a8b7b3d2fef99ffaf7942f5834533a592423d2cd66aa793e85bc8351876946a1e49e13ee374609932ec1af8d4d3f52e00f783368aa2bba882cc91c5fc6eeb657f3682dca8e9d63f319df3bd1cf52c511f600a6c815e4ad59426d9e1f32831dc5d8b0673c7c58e8bc1601d241bcb76c1306ddd5aea847dc903f376bc4d8e73a55f0a5ad331f57bee70533b29e6b8493d9f11ce4f27f9605f693c05487bd43882ebe8a1090a95abcfc186d74a3708ce3351ce7226183a21c08497dcf52727b7de08ad6a970b2c9f314bc7b33995ffc77a9a36ab46c7a05f61315d18b3f2217703be5753b4ee1670eba3af00e90a94664039aac93e89dcaa59d4566bf286f33c740feb763d0a385855f4410052c52abcfc972298ce03ddcb2e65dca251afbbb75c516ba77001dcaad8470f61e3391c1c68b1b7dfac9e50d53d2ad12876ba96419b39d7f94fd88b58ac1c123790bca733b12dadec6922384c6f3b7284334bed918acc06ecac7674428d56496e9d2e8f0175b3c7e384218380b6d59dc93541ac0a7419eb0ced7ca8c12a487fef9ea50280b7f7067a8855e784362e85703f6b848ddcd4bd31293baecda021fcaa7198b27d37900ac192d71de4e5124089bc1c8234fc455fe71171fc44494395b323fe3575ac720af5cff428326cca56ceb0c47e20e1432018a769f467405f5a8b71e15e0bd32f027640212d893678ec6fa16e5c00bf5c0eaf2de0333126ebba6b2306211cbc731a6baa8fc5a64a30141a8bde237c217161e384af3355b4a253d35766a55cc69be97abead95dc2ccdb4d243f64aa6d74330cbb2fc9fffa79fb6b6baf99e5ba9abd7966efc1586e72bd25f6563fbe125abec67f24e3510bcaa34c49499811ad2425c25593ff362c90c5c4fb3c4c45a4c63c46cae8cb1759ff2d82ac2726b60b4f094b6344191f3828c78d369956b7a28f650f63260c2dcdfa66d1df4731866efa6a335281d1cf2ce3635eb4294c8b2e1d4b7ced7b4b58a10d693e9f5a269b9d3451198735697af3a7b4b630b835e3b56e252f71f9aa6dcdfddfae13668bbbe3538d5aca766dbab6655c4aa906e0106640d21c30f1a241f4f5dedd526e8f579848f1b64808afb54bd2737a18d9a0e4a078705847b59a1ca4b2b554d03304daedca50726cd23326a6507393b2dff27921b5d7d322cb9901e0efce9bfd95039bb3bf6a99282f9dfb1e90289e986a657b3aa212cec6e611423eb3e4523f4723302b1b4ea5db2cc3fe3a7f0f3add38eaf228a6f0c02b9237e4078b438c01a0856d64053427af9f84eb04f022fd12986287b48cde73554b014f75a04d01f7d3fc6285347be643ce214b72c911e6c5360909ec590ffec8b4395fe271e97af852edd3801ccf04d3ed6684c66c67278cf331ac7c9b748e2dff377cafc7fc6732352245aabc9f5f25cc29d8f7f211a88a7aac750e488ad0304b7907bb063e29fccb16dd7ca0b78fc3962046a83f9c7138d49df3b765df47829e5f56e5155dba194d5128648b92e4f5c11bdc9232725faea4b87d6d940b9bd7cead9462736c7ef605336c40c9a053a000ac390b6340dc85a6905d35dc83c2d13786d233952ca8777b5981b761376f4ce2c5bec0587c2b28aecf39371b8899d227dd58c054aea7257dcfd838c32d6053362842a0baee7f967b6a4f5e1cac240896a8ec8fabbc4a551a55e674dc8cede1b9cee3874ff9fd3b91db433a12e78904aa3ec84d57a0169f1719297b467c46b278f671f74b8bb3c2c0cc2a093cf93439c1267e3be38b12e9b5881c27ab47bb01397c6470b80174ede3df34ee51ac116bad6fba58f8b8e2c7e0d1dde184460a5bce9e1d853d11ac017001fccfd5b767afb69691844e8327d39660c06b8916e918f5587f5abcd0f0bc45328ac01b1ace66405ed6c7a5080f5795f2ba0c0d9e5d05f462d89aaa230f240fa47c5c0de0b2099e93ae8c0f94a45f0513ce2797cddccb5216bad88333f6fec5805e0b9474a18ff562e78dfe325c1a6bb3648b41595690cab5ca9805eaa8e13526d036f4233f8181aa8efc76e14031d343bd5d9023fd6cd6b32947e173807883b6a964d398d3fdf9f34a44bc5fe41c5d72ffe5fedaa13fa1da68e19656ed70771529cfe822fc694be1445c79a041eff9753cf47a48ebe9f2c9f1546117b97a1c2bd6e375b957fe38cfcbb29f8eb726f18bc6131b1e27316064980e35d95fd913583b9735c6bfb03ec86e935024e60679a61d972b4aa296189fbc268552acb6cd890c68e50e325719d2f2c99b8105bc92fb582eafc1d618b4e88070e6d8df4924a1780f63ee216c0e937073725353b0c97acae72ebe521fb05fa78a4d6ecb7ba2b860190b6a5c340c83249919c26466c9cf4a9b774fc823141f65196df32edddad59fb05ba24738d81734004c42a7f92f5234b7f4fc0d605b032b08eda4cdfa3b03a3b805ecf5e4ad667a8cf399efb3c1d6822d9d5bb5eece6e08a515cd75c4485537eed6cbd55efb0a3d393d2cdcf44846f0c27cf6a664c70dbd54fd56b20bcc482de2eba84163375b1bccd43da63467557828b791dfb0a976628206e26e9eb10f1e9b9fc34571cc1a38f54909a1ee0b097e0f22f3ca58b56c631708e9baa52d7eb551bd327a6e0014fe98f04d7b0544fadc06c16a5652ea16b6c92a014bdeb2c070843152847293a0a925cf3c22bc9ac23464919ba6340cf233990690c94601876bc30bd5283f97cfdee757caee7b7b41fc265fb2ca9751e3b523e8498d665151d1c67624a084571f6c29973e624703d2e87f1ae5a5e0dbeeb96f46698223e063d10d85fd13fa0deb3891359844ad5e8100036d9b70b3b7831ae78c927a5e2c2ec62992cc424894ccd6f064e9ac307e6a2dd092deed179cf60b4bdc6c56c32a538d477d7917f7203f898659104ad5aab3e520a9f21d9c01b581cc968a68a77648cd95f66b5a1eb1b9d60b0a73c2eb05873f279c4ce43409853df2c8db254fd5b63af900c764ad4a0aeb4641e1a4e4089967e83603cef0317d06d1b990354c11b17c83c2a78cb9152615b9eed33e20f61a83179748ed4044a65edf285b155d41c735a883a481fa07c4941865b86d3cbd54c345d7933e32daa90a1291211191e0a3a5015f0f60d2ff07782606c164485aa469bc97f74dbf1345ea631bacb972be00547074759fab2b98a78cc43b7e4fee587e40e23d9f8ecaf03337d47d27bce633ccd97c0b18509afe35d54b1761a4ecbff6c44dba5402f3111eb671183b5e6bdcd69398056b980c35628f03214e0cb4ee5364e51de27843ad6c24b1e972889d54ed2a31d74000c32fc90b3c96dc3761c9649305c5f5e75f5b5ab7eaee213dbdda1039d4f3f450c77e6434752b74a55c42c98719836fd91fceb27be449d65c89a823218e882b987277622ce62fd0b46130760f10be6b49ec57e25cf6584a99433cedb1ecb1ce25cbf5e2b6eb716c12064f2cc45f4989c4c1b6c1ebd390c44195a16da16340d3a8588754ae676a990df1eaf04336b3252a5177ca3b3b2afd8e7555e92be6f6d7e64bea52c8d25adce3c580b5731574729107afe0e1025e6da2f2b05d6cc223778ac7de1202566098d43d0e4db6df8d242b57353cbadc0711030c6612cb92a9f9685c88856a0739e61d08c8fc5864fb9d8f41b27b43152ec15b3307e2c6f20e00254984e6284763acc977d9e16ffd4ca8be3ba7a289e3c5863371c132b8300f59d50f9efd344d1cf51c5ac64f29210740be2dfb720397941e2ba939e31c9ed563a674628b6ec3c8983be01e41eca61f869b920bf08db3255cc04a1f459653a4a3c204e6ec5496af1984f5e47caf56993bce1124bbfdb5d7081895a96170241307f000ed22ba92d5f5d920ab39d3ad1e288abb76ec3acbda6a7779be4c65e99bc7d7d5aa57d08ca1774e0fb146cd3a894beac12715bf322febeb256518addf26df507db3c79cb2883e6bb1e4716e185026cd760c76038d52a2e0695d76b3bf9da7df9f4dea5323f7dddc8ea1a0031851928e354e703651f7a21df505a4e7f9f7a8a398582aaa9f504510c0bc6f9af8942601bb3a6df3faf2e97c9df28268e1dd466857d413fa0bab4ff017f12554dd317455d6c716f9449c5273ffc959f147d7e0da0c2eab432b83f96f7d2de7b1ebc41eaf2128f8eb8f9c09c7b3fb4e95bb3424b216232406b81abd4c0afe11835a8425304376b08a4442c6eb0e88a51bc67a49b143bb35416c9ce613538483c091bf181d322efe10b2204aa0f0e01507a7cb809cb54b5cca5f44c20da32b2b7ec52098e53de672795b68a44ba667bccac558210307ac27bc5c203a2e6a264e7cf3028cb4ed41e29bc46985c1440187155b8bd737fbf9480749d62481d805463d75ec17c7ba83c60cc7020fe4b110ab1a248f6fbfda3e5b8a688a280f87a53ea7154311951c2001a7894eee171a64cba9b19a21e09540dc5ba85b1b2880efc39c8886dee72e64f045d00d99a90ffc81fc957ee65b7bb93e113717e7e7a275814404198f9e9d33f45335908f1ae917e0322b3d12c3d298ee814d22f8a57304faa93c18a14fdf53f05499239b66498512a6856ea194705521857a1724bc2925ba34f0e2707c84ee234c3436b4d3ab46cab863a28a011236e564ddbab3d49baf77be49ff2f5f2ca75252971a421aa2d4975aeacedba6cd3629efef8b2322b516c60ecca2541112b59d73b88177cd3be06163a463306cac2c0c1b11f84ab9b2fb6ab776bf0dc0fcb381975e4c1a0198b41bf6c1587bf6ca7272d8c722a581bce4494be5431cc5e3038ec33d843b9049b018fffa03cb3ff58e5da6bd6d49ffa6f776a5c4fee3cb258c4bf92e5e4079e38437f321e0c29d608cf5f69129e705e66a7036d67d43fd4a2919271fe07052fd30c049b793d2af0dec2431ea687077cb7a7a5badc21fcb0c2ac10bb37247207596d33d1c2232fc2a225acb9f30be7fe6da19514def9b595929c1c0c4b146099bcd980356b601ed0701299ca1a5547d62badd0475bc76fe51d0565b95b52a801f14e1f1ca62526cf8931f0706e3a478d20ce7eb1b1088454beac15277a72c90dd95f6146f961e41caccb2cddb2cd0680760731bb6db221944eab186425b0c2caedd840be5a2575d8dfd5810c4db5403d4491304130bbc564cb578d814d952706570e56641e8ce6232a2d4b18941c35301cd5c29211237c274dfb1aae379e25efdf827ff6e41cade1d57ed229a6ba76bf98de6592e5ae3ffcd481b53071e452a0b25f12919003474bf4ad2f36138d3d7c23c89b5b41a25c3622bf1dab6762cfa86a5bdeb6f2baa9cb3ea7dfdf9bdc700f4062ce8fdf477a17088bb2bf654e2eb9ab943472dadd73e3b63a4fdcf90fffa98983130e16d512b54aa0d4acbb1604d00fb2adc4a88e87d466237ee7b0fb33e5f384656a8759143db4c377e2cd264259"
|
|
+ },
|
|
+ "rotation" : {
|
|
+ "falcon-512" : "0x398c95150c8779a927aff8c6d9e3ec76e88a29b75d92eebc295296c2ee884f0a2379fa05bf5070639631133c9f52157b6972ecea3a9fad349a3417b92bc1b9eeb32505801a35cbbcb6546db5f67672940b1ea9fb8ab5fe58a3c9242b677355db84d2c9e452c4ccbd3dc4d95b2329b5631a429f4aa10a772f15bdba2bfc92a1b0d6eb02b4c70b45ab224b2c69d6f1ed771489a2c9e29356e63e3feca0c4a8d9bfe5f7c709385eb1225d93197e054b263e911c8132077a4564f1182a4691de144401f66b162fce3b844d67710d41ecc92398f3169df8fae4c76dd370355ccbfcbda290e1fa8c29685a7e077f58c9b675faadc3b9cdcd7df1ae9d6b209c4128f3492260f9230416739832c91a429ee2a1b1133699b1a427299d54e0917bd2047ad0061ba9c982d614350ecb0b6ae8b914f911a1b603344f954bd775f2f2311bb851ac8044f4eedf2a44dc4b1a26adb0d8ba9c7c344b4157873e72ba1a2d84e7d07dd99d05127bdb6f5d011e4bfab388ceddab572553f8363bf0d157b17a939bc96979239da528150b79a0c214de36805f170c54e9fbc52ee43770c2ea4d3dfe89b7e1cbe3bd0b3f7627db43e3fdfae3ecd1486590e609441166e24f2c814bb2487ae8e74a2d882e0daa657246ea5f706f60384edf767ec6465855328f3cc1b51e8669225a1cfdc21b9a52b6a661cbaa47e78c94bd0921c9474772e0c2abc9b68b9b3f848edbd2bcf9a531559a532adf16668220a55530d0c74ef93e52f3b2536595aea5362bc6fa14b0140487749722d3afb4bd26db204c62f115e01178626ad2426b7c058d0d419957461d3b9973b12fdf21e66d5cfbbed2c4c8e484ada7bc43cc023c2c99942314919a5f3a868c36ec3b9d8e6278f037966c8a39d32aaf0ec131b9350bfdeb8cba218387389b61d0",
|
|
+ "slh-dsa-sha2-128s" : "0x9ad59fc071d803b9023fd65b499d1f93f09fcbf693eaab05f864ad85c31d2b072baf524898af2096e711c65dd070168833d9f1565d4636f5a9c2e65d3ed87740da30981e2939749d5f4da0c91ca6520101a99d56b9215d3e2edd1e91df5ae968c04dfcc508aa70d16035ea7a7a7369c5f5e1b7edff39db94ea13ad4267802f87c11cee817f3f566d62e2bb68d43fe8ad9f740529b23aa944b73e38cc2b1d76337c9d7c020189e0982ee60d1936898f36251de7a94a89b8bf89ff45bf6c54dbf8651947cb181eddb6a2c1cdc481e552422225639534ad12345462c7d282324ec00e012515d2c2a382edef86fa87399de982cda3f59fb1cef212c09301d6eb10b6f5491d9442dbd70b362944a961ed2b0f588cbeafca796078f986a46dfc99636a31154f10c4721198c22f2ce35ab7911bb1f86fe08f4d4977fd0ba9e33efbfd8429fd2e2dece6ce1d1f798f7b3c501ca903bd248f977bbef2567c562d9f4bfe3ad522a1494a0439f10237e2758286b58a245cad505c662433a427b6c14883abe8be61aed798c4564c6c24dc072ef9d6b9ccf3d7aee26cc4e8bac1fb639f9af1ac5ecdfc6a412cca0a1fb5759230171d45886c0585d3634295bde2a2055df5c8949c2a52aade0785696c7c6fbda2db9217e71caa834c55f51646102e64d0f14ee16a18ab03d2b0c8540ad05a3b80bab5755c23a654dc60758e8130952bb1b1306e2e92ea15c9feb58bef481ed6e9d7335503577d27bf22274c7a079badb6117c85a06587016d1bbecf53aba658649554b67b2cd8dd4b94b519477f11db77753ba1408a62215fad93cda89498d14b387ded2a142bf5c6e85f2a658ee295a57861f9a408529fc5e83006a551a0f30c0996d8a34b6932aeb7e9c102ddc9e0559af6003a361ef9a9214450adaba2d2a04e11f27ee7e1a495c87da925f50d5afccd6eae686c100e817663aaf5b6a9bef72c928dc34de62408bcd72f791d398ffe61a2c6dc865bc28c324a2e060f2c7e2f8e9c6b913d6bdca590e81448e2d7317a661cb83393648814a2ed1d54ca14d1930d1d8d20a169f8a614393fc949063917ed099d2f6a7673df30ee8aa8cd5614069e4c612f4734b06130ca1351263249621db9f612dda4b853d9f9224ba624d8f716fe5e9eaecade48463d6e6da0f639f895c1e5f8e9337bb0e98a6347022315f729edd1e252ec9663030acd0fca1b7524391c3113792d3dd60e81b5b55fb58072db55dffe1dcfe8d531b647b5c64182cdf7794773d2ba27b7bb34433337e14e1c114daff27121a0feff0558254262f4073d9d692e662ca7773655ccfc80bf3b80fac6b507aac4c2a40345bd3e7598e2ab6eee8da230374b46ee6e40ada0e750d9c345e153f0a66cdf30cce8e2b9eabb46132db6ae6f45f87d0fa6ad092abc21594656688824da4536b5be57c3c0d7cab3bf21a268bdf0e1f7cdbf1e774d374bcdf9787f08631437e7d711d218db3c64a43fb5943bd114ac5a673082e8a687702cfe0d5ca620c994e0ee1fa76248972060f45ce79f25c070c1d147b9301c05a6cdfd385e0f5ba2ae78ddf2303dbe5cbaa2188597bf13e7ebab864d447cf06112dc1b38d1e9abfe82fc750585eb51b79f95176b82322e13a57cc6948a28728e98f7061b2a05967a26d19f81adc54ea613376495ea2cfc0c23b6f107c3506b33b367223dc88d5cc34342efecf9a7d66e9426c7e744f20cd89e26dc88561eceb65a16ceb6e330c82c9bd4b4d30cb5db50ad4ae0b2fd751ddb794dd434717574d4d485b29e9c767f8aa5c0277884f1de828e5e213bc05e75467f7b57dd36afb3d5ae2b48683d0b5dac05e6f104adf3afcc8d334c90718340a4c9ae880499e0534dc8ba48f605a38564275fc52574e0faa554a52c23f84853623c54db93acdc1c32a952593e5cd75e17e2619c48afd27c3cd8a3be62956babc6e2795565a48e21475a4679aeb9bdd13f5b304448a16e307b28791329173847d7ce6c0990b4a1b1a8278ad6671cb5f83af5bd6ecec387a434917f2a902fd36f7c79d898478a40076ee87f6ce03c6ce5b0bca864fe58a4a61ad8727ff11b16c8a28f7208b2ad4f2c30e79fea01df53584c40e8f3ddb66c3e4b25b7781c8eb144b55865bf2d70c8b8f1dd7778075ee906bca43b1d5092ccb811754c612df33566cab5c7e2b1e04670ebe50b2a4fdf80aa1ecabcc4366a21da389c0cc6ba252b587c714e98ee9e832c56bafbb9c0365d5a05c026db5ee72281ea64ef43c7da8c289ef3bdc82a78b7c1b352095e086d9b246e96d3b54677eb7af15121b4b4b59a00d5e247c9b22c98226565b19d393b5a412cfbb8515fc77f4e137fe2bd93c0ec3bc61f8c180ce57f45b9d1825df36148b2572a10ab550cf22bcac64d8605be4a0d18683a65a6720a9d765007709157f218d3b751f3cbb2e8733e3c05ab6938d568573bf65ccfdd682dde65c25bb288786ecbccd4d7dfa998267a4b4e6f9629b75909ac731c5a6530feb97f38e25961672ac6a8b2b3c39feed6bda2872ec2d96bc4bd708b6bf05ec6e38ea2e29053584ae53dc12668cbe21a851d225e773c8e9efe0c30a183d158771eb255df45ae91ed5d37daea1b3708f22ca2522aca6ea0c6269a16fedcd3a1dc9dfa8d4333c7dcf95e0c8a983d113423c5a4ba55428fa016bb15e1a42004e7d88df137a77914f322b456f9b2c9f537e75ed7bd6e25d4f6c51a2af8d45915f245892bad2694a56f4cadfff818e211c3853165d51d6cd91f129d85b14b067b9eaebbd3d3a3f849d0d45f51a690c4dcc9b4766f18ea30ddc541ad8fd97f7e4214640106b542db8fe31519d1c86d1e7a694aec2dd4a3cc97357e24c8f04f815a4bfe7c016d18149694d00a930a4f2ff889902a58d59cc7af6893ca538e1141a1f602bd6692e347dec834bd12dffb019490166a2aedd25daae3cdef372d8bd3ad02ae3ce4d96f22913a89534b6eb428b0ed3794f477ca5bcad0d1bd8c55e50444295041f45ba07f1f745a085aac47cdee14f7a4f0517a2644ca3c66dc05caeda11a3dc500d94326984078bcd9369c77b51cf3e7fb52f186b44f23b48ed6b12a24232d3909383c49f377f29d5650d6545802af24181c580e4b10f4f879146c6849973e36e00faf7cea302b0f86465fe0cbd5fa93e6f46e3660e9ddfd1ff0691d94d20005701a378a34c150fe5a1b33f6b484745c753b8b95d1e6424ebe566fccf7df7c3318482872f352f66fccbc3f8847796ff923fc59a129de107e251bf8bf00c09e7419ccd18ac92c26e20952c68c22706794a66b934021c031d98c8fc80447155455c6c7078da4ad9df937a61b09fffacda649e71be02590c8ac4cefb9a486cfc25678fb8bdac17a5badbb7f76a740cceaeb03e30ce058b5fdf707b60be946893ba67ab9d38da4640c928b071c36fca0b9c2176f7cbdcb8a595b04b1aa41f5339f64928e89ffbb3137e6ad9d14d31e2647b0ef1d92ce35d4cbf18e1d586433f310e5fbcac2a6737fa06d2469e3860d994816f54c19b9b3ee2b86b477537d8f9e285a4fd168ffc304ab2cb39e0e46ce105f01354c307cc670e152931fa4f24b0b10a4faf2d862d982e3ac625be859e4ae03a697dd52fa57ea20f72da895bfb16ddf8e666f3a8d2733775a5f9313ced51c7698110e26be215e9557f7824918b9d15fd690915e06299778e80bb29f82a75505a04d71ed5d84a1e9bff12ad98cceb9104232932d68d579cc8440bd1c2f005773acce5a2fcfcad20734927434b7f3e0aa7b49205d4a619e8480bdd94ca8c89cb729a6cd7cfe9bcbe7c13d831a4b0374c3bd7b1520abe3a7327d54f07f387900cf3f6a3be59550da22c9279d44499094194c45d57f666032a41f967737d75122ca5d0b06de9e996da34a86e51dd5b45cff00ea0d88082ac6e3d4ba526b0eedc50c0d7c781db3c6e5fe1f302f3ce7aecab3f6ea9006ad36bf991b2b2955c72bda72e7afcd06e2308b2bac2ff2d55e1cc20641ff5e3a70a2d20a97799b6b1da1fb72b5b9fc7e845d89afb64ea0857c61034d20af677b679c054f4153d9115a41ebc96365f61b0e8ddba55eacb0c5be73d56b00001b22f1c9fb39a3d655117eec07a7c87922cba12d5667bd4eccfac5f53e521023300aa936baac8ca5b243d1d68498eb552a79793bfd7d90f929be7f0e636a3f13ea18395ddbb879d98b7263b17f32fe7d046ecb6032d9f1ac44de5db1b73227822c12a1726158090ff8cdc45af9491eaddf269c06acc3ec727a7d17bd1505dc593f62405eafa963f93ec3d827efc9f97106750ad4f95f5c44958225df037144a1d65aaba1d31fdb8b7e386d4a89bb74d3ca3ca26972b45480fd9db7fd3ab7fae2e6e32ce32fb7b0d9a145b86982ada12646142a99adc42d5bdca59191de5ee33c40dd90f8a03296cfe632df8b12747be95ce0da70556c4cc4a68b794b50944c4ed12027ecacce071f33114ee7d0cc188bb0600ab2e334cded47e2691940343c842da0c954ff3cd79d477a0a734daf8586121eb004e7df29693b4f583f69be26f7074efd49c6a826a5454bc492f145a364233d86ef517202f75dedbafd42e9315ca81896b89ece648a300548adb71c3abbc6ea15cd0b493f38d848de4d26fc8ff9ac6ac6530b6d2a25c29135cb45e0714f8b47b36dd39c9b329c6d463b443e3407f006e73e72791225555fc693a0a44c52c04cad45da569375b2651a1a8398f746486412320e2ed9b621c490fdab93cc1f6eb2f994bc4c65b1a078d8e9bf56da9276add18d29f1a7f01416fdccef7f8e755fd759d7b73acef4f09bfe96bf7510e0e2d878609e38d1b70487c10c3b29302a139fac460fbca5d9e194754e995410b28f9aa109243e7808dd54a9ac24183d0a4978dc7932904595ffea85a34c1c4b169a1000c697a5a4b51c4b40b26fd145c5f15f8f7505ec75305a683ac860e945da9d596ffc573aa985232be6a0becbe936a6184271e434379d383ee1bd406e7e9fb566beeda09900caf84917330170a4f046b9f1f1e597bd4d070f91cbe641eea8caa07fdeb58fc2a6d77c692266048af382b76a2db232f53688fec33f322a2d205fa05c669a65f736bf2e53cc9e23bec381e894c4739496949f6ddbddb6fd7212f80ca5347edabfaedced56b64b8761d0c522921ae8e2ec18120fd41f2f00f97d5f87971188188f5264f05ba903a3e13a95376b30e4adfc43f56d1f49914ea03eab16608db50637ac62af4bd83ad20c02f1685336e70e758dfd4f2009eadaccab91550d8eb23db8131f9e05ab0cc61b4d565e5bfee741d557e77b4cb91e76c73007d77b671c6f6b749d4ac8a5217270f7b02e44daae56f3c198518aa199c89eab9807d30c20d95582b35f649f5c678d9e76af4ef19f4b5a10cd6624622ac427fc78f91b9ea01a15e6f61cea48f97fbd8b42f1a3cebbc27b1122eecc5209dd5a0cffbbf96d663667bb101dcaea40dacada24d3a684dbafc8d1096de701a660202e75c8d3049280c2924bb1bd2817b15416f7ef1c69829ba22ba014536e3d577dcd6500ea79da60ff8fff0d9bed956665a0a2ea693b603ea348d89ba50e237da560e954b40192d9ab0df63f604bb343eb7b265d5e1b2ad243dac135cd0be9b82ad4b3b11f953fee40166116ffaa168a7f8ad00ec1bb865d067dedef1a3ab8f176013697e03324f5a747ce17c3e516b13d3aca137046ae7999330699bb721d76a279778ac99485684cc922879920cb69fbb139b9de824857526149e77248f58ac8862b8221245efe6acb7ee8c1fd12b8ecbac3619230f4cef3d3867e9d504008a3298fdfce8e37d34a4e752b5a63692253cdd2859e50e1f2a8d73567131c98be69c2495a593b211532b6d471c78d76a4dab957aa8a88b5cbe0f2ffa5f87fc7382f7371719d8e538360c9048236966f19eef79ac680f1583e55618ddd439fffbefce16fc8159343a544545cdf786d861af25891447e38e6b301e6c787c15a7f6b253dbeae713df279aaf6c8f968c59417e8bed6b09f25f5611db5297c188aa2486af8d3ff1d59ef71a5ec8358e4ab428bb8e4911e746c498f302786010599d8cd773a7cae5ff701388e85c0f52dd6fc80da5eaab12a0cb051b2b8c9e251188b0c83e0aa8bf38fa1363e7a8c527b8c8cbc5142c3143e3b22528e032bd026589294efce133e0e62088044a602554c0c9f514c67a9c43db4cce50e4905c31ba935d811fe251874e92e7e9b0e4ca65f1fe3761f490416eeff598a25b2ca2528ff2fb7dba6929c07e6a567e1583fb634f293bd02ee99f7eaab121c85f546c74638f4bf82b90c27468d96439d1aeedd57e462a05a284d8058fc36b3afb73e47b51f5fe4098ab2697a1217d4be00c09bca71373334c26292d95565388f57d83757273136f3414cfcb4aa2407013381670e7bce0b0178b16f45a7962291a61bd2573caeed2005eecb0f158f2fc6b4797c2a2bc1a50d194f6506f516af12165fd617bd1ce9f1501591f99f9dcc74dec679263ab2ae63ab26233c32b2f10d39817f7be317dba040b83a86ebcb426f4e9fe351003a0e3d0ba58bfc502880c939bfebd20674c9ad7fbb80deef53ebc64f8596db14ffc92c4021749f17b35b34bfd047537005af6c21dbe8a85bd0a7f36b06f09a72359253bb2644f65e737017294530fdb6e6d7306f0b5e2e629c0ad9d2a4aa1a545ba90019fd7a3688ff2718d7815b215c6ce2404af3f89df3fa4b18696114c1ec9e2f00507cc1f240726152d36f8a8d2574bdc62bb1c1bb57ae33f46931ba71b0798aabdda2886dbe530047e9ce8a0570681f60e56bba402d9cf81a0b84ae3c3955dba65d9d947170647a4ff9f1e27594db53892d322db03441c693467cd89eefea6a31fba70d7bf77e59aa817805f953a0f371b81cbbda07782809e9704cc285d855da4084f3d3a9050b9d3371a399c9d59aeedbd979c611835739ad3088837174e2b60945887657688befe3f2cd829c1ed92dae43b877d96461230be1d57e31bcac5873415059bc46e78a6523ba40c6f8dc597a2de4884d7d10b30498e1904657e1baa6c6e47e0733fff28ecb845668469144caf18d17dd11eb09bcebc197bddfbf1f328c1888483206be387a4fb87512925543860e290284310047bdcd59ffe59317cf288e7784659c8e75d2dc55f8f561a5f3eceb7c1a691eec680a080a12b9ec491b3d96f61a6a17190033c580530afdb60559c197e58a2d769dc96c72744a7a5a92e65178cdb6ef888c1317a1f1c70f70476ec01d5a47af5918bb19769e7630b471d35bca21daa34242123eb013f770f9db4c0f4fefb38ca191ac9dff2e873dca9aebcc041728c9a9d502e96069d7387c88e7be143818b829cae60c21a7bab3e8d3f632af12e194ecfcf7a5967508ea496bc8246d4e3ba9fba8d4c7fbaeffd494aae82d73ee69f0b29ca537a18910dccf901292612436207d0d4161699fadfae013572537d9ecc6cb36da4f6ce91d7c67b3d5612af1c33259e06855d66df8da02d23e885b501f0756187da39fa61a3f50904152a7e34817a5b870630e0595824fb3e5065ca0c7863cf52418e5860cb3441650ebd4b3aae2cfc83964e1852d46be856b416ea7b31bb4aac92c1e011692d8b65b6bb42f3596d8989b1d1063e6b7c0e7eaf6cbef5139e1b78c19a042960d548abbe4faaf664cec2ee73ca30a021318e52689618a725998dd6187415bb071bc1126c4e74fa0b7d8815b61d0f9f63dadc9bd55695df4ca451bd8fecf29232d118596e4d8929a855a76e40871678e62e380b38fd9c11534946d831e398276de1f5dba90ef4c18e7cdf2ac5bcbcd2f5289c26c2054e3bb2cea1abf327ec163623917cf6448cb9f7d9e3a8312cab0afd383041b02a25107060d2ae266ff8d9c83746f2e11673e568986f081225f70d1be8b2d78030a2f5b51ac846bbce6d726615dfc56f355e5ed96e4dff5d56c4a564f9a9e1ebd1239bbcff471fba52bc4ea7e3f6d481017948da456eb18dcfb23fa9eab669b12ed6ceb800683eb5330b7e7e32010612ed8c471c594337fb9ac068268eff3eadc2f35c21082d81ca0cb5a60d590661ae8778dfce0271fa2dfa34bce8323da42bcd3d907dbb985a4d5fb889b905ed82e442c7d5e518b4b3f095b45252f7251d92c8c26a5ecf63eaf7a9a0828a9b830e332b736fa30e816b3430228524bf4723c733f75f5b959c50d69f358c8244c806efed3514a1ddb172ce4706c140ba00e94621e05e235d6354a305614dc0f2fc3a69d71c40619e75dfdf875e4375d20ac09bb6ef1bb781bf06bceebddce17ca9c81718fa48ee71a37c99d57d3f94cb4c7bf4cd56ccd90f23937bd978dffcc19f6ba92a0e86acf730edcb9bfe48cd1a6e205fd85e4e534a78f1a41007194f28fadc4bce7d573750ee311953e1af1eae9249c92c2cbde01a341222b5f9fcc5f61c313a45d52271c67bc980c3ab696e4fc6cc6ea1c20d8b21d789391b83747bfae0b61a319e20017433fba9289fb0fbeb661592d7c95c4ea490cab3a72eb535ff4f8ddc5d87cf449315768d7c193d296992a42d93f8916f9bd6da396119d12aeac64b06e60ff1188b7023cdc262b4db2e38af9b20bd58162da310ae8a274186ca7a49bff22340eecfac62c2f7b04180be8917b08d9bb8b00cd9d4523ad209abf6340f905b6e6b6f93a5c89132966216445db84e8d6b0f7c749e7063397e5714cbfac29c4e1af8865906efe738a943e8db7c07fe9f1fbad804297bb916e17e79a67377723fee95384b2c858426b352ad7a72305987721b2017c59e2f9592a8d6e433e58158c562042016e7302f6085b1f9efd07f2e8bc3ec588552784fb8226f9235ba94d1b6d7d759be7a2e43952511c17a4d453e4be4547e91c2ece086a8eff9d8ef36cbb4efb06c872ea929d60d438ba419cedaa0445fc2fa188cb4d77be5b294c3327d2ff5e94a2fd212dea59ba023898390ed118bfeda2470d4e217bd91e9e5464b974aaa3cf9fa7a3d9426c1e034a8a37dea325880a5b94facc17156008afb72d22e920bb96e022b67462510898b238f5914900e863800873a1de639bee3884f17dd3c04b62296088323d21db99163c3e7fca9e72affc5678e808c788651b00ad65db3e58e7c557f05c0bafdc3f9c7986f4cd6062dd76f08048c79538a8f4dad7d95578f6b343860628cffbac2b938f4d16da5cd3306cf01f233ea30ade11055b6c380d3f15de84832d2d84bc7483d52477abf14da42362deae1fd3ef4328b677bd434faa9a05ffb873ce0574d368c2c87af5a3973cca38f8caee04545c323886e695a1e1619197f79ac047c858ba33a2cfa23297d5c28e4d6b78bc2c8f3202a666578fdea43d395f9ca100e481d374d479e908f463a7c6b8367b7c7e4fd616df811afd2c09b4af69e49090c2fb4c1e8958d12eaad117b7d1243344471ae5cc4672060239172e3cb314de024b35c78a45b4058f7082cc978eaf68ccdce9f53d96d7b3251774fbe5a01eef1b5586e78183b74ff6924e0b1d532ef1a0478073d1a6b29a6bc5554a70770240d715a5979f34585e24aef0ffebbc4e4b15f713e439aef62e18b9cb0d9065192841bfdc36fe7f5ecf521e75268ef148ef16e6f9ddbe0d4ef25fb63249ddb21ebf3eacb595b5e56ef6356de198643aa12c6810548a4ea12e54fcce7a90e0f37f6357acb90fdf3ba928845f573604518cf5ab5b5111f9ec0ca12a5b9aa50429e23473c3ac0afef7704c8b57111bd07f2aa1d9a71613fb2f300de45291c68b848c254c0d7f92b5851b6a4333fe09f3bcf663577bf9219cbcd02147d8171562544bbca85feae9ed654ef6dcfb08cc6714c30c5600f3079a743307bc68f3ade52e53f8fcebd7c99bf8bc8db6757ea852c19b6a3bac2e33271ed49ec3671793022c7c8e16b6e80a428cd3404a26c409878571d51eff1c93b2e7bc2c692dadd9138e3ec076e4c86c56f44587c7dc2192811804f3ce2a63bca61564fbcb0f5ce680e5b085aaad8c1fd2fdf849a15323f17745becf2bf84c7d3525e2c684c078c92c83110f3db3a43b1b8f3d5d9d58f7a3862a6e1ab6293b816bd539c00eafbbf8668d95086c0abcddda726ce1e0ba43bed741d3b3492524228bf217f4ed608cd8aff731e93985d8c7c3229c702cd3b423225111db63c566f0daa63af7225e5d54aa2e449fb691cc45729079a6dc4a712be0c88ded413f70e93dd912a0557eeefd3762dadd48b4ddbfa48ed122930e515a852c1586c9a7db6ca2a21646d64537e7987548247fc0e819891638177ceb44e2fd2cb548a5f298630f744f02973b30cb965c174ba3cd0b13871a8a7e4ccea85501fdb04e7b3afce1e5f0970ce7d1bbf51bd0281337fe5d56d39ac8df51e134a0421635431802704515586861ab1ef9f0e555c4c786b5562dbae90792f4c42299f100a447a627efba8dd8272b9159b4a7eae573e708138640197f044863f0a1f64b9c011a6f805e1a055b5cb65aaf329bb9b18213ead439930dabd278f87523e4726555560ba195549d4a0020ee18dac609ad4a9e8986a9a9e487b70665aa2f0503776343ba30e0e71631fd716f2df46aeff73c768b3b1c4cd838ac365c46f02ac3ce04220c3016ffbbff234bfa00f25553912464a8a5aa6349597373060ceeeb56f8a66c14f8dea8219bf03044b955249b975b948b42aeb0fc97e571965a447b4204948250c230f8956583e5f5057b0374ac30acf6df8c2cdee0c154b4eb1f51e9e2b579901730fec315ff9ff344f913ba9cc1bebcb0d696217a6f7a1d0c14c23ac2d114a356efc62ad2c48ff456fbdacd15a06180bb2a55c50523fea3f447d11f4319b0e9daec9cb0df121c331bfd05ae7676ce6f8966b855c6c83d016b6517ffcb24be26f1283cd3cb2e8cc4c8b32126dd4b0dd50b63474f6b4cec5de2d05278b25408998e07ef6d74def57f6500beb2c87c2767e1ffb7f9b3d36280d0f0678e9313dae35c3943cb2d69b5bbfb4092dbfdbdc55d7d4ebefb20dc073e6efdfb23fd2d4b9bff2551d98587af13867fb17fdb1e77d95b286539260631bc800bd27f3cf3f6904d81d4cb8a19a924af0dc45253d370c5a1e7dce7a2d1457dbf59eba5e4a17545d1c86acaa4805e4aad"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0x41f547a71d1404f147606491f3b96e49f67d4658",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09b3f618864123704b78a9552a0b068f395444870c2cbd5d741a0c565554bc2785a691ff502d6ed0e14c925eaa24c075d20949d12f369848e178d50b085e87c9b251f68b61ec506435bf5b53a49d299409f54e906daed0c1a25a63563090f6660380321e786311b492bd7ff684a2650bec34d5bdf071c49f5a050415b2c3579b2994fbaa9a97b7f24a30e7e8bba68145196e0424471de31775aeca732dad506b16ad4f61a325136a6664f439e60687e764a009db3218f706785b98b154a625c168fa2ac541b8dce39682172b95e19424b98ba985622b2a23d8db2d46a7230bcb667372a924aa4d1a9e9cc1a8dc1ae11fe88081d74d857bf63e9814a08c9ce059a4b1ccab23a2fba765086b15bcba135d0937a064b90663ec69ab521746600610bec0a6b3c705277f90d588a00e908dd075059de6c52fe05fd8fa8ba1b3c2cf151cc810225db79aae0328b8ea1e92fc67b7bde405a1442128023128a5f7089722b954f15597ebba3aa3b55ae947be1e659be52af04c3205492387b51e72746a904ff13ae41964281ebd81783528269ccd6d2a7845d790fe4cda8ee58d93de3a3ca28bc4e6e18e812c313452a4468049a86ae39d5fe156fa2a43d29161bc911d515f4cb6b625f4679e37d5b55064a16c3e48a7f3ae10a09d9ab7f0ea4dfa2fba9da412af1978720fc47185c7ae16474833c8d278dca65b822c5526bd4da67c0700166cba95e3d23691e6e1e86ea4e560cddd59af18a689c4dc2b6dc0e114f2a84754498a8e299ac17a12fd199d1fd8d5c31b0a40ef4b2fc9627d16ec11241fddb4fee6c652d0119f7d60e852decd3489cdfb75c10a18f562154e542614427ee7cb0e96b99d74eb9585223760bac37de51697d86403ac877f823451d8c60e84188a8fa6804c3a8298f223169c4c61fe443434a76d6a51ccc1d06df3b962fdba9e27d7723a8390f4672d66dc2f756263ab928d9d14f6d550acb286647ed6dfb091c462cf4756194ebac9c94bdf7ae4ac7b5093ab9cb94455dad8ab15b134d31947df478a1aca5e28e98020dfdb6d4ab750911bb2690104b9606e78c8659c2f511bfa3254d32e65aab180ebb74f9848700a8cba3a1a546b77678a17716f232e57b204157761161670bf654f182a14bbbb1c16b14b652127241167e898e097b6270b062f0607a50bb040868768a24312a8da316dbc547237ace3a160b7835c805061f8f2723386929835251945908058905f625cd9a91eea83c0f693523128c68613038e",
|
|
+ "slh-dsa-sha2-128s" : "0x9fc24e59b10d63d59b6c448f79d029745c4f27a31903ad2a6f6fdd09b3abebb1"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39916580739423a110970dbfa8b6f06ebfe827b6503b1629f4008d64024e63c71af7a932f3f29cbf08eae4cca92f36f670de2f3a0a461999f431bd5da16b868d2230d6403158010384f0f98d2b95936e0a132f5b86f5d11e32ecf3cf206ab9d26c1cb7fc93ea3468109a59163b15391795b76ce450813b28d28510767270c1c474632bd6eab70174350d329d0039ef8fa6739b2f665fff021cf669156e3797da72e5913d08c94a48a16d12b5ad7e521b730bef92d7cc277a92b3e4c9f9cfff7cb3896f93dbd495637c2a47835f2afde4222c8dd36d4d6d9cb419b5b5563bcc1a61b640e70bf2c4bed6599c5ec50643fa302c227ae56adc3d4b044926f4bc4b26d58d0d0778e2b8ec5e18b5cb9ecb6d7a26808962082bea23a932afefd0d483a9952f98ea11b629b0ad74c367e09cc016b817b624547ed8fdf360a8a06acf7b5f0d3c92448d9f7e9453a4e29222611490a7188dcd0a8568b67d333228454cd9cb99fdc9d6d945a64d8d96348120295b8f2ea9e95f92d9dddfa2a91b6ea2c44de7b605db8e3e1019dbe5cb464e0b211713cdcc32ef3631caccb48b6b0c968492a5f1288e99ada3a4d8287b5c9f46236b4b3fcfa55135f1ee4b13e3d6765866a316d8cb3ce80d67a518ee974976172f91eff1cf973631ade2a2b81134c39d0f3c72bf4fe546a7bc7d3f1142aaae3f5b4e8f3932d9b516ff1cfd827e7395d576d96cff52f00e76abe5ba3f1f0887fb064ee11096e52d441d1b4dc7a69462acb7296c489f498c456b2336f2f112391bd7e545629697bd096ab373a34147643199222b8f1b05a95bba5877aeed29c43bddecbc814a6f2bb38d1dde30c352e06f19bf52717236488848599eaa1ef17873681e91064430aa2f4a23445fac0a8c8231c8cd7c27f928ca0ebf7ab08feb53",
|
|
+ "slh-dsa-sha2-128s" : "0xe922917f6a5d9d49338e445586f4b3bfcdd92b89a013edba38e598aad56f8d10875fa62dddbce6c66865eb7d14067931d640a3b7c5dc448bf7cb6309943c2f0930c78c03fad2cdfa1c21689c6f621bfb1cba1968dd28e66ceb6cd5cd4f10b8797a53a8ad54e93febced4dc1c48fc4bf768b85a811866f86f004fdc340628ccf44b295fb5310898614b6a0341a2456b94930d086ee75f67bb935e62c739fb87407975f78f372ec11c0bf8bce5144abbb2678711850174134e6e5acc3b87f14022d158a57dcc7916a8e75341488af6b1d9c0af90bf2ea86440fd1b8001d7fdb8ecb8cf392498e41f8be5c7aaa81841aba7422c45fcc0caadd52d36d1d56cd02d027b6ed9d122ab3d53597507079bd9fb476105b12e3406c1873a8bf6a5b9479b5cab9c370b79425b1bc7616e2f1f66a398c2e38f7a9ff1077918fb3f7e65f025d4feb8b13397460a753b1999b3d351c5b77ece3751686c02db0ea4ff23727527cdaf038ff060a09689a13fb7dc902cb82844b11f8092625272d8888090e60cb1040b6cc5b0ceb6854a7fa769a77523e7a718a1a9cf56b94be12fe8fc4d319b335757c6b4807e17e9ffdbb486d9910404e675648d069c55e96894c7b2ab17d91aff88f44ad609142ea3747117596c98831338c616cea7439b1754390604188018818a5fd2cac7522b2df5e42c14e77b7383744234da5fe1a02a60e18a178751eb9c0212cd847317d64dabe4407c4a4d2ccb6965eb33699c37c733d42e66f92b01cf8b0ba2c8d737711439de358756ab4ba374e7359f8ec5838f531c984e2903026acbce89ff2935855ba5e5f3d85c82bfc3975ba3d4a9721ffaab1182035bb7526f062466895c5900f854fb52f5913591828cef55cd07d70c5805327cccb9822860f32a8e8f78806e39d36ea7be59186da6ab5f1739b6716323b9379446ce6e50345cfc9b769162ba96929e2cf0693b77a558e5386945fe5c6410a2594805695a4cb602fb25993a0359753f4ecea67d0a1045a80054664a5f589dd823d11b1e440813b3bf141f119c38f9595c1eec85ce74fd0cd69ab783ff7adf32746d3c4db1153df20ca1ff94acfcf3c8ece27b9a7819f7751028435730771a0d7eee4d5a05627e9577de7a1c0d16400a81c6d93fe48990d8d4eb942233b6e81f2606c228423d52fa012ba6de7c24ef446f32ba1e1bee5ab78e79f40ddc3f8279277735564901682f03ffbae6176aa8c2dc6871cdea56cb875f25c88d955ad2e5f560fa25acb5d2130327aff86a324aaa721874c4276667404738fffa534f26e4e0dd67a9d0e5d447c2868af3f5b93dad621f528509fa6c3d2b9a391275396d3db6487ef219bf42088433b79d34ce793f024380319f1a0017c0cf821d998871fd35d2da47b774f6c6664e54090d74d087fa43ca622417314ac0a7f2d23da0e9be5242191b9096ab0e200bcee276a787ecb770a60f975c2935f24600869822ce96462d97f34c23eaa50b443a504670923b260e1698eb12a76a094b9a8b9bc2fb07c38b03b495a70e4976d05477ee88b58e2d66729a91f0fc003e56236c5285869a6eba073b36efdac3999ca0b91408282f83b179629bebabd5355381c4435bb173598ce3496dd8616eba46505a64d29a166b51b1033cafccc0c6cce63afe4f2dff7a2cc62a909853b14b40c418d3a180a922b02243637700c87bd0268e3ba09730a2e2e20065a7310d8cb86ae6b2174454ee4c01fc86c0441cbc51f1801a021da1f1fa4ba6cc0e8e35a11a0e55a4aec60d5c98330ea1822991083deb2a80efaf382d29cd0b04fc2b3289e024814281aad94ffde1a837da103a0022b23f223e63b852ce8bb89d50271b29b5dd805edf1f4339bed98ad4e4fa42cd726f3f70c7c434035cd9180a02ac954a1173c2694f0cd59942291c34a8071803a69552d71b8191c4299add494d05e838803e5e9de4e5a2d7b0f8b4a221ce677b5b365e57284f4b74c973c72a565422b2233a5b3770cf28645a18ce1bf7cd0e726566c382d801e655829a7c5e2aa149217075014492b80533bad2c8013c382aae26cf4dc39a6eace929903894f85c8e97e4be1df2bbd53fc780c46ed384e01fb40c515e88bcbeb2005df6c152f0d169a90ce3a43c2c3469a85a456991996f6e9ffab555233598f767b38307fab61336a8d57c1f6753749d46e1b3032532a5ef11082cb30e12bb6b292d0f37806e6208d4bbb7c7cba1b3b410ec1d29dd35af7d38ba79059999992088f06b587bd9570ad0a1e2352a6133a50a3a45da27fcf63cb7c6fa98e6d3d3d7987447fc596edd9a157d72d0bb60441935481c54f9c163b985c708ea1dc510f35f9aa8768e73843ba5e8621912f43383365f534f3ceef986e90664123079f7355e5a5193b0ca1bce0443e01adc00f18f8f07a9038cfbc672494715221c0b8c5dadf7a66875ad67300e5fd662ae7b4281f2df29aa0f5b7f9f70fd3180d7875aaf784eb3da36f9fd8abfcbf2f156392cd196ab952669a531bf941b48b7d2850cb8a66addeeb1447d89daac2079094bd4163d9e0d8ed52e9a93e31a7d4f5d2afc4b7d2c0b988d41c3e247237363dc05dd16d49d159005b42ab9def7290a51beb7811e9f4fb9961a7af09fd4f291f797f8eeb05bf76884ca340af07f62f587dfcbadb344c1b350960686aeecf772f59d3f5c9f6c01240667d1fa5c3d84dae1f0dc9562543e4636d81a3f0407bc29127bf4b4527d0f6d7815a941fb53e6527d5940739bd369786e710f6b0f69b05b2e0c49bfa51411319b9f7b172fc11d901e41ec54887a0fe5748b1d2403d23ed5494b96639126c1d3fde11d85c8c717fe8b01319a9668b109e2d34a6ef5911aeb31c88b71c32a6723b0ad2a28b2d8c75087a546550b0971dde64d3cd69434914d5544a8828c6e7775cc802fd71e467e0327d692cba302f681fdf0c7425ee580c413d1a3904974e55e7ddb19de793541a7a4310e50990744b4655e72b4eb5a3a8c5fcc09a545198c6475dd26a43338753855ae4dbd845d3122b16063b9d4f1170b0fb1eddbe15bf6a0f935565ea46bbbd6c00491a9ea8288822dbfe8788aec3eb3e5e42140fe3cdf16328587b736242c2aa85828dc84352bea3c6d985ac48437bd72f12adc7fc08d03371992547b91a3061c9f9bc6c32a8555df262c14dba813ae8e2f9c732bf7360b1e94498f5a1248ca4a0c020e381d8c25f4924f91bf0c649207b1314bc0088d2f15f662a2594962596ea66c036677c451e77f051cf9c5f6b83ada58109f68b415af541dff5d6cba732a938ef4d425243a3571f475af0a456a7ea5afc7c78fa195780b270ee1f4d69fca7c93087e103595af8757afa5dd23ed17bd723c1edf8701a1b4bcb2102ab2aaef2df7cf485370d310651f6e897cd2d687375d29c7f101aed941cbbbc12ac7ad60c3147e41fffafb766e548f0e96bc911f38a6d1864277c170fae28e4b06fee1d1925923432bbe28e41f8cc19271f68196bf4724278f8492a6d5c0826e03d8dc1232c0efe5c7598b71be7d6c468ccb1077d7c8bd4630bfa4a108d58d5498e40584f6ab690e27ec8152c1c39bb70ccf7c5f2c33e48af63d536d9e7ba90db931783a9cccc05c22dbfd90f84f75d139aa22b1246a15534f1521ecb9031ff0686c39b728fcf6e0323cda56b641561a88c6f78cb1d880d102d26b20213d03af41c91ba6924a0ae17a92fdb375492fa0b514ce2fe88fb95d72e5b1b11bff99d1b0ea0832a0d3472b5880b3ddef0bc0891833adec1f7797f86fc549b22df2a0a59390a900e588cdd2405e5afea987db98554585c85fa2428cababff59c17713cfb100084192cee9f4ee3855163ce76fc59ebd4b23766b0ca7c2d59754ca42ebe3c997cc4cdcfc2ef455d3afd488474b4da2a6ba278c196616f995c4398710c291efccbe36bb724bff2d097095f440f79917229a6fce31dbd89e58696c4571dce1e535adf5e1b0942fb5d59a13f7fb4eb17647e83e587acc50d920db2951bb48e1495256e10a62a8d43d3cb7719c54c24f546ce4937e2ba7b1911f5684068c365398e41f7153cb1e2b9ac014bb7395a36efff14ee94373dd128d725dd6ae6af408a5da12ee540fd8d2264b24cc7fffdb2859ce5227ec3c3d5e0bae49b5f495a39e5d6b3baf7c967b21a55e3528fb0bda0e9f2a3cdc37904005a76b07d044ce439a345f5ab69a3db8c711d478288df2d4776d53ccfbf49a06d0d0332814d34053c98ee3464bbf46309b763114ddf1073100c34466cbf3414b4bc7b8ee73c44d76c46435c0354a71fba7d8ba8b0248f867cee79a4beacb5dee9c45577e5b423582fd261b6164de192e98aaabb47179a6fff8827221a70c77df46d01357bf27392d4dfe3b8e24abe9854d3109b533edab16f495eaae07562dfb4428cefbffd748f144329f7653931a9f65a3b024bf19d2fe04764d53730df662469a19c4bd966dc925b1ac52d9094ff7dd7268697468135000a8766d8292f9079f9bb5601193df637f8192812a9a97f604015ec15c89fee9f700509cd745da588a86c7c756bc84745c593bcb7c7d9d34bea98d505a57b31a90833e3d1e154c3b686d5d8a20375111bfc6964bdf2f815e160754b56c59fec8fa533cca9e21d4f688ed94cdab427f9e179fd308856ab7f7206d13d65cace5f8d65c8b95270559a7d33c76c81794ec38d75e2b3f9ebd1351e07da0540e3981d447558d6c21ce6b0c32bf61a3f554cae9edac7a92e2e25965037830c57f30a021953d91c8349b94181ca8c3bec9f33327caa08e437e542d4cd9742ea16801aae94e19442030e8c95bd4f23d88ae9a1f1cfe4a80b046f2e54885c54572a215f17bf8359db4edc830c48941153bdff79a6777a67a9ca0ee3c5d2e4497871f4797974c1d932fa3417b909ca5b29dfb315bf1590829f1cfad84b9e068213b8a6e9171c1c41757e262d371b7073d1b90fde5bdbafab76426f486581bf52fb2a53df2fdd0a6d5065afa6148606a3dd311b155dc0dcaf9f741a50d105053225f1c223ad0fd8af47d27db808cd32f733fcc8e2655523fd36a906c6e6a1d6eba56311424458b446bc1b77b866af76be210b9a417e87903a1ba2e431c176a82cc5a71a4ddf29350efa6dd8d1707d3884b31b9b52bc876b6599f40b077c43d815d2e02ba043505abe7ecd7dcf73818ceb77a09ea4e582616f4af11133a80429edc9a434f3cd2b41192edad842b433ee7936fa5c7680023f0727f4337c53912fdf6fc7e6d5c0dda2e0a8722d5b0565ddd8f9349815bf38e8615b5c7ae35622d7feb7907e6423c8aa7bdf57355c0353da377977e180b88ecb1faaeee2d7142f342263e636eb99c78af9cd0ef0314d9b57fe1176bf8b13c221b5a05c1f876194ac26c35b0ddd91a2130276ac402314367d99c2e300a33073c06dc18cdf5361908d58a9553268c6d0ba19ef6f6d0bfbf2b1e2f5d284c74695189d8a3236e927d9598a4be253d0492f98015851be3693b0c1b3c4a73a95ea57c20699240887d501db5d3525e787dd1a583c2a831a9b59886c873b8ea5dcec376ff37fdabfa21b74b3968008dfd9784fec35696779217b4f5507ea15852f751af31243dbf857d66cdbfb2e290b52f67312fe5d93bdba25b1b7dfb0f3488974a7ff0e437cea09d0baaba7bbd2506fcd182cf0dabe7c262a823fa1dcfe00bfaf7cb5f54283763a45134dfabe9927fecacd648ef767fdce12d570693ca6aa10c74c41761f64f31139f3aabbabefe6c7bd79a6a3334cb465f4203604c0288c49db25bd25c6c4c113e09fbd65c0f271f4a373294831c33f7b2ef392e4a4b91a3973d38473b9f3a485cdb04b7f75a833e2c0461c6f27e6d8f518d3a4366ea3bf37f43e4408f00c4c72ca8d0a9fdbf1ac7fc9fed47e8a3f3f33ebcbac25fc2e70bd39a85519181383597ccc3503e597a734c98e98a15be8bf4b37330f585ea138e5a2e4104ec1cb6f5a23df7ad83751c32432033f072e8ee3cdeaae4e7de98f9e58633bcdceab69ff60004cfdf51b54e9a33232e1df86ca9708811a69b8759e5b2daf57eaa8f1f74ae6aedfd9106c105a6cd715b66f561c0a0500a501a9f3d50a0b5540ec96d24fa5f6157f5465d413b204a224e2b752a49322a90aa340e4422e60a449cab5b6106135ad34ae309ada87ce9a99cab959f6c2502b2da99d8ef296884f4255fa88f38908e4294f799afbf3d664900c5230ebbec54328167495caa99942c13e834da5c488f2dcbbe4d2448eea2657a2f82a91a53d09b2b5445de8c8c8ede11f028e067620f2ad83be80d19f3b9a9f3b81bc8a405c233b2b17ce8ee5e0ef05847aeb36f219817d735faf6092d13569cbf069696bcbc50cb50cbef921f8fe76775f1034e73bf04431b696eae4943efd78ef6c19436c76ab389825e57b23f4529fb848233833afa418d85a92fc865e634357071bc415da56078f44bfe306d3b00574c04b2e94d6b801d5e3bc03686d1bb27dc2753112b2c22a43610a4dbe1e78c9f4f6f2b4ca3ccbddc2ce0e78fa34cac5935bf0867bf14f40648c805876e61fa841292ef2d2d53ecc00319a6df0bb6347dc865e39d9da574ad93f9cc910a9eb920986d5e6b331cb29b45ff32ddbc9e09b71eef73c8673307d6684a34ce85ff3a4208741b205d31011555b17b7c5effc210ad9309468a007d76983011b88c818eaeb3d3815a02d76f735433192f1bc99a6c7dbb57e107caf9e986248ebcb2e9c28279ea1e19a8f8027bd6f8728c9aed0b974322254e686526cd9ee0c6720de4eac01cd83e5705570c249856ebd7ec76cddd98cc096fb93db8ed86a5aa0736c36d978c09b915f7b9290cc255ea1a4b355888fb96e506cba34683c6a890c77d92fb01bba6b69f91efb3e4313111dafc3a189db063195bb650e0cf353dd975fb5c286f86b8f7d982ca5f74a78fa0fa3d693980be09298bd41c4ef38874ddb95e928494b9e345525b00e4760a1d6a4d54675e39b1d955e20a58f3ee65ffd1e249eb3558ba348a2be114f396c422c57314ce6df0ae9406dc6bd0bf5f1db49f012a03834b3314dec7839860867033643aa7dab3fe17ee025812ad2c05484abd0bdeb67043be2a57533d294aa03f24ec8afae512537343eaa16b07eabbbd2cf6755261ee473dc457ec36775102e1c8150248e4e51dcaa6abb7753920bd5247ccf6dcfed9dde98c9f37938d1c824fce116f39f0d67ab9c1fbc79e034e8bee6f79715433d485edc70e5c098ef7bcf2972171da06cd2f19cde8f824e0f2bbcd816f7eb87b7bdad659a900f36df708d3446d8e412b92142d8414f3a0508d106473e809a0831953e2064c655519a8f22fd0c517df7ac44d72a0e7b6fb697b188133fdea4d16e51c6da3109f7cec1a43fdf47957a35f4651454ae04da9e9d5a1668f46cbc58422c38fdf204f4e9c0df3b1f0ed2e14d0e008bed642353ede25a5c25684e7d593eee9d14b3a5a81429b30895ff5d1f7f4a124d2fc9bc1eda61e8e4bd73b57ef1a168cdfb1ce1d70955567a3d949bab203c379e3676932f96c04ddd0271a6afa0bd55988134de26bf5d6c725c09e04aaa03d393a82805a366e0d98e4b65bf45e05ce45f4dbdc1f8ec052102df08f5852630b706dcde9a3efebca3852e85cbd7fb6e6e00b4bb397004db1602b7f8c0dd365eb2d946d00eacf0ecedae83d26555a1bef8be88eee9de9f9811074151f0cc747f36d45ea7290d53c18fa8ce73f77f54226e5b1719a9bc911c9d7565693836edeaa6cdb7b2e2f9cc8c86b7c207cc14c261793df6c4c623355db04d5eac01c011677d26b764e9048bff8d76e2b6bdf792c57e044eea4307f5a3a62900df3f57ae88577644e2121134d61bbf3100fedf83371438b7854d06340ffc00383a0a4789a6a85062aaad3761dbb3c77e61c5926b0488f711a77735dce429b6e028373dd341fa2db5394867242331168665b4d7fc4ef96b12a571b8b25d44fb0de64b9820734e5647821a038428d67dbe95885526c3f2b8064e8baa5144b7fabbbf5a133c4b8d7a2f950a4fb69f9cdb37ac28cf0421894f0b771f80db988e25fb4ba9991664c93116bab82ba808693d583a2b697fd2b5eb673f954255da410df58231eb7c89b8257c5a68ca0306d088638b2faecbe3cacbbf77725e1685aa81d965f1ef663f1e474eceecbd52943c2e4e0456b52aa0c7758cd2fe67f3132176113a16dc9bd11d6dc03ee643fe8bd6677f2ec0ea754ab499e00ced482d78147ecb2f91d3154e03b57dfad4e4cdab98e134a609a7512a5a0e7c3c4adc9db444238e0fc3c3586b389d8d090ca46222a9533672eabe4fabcf61beaeb59c507f2941ced1ee4cd2afefee5aebeb354ec33cb85c9695426126f016929b471b9cc07dd6ff787fc2d682cc1e80657bd656acfb865dc91d6b032785cdd7a1d66d4d5463e142b6f028e8fb5bd6c621109e7022818b39197f85fd6ad4785efe48c4509e9a537f10d4fc9d23f275fb9e684c2f827868c9ff3baca8faa59903c829bbe1992541d15d538e64329e886ade0c5517cbab3b15fdb4e82506e27f449e268b488de32fd036fcf80f6c97505a5f33e4d3a004772a8970a3fe54049513cbc57131ffca1c82918a81bcb879b8f48d4300b11cd90069912ec9e59d10b6bebbc24ba1061c62a8762156df586a4aa758f13cab5ab59a3b1ef7d038c68920eb0a3c8a673c27b6fb80e5e8741b3b7fedff0c068a83e72373da07c8d73abbd9fa0084bdc92866917b546dbf7a6304f04b18d9bcebe2b4bcf5ac7ec526abb4a52a19094c8c231668d063c5558bdef0436ac418f42c5f41f2df996d19d48f8bec412de05a6a3b079e5b6ac1be0773814acc3d20166874ef64a6cf27f7fc72e0232031ddef1a6a4ac9897a86605550dd635c995626fe985aaabdd937bafe3e2a4082f0fc875ba7ea963a8e5987ad400423967bba1c0e369263ddf16fefc88901be069fc617ba6dca90608cd4a9d86476f8cbb41fc8197a9ee6fb331aae55959d107bef29b4f6f064651964999fb8dc904b8193dc7582fd47b0b0fb912f1c0c3838dd489c374ba5ea614cc80d4d196291c4a54989ae628dff5beb61612353ea0cdfd75962ab057bac887ce7f5df01861c769b88c7e1682f0ec6f7cea63598c3e6f41093d845db95377654fc56702a4110810917521ffada7432b7b16a64699e6a955a4273fe9220976f8b1ae9ea79678a3a74344a44c32454e7bbbae9a1fc440811693f66d63663c84bf847e0a2e8299fb0a6413194231a666a2efe5ae1c41db1cf12dbd8d58408cbeb1a9507b5b09ebf416f712b0040f8300dc5188e673c5ab1f13156718031f25cd5156beb8e77e95b48f42d1361da25a94cf1bb4a2a5c41f8da5c3f6a30c00e7d0323f7bc14583fe20815f468928fb69a480673b6c775b2d1af6a176abe5f6c679aae41ee1d5c89439a798823b65ef718515ceed5a7ec87eff54479a9afb48d0fcdb9a240e946719598512220d2afb20840e3680689cbbbf096e7d7505d1d854faacf024935a672278c5dfad333373015b11571b2a7329a0d2fa792d838ba3fcbe5303f84cc6d0454b89cf740bb0f83b79c98b38fa17dca42c5d57d8e86cbe16d46c4c0caad1f55ac4a399d9755067b642299b6b023e47ef74343b9d856545a51907f86034397dc1cdeb0856ea9fa753ba82c5f7e44e4423684f1b03ec59e5cdd96c03dbb1421e89bb0d1dd570309d92519e2b90fc83ece91ec6b13134cad1272f0fb1092a21e0066cc0a783e566167b52856fa6ef12aca963dde340e94f04980279f67a1eaec339d0656c09a3fe91a2b1885f1c09e831471ebe78f2af2efa1fe5821034ae172082de7cf5fd8599f7c575311d35248f2b0e6342cf7ac4bbcd19942a74ae9a9ea3ef5641f70ad1746406ad9bc24a1a3ed17dfda75ad54fb920ee9c92b792b76d42cec2c22fd1bb0f7acfa398d82b5f016f2943dfb44ca1d96b2a54ceb7595837379d62feac76dfa610a82ec947047176aa74fa8d58aef3d34e79768ba7b213a8c44c6e9739f05eb197148b2d2f3c5a1dbf0d4ddc4ae2bf0eeb93d2d4d0990c2c21ae34300a3139ccb5cf216b4031f5be4fc61b137a952fd516e45236dc791b692910a09a600fce9c14ce9e429ef1ae3ae737ebe9921d10522a4507d0794fde66f639189cca95923c51f97cfde4d57c718b6e0ee709227fef69a95a229ab54a4ba9d858115ac04dd0a594ee8fba7d29a23d8df53c131dbd6f7f47c6ec482cb2da38e98a8bb51a2878950877408f0892199ae4e94c4c8eeb614eeac1435b2947ba67c30ff52ff4c958eefd318814a17f53c8ae691d3fd91ea8196bd82d4af9fa216e32636d6535d5c68f579d3066654f2cc067873fea5d56f9676800892f210363fc790086a778fb721854a0abf9a2403ac6de964c2eee9011a44cc0d66ced8bb0634cb986a12b0d5d875db0f26f008555f7ff57f42a441250dc5d13dc5342ef36c288127d46b4a2cd85e5189877003589579aa787c46843e47666be2ca6e8aa84e065ec77f0f77e5cee75785e2358a5e1fd7d540ba1d36052964d7a5de9d1598cb71b238c6a6f2a4b6c72d8c5b0a4c2f17342747dcfb2bf7bc52256fa21741e1f8e7c2b749005ef240296ff9935f75e943c2e725e9f54636c3466450a49eadcc6f330558f2146426fe6786f4ac6fed1943d616474f7665e8ecc2612479eac464c8313066de5fb652beb42ee17c0d9eac4496b5a732c3df31d90e24ffa8eacb12b72dc1d393d0880959e0ce9db8141ae1490bb12af9bb2d12da5809a348714024d7beb73dbdeb4d7adcb68c59ada159fd1855ddfaa33e0b985d7bc3f509e64ee52b5057656295dc669939c45d89a07f03c0062e20e309a0388725c993f74cfbb8db38b85f13bae8b27a4da755398f228d79eba2ad5101d80c75eebee608dae268dac0c3a1c63e311fd82cddb78f06fd576314ffbee8ed598818894fffa54b56e7a7be5c20ac553d106609f4bc757acfe7b116f695fa4ac3ac93bd0de4bf87aa6aca5535e467298aa934c11143bbf39c464db663b97ad416b6501daa12fa8d9aaa31334851f36f654356467cf4f42fcf0c4cb239c2acf7c7938c0760a6a8f953e75471881c59293285241f7b73e4b3dd5"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n13-rotation-unchanged.json b/consensus/common/src/test/resources/aere/registry-v3/n13-rotation-unchanged.json
|
|
new file mode 100644
|
|
index 0000000000..76a1d938b9
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n13-rotation-unchanged.json
|
|
@@ -0,0 +1,55 @@
|
|
+{
|
|
+ "description" : "index 0 did not change its keys and carries a rotation",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : false,
|
|
+ "previous" : "ok-epoch-a",
|
|
+ "expect" : "AERE-PQC-REG3-13",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 2000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x398b261d0e1e172f9837179889a04cb790cd1c950e473360af30a5ffc3104a52fc9954ab058bfeaa8c2461e0173b276340fc57304451188b40f8514af3c4efc0209f2f4eb9aa21374ac202ea39348edb08472f9b4ac6138118ec48d524c7db633331ed4aa0433ef629d183b523fc9d9ea70355ca1bdc41daebfac9cf17d704271d9f36b7a3171faf1c7be709222b643d9b71bcb068ca322959ec8203468ad0ec96db7eea7d5657e59402f31486e27b50667e35ae6acd5a4ad129ee2d164e7b2d9c140efbaa843a5869075588891359098b89b93e5e4e6f006399dd5d2587efc5aebf7445c1e61fc1b530932c6a70ab2586e8de73164a031d345731ea341182e1d9729a0309ba620ccc45ecc27090342645c04066d497e71b7b847f30cb6748b47b75bee56ed101202d8ad0dbca51748f4734b190dd191852127d79b4682cd7081ab2a1100854158f7f6439b6b3058c80c232b2f9c2f8df205f4c93409fb51a4373012c5609c6c567d665d43d0d32253f5238f0d4be0f00e8eb9779371cddf0f1372a93f2ec72e56cc2a2d6eca7cd7d14a630ecda530120317b0a0252f921d8f2a279b4213f3719386681206c88991130d48cd9f9b87d965f9abb0aaf0c59406ff5592675374a38fa87f7384c0b4b5f0ef25cda1cf2df5cf2f51bf82427114ed4aeba3f63830bf6cdee15b91e95b6c86d1ff88683755771b8e8f65e28aafe4c21096e778d196acb2be8cdc1eb81bbb9135ee56bb61553f36cda6f9857b91b39b669d282ccc5a7693cb39952f4c1657f7d02ef18c7288dd6ebe10edf147ccd236bda94abe49724105dd9e3a86f57a78a7c5616464906cbeab453e49d5f75b81f5f778d85843c71e97c520ed6b9d1ccd5a9387e5865695e9261e0d8c748ee9e8155bdb696575f4be0c7d668fb78",
|
|
+ "slh-dsa-sha2-128s" : "0xee44a0de25b75a42e32080200c89b82e2f89551d44da272720c816fb144aa42ca29cc7a0045d97c82676d36286a9f1bf4d5b9e44b6855d90f25e03e3370cccc7665f3c7fdeb6f9565b76745a7652f70b7cb18989582559b81160fa32c7db7915f14c657ca37224955d174cc69de41774e4ac576f362306f3383733b322f8b333d9d0dee44d80e36a86491bfb7441a3c66809bc600399ac9788b4d7796604d4ec423c40dc1a6fb2b02db9a0d35072cb5aa617ef769006c504052596186ac0d504561c815617067f669b29757aed1de7a03c9c0410fb8b040dac268aa95232533eef1f69cc0100b33c9726d55af73b5d608b501b0470c4e9340b68251fc645bca481dc2d375de626580faa7b7faba8f8a596f795481cac23240854839a1100cd92a6410291ccd40cfdf1f70981c568b32904a0ad649de41b32299dd5a8bf50c35e5dbbd474c258946881b49e335e01c72ab6654741e657bcc5109fbda7297999cb4b272302739ee07cff0d1c9ef454a5dc5403cb7c170337336f94d56f6ccf563af44bcc8382de301720076a7ac1edc1ad95dba129760d7e9cd4df609bb8f7b389e7ab1e85e1b54fa5e3f2163afd7e24c5e5eb61a9e8e79dccefaed30f5fae83bdbd8a1673b36ce894891720b476652a26401e7890af9199bfc74fd0aeb6622fed8e488b8151a6c51a11bd808702f945ae9f9a016bdd94f45279d4765bb376df7fed5506b52b74c867c087c3386f74b130cacd7bcb4e832b697b50c796fa8fe4881c3f994820799417885af464f4f1a85989e5e3b54c3bd878a7ab054bd08c1ad850c96f3c0105380323908fdc94771609b10e489a8445f751f75a9b617cb1aec4460be2b53920e52f7d85096065fecbc6f19daae458f657dfc894758f3d9a6519fb4276e16b38aaeebcefba89a7686546901c57a29b95266d7ab87155a854ba9b269ac94a279e9c4bb38e6a4928cf6fdc3984b4363cc44e0e3cd7a7edf08388b9ecd5a04c55ac26b98f98cda79cd3f402caba28360899cca559be68d7a825022f9010e65f9a6564fcd0ec1cc4c0f4029086c90288fa83656cf2ca2cf30d5c423342cd15b9197905e9ab30a9d147aa2599abae71070e40058f0787ae39f39d6e5c1a8184b2cb3b1e6e45c40c61d46af8490cc9af6422a439f16adfe93a3cbe88f63df5eb8fcde9ea111ca96ea7be416d030500f2c7cf967dcaa4d3ed76a613b2bcc034ed3aa84f35556e7a65a8798825b576236798318034204f041dc59a9f9c407d34c2ca2d77470700ed6442cea5282ee99ceb71c6bf074423dc0785a39b89b062f89231af868812777536d0b144212d5b4b6fc7b87ea04fcd6f94438704f985b746a13dd519c57260f87150db4dc483b664944b9e805197df797be099940fed468b1e214ae99a68e99c6b5cf3d30fdbb1b3cc009ea58958eb4c4a7b7bad6b34fcea2a87eeafda01dca5223458affe54422ca70ef541ca8437171943d5bcdb70eca8de02b93098653160cae52f4d72fe5a6a7ad51c6465388f0362e6e72a3c96b9cad2248e8d9a2cdf89747444c7e51e2f89eb19daac76da37180e4133e0dcab15fc72c7bb90c1024d03eb2e630fc6d2537a101961b388e32ca5019a626b5a23914b06e7822905a5e3c21369b69fa63fc9f43cf7ecb6749c668c7a940b82f88c71802ce6e3c68b5c10c9249ba356bb3bb0539b581a8bd6ca141e5dc2b5932251746c1fc1c3da475581f3e3717f5d905f5ff3c83f1523f57cb750dabae0404beb55aba1105b995268906131835718cd43240bae9aecb30c794a8b186436cf752179b1de65b2a87917147612e3c95288a3e816238b3fccccae1da8041b4f784ddcb3d37ef3f019ef997bd8a4e172d397106a5adebb166c5f565016bb1c5f7f1a0cbb5bb22cd642fa4390ea640c04a968fb5a49ef929df1cafbb69c124ea58b31bf066be388d7b6d4c52409581da785d6447fd72b54949e4c1ad08fa64b520f2b8df83bbfa417952b87fbf802652a65df0d388ea32dfcab3227f645b6b28b66087819b4339ad171a48760e2bf90f1a01184389e23e7df583eab7c2dce385bb7a4d60ae5573966f916bb84aaec6cafe710f839b103532f9a7a556bfa116a05480386ddefa2858ac7ebdb58664a0e633a53e1685d71d5aad11f5eeb3d9ae30ab120fb88f96f383bb86917b72e02768f071ffca7e3fc2ac79846a36f6bd72c58aff03f9e87fdbeb65c8ce5976255227778cfa40ce0eee943b66a382e172abc814ebbcb0bf49efa75f87ef8621d227224b7be51b73a928c23a8937570e1a046bf1fd4c6993a9c14e552915953776265f78882ac8302f70900f9d612d2e7b7dad88cdedcdce7e615baf89ef249d6d535f92a2ec90a7435785f4d0c7a75812b875ec22e638f4af1705cc362ecf52c67900c888d068dc6f72a161013c30dcaa49cbf25c56e8937aa4897451061dcc7579ca99a25348e76ff121983444553419e820a3d1a41744f4227dca054c454a6497e0762155e2a06d17acb44ea55f54e4d6d2e1631a63d9494cf69c38ba66deb9d95c0ee01950dff8e6a5d1c46fececc7027997b8ec626f8405ae99ac20600898fd7fc422e6cd3f774b4009f371ce38e1f089ec93ec0a48d6bfb90ee79c3bcff321eeea33a44022ab910458984b75c5089cec0d8beec20c4c39311b991154fac7c0461b7d667488dc9f0f5497cf66166782e2dfb69a71031fd0251918e4c1243aa4dfb9fc2b6123b4f02f436c0f8737a6663af2b99fbd22c6af539ca9389bfb4e55da2c9ad42521ca6978f71991f53fc8cb227e228a62f3e22d7c3eca8ecee260e55084ad3ace0d6379d5eaf82bf6d3b69c4e74fade4210114d95b41a4c004858119a9a9b178d5a0cc97386bfed0dc6edbac5281c2842951a0c4d7da10207523973c676b8e6887a087c1c2f156970cc6db9cbd3c8ec1c9c1bec41fcbfdb4e8929b67e6c1939bb990ee2cfec3197b4ce824d25a7b4c765945e85ff2b096037adc4dd763b87850fb39aa98f1d395c9353ae3b5b53842a7056c011fb690e856401fc6f67b1c0a5414fc229284e74c230ced260d4fafc5fad153a5154d35c3bf9c559239ce18ca9810a1254a0a6c2960a53d838431447739261dc3b055a0b115914af263ac9fce2b512884620451156c40cd84b7bb2d449aad243a8aea3859412476ddbb5eb73028bfc6b2a942839e363262f94795aa45f6579680997d6acd7a8c8daeace08362fcd420f2f8a96801c002361b942493cc5ae79884eddee989af9832d55319ec033956660c5f11b9fbff9f1410a18c0e9a38e9261bdd13bc392a18a3df97aa33e7f59c125f88d78c86058f3c7e9a9d3b37bdb1e05d90375de0090b418de3ca761560f079a6ddf328e72cd89dcb63c9dd0357ec736782696241e2095aa6107a8bf7bbcde26d5d14533f28ddad7fe1b3f0c181c0e6d55204f6ce79cfc557cfb2d54cd2f33adf17a837243b51705bca7ad8cc452e5340732e678274f9eb532bfea122cfd2959b2499ad25a18db7dc387e976f8b5510821cfff778be799b80505cf38ab1ba6b01561ff81ef17f7735a1ed6a319a7f571daf92afb7490fc17064ccb6a8453ae6e66a2afdcded0c7359461278c49d342df84c43a0607b7327853db675e4c9ca95c52ae013461ca0763d157ac992e219a6683a547c32374631b53138676f50ae0d30588fb25de808e1d9efd5fb9485192428477c2f64fcaa862761c7f5505cc650910224400e2a2db13fbea0b0cc358d163c6d4a8e6296e4c9554078a55f23e60de9bea12ac199cd19b97babe61b2a3b853860b4441ae8dcd85d59695393816c64bfc074e945452080e15bcf6776cbb6b251c13be63932702468679b2bd7e1693a1d910e1b62be91e177a8dec8e4d7642e88e513e3a871ca502854ab0fb7fb8a099d0e0dfd73064012051af337abc78bbbc6fa2dc7169ebfde2d40167048d78f12cb5e7c130a2137a0b26922553f43aefdcdcec55bdbee0fa752a4787ea9d1c75d1bcd9d28135515a0ecfa9735901a0eb89f915d036e21263f90606f65e62f6e5c8237db14d570612611b3ceb4d026ac13f473e5706cd7975c95d49734253757f9c1e6aca9261cd2b95722098c5f7c74daa6c926ea4867ab54e4605a15bbf7ab94348d9b45c31a1fbdc7f420cccce25abb4249cf413008a01e53296318414dfac822cdc0bfc4298273f65cda3fcd61236e255dedd879fbf20b8c4843e27ef413c7a1ce2c714c88358091abccd7fed337a7d4f725ffbf7856ea4694113d605b1ff7b2bdbaf60f7abf7d43eebb1e82f4b6b7f3f8fc23ae27b09f78a7a3b324c7790431c800293e08fed2fa49aafe8f5670d4e6bff4cf6e7924993d6e18ad87699da99a2f2ca9f3c7b44b3b61dcfa5f041f7a6df94131b8e5c04069678541c87872daeb2943902afa6ff4798e45a75659568a02471afde44f8e116fff4eb7c16053a7aa370bcddbf5229c231ef8f2e642c1a88f90e0a309d24a3ab28d3adc176665e522cf5bda0285baca5bf2a0fb4c0fefff3b8ea1522c9ef29342ea57eb4f16d69bcf948d66247ed2f2cc4e567476f736d170c98398ac7c0d158f294ff33ec8d2794ec1929c57ee6d7f46da8e40337a2b380717227ed82eb13a14d129069e98cdd65bc34472fe1a52dfa7e466e559705c53d73d97239e38bbd600aaab107ced36fe7d8ef2387a05d8548a48a684fdf02b984022aeb28e8c5eccd1941ae19d2cb12a31de296b4fd1409266c43118848962e9e59a41054a52bf2f20b09eb4e77cca72df70cdc4d712d5c0313ddf9ec8df2d901145341b3ccfcbed77288ce3e4afc677ad8681c746eca02e7f7538d0108b68a922a21d6a8c2cfd67d8849ff5779de1c00588133309d4158d1738e508a1a2ba3351a46fd3f86339d66b1244bc2788de3fc60144d03c08b0ef08914088f9ce947d2b230ffb9ce176a4bd45b0c8b100e17ec7829eb1ce10b1a514b5e33d4f40792f0a300a4c3ba7a912db8e19cb72ee02ae8ddafc2caf116df905640d0cb65cd0c61d38e0a9741d3dc2b7677e8ec051d329183c954ff9c0c2d8771182d5550a742ba8147ec6571bde519c2f57f10aeb1c8900f8324f017f3b1dad92fb0d19a76de75c0c7cb67d079c8bc0bd7355fa25752d5d00ab00f9ab332aa23aaf8b5cfa4d2723b2020c9e494208c61a76e18c9a583172d6ddf544a327c931e8b908830e46f184998fc0d34ebe767e4f5d06f99804759c7e2b76a8baa302d6950f90194b0cc694a0d351374cd028ba6b0414377a850ca2f209d13cb7daf43d14f606a0e549ce14189023fc7b45e2b095a3f45930a72296eced3e2da24bf237959c0b966bb88a3a9818932b1cd41e8ee002df515ec94901902b2e67545dae53e08810b99dade7b579b847a6570211687a62a56dcb324bb442c4fc22f9d85e54b3f939937daba84c86fcc36c83ca87de70fc7f4afed335e8f9aae027e854e3a022a053c3b22be3617240f1355be9af3f4c8e9481005cbef07bf1380ddc012412c31b221275b56c3ad52cb2f7a9b340526e6128416025d4fe497f2d502070653d36f924420c0844b5560a8728e4a3be8b1ce67a1541c00e97aef9c808bd77af5aa280690d98f5ec218bf5c9d135d85069405b82c221d834b8285402f481b7d51ecdca91c4c2b27c12f486d382e0c14ec23c2bdf33ea8ff693af551fbe55e46bd84f335a68646bd092f914da4954c57201d7e812f4974a553f043ace9c6ce2c609cb4d90dc1ceacd5d610cf4723024538cfedc1bb22c9663ac541f89f97b37d2e1b4d8073ada1596e684b94e74c2c2f0087251f1eaa6789ece436b2940d3285f297cb7482aa9b8c47118a0b1d2031fc311689828b64855bc17306529e4b0a3326438b42698dd4e2e0c2f624aa510a2363583cbac47fbf9974925d81af9534d0ccb41e2b445eb19569d703cd8ace661139fa344a5e097290c233114370831d4710676f7e93889ed533454928333655b06ac5ae67f301f2b7944d769892ed76374a1f3861c8624b2a302df1a2f1a60d41e61379ab3681d8eee152c251e1b7b0806aab2f287338b752918cb989d864e9acaa92944f5194f8eba19a18a025157d2c3988163baf8b7ca9060edc2227ade8e05348d86d18f9eb633e4f06ee346e4c2912ed1c763a75fd1baf32cffd0c856ff9b44f1470136c0a8ae0b88175a7e7f993d8469cc8ac3f643aa7db36992cc97011be0a42ff1df8aa7cd82e260e05fdd67304644335b386c7825858a438c51b63f877af005f7d95202b54a2130a1f652ff7addfb798daf4415572376fdd910cd099066e8d2fe251a907e41bb950e960fe5116f4a4fc6037273250569b41ac07002ecf3b4b63f8b853f9693badd2e8bff695266095f4b2f38ee4d60428a45e7586d9d47c01c12c5e18d1ca9afedca6f03384567ddc730fb8fed27516eb7c54135cc7447af831f0c37727997ab2b01fdbc5e12c112aa987e95cf5aaaf44be14bf4882f49cd84894d555655d17aff21f077b2cca1ff0922afbcbf4781145cfb87df585e6af1955db04843a763fa735d33b3df836585c5894e5125d500673d5e4d0bdf6708d8d28c80298a9bb47c7430ae8ec52285a4c14371b3f8ac1e21306b34bcb0c1e3aa7a8dc8955cd9cac32a0f69d0fa0aab30abcbeb2c21d655ccdbae1c2040faedfc7a5ef29cd5d9227908335ebd257ae8c410b1916b9a5bf0e72902c2bcf701a18c1fe13695a8435b0d0129f3db883f428acea8b7f274a629865f1849d4c263a1536421875ffacf058f0128f0d012fd60f2b3fa6b71fbb96f3e1e33faa09b1d20b0919018e91a6bd9595e9c16d4fa6665c4d0adbd77a59cbbbd587029a4f306c887277a7a27748a6f289edfa16c7e4042fc81355b85a994cc6784f5fde054f188b9775836594abd82c1309a66db4388ad49f60794d8c8e1fe279f8965312a1e23c2956427bd6e289e55ec728f66c36526d40aed7c44e5352fa3e2b5d27bdc1f7b3bfc4f095d002bc8e7b2df2032daea9bd3e0bed2733e7ba13c6d8b45c492becabbef0e8c62c257480faaf6aefede888ce1546046f04ce7e06936cbda44c5f33c71c07b53fb3ac7a72c3770838471aace69f7ea454d2980fb5462173aaade7964b888606741270f92bc18950284d013b692bad63ec3726d8f6596788a032eee6eba08eecc836202b06ca43fcdb062e65f8ec91f7400963bbb8094de4b4e1042e040e81130a3ff037e1b7e947b0c3e8b7ab5b539f8570ec2cf08971a1bf0d4f3e8311b5c625b7d032fe2e0603ac1a4824432b4c7bb5afa190afa30c36f168d196fc89015aff8229fd4b299206e8183897229e95ba06324edc1a9ac81aad786d5c9d38c87c48fc6159934a8532489f06e1aa314a057d91c0f7218861ec241dfccce63d60bfa624652795229fff21cf5ca61ce05ea0ad6a1763173675377d1f2427564e397683428fbcc4b97495735d075f84b289b73389a1fece959f9d9b4932f4d33a0907202c650ccf65327d24cc24922d0d675fb59621e2bcd2eb31ed1ec5fddc96593d4f936ad42731a50f164e404b93920283bf9fa43f8be5878d18e07cb8813914508532625f71d02a615bf47018e3b3efed72d17e0c974d33df18ae70e3a4a743ac3c955d1c366bc94d789c90a8b3771969210c7f0c4b9b12f9fedca5d2b71b6c04e7024a0a5e3d0d3c7d30cf568a659cc17309b223399b39ee5efd0cdec3a34b0735df8d7e0bafa40a8aefd742b3e0157fc89d113af5fcb0cd136a9cfb82acce406054aeda30b83ade59cb6771c366c86b5d9b016a74f220a967b83254db3e24d3e1f5d5e23b21354420dfca6bd8454575c6b0e528744f44ff8e1b9679b084d083b9ebeff09df273a476332dfa172cb98c79ecbf3ae4a722c25be71a3b206d848f56b02fd04bd32ff959e6931bf6cba042f9fde027d832632cc40d4320166f9644296d2dcc845491ed780cb609c0432408d08dddc70fa2d52884df47a55a8a3e706a24ac6ceb375a894636e1ac121040561ef486ffeebed3c5336d123dc05a5cf221b9e895f6d3ffb24b3674039d50fec114d3648d6dcf4fbc0b503658672d675c4ac64dac4db4615d011e82bcabd9573fe9e2af224103f99c4e6e5acd2196f1eb2260fb4aa61c298f99c20c4ac1c9e70a9a9e28db441c3adf2f2b3a00ca3f1398b5a112126fc3f0e2d11d40db36d0aa47d59cf8ece36df8daa854509e546295bebf92465f32a7edae6af4218b49781034329c22ce9e87258216b4a901b823a227e46f2938df336d3fe03fdbff4efc7b8ff8142b4bb60592abe508675d04081e5eee99468971fd49989eddf4648d3948266b08133b8c22ce3523757821a05f254cf5691848b1532655e85fece5eb186e87fea61936fa63aa047b5cb77c08aeeb2991c26619139b951ba4c2ed487703a6123c9c16d7b6cd3a17ad108fbb7c79fc3706f654be77a6cd8a5213d3976b1a4527144e788b712f37cbfd5f4ea5aa5fcc0f91b98d74ddcacb83fb33e039e1b88811a2138743ffc0dc5eae46c688f48c0be92a7094f92c2d4bae0c1dd95d40ffa113f27b8fd1808178be0c3bf77b677df2a17c9443fb6023c9e43c48614fd7d09a904e7a064125f8b7671fbb7529169138feed4bf3e6c215947efbf44fdb5eb1e3a5700fc8bcd1cf2a393ed438e68b607a1061e6cbd46a0b4f30fb4a492e786c5cc6d4f80542d64d0d271308ba072deaf7b1ff1c5200a2bb24c68aa2a5cd07052ee5760e0ede484e0a9c482cc74ab564654787e1698bef1386fe446106af25cf2fd950a78f4b521d547c83b6e4b6ef652444af342e90bb5761ea0dbf6b8c315996ed3d3a1a9d1e5f2b75ab18d0bcc87ee639299a248406d9deefecbb6883fe81ad12f20d80fc9b3c8962cd84e5da215b96bd457d5146aeb36d08185b2ee021fef7fdd43d0555c0fd16e7b66d1f534ae0b87f6299fc3b8e70236f39c91601564a5c2b3abce248ecd5450096e65df8b69de8b5cd963127f207f0df538f990bf29ff0c2930ab8b378b86d2619b150ab4dde82469e40e9e6e503182882b03442f92cf7449fc2c4b2f7ab91cf5ec57b8b0ebc18b27ad9125da57b6c139edbe7495defc73d68e71019b2b808a1ecb89fde58ed9dfce8b17e072170983e3dc3551149108582b95b2e4bd9552faff0bc7fd13dc0130f62a967761928dd62c9cae970ee447842a15baac31a280b443390bfefb7d4115e8d1c6458e1920485985635b75bf84b6af5226dd9b36c94bcd1a5f3ed99fc3e5adc6f3c4a592d2eaecce02d0e5ae97e6c4c7e101d4138e526fe3f090123c6df8596505b4d28c1be9e0c3f83dd4ac07946617eb553f7688f6724c8d8d34281a8c094740170280cec80b61b07eadb2c63427690ce73233f18593537e07266a71523688e6fdd36943d015c1bde058ebf5fcd12ea00e6b41565d062722941ca346b5949078421cf1f32fd38ce1be52fd65f2e9862bc5c57b45f33581eb72d387f0c212d68f85baf7e42058e41966429b0189da4eb4e58c1104e59d34eb0678a1385c38289210ac86f77cf8bef670b9ed04414875a29c27b79bc97e7febc40c39cc8e201ca56b25cd8c96f1a37ff688fd5d55cf5232d216283169b51cb41c631ca323056f2e8f74d5178a83b3bf43cfbbbb40f2680f338a89b294d4b611b0f275cc60e99bfcf270cb761c1c2a6773503a3c0e03b2a858d0cb5f81b032012bb0e15add080cecf19bedadc4d0c7e9d81fa75b97e7ca5e1c9eec88bcd10afc0d8e48f83aee498633bb260d731e0f900a9b0ae3f0d6e57346b8d3d8019bf079b4f909b6dce5718052416de8b61e9ef317ecf2faec5a64c0ce4bd5aa72b79360ff9b58d4a5f3e0648000d90a947933b0fe71d81ebaa96cd4c54c5d42b941e73423efb1f6626767f0e6dde52cd8796b0db31cedaad75b4ff72b83e0e9ece164c4f4dac170cca65e42db8b7ead0fa6e2f0b2d9576c79d1d73aa4b7ce4b954958dea381a65d4287bb1e02b7b88b33b2f1872d92ec6bf79fbb726aa436434fc7f2e79f0ff8bf243e19c08f680a5012c3c3d0501abb46026c420e485166fff457412a075086266b854aeaf5ac3a300ff5501bfd7ae96ebe56a5df5b7abb5fe2d9bf7ffc0005b6aae9dca8380a66c8c14e884f9f3338346ef1daad62042d09cd774b43016b0339aa208c5d6c2f7373797202ffe680edce71d684030e5841edd57cacb0cd596c63515a1b992de113fd2c8330840915d3409f608c8d43601f09dddeda6c504352e4d8ed932d8b5076a557fa2d87914ccbb0fed61c1f4d9950be0900b2212a82abcc4d9f4466d1f5469939c1e35dcd2d124623e2e1aa2dbe90ce09b958edc4e60d7e7502ed16a8a1d08dfcef84eed8a93d6940441ad41e493ec09abce869a8de0a778fd8df55cd1d9d7f053a72314e786088abdf968a3b1d1427e52427c2313182f51b5556466960017468a35ed2594280ad8493a5d3503ee4c479fd4c8db0141fb6b77331b46fb228f94e213ad372c09ebfc8bbcc79eb074162b4694b7bfb8444a4938a80747d2c15879e28e3cf44a8ac2ef8c5d9f93e9cb42f81cf88035dab96b6c078bceb4fb9cf293dc964b0cc9b722a84f3423bd4fbc57ad1f68a8166e86da595fb3b7a4dd87190dc65756e0f7750b68e3f605def2821619fb4fada9cfd1c41343dd4f5424a1911ca709ca745962a484d981db73a23a85c046a3eb73cb48b085d3286738e689437cd4976cbd3e2c5a4a4e385b3aadd09b08859bcf5506164db33d414caee679c65069543f1db8b242dc424af5a45bcb5ef9b939ce94e4dfe56ca25702d7912c38dc44d94670d90109ab685ccd59988bb7e932ffebc882b7dab274065578c041591d481501797b4039da17684a7242622f4390544b05023d3902949d348a44d9ff421d04a55395cb4248c7cb0f13b697f1423be1342d31fa9b85aab70c16bc62eae5660256d2472dc908768ccb7ff02cc84ffc6059752499711338e41d37f8751d84eec47a51c7daaa273e19c523d3d97ee5f71571def6f7268f24afaae71eafc84986eb8a0bdd50fa553c815939a4b56380b22b650fbb989b525d2862c5d420c83509b5c76b1a9a2105b45c2182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "rotation" : {
|
|
+ "falcon-512" : "0x39f115ea80ab1e9d88aa542ea3b547b6c7ce5e1a0d149a3d6e9254322219553a87ea2ffcfef8b8900dc456a4265d22a81f8ba45edae8b52288b665ce560845f42beeb7194bcc265815e1984a7c4ad9029647d54b124f52b4e814fff6d1fe933730fa52e14fa28c6f8bcb4ca79dc6117da3eb5177779c5915f729898de2d7374260c8219547f1119a9d3c0bcadabd8d5237b4887b65b23b0d197ce1f8f874df9bad08f27a86fca319a4710be8243245af2a997b1e8cee6938470c21238118ab8e4fcd259622e928b86a5343110209a77680c7489d48121ac430a5a6912c60d57719624f3b997481eb8ea664595635cb7ee20b9ccc59f2a62b91ca55b36d22196d3da9f4fa6963dc12991ea11529f883795fb6556e5c9c9ad8e3489ae8d6e57482ad4a1634e92de9fb8d6aed2a90a5a21341f7a756840230a54eb37e76b289376dbc5ac29383612a5528211d0b2b058469ff96436c691944d722ec401af9e32db94013569f5ad2049f07de42d174e524e09329757586c64633f4bb8abfc38cccdfcebc1aa496f9f4af6304eb6d25ca571fe5a24fed2b720194dda6171a0433e1c252e6a7e6e4698eea1b406a4956d1054a500b0ca79d2dd443ecb4dd33fd77963e6d5cfc5376f973590a204d2a492fcc472eb85c4ae7b59112a9fa173b51772e5f7909181f0a1e81146d92048e3d3669de61502948b9d9cf2ff3af2a503788db5d06617a7b9fbdb90025b9c6a0c1a9b60fc5ed512d8ccb7551e33e84b30a8621f8ce4b379450384c652b5f2e31db8bd3a645b26bb2a2babd89c5d61141576265fa4f8198702e2ee2e0e7e6fe1bc7b2086da34d6a00120c91849b1df684dd623085bfd0da56820bef4ab36f27391becced9a82559c1e6eae8d3f4da7d864cf8d1cae4aa44bf37590e777e70cae2d63ed67e7b",
|
|
+ "slh-dsa-sha2-128s" : "0xa53ea1956641fe8e10ca42ce4bb87600051834dab4a141d128620fca7fe2c64c2a2a21ada2d9cfeebf5c7ad6d633a405ef6da081433e4f2b173807b7b89a8074de4d6ead4d960d161ce71f31e2e806f0bb0e82ce5a345fa84f6e91cf4df73030c6899feceab88a7a4a62784e855c11581fa66afe6f75e3534a9eafd96cfb3dc0964207607227029d8cc30e1d562ae043eca30ed796cdd7495a8281d04608a388c7f0022dd050a5cb2d17118c07c678b7fef93d02cfb3417498a0b22551ae3789ebc40738930fcb5304f94d65488135f8e636fe541426b03a7c86d4c07bf75dd40c78147b0be6df6040735679f3d5f24d4dfcb2e44da06a730fac46b68cc9025b31bfbadada47102511b94fa735fc8b330ac237448acdcc393da40a6303a3890c3ee0817c23a916a8a328550a120ef1eeb7679ab69ae8cd2070968ae8f8a83a1fb597d7bf777cdd54dff3b34393d5c5b8fe1fa0886b7f7a2bab18ed6593024117c357708eb964b66f163a3fa4b23b554ae3ab58af3743bf714d431c4377106e4a81c4fd23453d6b195bd00dc0bd2cc209428822051c3c58d29ebdf70206e2f116388565b0e32749193affd7e4de644d3b69d4626c8bfde76c75b200c5e0f7fa575e3f867b9bc2f370f37b7662ae2e5c4d86a34ff776cd83f3fc811c1b4db609ad79055cf3abe0cfcc4dda542750f50c1f40a0c5825e017c6e9818be0f0c468b486fd42b8d644ede762a8ab55436dde489f267c7f9e3a565a338270b94c76bde1f453eb0aa4934e6e45f9d7b7004f703e7cd3622dc2d4851ee71e87b2cdc952b3f07d8e28b53e05ad33f09efeb1223373a72380e28c5cb55cf16d18625a8defde8841ce878a0cd8c0aba2ba4613104b68a317910ee52a3f119a8c0835db660ef763a152fd7a9d12adb28572a24f1b9f9a2bab635fef204afc20a686673a471b443f261c9a45ebb64fe23c11dff5f245081dbd5c3ce77f2a9769c96853aedeb3d251697c7ccd5cfa5715c308b05b0e1149edf10e7e62aece96d12dcf818936ec9484b1b4f98ff97c09d16b75e4ad9e6ac8b11e912dcd4bf4163bb9d75cba3317a469cc6b7fdd99146ca182fa81291da9d005a5ba4b794e435b27d491998143f615eaea26f2ca9408cf5fb1ac3633556471bc01c7e5124c0dda64b8c9371bf9cbbc9324fff2761202acaf196529e1294725c9062612626ce5f7020490cf0e9ea90fecc1290dfbd1a5dd1eaeb4fd12e3e7844101e6aecf9a8c8f84745dc6419bf9edeff3045e225732da8bf56ab301581d7f7bc54eb36edfeab87cefa342df02bed2fbcb20dfb37e258424cc0beaecd37806430648464f8fba3f801fb16ff25d9b2c9acc6e4f4edfac10b6f37bd6733ea64d145c84979403a2591281609d0f9a06b35424a01ffbb5c8b5abea5fe29d553ab3d611fd83a2b6cf2dc7986e8b227874a45fed0573c8b48230a0a22e32097657c7dc188e97a7c258bec3e058254132119d68784e28c6a58ac85e3e4b3cf66c4da8c25134039c0748e78bf074c89196585f288e0992796f14825eab121d81351949b366ea6268deb8183620236fe8b6734b78ce6210e439bd27df471d30cc5862277351166aaf481fd3a5c54947aa1d2ebe277157ad1a03cbb2d9751dc9a0efd508c72d661bd878ef3eb9d0b2e334cf1591db86515d91c02de7a05eedf41a677d382513fba69198be0366d76a035b372b183e9a26d3eeddf9bd225a8d03ef910ae58c4d8583d9ed898ac040bbf587a3542e11749b3e343b30e6579ca5717fc3648e5546e88705df59165ecaa2c7e966a5c85359363c3f7689eb9b8cd3e9f672f7c5fa2c9165f044887c620492f8cac4c7e4c6bece51bfcfb2666a69522eb2bc5bd3f30f529c7b139ee2df22e718c6812bfce08c38c863b1dcd977c6a9608c96cf2465c019ade69c76591429097ef54dc26977f2c2987c3c016c3b359b2ed7f174aef9f9703885cca4533d94e747fc41d44e67f0926c9124fd9b5931331466f6c15b4797a302db465f332a01bf3e7923286bb58d624dc67b918e7299fc4701fef78cc2ef5c1c7b44477a85ffd1e344ca95d795747853de95f73feb53e264004d74871cd46b79a1249f63c9d4d57524e637fec7fac85546d9855fd4f6483be332b47a93714f18ff0c06912f92363eb58876f9e23a912d1f86bee005b3763ad1e2b2ede5efcf5cde64ea8eeea8b5a8be2e716fd490ad5983a09fb02ba826bd8a0b9c4cc848d0777473caf70954d0d7dc0c4203a929687769cd22701a698552271ab45364eb6925443702e63bb24c85c1c0d421ddd3c61e78dadbf08b5a05754de1408798c1666b55ce6beed0e17f2fe3b8aef4d07352946df6b19dec49bac5ca5be611683e015e2445c24678a5b3e3592ec6e3420bae389928052cfad9fe9ba31da908c9617a04420e56ea54ab9d28444ad65f9ec8a2e69779bd5e2158925f6dc89fe431d0b174f4e1bf2629629ebabeccc008105cca3dd992273eb3fff1e153936a3f29ba376820966eb81aecae4d4a392732c4259ad08bdea412f9669425f79e645056db58b43233afc2766d9872328d5f6693b4caa05cafb1d09f72d1a4febcdc07589bf58a1cf541ae1befa27c5e755b2ab16d2ebabc8ba0e2c53c019b98c21a93b81eaff42f080fb460478494bce14a43b12aeffd3cda505f388a64f2d7c199ff36c0d9f974680ab2619493dd3777eddf718658014215cc06eab5ebc7440321d60266d224f8a8e3a11188071aa9879c6b2d235ce086c45738faecf7bf9b451d5d257a301f59b952750a6bb31d625e2013d5f9bcc802e6603975c38a7436ec90613d374dbe97f8f750d2f734640acd7928974835d7bbb40569a8affbf3be1662af0bc257ddd77b1c19409093de658b02e4ba9db9ec49b0406877a66d429589de6bc478e74b946e55b0dcbcf25936bc5d7f21ab9862b4aa1ac41f9e3ae3120ba6d88bba007c599b82e7bdb7b1e58f8538cb60af18d419311695b480f6ee3373bcad379acf155aabbae67d020b7f9828e38626ceac93462494d82c1972f9eb473175835bedb0047624ccb0817814ad1326238d2f6fecffa7a66f4871e47c12a678d4ce72fc0980c3fb355de325bb42f4507bf7c359162158ee2044edca11b3e6b14a2c57376078d6a539453b31380a1a2b42c977e0f1a7412fbfdff53d817cff7b6ff9ae1df1c6a2e4143998d8ee70dd5791efb642c7df7feea73c877cc60418bf69ca32b340442dec14a482c9534acc1bbb981db0c2e3d24d516bba78411bb0888a9b29b44eec576ac6367216991cf89bd5c2c7cdd7dfe962a24be494606bc7dc974ba365c0be85be339aa03fcaf4e1a7a48e93c1ac6cd86e8af6becc6e1790c9bec9d3e127531d1e6cc30d6754a81f85214c13790df04dc5b94482dae16905882745a1464a84459cfc96fa9f4095d5b892407aa464fc1bcf0ea241c11237469df6051ed0621232385ad34ded98d7eb47a85297cadef9cf009f82788ddd13c1889102015114849c7454bcfea6b9870fb4d26adf3ab267df389acf6e87496aa216cd0d9502580884bbcbf46ff5d3038f2d1bd7a96f39369a7f85b0a4c433c47582b1bbfef049830b62df062db6beef32e1641295c392c28c34e73cef38b7b9e82215474a428e744b98c384d12065444c395e6e3f9fbbc7e902dd65b6a06715723944e16e59da6554d1af6ecf45bb41b9afbddd2e42a098c47e71b701e2551f753eca08e5496509319bd97ee98cd2609c4d6b998598b2ebd8c010dfcc9be7f29f3f195c5b55ccaf9af13300d9c8a22b33d85094038faf4a66112e9782b2ef19095ec73a79d8524a9d847e1ae6725b9a758467c1cddf9b9b9021289767e4c60a159167d2697ff6420454ae0727d855355f82afb67bc8675edae3a31e6fcb5140850667d3a23416c7c448f64938f068cab7ffa2b27735ccacf621a219924a53e69216d4f0f88ffa9e2afa4810f948a8159926886255dbe53a6275aaec7e66b2daea93ecf8a504334ccca6cb0d157b0e1cf8e2aaebd004b7edd54a8a43c6600fa77f067c3e6e7416ca70051ea1bdda14bab7fbaf5bb31f9871542185ee8476c7a79d200ab30825018e472c92ab4eb26b1de4119577c3443f274ab3bef4d2bbd19161c4c9818a36ec6670cf7345786105b83c5eb8215d0050ea184332a437a10aa6a340e07d34af8e54a6f2133ce65a4f724c08acf8c43ada3b4c79ccd5e86a3368e12d131632068c7c2ab59e1658897bf184c1eee536989ebd0cbc4eafe744451ff93a6de2274736e0819242262b695b5d468395ed212e356b617157026d2b9cac918081fa4c05c7f96a0d621992346592abaf018b8a7c6bb9ba48209512ee45b0bb5f2ea7e9f5ec0417d785b65abc0ae322c065ab7686b4b19afe7b96d55afedc9be68c9904407d7a0163b33004d1ebf5a1ddef1633143ee6be90654512885ce8f9d56223daa81db625ebbfecad98f389d34415cc70c58e9a4398aca7228639eb375589a8b8bc440999ab671c5993b9c9e7f3aae7d89298212ac0e29796b99ee8ff6432fc892524a84e0c86bedcd7c3665102f57604404c7eb002a74f5b5864b137ce326a9ade8ee00d7691d5e18d75c91e07c666cf8d32b3a066d4a094bb6d443b05e2172f1907f061d32d3f54db0156b3829d780ebe7530174201c8f82e0c9afe944e9211c2547bf39fe3ff1310a2816d75a3e15e37d5cb826fd41a3d7aed8b23252a41aaaabdf6941445cca1020fa172267fdc5c0415d20b3121ede3fd34988375cbc2d752a066efaa3baa2432a7eebb6793c3da39cd4ec5411150044de744fa7f7dd505b03625d9f9be9c4881d10b706f9dc67fc323f0aa2df04db2b5bbcfc91724a1eaa120369831f9d7ea0e31ae897c0f38afc79cf00141257e18598ba63ad92544e59b4c341bd7d64073180ceea8372a732d53d9f9641e7d290d06be30c8fd8a4b891b1eecdadae64e3f2bd94df87adbb9b4d5bd830f264e1d9d727cd48eb3af754e5b7d00035a93ccac36ec31f9a917548c7ba876656f6561d8002cd17521958c78df3604b3354a29e0cdbcc0377f0a936f81fe04e8cdbe850935036c28330702a39a07bff578a854e31ffa8f5ee282cafa1f088dd3714083c2c38999b2601883d02c083da105655c9adc62a429e883988638365bea25eba6ae7d006719551ce6126edb4750a38e3d78ca6e15357cca3265d036daea984d9dfe93e2fd6ae32e3ffb835b3d6103c806852509bf869a4a06d62e28a51eb1ddf06a83166509c8e138a7241e3750eb0ca4fe66b301fd537ba1d6d8a00e171a82792e5ba782f60c77586d1780fdad08cbd515d01e56cdc022d910b17c22d97f232bc16f5c44c4e28e2c2e14afafa49af61c4bf81714a15e6ad0d6cb3122ef288d4cdeeff8091322c57997dd6064a60748f7d686be7e0e877a5d9a00b06a11a6c436f9b0eae1a45175b3327640073f4a20030edcf2467550a43e2a808b37023b1dc9fbfb3762bd8c3f7705098273b62e6afff7bc8eb05b1a84047b306db8f54a1a48417223a68ba50f6514ffa915e3c0a879ca13bddfca5cf857f82c200109966edff38b092f7cbe07b8dc337ea8c77631f00e589cf86a4ceab5c6bef95bfca407d237ae7accb93a9844bb7eb76346ac1f2876e89051bbfa3fe829b65441e31bec66c813774d0f9877ef1d268305626babbd2bb01d3775ee7a3e86d92c4b96b367812b088fe2497df7ba4e30f0a63475a94343001f011b675d62ab72732914ba96610413a9c7761f35386947faa78dc71b9e3cfd3a1b0ccd7d86b66c02b3fd299608ff3d3429ea4acaebb02b11c9928784a558daa68cfef4c4b042576cd83ef204260231e1fd41946701d60dc124038a42e7112a8c0c776d3545f41d7f8107e86e09efa5de3db87f6df0dc28d9477497312536a3920d843c76125bc2fc2e64b62f2867bc4d51a733525a703730bb076da6b88e78626718af21813e113cc9b282e2c0440b6437c1825300826ca0e212a71c586339e726702c73178cbeb07a51751b28229f6b9ce5dcbba20632e05cd0860506daa291884cfdba3940abe879eef15441d0bda745e44813a403df52f3f43f0dae7a29252f7d41d49e75d0fd1c1fb60ce8d8c02838fbf1377e814a3c56d42dbdb9d4004069e886d548cdf9c14c2a0a96c346238cac08246718655b861d591533c71bf9d339781568fe473f770066caa5ef3c162d57a9885f97f02751994f79fd72e1b875132decc54f2c4e79ad1099cdcb7aa7c1b841f609dfd7da7b8a95aaae31955c28063d2ef4d9be8c9228eaad0b8690f43c776b1e9990b6affa797963a09e1cb0989b2af93c4e6c03076a4f42ba450fe2f9e1273365abcac6b560347d9747629581a7b618900acbc5bb258a4279d3c97754ca1de1b0c020fa3f54eab9ba30bbf5d68c356c660d053628887886660be12780497d786a940bab5dbfc47afcc19b050aa9ea5ab975b155afa0b32ca74e43e6d9f6702b033ec252d03acc4b23aa7c184cd6cd699174fc5ea2b3981b7205501427a5bcd6ed558b614b1b03edd4264bd9c6d12d792bf6c3739143e9ac09218b4bcb7ae03101e82147701ddb469f5ec87b8e4dc6f35b80b02e37a67a3d130813f6afe2006ec481f789c5b6e103ab55375eee8ebb3b5f4ca2028ea0b8dd5d76e3bd892a25d503d2d2c616c5b51f843ef173414b9c1178a623eaf87b9694d5c6676e702c89526c7e6ace13d1a406b99753c0df0c4124578c189a5911f5fad1ee13c85c4beea785a2c7d0ef08521de31ae4742e5f680b25e0c7d8d3457fb7a52d828014d5eca16ecada44bac06e75560a14161ff6401fa8d3312d4a903585fa940e0150fef558127b7ea4a81a099d629e82e7d8ecc4bafbea67e1746c94a458500b2024a6cee488afa305a7d997f5663fda179ccfb2c7a52d3c49c4303ce21832b1e8bb0bd1200d0a0750108da7a21e2a001f30f4691e5e6a2a5d833529316f3cd5fe573ef91d0aa6ef8ee0c230bb2d997a9b9de7bbd340dc6b2fc7d0d375f7284e511ea278f74af92f79c9821a26ea69e944d81b9da5cab728c1c3eb638fa69499a8d5ff8eee14ceab145df68ccdf49814c8c58adfa7a0942e5e126c7d1ca254dd5d2d88a7498e5b280aff9d76e7b6cd85ed81e03af2bdc710b75ae07bfaa09f11d493b53ea17f2a7c427def0056b0d0f235d792c8ee6af097d4358f4799d4ae39a596b095e19ad54a4aa19900ee5599f80675baf516d151034e92e0e032356098f3860e3ceee81234576e393fd8e0e115d813584f5764dde2aabf5326ec8279e3b8cd9a0b7aa08051fa1f6dcc814486e8b68b5ae13e999ec3b71b802b443934dc7d39c999fe3b31b47012b13cd95abd12283ad0fb615b3bd071dc6474e26fe0c1c67c099ec017f4ae703a77b645932d9f309c843b23f7f03b8b6bc818c3ce067036001ce72fe7d65dd454e3467792e8338c389749d80f37af2a54dbed9bd0993a942c88629249d5a7a94e8b8731aa44cb8cf0b3cb619e7a6e9414439fe03d157c64e06e851803703f78de4923c76367e409ebc7f6573e65f6dc1f8eac9922960e2bc318ef2989b2a87fd0182c0e11f5a7c6f50c68bfcc1e813001a7c7af84b0e104415cce4edefd565fcedbb7b5d2cfe3601d91d567d72ed385f34cd32a222b46864bf51fa77969247fe7df40325909c3b2bf7dbf7ea2d2bd873035be6de1cade7911b431ca33835a497fa588e75f36e026d040958aec12752d7b0d5e0b23d8087f4064b8cf57dde3385d43b0b419d147ccd179c4da58d026987504b358077af9528f9826b2afa5a544f9bd0f3f7b80774a47b1a67093e38725286f97066532bc86b444a8f7add918f9bbaaf7d90ff93c092647e137c8e798e714d62313ceffdb104010fe0c8feb379826bd12f7fa165def9682327265e4f5ac242517abae23602be183b568eb91c20ebecf4b31785d92ad00ef32ed72cb680c8439b0f31b2a5603c0183f28f7d59c16957e0315335d7babd3a7cf9e5b84d03b207f88b12265d8caff8ded8d8f69f7423b74acece7b0a77a6f153a28788ee017be1d47c08a3405cb172e2aa375a586b361ac28c8a8d167bab8dbd8f4207c97d6dc7b2b1ca6f4ce5b96cacfe8616a0af16efe67998fc46b0417f89e233f89cacabee5ea435d7fde8005ec2f7c0b95ef47594bf85fd1b8c56b478683d07ff30851096715e3d79af9942f609f31ae35a6dbf4ddc6256c33a69e65deaf0e30974c3439f7f512dfbb4c23a1c6bcf2e2e5c263d15af3adef79549fb3133bf232a13960d08ec5f64f04e9018cd8e1149b8b0f909ed24e155c29f6c39afc1006d38ca85bdd4715e745043bf0f4bf29a509e2282aff60e5947103645741c0daea3bdf7e330587d77d8d57967487eaf6ff6535bd6ff8746bd44171396093fe669f8f7b7d436ab1ca7e0bdfb1d75a2230ee6ac795c05110b909fe648dba2a6fe6c0dd7ae4a1c0011f48ded446208f88ef297b19ddd65b54e26886250c544dc3732358e43b6776df1dcbf2ed72e74d25830f4a61147e07507537159683113d7b8ea61cb0ff3eaa673381f8160d77d7cd142039d89e1bd957befd7ac7d41a2608aee47da6b97a42e9f169c347d7f4b309f4f51b3c47966b5c1ff5d0e368916a9d162a11f9f62daf90994ef05259ebb761d8d562f682552d0cce1fe4b3cde1bec80835705315d5df80b642f83836ecfa2da743555ceb7e06c7098c6694ef402f081b7323bbbe36f7ae231412b8a87916091742fd40ffad6c0453a30f69c45f3d026c3157a608666c776421afc525cc40570e61b7ef8a77d7dd59325da65b2beb1f9e2d3d95785366f34ff48a13c343db5cbaef44a3962816d0b4e09993e810078dd43cba3df88fe4efd28f5180991632f2c8bf83c0d9bf8cce723c42f6ed830c3899891e7e6e0c09c2a57c6307deffced4f91fc73aab9864cec18fa3b9d0c2f9595ab4d6fd5449ce44c81b169a18af80f0db8309c70168687057497699f66961e0c8fb5a7d5039fa251ec40e1f1249a89475093f607b19f354b4af78af2cc538116ae79f1d2aff8358fca0ccb270979a57109d20bad7b530cce37e4ba757f3673239becbf79749d6242dfc2c64006ce0d884a456d07a61d0e4c0fe396d544f6aba340b5d8163c99d230428cd4b3e46127e38786060edf6963c4196b61441e0d551d7dafbe19ee2bd28a53bf249c2064c64a4e60ba99ec4104ebe4909c36b8b6d36ad55e0dcbf257da83a775787254c4f0a0dcd563c6dedb2fbcdd56f11fb13cf9b90be8fd471a635ba85b36627ba2ce559c06e3cee092351f0867e6ad097fa73be4c8b3cc2af033768251a893a0169bd265c9aeb3dad7dba93063e5ae734c1a27ab1f2572b88c5302c1d1c059cd7fee85ef1f2dca147bb4477f5bad06ba4113ef70535af54972d3e140495820ade812a448205a157dd12c5b6a28b31c6d31740163da10c85894f6ee607b8b9a0346df5de0c5d5f420556dc158131d4d17ee5ed6881917de2c212809dbc4978b1ca69572d97e8cf3a773db80e911bfdbb0de20f9b439e026b88f2314c0f360add286857c11bd74e911b1b7cb46556c72b00facd4976ecc1fc45bcd5d261eb479f9666683a6d75cc3c693e15194fe902cc3673269ec9fde63fd787e32833520aa10c99478a8c1bd650cba3da7dc983cedf0051667a328cb343243e8ecac0da160de5858146c355b967402c2e96e3bac53e5ba8e5311bc16a22602146d2d39722fdb7db2e068d6b04fc46f76a92c869c0fe3bc132090847a72c4b434a0991afe6f294619d32c4c2a473d5c1202053fd23b6f21a103dbd45afe7a75c7248ee9d5c0c805290e8f259526e65904a18739cd87d55310caa18119a87098666f60e97d91c4b2ab71aff6e876c554d0ba5dc34a18f5e79dfa1d2b35da90cb53ff5158a91f3586ab0cb43634d02cf4e5a06dbe190f74de0b55b48f0c571eccb977ad01c0c352c455172ead2bd01ec28a489e80754bd7b2a3c07e46117e7f1354abf94f27341df0bafe7588e0a2d2735eef759b8d30efbba3d856a121cf8ae6a017d5d2e2223713875dd8e209aa0cfca3f660535e62b2b3d70a30ccdb471ba649f111f34f1a622d65a0aa5202c02498019a7664c48087e4c4e5941ea4cb3a9c1818d8663c0eb5e80479dfe3a7abffba62085ff7553f8e7a645cb479c570f0cdda505c0528b5ab1e9c0558f90c291e836b9548b4de93bfab2d97aa7f755e6f7bea85662c0b61ab0050a85adde2d514aaf6e5a938d4656917cb056ecc186ce4ec079196dd5179615e0ab1487b960c95254e98ea97b8248b382543975fd7e2fdfc48686e8e6d41b80faa92676d428e70b99ba78788f1b35a87a982a2ebc267561a91054d293fdb88964585d5212cca1a76acd00f418798faaab9bedcd339b3f39fe64aff41f3378aaec32b99948d2ac4845f9b574008ecfe8cfe01be788b7b7f30706d523f12b84adffa5e1ddef70582e27a6c32b058f2654b5dac30ae68cdbd57fa1b3983fe1c9083a3c03e73a452b4da00436d2bc8a6156baa14cb4f2e42818b3a763b000987a555903bc4b11f0e0f08e0ba99284462013766fc2379c1d93cca728183a970b712d9a9181d1b4b99cfe8d3dabb09a3c8321d94924b0b3ffd6199c5f07cbf9414fbc758661cf5654f9ea6bbf256992cacfe54ba9f2b2a7a39b2fdd5bd2613e8926ce4af2faf335d8f9e8e0ea25a4313b7ed01d71801f58037295c1862644b7b079d926d93670ee984857d323d5fad43916fd2d859b43713c7262ed85375959ea8fe01b8070441ab0fe48e551c67d10704db973ced0636dcfdc324401cb9f3a36a8d381adb5f2e0046999d26f157ea648abe0a1c2ab5ae0fa63b6404423c4d2d8d4326787f1b0eb375e26160f535b00973e795e27e35f27ed4f7c4683105fc6e2d655480abaa4ef403e1392603ff3b3a69058e2861eaede45effb4a6f27e55b01704cba7cd10fdfa574bee7293d06809e47d64bee751cd7c2de89d9c14a67a8f80e5047f3fb79aea411627a1cbaf56260d17e308caabcf653a4ec3fdfbdc13ceb919aba3822b1c0311b115c861290fc333c32aa74f38f7ee4c1fbc3f1ddff350c7393a48dcceb1e9ca"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a89834aba90aa88f605981578667395d730a408f3d112231997200c28865ec37a4a1f044c8817949cfc8a4fd9028832fc406f1bb919789f2099629c2c8d6bd128de4f51c02a73c49dbf17883ef90a9dbc0350aa67e024a893e555b4f989780a45320af4858421346445f66aa86e4954c0bce0debc896f21bc960e4fbd4eebed93e943a40387210ecda652c36b6da73570500adae1a2a03284dc47f1e370570a07007d8c5a64089e81e2c4d45eb6ca01530884070d46f4605ffe139457d5155c8e9ce8f201715ce7b9d18755304ddb6871551498985ab400cdc4349c6b5ed10b76b425e70376e39a6167622eb5d4b7cbd932aeeaca53b3e28ea06c44780b01684e66eed712559543cea677f1d9807e2ad0312c42e43d399302a0c4c506da7cba37000c3ecd10b58922889e5c8d31a9882ab8ae4b69d3d3d3abc6450881e9b79d9e2ac51085f61ddcfde73e57c1784a6a766ee2bc434d4973a9667c1c8e00eba0c544a36c593a764f519de83251ec48fb45a63e00ad4aaf01d1a295eda0eb95b27fc364c33e3482f4e5256cd622242840d0630194316033219c3051258f548a23c08d205a7b15199ba8d6507565d06a1f20db367183d56d9dcfd2e12c36bed83d239ddbda9efe8507451542942033282bce486f002a215c2ef599a6619247888a81782b005acb3d550988c1f22c6b186038bbfe1c583d165588e00c7f0f7e462a778e6a8126be71ee0dae7b5cfc6145aa6e65c8c136d34f7b45252652995898150cbf177f47ca8d16b583ce5b0e809567c08b99c06095c879b4d945b13c8a62429966347946b606dd78803a3c8113a431761dc868ba2e2541c66b39f30ee21b0ee3fba5eee922d56f49ea60c25a1094381908a69b351e325357d9b4b9e2d040d8be7795891ad46a334a057b0aebdb2e5a9cd760b02c774f60df240e05ed3708840b1663cb435adf9929c138b9fd15461d86328d5895d8778ada79d9b567386a6302b67b4b99a37f4362dea36fa2fa1f1ee2f4f8293b131c57595468aa5ba62a03dfadc9784c8190559887603c4b50b7487e795285705f07f90d8a9ca50e4abf0905d7487f04549132cb3a62ac2e490d6d5bfde20568290b693681218426fa0458eb356b198b41bc60505afdf7219ce5959124e4d1a56ba63345f91ab39afd970997895689c8397c023b1c8b774f92f0e5940c764abe3bd609a0d50a98dfe291e1677e6232896ccdea3d047f35c558daa130ff53cc66aa03ca5687a2006cb7c8c3f",
|
|
+ "slh-dsa-sha2-128s" : "0x3345627b00d77c13ce3ebdd12964c45d0bec4dcaea60b64fbf6cbe7b897b8136"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x394f68dbc8384822df8d4fd86c22e55256ce421178ceafde6e1a5f6437900ed2a86a72cd648af5e2ec15c79027aaf194847efd5855472b428c647a7db9d6e97dd15f70c3992480431ac6919e5b11c9154ea5dd9ac630f866c589a54b84a4c9fc57b86f2b5c835d3f6fac9de77d1f08abd507f514df6e7ba1c33518d3d1e447638eecc8a4b7cea388c2a57a6640fc599e73aedfb4ce6b3f147591b9bdd10fc7539fae4b2931eec267fbe70a5c6dd8b24bc98276db5d8da487bc38298d17aa7fa5facef7cddfdfd6eecbaf7e8086cab1df3c8f3be1913d30892aea7bd03d7ec1296247593835d8a74f467806259280a4e652f7e1bce11aaed31fbe2e155964f7c37243a59dad5c8d19c3c6b9d0f62d59ac39578dacf29d9ac2c0d5f160f7bece5902417ea82a0736bed8a4d078599134506a7b0f8a3ea8d6749fce0d749722f7c5198c340f53af2b4e1054fd97239109aea654bd2be0307a2d868570fc34f56a95ef5ecca1995681cbfd52a0e309e9db779ae71aa921796ba86a2aabdf6a39250bc71cdf8ad4d94fd6a758f29c90a7dc44839761f4a1a9c6d1905dd18d0532832867e48e91156ca67f2e2731bcc949d8140a850a8aaf9dfeeb9aa339b453bc906fe07f0a3e30f59a941d9f4f7b723a639e5e10f39cacce38936fa58e36746b0cbdece2a9122a110099104543f066515aa7750ae0080462d9254f58b5064a55b23a06dbff5875966598a7ef2417a8f32231c630c7b3d574584c2344e2fb38d8bd4d9437aecd68dc690b8f1e93f0109ee3747bae997419d1255a5c14fb1ed17b112ace324a41dc34a5ab81630fdb178641536da5268d928d19daa49507a5c81aca3e061b4b5c490310b13292385bb341b0550cfff7d8c72de94a6462defd1e6596b351ef32ca474b61c951ca5bc4f919e4",
|
|
+ "slh-dsa-sha2-128s" : "0x6e16547734391aae71d29745c3ac8cdfbc98f07ad9a8470650f0a0085883ff970643e21b67d6ffe83653a99f2198f821cc080dd7f0cd1a612ab5c6f18d9903ecce34a5cdf069ac66483448219c06b131b377900b999f9aecf637713feedd8c7d4beb03ee11bb297bf4a97959ac5c85c0c83b48147fa9a3be7543ce1050394e83ed745f9ec0c555328d3786da46acac3074c0611667ce5bb4613436dac210c2e9cb186e9540d7d43ceed7f278363811083368d50f6d258a46a32c8df5d62c42c4f6f34c627076169428e646774dd6dfe6924e2240e720fd4d53dee8f880c782862de1ff96fc5204a17625ca008781cb120f74caa37a36dd20136567c05e8e7723a2e21569f065d4fc631811ed0b2d9bb67d2c82b755d14cdeaccb797f207427d572419360af1c443fa68064a653b1e21a2b83fbd93e38c7cfa5046eda9b86c68f3855c61cee9f799ba02e611a1b7df6a15fdc4b4b09e51b3b5e1101d0dc90a213cfa0522e93808fc4ab3d8cef74d279b98069988f6b8c6b4c8d3d62fe2a5a62f1a7fb0fbac7fb36529dd85416a330f35a7e4e161757a83282ad50ddf92c6096cc1fe071952dae4540e0c9d0507d4b61ad34751ce17fdf2e99c3e54cb523d3ffe2cbe8a5c58b84bdde119175e9599df6b2666a7721e246305457cdb5ff5ab4ec9d04bca439d59989253bbfd9a91cb10a9fac3134d85ef28f1e4d4f884aa195216a4811be7617c0d6004c7833088851fb7758aa5aac838ddc5e3a51d122fbb03b0b5d0a3593b2b97eb69c2266eb236bcf3134414536ff36895bb081e9fdd2e5a9f9ba71310af0fa126eddac07ca67020ddd4caafc9b102afd4d0bcae2a957bd65d0a15762b98f4dc7b548cfb463ae10ec3da3b5a4e9976b8f05405904aff74d3d536f9a321b41e0c1d5e4fdbbf61b42d868602e112b53552b8199a6618723e5638273822fe0afc5e6fe068d117bd5af3a1c1e8bb4ea9ae639674b51a523d19f950629a76e9a52c673dd153915863d0ad166d357f8d23b85010aa0b8263de0f253a0ec29b0973af15e4419d965164b5fc6a0e782716d86bfeedfabf4d9705e7093373819a814a45b245cdd13a667b31f1724b5cbffe3b5ed3087118715a0ee68af333bf26f1ac1ff13eaad6a5edd5e760e89518e24a982af4f44386c6d92db7a2229bc9c4df23274cb0f10d348f2373a79f55ee05e3dcb256df464c5f3e54ab790f1fdc585cbacd93c775e50bd02f451b69972728bdce813b46742ebe9e45d45c8bc23d4b298b5956e03b48c0a11c602ccdebace8f92e2521cb346f291717cc1881b0fe3a2e23d4ac694b7f1cd296b32b7f2f139877a129079a524d7e3c4f9c36b5836346a6944c49967796d8564ac8d2ed5e804a14c655ef235fcac5a8cf0372f7df952af0de7e4319089b54ea3f718b539a9bca631ea0bcc9259c64626d252245d541d90179364072b081d70da0a7e561ba2902e8ce864a398dccf55a4f583df7b6f6ad6738813eef6815f8f67936b7b842ed7dcc48808156d236d70a9ecba41994bc0296c3a236f2772c747db6ad62723c4457bf8a2e526f306d8012e04adcff0015a88167d199029ecbd333a6ea35f5b9dc2eaf11a14fd09b35bb2842a4e610da4afef15f332d5d1e82c7b0b452b7564eb45193af060595975d496ee59151e3c0f1545ef2694eeb1a2e38d4e008c0943c8e7f181a258c35e5068df39376aad6ef356e0010303d9a0dbcab91dc708b8e9482f50aa18f88f45864d539dc0818148149aa259eeb270a474b0a117de91b6834672a5cb4b5fb7c2ea0ea7e3bc9884163887986aff1cd89c49a6ca417dff067da528dd33dcd1f7db96ed50820bd72dc41984ed5c767478b79d8f61cb7b417893a3a4451129525a915b1e999086e6db74ef627534015206953ed3a5e2bbc5c629b00f3f3b22a37519426c20b2a10c60087ea32fe606d81c6457a02bdcadd8d56360dbd278ced2d4cb9af64af4ec77989475882f3c1c0b9f9e0b6528b9834e34024dbbd64dc19fab35f3bfda66c086f4c0ff06a29e9fe881340d1c0719ef568e3f8f683282b963005e93620c01de327adc0af4ea7f968fa987cb8f38350ebbb3b91192ebb009f9fa85657e06cca6f71edd3d0dbcfafcc11b908cfc38a08ba288910fcb14f97746ac20ff6e6c43eb099d09a717ac03f5e0600f0bb611d6972626999f5661e048476aa999c83e3f476e77e7ae09c6fb7c343a196e1846ef061be75fd8b662932fdd2c7d8784c6e498d4d828c910eca00ac199957fb44d572d4bd2c599fa6c7c2a166d96aaf4959c561d1e9dacf502f76b050c836194fe1897d54a017944a973f49b2ea59b66c24d18f13048e093e83af249854da9fd6b4974b4db3e8e65684b3b6a0a11d942ad5bb667460dd98ab54319cc2ab704a7a57c1583b8289477f5557d2da684aecf66eec3a54da742e2d24a6935ffc4f439d4a8abc21921087df93da2bbdc3a0f61729b397faf12bfe59c85a6af75c9f4ce4af19239840b57c3a4ead6096f2910da23bdfd02ee4f3676897f475d625d0e9a9cc930116bb2327232dacbd0ff32cfaa40aed89024b9ccfacdb76bae77a87b569582442ad2230c8fb3e0dca3937dea5685c46aff9ae6e16438e0e9ea8ba299936a42d68967926edeb3ef955d95c5a0b74a13edd280bdcb462dfc2d82e7ec89377edf6760450e1ebc61f035fff661173de5fc80dc66b8e3d38c67f4ef8c25c2c5626dd2875e10d870f12b3f36f749eaa0c82e94b2f30686cda1da606e0c815a35fe6fd671915483e1b2b48fab000ae560dca0119be7a0a3dfb347ef95c7fcd9a78e76911cb5bd438a7e96562e437e32eb399782a9498ac992716bd9f3d7d4e35a1f1821f9008f547d171ce2b69b007b5e377a3244092396acf958932616bc5cb95059762f48468a94f9f897736b11bec2ce0af9ebaed9add43bf5c262106a96083ad967b7fcb127012b1b37970a6be14cd9088f6ea927a66a76c35e1320452848bf7496fadbc613b2e122e55634f0491397ee5d211d780971998244f303802d7630837d05f3dcc588d8ca32e02f16d2297aa577576ea5c1b90d6d330a18444dba772d7aa94d0bf2000d598a069d03e7873f114cab9174af2f28e257ef2c0e44925da7ccb593d6183fdd37a1abfd7107ce02c655e7966286b72d65394f312d72505803bd53621a08100a041210cb912d5aef260b84e39faa7b5d8a539b6392b32ce6287e1a619804677b3f69ac46fbec010e726f3eb3458433e68e6417ee375dc70c2b2ee16b2cd9b228d6a46f92ba66a8c5b08cbd284dd759478c9f690c5e1e16d6332b5a0b9aeee43ac8ce3eb0c3eb6940b61a65bf7c3348d8dd15302b8b7bf6b6257e074d0af3eda088f7c22e6778c8cfef1f15d9f86c76a4b05c9afa228bc4f116ee8adb959b4ed9afb2307f2252b10baa436795028629d05277ea2722ffc14d9a5fd56e6cd6f0ba218675df025e50586e46429f1c6028e305d22b5479dd045d98a93fa30de08bec1576ea692bfe6b657b4be65578fa2dfcc197212643ec9a1a8de5971c07023abd8767c528025281f9854145e3d9c47e01bd37dc3a35b76639e4716465b862b705ebaf674a64313641de333828d75c16d4f6ebc4193fc2c92e5a3373fc79dcdd8505a8ea7ef8be6ffcecbb2e80017b6fe401e49193ab31e67a56e8163cce767abc393608e7485f41983ce27b9b1de1a0281f237d685d401641f860f8f11d10805fbf0c7125deaf583458787c6f2850b0cc8c62053e069df241192c6af9018158c27e30574a9025af5af73bd956bc008efe84b31fd9a49c110b803947fc939faeb773cd3c33d1b6a96fca0c079f2eeb4e3ff768bbe1cbada9ad22c2d97928389e5f7145a346931e4138d66319f0154cdf3b28cc9bc04139f92e421efb522d0639f02935e228d6eacf3ccf0356b32c163dff6b597d51b64a13c8c93f60f150f445271489db644665ed1208c025b35dcebe82e73034561704c602d1b24e04c08e4ca8fab21c5136b6d4b7af05cf8ed62961b4bc1c2883154116a0ca8933e36042eb98d851be695d8c4de2c2530372c606c93bab254d6b00e59fdaaec98c56415da26ea8449061e12bd22743a1a0e0e1e117a4a9448d75b3a9dfe6f213460ca639632d404af60c764d91405391137ab9ec4e8519d11e3dcae18dfad0404ce14ea4dd36dc3ee24b7a15709410818ed0a42091a01ed9b7f39f7c87d60d2b3dcbba880001a519fb7de152ec06c73d35c08b3e375b9186752931b6108a4b84189fe07a7165e18357a94962dc2761f4eff0df829427646d2210b55915be710e2a1bb413df2055e7aa0b0b9a4067d35881f22c08e61b587a59ef82ed4df267afbcd4c62f22435167f2d7a4a939eaf28a6f1903c8c046b2d7719b7134834cd56964ba860e60ebb6fbf4605a11b52aac2d595cf3b6533fe2452b65dfa0fff71aff39124a88e3e02977d6063a8370f98e3cb8c80f35260a8541b9584b1d2bcb315b394d7641ca56539b4ca8bd9e4fbc594b0a3bf1ed678be2f9a18d31d610b55ee175514738717d47e4821150a799ebce655d0c75228c2160aa1936dd42f9923de2ac97d0dc3ea062d41d5beffdd1d69672b73490d6a5e14a655228bc39ffc8f1e862fd39dc950dfe648e0ff87807e543d02c40411ddfc6c1f8eed733750557c9f68d830c83af737c9d8c3ff0d23987a8e09e6293d707940eef4cc838365775046af35dd26acfbb4264a9ab84818a71c5a13d8e615c5675656671e5fc2e91b682e91eca76ebfeb1c09334e962496f583affefc56dc144873c79d4df77da394845fa29ff348007c8ee7f23f2944c121ee3177879e6938eb043a0abb75991b3e789571e3eff009cf089acee93612e97be85e1cd83da9ff5006c14151afa67fddbd9262667f98df52dfded25f28b36fa32ec662cd5a6b0f844030dbe1c87e9e2d435fca1a81045b8de5b8ccc411a839064bfd133731f55ee2ed2ee727d9382d130ced8a48942ea295bcf75fc74e24204b808956bfc171392f18554764aa80e75a539941d90a4afbce1f981f0c35bcfc78330ecf3d416d0683c7682cbca066a10c43273a0f85495cb4916ec0eee9952431a11717cadc95c7626436953fdd5fbfbf9ffe329159d1bd79499807796d75c458c3e3914d1f73f656e9fa273244615710c3eee84553a7ca0250e97a0b8895695bf86408d2f3cb2fbffffd62c8583af5b25b7e2a38e266c9623429f8d80ab8fdda6774df598f966b86ac228639af66cd0e3ee7ad7714b4ecb42876c31eb2608fab0c6ee26e97fca305aceeee80bbe22cb5e9819322aedff05cdb78b1fb3060ef18ce0385ae0fe6803b414aaf0b340eef94a7517e5cc3df4bd273f92120b8ce73281cab96821ddaab08b41b97708dbc7d0edc49cb362759905ce8d42743f83a0d75878596c4c5ca878b7aae6fee6ca7b20f2ee60ea773499a781b958f4353ceb078e5c04b0fef3e0112dd0e3a7ef19e4c63a202fdcb8ea56d15b2fb0deee4198a19c9aa59c1ef2b3de73f291445c248779eb5fc76953137adce5dff20f2198cc9e729be4adf385e0f25f67f68c04b4cc26987c133b987f477d89977621b8313d6d18a5ff6a76c73ed608f5e4adb860e2e8a6cdf237d4871a98f0c448668bb42f29ccad560fc1e571f8abb3c75665a65a212fe9d2c1c48eae9b92bd0a8b7b3d2fef99ffaf7942f5834533a592423d2cd66aa793e85bc8351876946a1e49e13ee374609932ec1af8d4d3f52e00f783368aa2bba882cc91c5fc6eeb657f3682dca8e9d63f319df3bd1cf52c511f600a6c815e4ad59426d9e1f32831dc5d8b0673c7c58e8bc1601d241bcb76c1306ddd5aea847dc903f376bc4d8e73a55f0a5ad331f57bee70533b29e6b8493d9f11ce4f27f9605f693c05487bd43882ebe8a1090a95abcfc186d74a3708ce3351ce7226183a21c08497dcf52727b7de08ad6a970b2c9f314bc7b33995ffc77a9a36ab46c7a05f61315d18b3f2217703be5753b4ee1670eba3af00e90a94664039aac93e89dcaa59d4566bf286f33c740feb763d0a385855f4410052c52abcfc972298ce03ddcb2e65dca251afbbb75c516ba77001dcaad8470f61e3391c1c68b1b7dfac9e50d53d2ad12876ba96419b39d7f94fd88b58ac1c123790bca733b12dadec6922384c6f3b7284334bed918acc06ecac7674428d56496e9d2e8f0175b3c7e384218380b6d59dc93541ac0a7419eb0ced7ca8c12a487fef9ea50280b7f7067a8855e784362e85703f6b848ddcd4bd31293baecda021fcaa7198b27d37900ac192d71de4e5124089bc1c8234fc455fe71171fc44494395b323fe3575ac720af5cff428326cca56ceb0c47e20e1432018a769f467405f5a8b71e15e0bd32f027640212d893678ec6fa16e5c00bf5c0eaf2de0333126ebba6b2306211cbc731a6baa8fc5a64a30141a8bde237c217161e384af3355b4a253d35766a55cc69be97abead95dc2ccdb4d243f64aa6d74330cbb2fc9fffa79fb6b6baf99e5ba9abd7966efc1586e72bd25f6563fbe125abec67f24e3510bcaa34c49499811ad2425c25593ff362c90c5c4fb3c4c45a4c63c46cae8cb1759ff2d82ac2726b60b4f094b6344191f3828c78d369956b7a28f650f63260c2dcdfa66d1df4731866efa6a335281d1cf2ce3635eb4294c8b2e1d4b7ced7b4b58a10d693e9f5a269b9d3451198735697af3a7b4b630b835e3b56e252f71f9aa6dcdfddfae13668bbbe3538d5aca766dbab6655c4aa906e0106640d21c30f1a241f4f5dedd526e8f579848f1b64808afb54bd2737a18d9a0e4a078705847b59a1ca4b2b554d03304daedca50726cd23326a6507393b2dff27921b5d7d322cb9901e0efce9bfd95039bb3bf6a99282f9dfb1e90289e986a657b3aa212cec6e611423eb3e4523f4723302b1b4ea5db2cc3fe3a7f0f3add38eaf228a6f0c02b9237e4078b438c01a0856d64053427af9f84eb04f022fd12986287b48cde73554b014f75a04d01f7d3fc6285347be643ce214b72c911e6c5360909ec590ffec8b4395fe271e97af852edd3801ccf04d3ed6684c66c67278cf331ac7c9b748e2dff377cafc7fc6732352245aabc9f5f25cc29d8f7f211a88a7aac750e488ad0304b7907bb063e29fccb16dd7ca0b78fc3962046a83f9c7138d49df3b765df47829e5f56e5155dba194d5128648b92e4f5c11bdc9232725faea4b87d6d940b9bd7cead9462736c7ef605336c40c9a053a000ac390b6340dc85a6905d35dc83c2d13786d233952ca8777b5981b761376f4ce2c5bec0587c2b28aecf39371b8899d227dd58c054aea7257dcfd838c32d6053362842a0baee7f967b6a4f5e1cac240896a8ec8fabbc4a551a55e674dc8cede1b9cee3874ff9fd3b91db433a12e78904aa3ec84d57a0169f1719297b467c46b278f671f74b8bb3c2c0cc2a093cf93439c1267e3be38b12e9b5881c27ab47bb01397c6470b80174ede3df34ee51ac116bad6fba58f8b8e2c7e0d1dde184460a5bce9e1d853d11ac017001fccfd5b767afb69691844e8327d39660c06b8916e918f5587f5abcd0f0bc45328ac01b1ace66405ed6c7a5080f5795f2ba0c0d9e5d05f462d89aaa230f240fa47c5c0de0b2099e93ae8c0f94a45f0513ce2797cddccb5216bad88333f6fec5805e0b9474a18ff562e78dfe325c1a6bb3648b41595690cab5ca9805eaa8e13526d036f4233f8181aa8efc76e14031d343bd5d9023fd6cd6b32947e173807883b6a964d398d3fdf9f34a44bc5fe41c5d72ffe5fedaa13fa1da68e19656ed70771529cfe822fc694be1445c79a041eff9753cf47a48ebe9f2c9f1546117b97a1c2bd6e375b957fe38cfcbb29f8eb726f18bc6131b1e27316064980e35d95fd913583b9735c6bfb03ec86e935024e60679a61d972b4aa296189fbc268552acb6cd890c68e50e325719d2f2c99b8105bc92fb582eafc1d618b4e88070e6d8df4924a1780f63ee216c0e937073725353b0c97acae72ebe521fb05fa78a4d6ecb7ba2b860190b6a5c340c83249919c26466c9cf4a9b774fc823141f65196df32edddad59fb05ba24738d81734004c42a7f92f5234b7f4fc0d605b032b08eda4cdfa3b03a3b805ecf5e4ad667a8cf399efb3c1d6822d9d5bb5eece6e08a515cd75c4485537eed6cbd55efb0a3d393d2cdcf44846f0c27cf6a664c70dbd54fd56b20bcc482de2eba84163375b1bccd43da63467557828b791dfb0a976628206e26e9eb10f1e9b9fc34571cc1a38f54909a1ee0b097e0f22f3ca58b56c631708e9baa52d7eb551bd327a6e0014fe98f04d7b0544fadc06c16a5652ea16b6c92a014bdeb2c070843152847293a0a925cf3c22bc9ac23464919ba6340cf233990690c94601876bc30bd5283f97cfdee757caee7b7b41fc265fb2ca9751e3b523e8498d665151d1c67624a084571f6c29973e624703d2e87f1ae5a5e0dbeeb96f46698223e063d10d85fd13fa0deb3891359844ad5e8100036d9b70b3b7831ae78c927a5e2c2ec62992cc424894ccd6f064e9ac307e6a2dd092deed179cf60b4bdc6c56c32a538d477d7917f7203f898659104ad5aab3e520a9f21d9c01b581cc968a68a77648cd95f66b5a1eb1b9d60b0a73c2eb05873f279c4ce43409853df2c8db254fd5b63af900c764ad4a0aeb4641e1a4e4089967e83603cef0317d06d1b990354c11b17c83c2a78cb9152615b9eed33e20f61a83179748ed4044a65edf285b155d41c735a883a481fa07c4941865b86d3cbd54c345d7933e32daa90a1291211191e0a3a5015f0f60d2ff07782606c164485aa469bc97f74dbf1345ea631bacb972be00547074759fab2b98a78cc43b7e4fee587e40e23d9f8ecaf03337d47d27bce633ccd97c0b18509afe35d54b1761a4ecbff6c44dba5402f3111eb671183b5e6bdcd69398056b980c35628f03214e0cb4ee5364e51de27843ad6c24b1e972889d54ed2a31d74000c32fc90b3c96dc3761c9649305c5f5e75f5b5ab7eaee213dbdda1039d4f3f450c77e6434752b74a55c42c98719836fd91fceb27be449d65c89a823218e882b987277622ce62fd0b46130760f10be6b49ec57e25cf6584a99433cedb1ecb1ce25cbf5e2b6eb716c12064f2cc45f4989c4c1b6c1ebd390c44195a16da16340d3a8588754ae676a990df1eaf04336b3252a5177ca3b3b2afd8e7555e92be6f6d7e64bea52c8d25adce3c580b5731574729107afe0e1025e6da2f2b05d6cc223778ac7de1202566098d43d0e4db6df8d242b57353cbadc0711030c6612cb92a9f9685c88856a0739e61d08c8fc5864fb9d8f41b27b43152ec15b3307e2c6f20e00254984e6284763acc977d9e16ffd4ca8be3ba7a289e3c5863371c132b8300f59d50f9efd344d1cf51c5ac64f29210740be2dfb720397941e2ba939e31c9ed563a674628b6ec3c8983be01e41eca61f869b920bf08db3255cc04a1f459653a4a3c204e6ec5496af1984f5e47caf56993bce1124bbfdb5d7081895a96170241307f000ed22ba92d5f5d920ab39d3ad1e288abb76ec3acbda6a7779be4c65e99bc7d7d5aa57d08ca1774e0fb146cd3a894beac12715bf322febeb256518addf26df507db3c79cb2883e6bb1e4716e185026cd760c76038d52a2e0695d76b3bf9da7df9f4dea5323f7dddc8ea1a0031851928e354e703651f7a21df505a4e7f9f7a8a398582aaa9f504510c0bc6f9af8942601bb3a6df3faf2e97c9df28268e1dd466857d413fa0bab4ff017f12554dd317455d6c716f9449c5273ffc959f147d7e0da0c2eab432b83f96f7d2de7b1ebc41eaf2128f8eb8f9c09c7b3fb4e95bb3424b216232406b81abd4c0afe11835a8425304376b08a4442c6eb0e88a51bc67a49b143bb35416c9ce613538483c091bf181d322efe10b2204aa0f0e01507a7cb809cb54b5cca5f44c20da32b2b7ec52098e53de672795b68a44ba667bccac558210307ac27bc5c203a2e6a264e7cf3028cb4ed41e29bc46985c1440187155b8bd737fbf9480749d62481d805463d75ec17c7ba83c60cc7020fe4b110ab1a248f6fbfda3e5b8a688a280f87a53ea7154311951c2001a7894eee171a64cba9b19a21e09540dc5ba85b1b2880efc39c8886dee72e64f045d00d99a90ffc81fc957ee65b7bb93e113717e7e7a275814404198f9e9d33f45335908f1ae917e0322b3d12c3d298ee814d22f8a57304faa93c18a14fdf53f05499239b66498512a6856ea194705521857a1724bc2925ba34f0e2707c84ee234c3436b4d3ab46cab863a28a011236e564ddbab3d49baf77be49ff2f5f2ca75252971a421aa2d4975aeacedba6cd3629efef8b2322b516c60ecca2541112b59d73b88177cd3be06163a463306cac2c0c1b11f84ab9b2fb6ab776bf0dc0fcb381975e4c1a0198b41bf6c1587bf6ca7272d8c722a581bce4494be5431cc5e3038ec33d843b9049b018fffa03cb3ff58e5da6bd6d49ffa6f776a5c4fee3cb258c4bf92e5e4079e38437f321e0c29d608cf5f69129e705e66a7036d67d43fd4a2919271fe07052fd30c049b793d2af0dec2431ea687077cb7a7a5badc21fcb0c2ac10bb37247207596d33d1c2232fc2a225acb9f30be7fe6da19514def9b595929c1c0c4b146099bcd980356b601ed0701299ca1a5547d62badd0475bc76fe51d0565b95b52a801f14e1f1ca62526cf8931f0706e3a478d20ce7eb1b1088454beac15277a72c90dd95f6146f961e41caccb2cddb2cd0680760731bb6db221944eab186425b0c2caedd840be5a2575d8dfd5810c4db5403d4491304130bbc564cb578d814d952706570e56641e8ce6232a2d4b18941c35301cd5c29211237c274dfb1aae379e25efdf827ff6e41cade1d57ed229a6ba76bf98de6592e5ae3ffcd481b53071e452a0b25f12919003474bf4ad2f36138d3d7c23c89b5b41a25c3622bf1dab6762cfa86a5bdeb6f2baa9cb3ea7dfdf9bdc700f4062ce8fdf477a17088bb2bf654e2eb9ab943472dadd73e3b63a4fdcf90fffa98983130e16d512b54aa0d4acbb1604d00fb2adc4a88e87d466237ee7b0fb33e5f384656a8759143db4c377e2cd264259"
|
|
+ },
|
|
+ "rotation" : {
|
|
+ "falcon-512" : "0x3981b03586d7884dfe64c33f5b7b388f166ace48916b895ced22b34d428da6cb1bf0b0f292968d77e45343982d586dc6c556f8ac4afea15682ff6aa72683367a22398495006bf5ac0e830f10559bca255d2149a0740e61f05322d4acfe3a86645817823db5c1524f27b71c99374eaaf72ac0f59033a05ca55c563d1d2b58ccff25c58e779666306e18c1a9a4bcfdd7b47d34f68a96f3c18ab227b263566951271db2b7d6e20d9febc759c0bff4189c59f6add4708f3d8e532d58660cbc12ff5ab24a6525d98e4ff50f2a2b14f041e5cd6f0b1c4be47ae745ab7a59e8a220e5fc390c92ea8b085334d6cdb33fdaf1d7cf3c477367f96a54c46f9aa448cc53ae521bd73dd8c6a652f69373c3c7fb18af3211b3969ae922a3ad33babe49c88116a97125ae74780644f6c2d31dfc5987f550e2ad8c798d4f0f5a05b356dae5a73949b876f37355793ae6b0c6729ea2d70b12c74c2884d76844faa866ac685de8c74f0bb2f5ee9027d731aa55b2e9b1ef5a13dd33656699333004392ca27769c6a91d5b26f3ac3d65d74f9219d938f2b02f5fab2079e2ebe905915224480b53e2a89beebe3ed153b1bf1f8e296b6128388a5625ad48640cac171c30e689dc6593eb24b8f575e09438162d4ed215083142fd8df2f1a67770ba392d92a11fba399348aec782c16af5a41168b17eb6104fe43b49a7dbc01a4766fb962cd20eab637aa3e420a6f9aec4a2f9697ca26ceca1718843fa445abf3910cd92d877cba165d6bbf86aa5536f5ebbe450e62b06f2a3a8cb03dc5c198f5c6d90f5337789924ea67fbb0a07c8a06ff158d72f86daecaf9c96f12bc0b30a5e39c7e926bbe241f0ab69930aec2ec3ade0746f55fe3b18c536132cff870ac4f9bd0efe7d84df72fa1b6cd5334e8e2324e18da66ba979091080",
|
|
+ "slh-dsa-sha2-128s" : "0x563b16e5f93863fb9479ecda8e51da4c5e0b8c2ab218e682251dbdc02341a70a0bc0a8bfcd7fe676b4a88ed00ab7bad29a5226e6bec830015cc98a88e82d8907e4b66e4b39fab840bc60df099fa85f9e079a4afc0fb91c1ff5f8bc18679ec741add6e6a35870278fba0fb69e912c6dd01dbab121ae9568e4fb8d2be66f506b4094ad1e4a249a01fd55d6956780c0252f978308118de5a33edf8b1de9ecd158c4c1be63cc25aab2b1137868c2cc9e5c5bda02cb50e7a5ac5cbd6c3500c755bfad4f65bd913f3e8faf204a3851410354c9beaf9ac2b69ac726a1b61a9bf625e9bba4d3ece8511f6f2aeadf08fca28d772bc1511a4f3b659b0a8f3c6c8376531540a9866870faa1b3306ad1a8d26022a08bc2a90a4dae1a3b67491357c619df90d0b25d7329fba316d7e845f1c324f99a3f4dd60a0f58ee0f2f0d28efc4642ec3374bff548d20d150c31bebf560805bb61b8638fb8940def864a2e38402257a0fb446cee1e38e000bae954fbf1f4f26db7631bf01089f0d81d4bdab306e142bd1e1f356de670679e7d0f3713216064b14bb0f85a56e9b90dfbf0b1c81aa4968a855fd9d60cdf4ad35090e2dbdf8de9224d9fe53902bc02abb46bb568a0ad2db5a73673746ad968780621277519e39053252c9e8fb46d44fdcbbc973875ef2e3c991eb5ee02671cd1580d2ec9e8c8035638d2f5409b0343173a071b2a72a237f8bd4ccb5d080fe6510ba2b355b9d39b3ca12ae06f2766d634457455d72d519bbaccb2efd04a142c7ede443d0db7b44c2d5cd0a3a468932a9a5370853bc475c622bb5c8c52eba04325d20a396ed36e5d4a59e1c00861f3d0b0e08a9f778c70c7e8ceb448ca4a52f6e0bef75b34a5471a3bd668d5d693f370048c93657adb1e5bd768b5b38f6efe11f315b3e6e62358c28894ad8ff475f98584ae32ca9c56b39f4a9f3aece99d8e3ce5d2443441e183e479964a18d53aa867d07ab6f6d9d019160421f283678a0e7774820005020b98fc058076fbe1c65d188c4d5bdea7cf0a5d67fc39820c80726e72837bbccbe1c396a79ee29c0c23ef9871795f25afefc81ba91aedc3d6799a093a0c0d533e094d5f1fa60c6ef72a4122ed34f3ee5ba6992b419ca1de2a9585bbbecb2a705386096e929e7bff99ba7a5e33805288c8ac315f1679e7f055d1c63d3229a206736ec1f7585653c0bcdcb2974d9bcf9fb805a89aa2ff4f57e98194ddf8bed97e4c985313b6487ff4a4131bf0a3e86837eaf9caac911548f3a60a3e1bf04d6720b1e4d60685b6db4ccca66123d23e17f2f004354bff43c4d61ceff52748c197296ae3c8c6380baba17d00531bea8f4c1becf6eb6e9fd50c86bdbade0f4da4015f486f970a812c778fe413841f0171743044d6e77789f1bafd6abd4234aff922148f3dba40f3c194053713b9b9a3d7047bb849cb5a806740d9424288bea002261fddc12a6123fbfc3c8dfa26753e92e2f6fd14e4f1895ec36d90f572198427f65e92a1ccf92bed4f56cfaddd747cb2a0a6237325eefd74da45cb52df13c7e78e2c60bdc332d118fe51e3f17cb85edb9d5070a8addaea082767ad40a9778e46a61803c733d1f27e36a4d1810d4cc77757509622ba4464ebc3a2f8bc9c9e49a650450f0ea57619c179e94eae7dba9c66cd079f160398a0ed40f685bf1a405752f9b2820525dbf697e5c198905f09106dfcbca5a5bc62a72b2dc8b85e991871a8e4d7091fb097e0ef13c63f59a939c02b94c58ed9ef9cba75db728d88c81619c86d95710c5b51733a84b9a8cf068869464c35d27bfb1daaf140d65afdee9b7ccdde62d5d4e2d83ce670dc49ade7b85d1d8167893d0c68faa29d159ef95d4381bdc6a4234ead47a472e7f9740db9e1d8c5a4c66a84907a056d625b6f8e192a89b10f6d4b655e74ca6b01e6fbb2b187ed75b0da052713862e7cb3457df4202bb8df95fe309b8eb87a711767afb1a3003ace4cb01cf3de67cf13e24e6d166e763a8962ee7f47d5ae9a82b951362ff226ec3bfe12b188ab659d8fbdc38e0ac6d0a8c68c5ea7a273cde1b53d5063c5c9bb6b80e803261ba27bd88330cbe619a580f2554171173f046ad43e2e5be710517889ef08cc9ba4018b68edf3e843ce09d0cb226a2f84ef49b60e0cf97b70dcb84a353adc79bf8dd7682bb18ace2282b0d78ab1854bc7294e3889c8eac041dc31ddf581e9697256428c469fe3d2c68d6ab627bc9e8e730632c518837a25d4e89aebe1cddb015b57a88ac7c3c6a2f62f2aed77ad8e19edfed15551941e87b560f05b24b3f261230ef1c3566b8cf121271611632e111756ce0346ad9ff9ce3c8caa1796641f5e019420273243dc1ca62721a62c7f182a53eecf09acbf08afc58907814f0ef90675f634b6c4e565a157bf4acacab2c01e6cf62f0d47eb3ab93ad79f2d1661b1aff34065e6d7e39746b3d94d92670c7c78e04f16b63891675667b83fe689d18b348d640cd5dc302c0b7a149eb562f29ef317218d5958763685bf2d86f756853538a5e699bb3f0e58c1934892cacb9854e25211ac4dc4fb6eeb2f59d99d2dae281f2592f0ab8f1f4e59708751da251342bdd5864e7a9b563e12c74e7ea762fa2db1bb5cac5c2b02b680f27f7372e7bb7914403f267c0e5a8a8e7f59b4f28fd0254b570c158917245d976bf85419d8778a3f03c02f99f853185882ad19d3aeb2382185ae6ce0349ff3ab4b7b419c6647b0edf74588365339b4c22c54bae1522c82318225c44aff5341b13a09df32eeed978da9069fe9795cda0763c78ff688c1c456a550ff450bc29df105407859dfb13655d8e6063eabcfb209a9af22f4dabeba0e151563ee2a20605573c3e5bce979c420928688be7c5ca0c66d6c4760299fd0699a7b96be126bd16c8b57d2b3da3a31e44ccb85626c1a5845926564305db1575137fa505389c17c736d648c96f1f529b100123d7535cfd9e6636d167083b1f2f6462ff227116ceae90240515329fdfd232762aee1d9bbd50fbae995cc4c27f34cfe21c924a603564bd3443ae0c2a6a78599705cda7d8c1224adfaf1cb0f1b7cbf6b2f8e1d3e69e200947a8cbac5704613c041b9eec1a947a5a45a855651275c63bf96d0bc26c964cd283e5cc2e81f7b13db18d58fe5c31da90bcd5e03ccbd9b7cf4af67897e031a73f7661289907c57455bc2e77237d6959328445b2c666bfaa5073914220324c8ae9043548f2cb28167d6d22d919f6ef05c0b71704fbf0e6ef338290b043319013eba466edb620c14c27ec65c853d0f07e55d56e12295e7e0b2c7d0cd342a428580645511780193dcced94a2dadfaa90e789775f42a5220f13a7757b966219da9ebddbafa76281fb4e4f10fad3b2c59bc1279e7892cba7c78f0492b683d6ad565ce4cbcc8678cd7cc8db72b2111bfc5881042c1eecf57ecace2a45e83dd10b60deec32830a8edba51a31bd72abaa26e47a59d7db74612a52544f05e3989d93f0c25a3a3802d86f025afaad0c8f9383b02bbd671d5b308f7416cfd3caaabc7875241e5f13643022e2e80eada5895a48d2d4fb5dc190f197837463b6ea5d8cda125dce4e9a1c20dbdaeafd6d5c14220b49ecb149848c9714d41e9324226e6daff80949fc51cd0eda6290a75d757200fd1832fe20a3fcac026cc04bc75f91310e6959d417a1370cf88e132333439d5a71c9165ff1a6f1193b2335eacb42b5ba5540def54d6d0960fa1b37b655040b594c57ec6984b273c58228a9bde8614b8f6bcc874e7dbde109fbdc41684051fe05c4de5dc0bafee37fb2be501e36e4d8ea55864432cc554a01c4c202531edc612f41dfbd0c220ca5b603c7ed47e9be4145b1490161e31a2e6c82eace746e62bb8862a1b85d35af5286587c3ea6bb72444dad67abee707a9d583455181c0b246fd0c33d3522458ca4abceaae209ea5464d294837e7678150add9a37f3405a76baeceb0eef3f3fe7038980e96652c5e53d77b15dd8197f304bab443ca94d66f43d69f4c7ec1c7bdc57093893a67d20d89e587a9988e873457cef966d9270216e65f1eae2ad0d3bff25650d884ec197a69e5c76d39d77f7e5e1c623bd664645ed7df0b69e8dc3aa7e6260ed481ed07cce4405de34313561fa30bd3a78a7bed156fa773c0405cf20d4b0fd1cb60d58a2eb136dfac1e388def9e81a9d1f1f769be49d1627f206364c61c5a09d9d35d7ae05f8eab1d0cd633cc4d92fe1fb58ec4845c16e1578e80c0702471577e49dc9e106dc59c02b534f59b0c449a2ddca0f5590d4c34c5f877503094256f017c9a4a0ba613d136e07d7eeb3a4cc23121a934ee84249820bd64987ec55351d3602cc7afd1ba272557e531b3371b99df3528dec1f8d1d4eb6d49ddf94027b9390eae72f740ff649a4438448463778df7d5a0a5f764336a2efe509afef92610de6dbf22cf51381a3243171cfa9ca8caf6ac9f4e0ea6238cd7ef7bbd5fb06d3426aafe2bc94c8776f5ee74725b2f7f1e91b533ad9ebc626cfc5d2a6eee2c792602be3e838f4fe43e1851940a1e21d2c4fec3fd672b0c7d3e266bec169315a9960c7c433517484693894f71328b5738127fa6e51a6b0145f7316f5677581146028bfc4a6e3399037e6cd038cb993bd1e63b7c5c9020ddb57dd78da6b80b9593eb0252b499e66c0d3526ae41d19f9430ea7de2c8dcff825ab026e4bdc2da80340d14415f22a009bc7b325d615855a98b403a22939ddefe7d82f9b48814c09f4a121ed92575cfe32e04df38cd041fcaf0b1e572fc18992c182cc8ebe05969d90970ca0ee9b651fd65a4d002490f04639bfce86058cd1ed219457242c4c233e5a4b84cf3e62f45cf2f2e308b43ea17839640a7e93570a4ae3760ac79ee0a61290944fe47ad43c67f01be52d639c85b3b5b07a9aa98b2e7cb3dddb82d2a0edf88c38b4119bba29cf812970bf79629d295c2764a3d3c8b20743e939102f6584458ddd1da577b5667dfdbb350b596f565d64040eb16e6b00a1c76af2e6ccc18273c3075b5bad660017506a24b8fe728cfb6531c16c92f6726127e93e919bc4a018b29cab8b098ec0390106d37e73e14d647c00a723191ac447819457e1882e7930e147aa05c6a6648d073baf7e0a379cf4a079cc2aa7111ea0b81b6737a50e2a02c3e862fed198020f295b1f0a2fd42a19d69599f3ea4263b01d0899cf13509bc2f0490c78c69cc8182d009bab3a84d12287890ce43424ec7fbbfd0daa76f08fb3e0bfee27688ef5ffcc366701539cc87446ae2a0d910664626992cfb8cef95990e59ab088db3cf5d8303820ab67a3f463c8a38c054e1791c1d07e9f2e14ee8d1138ba4b2f9763fb9faeac3679a777c60048341a9c3f370b855d4125e9597db28248e3d38313d18e5ead92def8d04f7b286c4f05064a0137a1821f5e5da38e69297b9fce7ee55b595ea05272509dd1dc96fb28e35547e2179808d333aa357fe87dabe64cf1c3fd4dd75bf30b9bc7d4135d3432df069f5b60e152b287e3be28f552aa867b58e47574cbc5facfee6dd2f585356bfffdf2abfbb13cc957a56b0e47225b9df42c4bc44f7da0cee1b64d4bea4d7142dc18851a86eba8ca3a632820088d1d0f277612181d33e66554a538228cfbb163174114fe8b5b143edee891d6cfc697b0dc486b384db8cbd20d1b48d43d254a5174adfa368a793f060c922a59bf309954546648d174ad56f045f9712d2a064ab37b05f92b71f3e11cee5d6709e8c79b501b103db8261574533fcde6bc4c26b257ec4f0a3a237b9ef488e17ad5af95fcd176452d1b7e20106a2119508d9e74de932ad79c4c608f1ac76e95b9ffbf9637cc0267b8ced6d139103528fde29e1df10e5adf50882053986d1670d420bcaa3365fb662e0d433508db556ca2a5913eba6cdef737e856c2a24be7007aed60ed10fb77b7e9b339a1c7da723b3ffc12fa12a012cac3b0be1e4a317b17247b5f1102e006c745fda650ab1ace51adbf3bed3c15281ff975e2e7cc58b7998ae0dfde1e0c1376343d0dd0aadd07d8919c296a7cbd4c8265ab3e0a4f5c1f6da51d946f9bb2b00bcbd134335691ff4e797e9d07779493d88e1e91b033479207e36e76f1d4264f551ee2a9a95c33f4c588e5f3d366e2f187d8eb77ebb3f9acd757d7384aadd90392aac2b230804502cfaafaf2328420a41c173d903996cdd87366a33efdf9d565cb0ac0078b2f40cdbf773b86ea3f44eff5b86e822b536dcd72006123a4e11b26d21120d8b250b8dec716b091b1eb150857bc64759f31d7add4b058841193c58417c33e9238f4741804f9f148096b15ce8cec22dd2c4636a39e86eb1325dfa7ac87e58d34950a309b4c513a7e14f00cb5c8b6bbbf3487b3bf9f29ce445a9cdcd1eb402724b2f092ea52ffcc3b24a482a24d19f89d44afc6e166082bcebafd24d54bb5022a08a2469e1633edd7832e6c74e5d9976beebb6928620c9e865991d093313f4f24d7e8d7e63bce3e4bc8ef79be24f2b7278dd84e80801d304cf3d775e53e8f670fb0ad4dada5fca06536f31ab452a7d1dbfa032c2bed87b66d0a7fcce064a4a28b60a7e626605385b44fd54286ce871212268ab65415f69ad0f60062f8f7e46702d5f54895d9b2e7c219c30f1a32e061fcbb5875af955f73f2bb31db7b282aa12dd0fba2c8e469aacc6914c230d499c8b7ba92572b19dfbc2ebaf4ebec1842ec54ac05d95cca796beb8cf14f5fbdd8e4baaf2d59833b5a329e4fc3f32c730d5fe55124b1a7e4fb7f64f63f74cf928552e4b5eb1f2976a99198925c0ccf5ba8ecaec313d216e7adfb1fcca3693b9e74b326551a0528c5097e1f34247b5eda7bbacbeb21fe6491ce67c3c7764cd798b1fa813454bda9e017b1c8981d95b3e65782f89514d93a0ae33ed10e6c8897a3cdb9d01cd0e0e12f3b398ec72409a4adcb18c7f6091823079782cd68ac017edd272464805f3e831e06f02ad1e1da0acb7cd6807a9b80c29fa3b2ae5b1b75b43425041bc26cffd0c9bd4372925f3ebca751480063084a888fc9c0bb5243dfda4b4a9d4f8dae59f4eeb768788e4db8a601082ffd3e09d9336d5f339a825676c3e3367b161ceb3a6cdd80ce650fa711452e886b1aab4f4a92f07141ea3c28bbffce0bbc4b4587d4cbe42b3dc7d92d0d3298dc751aa71ff7aaf353a75ae3f23363cd925247660562bfd43348a7fd2fe33b2c46196a0b7f30ae843f32c3141e7cd523963162eaa726a8ba34b6f34d8980d8a69df2a103e0462d9d57faffd6c1bb3967b877b9e319ad357fa05c25c27c823025f246086de0f60d668930a5ffc304a026dd3c06a1ca2ff6328dc9046c28664087cab513358de893da3fadb740618b5e0086ae17aa8ae59c2a31592e21287e600fd14a4c57b285991398298944729029d979811d3784484e2d09a883636be1cebad5ae042187b62fb858e47ee7b66eb0303c3ad215f3f1877e6298bd439d10dfe2055655c68527efe9fb5188a3345959a36d49e3fa5f05d1bf880cba1827de4be26ff650daa1f0a4727383b2601168996303c550cb8ba0fed5d739905adf7ca5655d34a953cd6a6f47110fe9330b831bfdb79213a898f1e1e719786407e10bea78527c94799458c64706afc3931426326bbcf2490db4fc85960da9431b9028eac16664559c32e55ceb99c020126d65943eb4eaacf0fd642a1fdc2885a749a53e27eec2dd4927ca58cef7be2fddbe7e3c6a9b7f8a1a047e1720b36f92cee110c5cd35fe4e5fd88902feccb964953059a00c783d7f8e480955bdaf448170d2003e14ed223c2b9938744e1c14a619bd67c306df9bb00620cb300882c2c48de11e512fe4e249ba69aa527cd718faae2989b9306144e63ff75543e2a8ebaa92b19754a32ef4d4174c8c25648aec0336af2ea17f85096dce5affd0a6da6079cfa04c1acadda7f91f1a15f4d2fae5b3516a69c4bc0664066ba697de2de4ef233143119f5ff216c68d9a37b6ac5d24f334851c147657f0de1926c1b026b7028d54578e46383b4d83feb0fd1e366e682aedd5eef12b35ff8e192f82d59db1e82adaef5f0e3138d5b408e5948048df66f20501013b5cf09755484236c6e20e98e9deadc7c6280c463c002c274243b85fbf8434200f8f6621e754a8b1dca5a366bbab3fed0e22cb235ee6d8756908fc49a72cae7800e9cbbde623963e12a1b1c01e2129d65ff53d6e363da80b47323d15cfe7f45bb9f3c1619c59053584cc4d68d586c35540a907d590b7e076176609687af7f06f811c6393436ec08767fbdfe08145165869dca0ad295de1d4b170bb30b0184e92f40b3b0225aefee2ff8d3a9a94827bb185d48bb9dbeb2169a377b9a9ea40666eb61009a41756c7190cff6db52152119e97c919f9a327bce47b0c8ed157207cadaecd89375155c9ede0ec95dc336e038cfcc3fa6a14ec85371cff3a5e28086437c5b4f343faf76f77980f2f35d9592b9549eb94cc402855d1a88bf04a67484e9a7b7425179ffc5d5f8eb6474dd76d5f64c7cdad8e002d65bf34b9a7f597a515e47060a21ec853eba88bb8152ba22e682ece98da7b90b085a80dceab5920668cbebed0acaee891d7b16c5a5075fc007a63f954a5b8ecad07ef54ea9ae6d67305591f6042fa1fc5d092300da6c97492653d2a4b1fc3611f9e7222451ebf33a836d153869433466957717d5a88abd01f94783102efd01116d4f25a5a64d8ad5946f4e798e9c4cf7ce615aeb0bda6f7c9deb632f3be4283fe8e7a45a920e15824b8f354144b71dc580fc6c1d5eb5768417eb99149a177f07dd61216fb1f85e100bf2e8c5c4d73055d19ce09e970085d2213617b738ebeebfb386b0765e2a5d0de3cf7cf147859cd9b5e28e388f2b9d1de6987fdce0fcd20ecc563331290fe28a4e1de9c327829c4c69bd18745a8ac8f9a0a8e4ad65b07495a63b20f4b2f4c8dd49cc43d9474072781ca60637837eef9a2c9596701b607aefd8c679a3c714fcd9a85f73108c87662a37376f67e623bebe30995f02855d216a4493315ef3ebe9160d9ee0c05cad991f7f42def8d662a144d5222a1f3cdcffc0ec111b3ea555de6726fbc4d0893bc87ddff378628049f1fba03647d13ee4f98815843c619b9f02faed2d3fe3da8bcd4e839ed749e3c5834597ce1e2892ed0d443d8d983aeb8fc69ad80184e69791cfeb634b98949a17ceabbf7cb2e85f7d3d771d5c9a23f327c4ebf8ad8495830d2f2f43b0a500476c5a37ceb9d475a23f15c69e07d03129265dd70a83ce8a5cd40e929c2494830897e41c62de0ff8c8dc9afdff4844b28d4acc376abf59dbb0d08a2f01e7b622c702dc514bc277a1129619cfe00cdec4bc9a60383f43b79587efd3eb9bba9637641068430ff7e7c62ce572f1679962ddc524d200c07d427e6db62657ddf872200751be788d462723d1712e06017f6fec18ecd978ad377d8db8661478d2cf60847baa34dc43e1910482d42c02c1eabf8f3a3fa7fa8566dc61756c246c44a2bbdc6378ffd6dc8e35242a057c7b2751d8f537f6596426be24bf89cec38c7133fd1ee024e53321bd787aa1d253b608e52328240618da5d45af03710cd1613211f87768ab518bc4f1cd01254cce9c151b2ab653c1451c72b9530142fff1bd6f409d8f4b4cb2c589b7bd65a73aac8980d9dc807856e37edb7c31e27fc7eb812d5c39d8f95ef26626ba580b03390c180fbdfb2a3ab2d6fb563c51f49e9a10f25f46289e74981e019e02775918fbe9a8cef65586cac7b9020bfed88ff27d60174f73570053b1bfda473050b015427b14d561f773c2f5b4ff4e7eca0e4e7177e811e6eb60bd72b1c0459d1ef6615e5038d7fe06847ab24a7f41d1593acb4b54d8c2fddb6ef23d62b0246cea17a1cb2dabaeda2625b1a64b9da3b88496349c41b33935e39700913b23ca60b565d961442cc8c7a8991afe7734965774eed9fd267fa62ecec64f32792d9d0fb19d8e666d852466da5a73ce68275785b983d16ff3849ade8adfa672743d923858e886fb344f653a0247d40c7b0b87a7469c48d6056c340eb8d7e2a04b90930801424c6b9b2547486595f505a89e1492d015e082957168fb103d11bab79cc4852638193a855fbf35294ac690bd295f6fbc28aaf194e13e4b76c6d05772a6b2f8513ce2c03d884fad0df46228e19b940398ffb09c3d5300b4ece8e71bb25485d0d44bdbfee6655bec314759e46e8b826b98692b31bfe2c817e4f5d6cc87e4964770adc9c60178e5590b31e9880c80ac9125a972b04f4e24b1eaad78a691f70823dea467f61a7b308f8191f2b8b7c006e92d950ca5b8238f20ef75c28f81180ce3ae09e72db1700740e7a252ca957ad52c4a74eb8207d3eb9d053febbe48b8640585a2106857144a1c2dc3d12af55a97bd93db5dea31a28bb94a64a54947f9443c762eb8efe68499c9ead28cdeadc913828f00c82fc4bd96aa32ff31975daa9c61b4b6349496292d9b75a6f0012280eadd9853ee4d0130cc57b0d24a0b8115fb5241037e91b93142810ba2daeb6e2ce3647f367111082dbf7083854d395b47999026d112aaf90db3109aaecf7ce10e72ca13d5f6da166e9a938fe439230abb58abf47d72f39ea60436f0b8f939d76832abdf58f07d90776f29101b99c808d44ccc7fb60ce155cb3d2a38e5d4f215a7ff552cbcb64d964f1c9e32242bef9175437cd507daf55dee7e3d48f4c0c5799f2a692005c7783d11eb84a533e79a1dae908b2e8b8924b0c9819f190b3f8ce61bd3236b2d48025b2e707a2a64401a821603b79329d390c3a75aa4de23ecbcf7d90d32d6a42c160e02843ed80134c3c542e16791b0a60ac2d3df46e9079d3eb37b7d220513a636c9437945022c8b9305d90953d478bcb956c28556066200109faaccb090c4084ae2e8126bc01c9d07a7f6cc2407d0c4a56f11b2d69780ad0c6295cefa259169800019908cee9d52804c16fa34b4c5e7feae98aa5e1ce7c7365ba499fa1622bb5338b1fd951134e48e4bfabd055263bccb2f204a710dc531c7abc412c92cde71b096c9d4d2ebf98d33ff42c3a30699d14f111062a78b5090bd27f3cf3f6904d81d4cb8a19a924af0dc45253d370c5a1e7dce7a2d1457dbf59eba5e4a17545d1c86acaa4805e4aad"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0x41f547a71d1404f147606491f3b96e49f67d4658",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09b3f618864123704b78a9552a0b068f395444870c2cbd5d741a0c565554bc2785a691ff502d6ed0e14c925eaa24c075d20949d12f369848e178d50b085e87c9b251f68b61ec506435bf5b53a49d299409f54e906daed0c1a25a63563090f6660380321e786311b492bd7ff684a2650bec34d5bdf071c49f5a050415b2c3579b2994fbaa9a97b7f24a30e7e8bba68145196e0424471de31775aeca732dad506b16ad4f61a325136a6664f439e60687e764a009db3218f706785b98b154a625c168fa2ac541b8dce39682172b95e19424b98ba985622b2a23d8db2d46a7230bcb667372a924aa4d1a9e9cc1a8dc1ae11fe88081d74d857bf63e9814a08c9ce059a4b1ccab23a2fba765086b15bcba135d0937a064b90663ec69ab521746600610bec0a6b3c705277f90d588a00e908dd075059de6c52fe05fd8fa8ba1b3c2cf151cc810225db79aae0328b8ea1e92fc67b7bde405a1442128023128a5f7089722b954f15597ebba3aa3b55ae947be1e659be52af04c3205492387b51e72746a904ff13ae41964281ebd81783528269ccd6d2a7845d790fe4cda8ee58d93de3a3ca28bc4e6e18e812c313452a4468049a86ae39d5fe156fa2a43d29161bc911d515f4cb6b625f4679e37d5b55064a16c3e48a7f3ae10a09d9ab7f0ea4dfa2fba9da412af1978720fc47185c7ae16474833c8d278dca65b822c5526bd4da67c0700166cba95e3d23691e6e1e86ea4e560cddd59af18a689c4dc2b6dc0e114f2a84754498a8e299ac17a12fd199d1fd8d5c31b0a40ef4b2fc9627d16ec11241fddb4fee6c652d0119f7d60e852decd3489cdfb75c10a18f562154e542614427ee7cb0e96b99d74eb9585223760bac37de51697d86403ac877f823451d8c60e84188a8fa6804c3a8298f223169c4c61fe443434a76d6a51ccc1d06df3b962fdba9e27d7723a8390f4672d66dc2f756263ab928d9d14f6d550acb286647ed6dfb091c462cf4756194ebac9c94bdf7ae4ac7b5093ab9cb94455dad8ab15b134d31947df478a1aca5e28e98020dfdb6d4ab750911bb2690104b9606e78c8659c2f511bfa3254d32e65aab180ebb74f9848700a8cba3a1a546b77678a17716f232e57b204157761161670bf654f182a14bbbb1c16b14b652127241167e898e097b6270b062f0607a50bb040868768a24312a8da316dbc547237ace3a160b7835c805061f8f2723386929835251945908058905f625cd9a91eea83c0f693523128c68613038e",
|
|
+ "slh-dsa-sha2-128s" : "0x9fc24e59b10d63d59b6c448f79d029745c4f27a31903ad2a6f6fdd09b3abebb1"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39916580739423a110970dbfa8b6f06ebfe827b6503b1629f4008d64024e63c71af7a932f3f29cbf08eae4cca92f36f670de2f3a0a461999f431bd5da16b868d2230d6403158010384f0f98d2b95936e0a132f5b86f5d11e32ecf3cf206ab9d26c1cb7fc93ea3468109a59163b15391795b76ce450813b28d28510767270c1c474632bd6eab70174350d329d0039ef8fa6739b2f665fff021cf669156e3797da72e5913d08c94a48a16d12b5ad7e521b730bef92d7cc277a92b3e4c9f9cfff7cb3896f93dbd495637c2a47835f2afde4222c8dd36d4d6d9cb419b5b5563bcc1a61b640e70bf2c4bed6599c5ec50643fa302c227ae56adc3d4b044926f4bc4b26d58d0d0778e2b8ec5e18b5cb9ecb6d7a26808962082bea23a932afefd0d483a9952f98ea11b629b0ad74c367e09cc016b817b624547ed8fdf360a8a06acf7b5f0d3c92448d9f7e9453a4e29222611490a7188dcd0a8568b67d333228454cd9cb99fdc9d6d945a64d8d96348120295b8f2ea9e95f92d9dddfa2a91b6ea2c44de7b605db8e3e1019dbe5cb464e0b211713cdcc32ef3631caccb48b6b0c968492a5f1288e99ada3a4d8287b5c9f46236b4b3fcfa55135f1ee4b13e3d6765866a316d8cb3ce80d67a518ee974976172f91eff1cf973631ade2a2b81134c39d0f3c72bf4fe546a7bc7d3f1142aaae3f5b4e8f3932d9b516ff1cfd827e7395d576d96cff52f00e76abe5ba3f1f0887fb064ee11096e52d441d1b4dc7a69462acb7296c489f498c456b2336f2f112391bd7e545629697bd096ab373a34147643199222b8f1b05a95bba5877aeed29c43bddecbc814a6f2bb38d1dde30c352e06f19bf52717236488848599eaa1ef17873681e91064430aa2f4a23445fac0a8c8231c8cd7c27f928ca0ebf7ab08feb53",
|
|
+ "slh-dsa-sha2-128s" : "0xe922917f6a5d9d49338e445586f4b3bfcdd92b89a013edba38e598aad56f8d10875fa62dddbce6c66865eb7d14067931d640a3b7c5dc448bf7cb6309943c2f0930c78c03fad2cdfa1c21689c6f621bfb1cba1968dd28e66ceb6cd5cd4f10b8797a53a8ad54e93febced4dc1c48fc4bf768b85a811866f86f004fdc340628ccf44b295fb5310898614b6a0341a2456b94930d086ee75f67bb935e62c739fb87407975f78f372ec11c0bf8bce5144abbb2678711850174134e6e5acc3b87f14022d158a57dcc7916a8e75341488af6b1d9c0af90bf2ea86440fd1b8001d7fdb8ecb8cf392498e41f8be5c7aaa81841aba7422c45fcc0caadd52d36d1d56cd02d027b6ed9d122ab3d53597507079bd9fb476105b12e3406c1873a8bf6a5b9479b5cab9c370b79425b1bc7616e2f1f66a398c2e38f7a9ff1077918fb3f7e65f025d4feb8b13397460a753b1999b3d351c5b77ece3751686c02db0ea4ff23727527cdaf038ff060a09689a13fb7dc902cb82844b11f8092625272d8888090e60cb1040b6cc5b0ceb6854a7fa769a77523e7a718a1a9cf56b94be12fe8fc4d319b335757c6b4807e17e9ffdbb486d9910404e675648d069c55e96894c7b2ab17d91aff88f44ad609142ea3747117596c98831338c616cea7439b1754390604188018818a5fd2cac7522b2df5e42c14e77b7383744234da5fe1a02a60e18a178751eb9c0212cd847317d64dabe4407c4a4d2ccb6965eb33699c37c733d42e66f92b01cf8b0ba2c8d737711439de358756ab4ba374e7359f8ec5838f531c984e2903026acbce89ff2935855ba5e5f3d85c82bfc3975ba3d4a9721ffaab1182035bb7526f062466895c5900f854fb52f5913591828cef55cd07d70c5805327cccb9822860f32a8e8f78806e39d36ea7be59186da6ab5f1739b6716323b9379446ce6e50345cfc9b769162ba96929e2cf0693b77a558e5386945fe5c6410a2594805695a4cb602fb25993a0359753f4ecea67d0a1045a80054664a5f589dd823d11b1e440813b3bf141f119c38f9595c1eec85ce74fd0cd69ab783ff7adf32746d3c4db1153df20ca1ff94acfcf3c8ece27b9a7819f7751028435730771a0d7eee4d5a05627e9577de7a1c0d16400a81c6d93fe48990d8d4eb942233b6e81f2606c228423d52fa012ba6de7c24ef446f32ba1e1bee5ab78e79f40ddc3f8279277735564901682f03ffbae6176aa8c2dc6871cdea56cb875f25c88d955ad2e5f560fa25acb5d2130327aff86a324aaa721874c4276667404738fffa534f26e4e0dd67a9d0e5d447c2868af3f5b93dad621f528509fa6c3d2b9a391275396d3db6487ef219bf42088433b79d34ce793f024380319f1a0017c0cf821d998871fd35d2da47b774f6c6664e54090d74d087fa43ca622417314ac0a7f2d23da0e9be5242191b9096ab0e200bcee276a787ecb770a60f975c2935f24600869822ce96462d97f34c23eaa50b443a504670923b260e1698eb12a76a094b9a8b9bc2fb07c38b03b495a70e4976d05477ee88b58e2d66729a91f0fc003e56236c5285869a6eba073b36efdac3999ca0b91408282f83b179629bebabd5355381c4435bb173598ce3496dd8616eba46505a64d29a166b51b1033cafccc0c6cce63afe4f2dff7a2cc62a909853b14b40c418d3a180a922b02243637700c87bd0268e3ba09730a2e2e20065a7310d8cb86ae6b2174454ee4c01fc86c0441cbc51f1801a021da1f1fa4ba6cc0e8e35a11a0e55a4aec60d5c98330ea1822991083deb2a80efaf382d29cd0b04fc2b3289e024814281aad94ffde1a837da103a0022b23f223e63b852ce8bb89d50271b29b5dd805edf1f4339bed98ad4e4fa42cd726f3f70c7c434035cd9180a02ac954a1173c2694f0cd59942291c34a8071803a69552d71b8191c4299add494d05e838803e5e9de4e5a2d7b0f8b4a221ce677b5b365e57284f4b74c973c72a565422b2233a5b3770cf28645a18ce1bf7cd0e726566c382d801e655829a7c5e2aa149217075014492b80533bad2c8013c382aae26cf4dc39a6eace929903894f85c8e97e4be1df2bbd53fc780c46ed384e01fb40c515e88bcbeb2005df6c152f0d169a90ce3a43c2c3469a85a456991996f6e9ffab555233598f767b38307fab61336a8d57c1f6753749d46e1b3032532a5ef11082cb30e12bb6b292d0f37806e6208d4bbb7c7cba1b3b410ec1d29dd35af7d38ba79059999992088f06b587bd9570ad0a1e2352a6133a50a3a45da27fcf63cb7c6fa98e6d3d3d7987447fc596edd9a157d72d0bb60441935481c54f9c163b985c708ea1dc510f35f9aa8768e73843ba5e8621912f43383365f534f3ceef986e90664123079f7355e5a5193b0ca1bce0443e01adc00f18f8f07a9038cfbc672494715221c0b8c5dadf7a66875ad67300e5fd662ae7b4281f2df29aa0f5b7f9f70fd3180d7875aaf784eb3da36f9fd8abfcbf2f156392cd196ab952669a531bf941b48b7d2850cb8a66addeeb1447d89daac2079094bd4163d9e0d8ed52e9a93e31a7d4f5d2afc4b7d2c0b988d41c3e247237363dc05dd16d49d159005b42ab9def7290a51beb7811e9f4fb9961a7af09fd4f291f797f8eeb05bf76884ca340af07f62f587dfcbadb344c1b350960686aeecf772f59d3f5c9f6c01240667d1fa5c3d84dae1f0dc9562543e4636d81a3f0407bc29127bf4b4527d0f6d7815a941fb53e6527d5940739bd369786e710f6b0f69b05b2e0c49bfa51411319b9f7b172fc11d901e41ec54887a0fe5748b1d2403d23ed5494b96639126c1d3fde11d85c8c717fe8b01319a9668b109e2d34a6ef5911aeb31c88b71c32a6723b0ad2a28b2d8c75087a546550b0971dde64d3cd69434914d5544a8828c6e7775cc802fd71e467e0327d692cba302f681fdf0c7425ee580c413d1a3904974e55e7ddb19de793541a7a4310e50990744b4655e72b4eb5a3a8c5fcc09a545198c6475dd26a43338753855ae4dbd845d3122b16063b9d4f1170b0fb1eddbe15bf6a0f935565ea46bbbd6c00491a9ea8288822dbfe8788aec3eb3e5e42140fe3cdf16328587b736242c2aa85828dc84352bea3c6d985ac48437bd72f12adc7fc08d03371992547b91a3061c9f9bc6c32a8555df262c14dba813ae8e2f9c732bf7360b1e94498f5a1248ca4a0c020e381d8c25f4924f91bf0c649207b1314bc0088d2f15f662a2594962596ea66c036677c451e77f051cf9c5f6b83ada58109f68b415af541dff5d6cba732a938ef4d425243a3571f475af0a456a7ea5afc7c78fa195780b270ee1f4d69fca7c93087e103595af8757afa5dd23ed17bd723c1edf8701a1b4bcb2102ab2aaef2df7cf485370d310651f6e897cd2d687375d29c7f101aed941cbbbc12ac7ad60c3147e41fffafb766e548f0e96bc911f38a6d1864277c170fae28e4b06fee1d1925923432bbe28e41f8cc19271f68196bf4724278f8492a6d5c0826e03d8dc1232c0efe5c7598b71be7d6c468ccb1077d7c8bd4630bfa4a108d58d5498e40584f6ab690e27ec8152c1c39bb70ccf7c5f2c33e48af63d536d9e7ba90db931783a9cccc05c22dbfd90f84f75d139aa22b1246a15534f1521ecb9031ff0686c39b728fcf6e0323cda56b641561a88c6f78cb1d880d102d26b20213d03af41c91ba6924a0ae17a92fdb375492fa0b514ce2fe88fb95d72e5b1b11bff99d1b0ea0832a0d3472b5880b3ddef0bc0891833adec1f7797f86fc549b22df2a0a59390a900e588cdd2405e5afea987db98554585c85fa2428cababff59c17713cfb100084192cee9f4ee3855163ce76fc59ebd4b23766b0ca7c2d59754ca42ebe3c997cc4cdcfc2ef455d3afd488474b4da2a6ba278c196616f995c4398710c291efccbe36bb724bff2d097095f440f79917229a6fce31dbd89e58696c4571dce1e535adf5e1b0942fb5d59a13f7fb4eb17647e83e587acc50d920db2951bb48e1495256e10a62a8d43d3cb7719c54c24f546ce4937e2ba7b1911f5684068c365398e41f7153cb1e2b9ac014bb7395a36efff14ee94373dd128d725dd6ae6af408a5da12ee540fd8d2264b24cc7fffdb2859ce5227ec3c3d5e0bae49b5f495a39e5d6b3baf7c967b21a55e3528fb0bda0e9f2a3cdc37904005a76b07d044ce439a345f5ab69a3db8c711d478288df2d4776d53ccfbf49a06d0d0332814d34053c98ee3464bbf46309b763114ddf1073100c34466cbf3414b4bc7b8ee73c44d76c46435c0354a71fba7d8ba8b0248f867cee79a4beacb5dee9c45577e5b423582fd261b6164de192e98aaabb47179a6fff8827221a70c77df46d01357bf27392d4dfe3b8e24abe9854d3109b533edab16f495eaae07562dfb4428cefbffd748f144329f7653931a9f65a3b024bf19d2fe04764d53730df662469a19c4bd966dc925b1ac52d9094ff7dd7268697468135000a8766d8292f9079f9bb5601193df637f8192812a9a97f604015ec15c89fee9f700509cd745da588a86c7c756bc84745c593bcb7c7d9d34bea98d505a57b31a90833e3d1e154c3b686d5d8a20375111bfc6964bdf2f815e160754b56c59fec8fa533cca9e21d4f688ed94cdab427f9e179fd308856ab7f7206d13d65cace5f8d65c8b95270559a7d33c76c81794ec38d75e2b3f9ebd1351e07da0540e3981d447558d6c21ce6b0c32bf61a3f554cae9edac7a92e2e25965037830c57f30a021953d91c8349b94181ca8c3bec9f33327caa08e437e542d4cd9742ea16801aae94e19442030e8c95bd4f23d88ae9a1f1cfe4a80b046f2e54885c54572a215f17bf8359db4edc830c48941153bdff79a6777a67a9ca0ee3c5d2e4497871f4797974c1d932fa3417b909ca5b29dfb315bf1590829f1cfad84b9e068213b8a6e9171c1c41757e262d371b7073d1b90fde5bdbafab76426f486581bf52fb2a53df2fdd0a6d5065afa6148606a3dd311b155dc0dcaf9f741a50d105053225f1c223ad0fd8af47d27db808cd32f733fcc8e2655523fd36a906c6e6a1d6eba56311424458b446bc1b77b866af76be210b9a417e87903a1ba2e431c176a82cc5a71a4ddf29350efa6dd8d1707d3884b31b9b52bc876b6599f40b077c43d815d2e02ba043505abe7ecd7dcf73818ceb77a09ea4e582616f4af11133a80429edc9a434f3cd2b41192edad842b433ee7936fa5c7680023f0727f4337c53912fdf6fc7e6d5c0dda2e0a8722d5b0565ddd8f9349815bf38e8615b5c7ae35622d7feb7907e6423c8aa7bdf57355c0353da377977e180b88ecb1faaeee2d7142f342263e636eb99c78af9cd0ef0314d9b57fe1176bf8b13c221b5a05c1f876194ac26c35b0ddd91a2130276ac402314367d99c2e300a33073c06dc18cdf5361908d58a9553268c6d0ba19ef6f6d0bfbf2b1e2f5d284c74695189d8a3236e927d9598a4be253d0492f98015851be3693b0c1b3c4a73a95ea57c20699240887d501db5d3525e787dd1a583c2a831a9b59886c873b8ea5dcec376ff37fdabfa21b74b3968008dfd9784fec35696779217b4f5507ea15852f751af31243dbf857d66cdbfb2e290b52f67312fe5d93bdba25b1b7dfb0f3488974a7ff0e437cea09d0baaba7bbd2506fcd182cf0dabe7c262a823fa1dcfe00bfaf7cb5f54283763a45134dfabe9927fecacd648ef767fdce12d570693ca6aa10c74c41761f64f31139f3aabbabefe6c7bd79a6a3334cb465f4203604c0288c49db25bd25c6c4c113e09fbd65c0f271f4a373294831c33f7b2ef392e4a4b91a3973d38473b9f3a485cdb04b7f75a833e2c0461c6f27e6d8f518d3a4366ea3bf37f43e4408f00c4c72ca8d0a9fdbf1ac7fc9fed47e8a3f3f33ebcbac25fc2e70bd39a85519181383597ccc3503e597a734c98e98a15be8bf4b37330f585ea138e5a2e4104ec1cb6f5a23df7ad83751c32432033f072e8ee3cdeaae4e7de98f9e58633bcdceab69ff60004cfdf51b54e9a33232e1df86ca9708811a69b8759e5b2daf57eaa8f1f74ae6aedfd9106c105a6cd715b66f561c0a0500a501a9f3d50a0b5540ec96d24fa5f6157f5465d413b204a224e2b752a49322a90aa340e4422e60a449cab5b6106135ad34ae309ada87ce9a99cab959f6c2502b2da99d8ef296884f4255fa88f38908e4294f799afbf3d664900c5230ebbec54328167495caa99942c13e834da5c488f2dcbbe4d2448eea2657a2f82a91a53d09b2b5445de8c8c8ede11f028e067620f2ad83be80d19f3b9a9f3b81bc8a405c233b2b17ce8ee5e0ef05847aeb36f219817d735faf6092d13569cbf069696bcbc50cb50cbef921f8fe76775f1034e73bf04431b696eae4943efd78ef6c19436c76ab389825e57b23f4529fb848233833afa418d85a92fc865e634357071bc415da56078f44bfe306d3b00574c04b2e94d6b801d5e3bc03686d1bb27dc2753112b2c22a43610a4dbe1e78c9f4f6f2b4ca3ccbddc2ce0e78fa34cac5935bf0867bf14f40648c805876e61fa841292ef2d2d53ecc00319a6df0bb6347dc865e39d9da574ad93f9cc910a9eb920986d5e6b331cb29b45ff32ddbc9e09b71eef73c8673307d6684a34ce85ff3a4208741b205d31011555b17b7c5effc210ad9309468a007d76983011b88c818eaeb3d3815a02d76f735433192f1bc99a6c7dbb57e107caf9e986248ebcb2e9c28279ea1e19a8f8027bd6f8728c9aed0b974322254e686526cd9ee0c6720de4eac01cd83e5705570c249856ebd7ec76cddd98cc096fb93db8ed86a5aa0736c36d978c09b915f7b9290cc255ea1a4b355888fb96e506cba34683c6a890c77d92fb01bba6b69f91efb3e4313111dafc3a189db063195bb650e0cf353dd975fb5c286f86b8f7d982ca5f74a78fa0fa3d693980be09298bd41c4ef38874ddb95e928494b9e345525b00e4760a1d6a4d54675e39b1d955e20a58f3ee65ffd1e249eb3558ba348a2be114f396c422c57314ce6df0ae9406dc6bd0bf5f1db49f012a03834b3314dec7839860867033643aa7dab3fe17ee025812ad2c05484abd0bdeb67043be2a57533d294aa03f24ec8afae512537343eaa16b07eabbbd2cf6755261ee473dc457ec36775102e1c8150248e4e51dcaa6abb7753920bd5247ccf6dcfed9dde98c9f37938d1c824fce116f39f0d67ab9c1fbc79e034e8bee6f79715433d485edc70e5c098ef7bcf2972171da06cd2f19cde8f824e0f2bbcd816f7eb87b7bdad659a900f36df708d3446d8e412b92142d8414f3a0508d106473e809a0831953e2064c655519a8f22fd0c517df7ac44d72a0e7b6fb697b188133fdea4d16e51c6da3109f7cec1a43fdf47957a35f4651454ae04da9e9d5a1668f46cbc58422c38fdf204f4e9c0df3b1f0ed2e14d0e008bed642353ede25a5c25684e7d593eee9d14b3a5a81429b30895ff5d1f7f4a124d2fc9bc1eda61e8e4bd73b57ef1a168cdfb1ce1d70955567a3d949bab203c379e3676932f96c04ddd0271a6afa0bd55988134de26bf5d6c725c09e04aaa03d393a82805a366e0d98e4b65bf45e05ce45f4dbdc1f8ec052102df08f5852630b706dcde9a3efebca3852e85cbd7fb6e6e00b4bb397004db1602b7f8c0dd365eb2d946d00eacf0ecedae83d26555a1bef8be88eee9de9f9811074151f0cc747f36d45ea7290d53c18fa8ce73f77f54226e5b1719a9bc911c9d7565693836edeaa6cdb7b2e2f9cc8c86b7c207cc14c261793df6c4c623355db04d5eac01c011677d26b764e9048bff8d76e2b6bdf792c57e044eea4307f5a3a62900df3f57ae88577644e2121134d61bbf3100fedf83371438b7854d06340ffc00383a0a4789a6a85062aaad3761dbb3c77e61c5926b0488f711a77735dce429b6e028373dd341fa2db5394867242331168665b4d7fc4ef96b12a571b8b25d44fb0de64b9820734e5647821a038428d67dbe95885526c3f2b8064e8baa5144b7fabbbf5a133c4b8d7a2f950a4fb69f9cdb37ac28cf0421894f0b771f80db988e25fb4ba9991664c93116bab82ba808693d583a2b697fd2b5eb673f954255da410df58231eb7c89b8257c5a68ca0306d088638b2faecbe3cacbbf77725e1685aa81d965f1ef663f1e474eceecbd52943c2e4e0456b52aa0c7758cd2fe67f3132176113a16dc9bd11d6dc03ee643fe8bd6677f2ec0ea754ab499e00ced482d78147ecb2f91d3154e03b57dfad4e4cdab98e134a609a7512a5a0e7c3c4adc9db444238e0fc3c3586b389d8d090ca46222a9533672eabe4fabcf61beaeb59c507f2941ced1ee4cd2afefee5aebeb354ec33cb85c9695426126f016929b471b9cc07dd6ff787fc2d682cc1e80657bd656acfb865dc91d6b032785cdd7a1d66d4d5463e142b6f028e8fb5bd6c621109e7022818b39197f85fd6ad4785efe48c4509e9a537f10d4fc9d23f275fb9e684c2f827868c9ff3baca8faa59903c829bbe1992541d15d538e64329e886ade0c5517cbab3b15fdb4e82506e27f449e268b488de32fd036fcf80f6c97505a5f33e4d3a004772a8970a3fe54049513cbc57131ffca1c82918a81bcb879b8f48d4300b11cd90069912ec9e59d10b6bebbc24ba1061c62a8762156df586a4aa758f13cab5ab59a3b1ef7d038c68920eb0a3c8a673c27b6fb80e5e8741b3b7fedff0c068a83e72373da07c8d73abbd9fa0084bdc92866917b546dbf7a6304f04b18d9bcebe2b4bcf5ac7ec526abb4a52a19094c8c231668d063c5558bdef0436ac418f42c5f41f2df996d19d48f8bec412de05a6a3b079e5b6ac1be0773814acc3d20166874ef64a6cf27f7fc72e0232031ddef1a6a4ac9897a86605550dd635c995626fe985aaabdd937bafe3e2a4082f0fc875ba7ea963a8e5987ad400423967bba1c0e369263ddf16fefc88901be069fc617ba6dca90608cd4a9d86476f8cbb41fc8197a9ee6fb331aae55959d107bef29b4f6f064651964999fb8dc904b8193dc7582fd47b0b0fb912f1c0c3838dd489c374ba5ea614cc80d4d196291c4a54989ae628dff5beb61612353ea0cdfd75962ab057bac887ce7f5df01861c769b88c7e1682f0ec6f7cea63598c3e6f41093d845db95377654fc56702a4110810917521ffada7432b7b16a64699e6a955a4273fe9220976f8b1ae9ea79678a3a74344a44c32454e7bbbae9a1fc440811693f66d63663c84bf847e0a2e8299fb0a6413194231a666a2efe5ae1c41db1cf12dbd8d58408cbeb1a9507b5b09ebf416f712b0040f8300dc5188e673c5ab1f13156718031f25cd5156beb8e77e95b48f42d1361da25a94cf1bb4a2a5c41f8da5c3f6a30c00e7d0323f7bc14583fe20815f468928fb69a480673b6c775b2d1af6a176abe5f6c679aae41ee1d5c89439a798823b65ef718515ceed5a7ec87eff54479a9afb48d0fcdb9a240e946719598512220d2afb20840e3680689cbbbf096e7d7505d1d854faacf024935a672278c5dfad333373015b11571b2a7329a0d2fa792d838ba3fcbe5303f84cc6d0454b89cf740bb0f83b79c98b38fa17dca42c5d57d8e86cbe16d46c4c0caad1f55ac4a399d9755067b642299b6b023e47ef74343b9d856545a51907f86034397dc1cdeb0856ea9fa753ba82c5f7e44e4423684f1b03ec59e5cdd96c03dbb1421e89bb0d1dd570309d92519e2b90fc83ece91ec6b13134cad1272f0fb1092a21e0066cc0a783e566167b52856fa6ef12aca963dde340e94f04980279f67a1eaec339d0656c09a3fe91a2b1885f1c09e831471ebe78f2af2efa1fe5821034ae172082de7cf5fd8599f7c575311d35248f2b0e6342cf7ac4bbcd19942a74ae9a9ea3ef5641f70ad1746406ad9bc24a1a3ed17dfda75ad54fb920ee9c92b792b76d42cec2c22fd1bb0f7acfa398d82b5f016f2943dfb44ca1d96b2a54ceb7595837379d62feac76dfa610a82ec947047176aa74fa8d58aef3d34e79768ba7b213a8c44c6e9739f05eb197148b2d2f3c5a1dbf0d4ddc4ae2bf0eeb93d2d4d0990c2c21ae34300a3139ccb5cf216b4031f5be4fc61b137a952fd516e45236dc791b692910a09a600fce9c14ce9e429ef1ae3ae737ebe9921d10522a4507d0794fde66f639189cca95923c51f97cfde4d57c718b6e0ee709227fef69a95a229ab54a4ba9d858115ac04dd0a594ee8fba7d29a23d8df53c131dbd6f7f47c6ec482cb2da38e98a8bb51a2878950877408f0892199ae4e94c4c8eeb614eeac1435b2947ba67c30ff52ff4c958eefd318814a17f53c8ae691d3fd91ea8196bd82d4af9fa216e32636d6535d5c68f579d3066654f2cc067873fea5d56f9676800892f210363fc790086a778fb721854a0abf9a2403ac6de964c2eee9011a44cc0d66ced8bb0634cb986a12b0d5d875db0f26f008555f7ff57f42a441250dc5d13dc5342ef36c288127d46b4a2cd85e5189877003589579aa787c46843e47666be2ca6e8aa84e065ec77f0f77e5cee75785e2358a5e1fd7d540ba1d36052964d7a5de9d1598cb71b238c6a6f2a4b6c72d8c5b0a4c2f17342747dcfb2bf7bc52256fa21741e1f8e7c2b749005ef240296ff9935f75e943c2e725e9f54636c3466450a49eadcc6f330558f2146426fe6786f4ac6fed1943d616474f7665e8ecc2612479eac464c8313066de5fb652beb42ee17c0d9eac4496b5a732c3df31d90e24ffa8eacb12b72dc1d393d0880959e0ce9db8141ae1490bb12af9bb2d12da5809a348714024d7beb73dbdeb4d7adcb68c59ada159fd1855ddfaa33e0b985d7bc3f509e64ee52b5057656295dc669939c45d89a07f03c0062e20e309a0388725c993f74cfbb8db38b85f13bae8b27a4da755398f228d79eba2ad5101d80c75eebee608dae268dac0c3a1c63e311fd82cddb78f06fd576314ffbee8ed598818894fffa54b56e7a7be5c20ac553d106609f4bc757acfe7b116f695fa4ac3ac93bd0de4bf87aa6aca5535e467298aa934c11143bbf39c464db663b97ad416b6501daa12fa8d9aaa31334851f36f654356467cf4f42fcf0c4cb239c2acf7c7938c0760a6a8f953e75471881c59293285241f7b73e4b3dd5"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n14-ecdsa-wrong-key.json b/consensus/common/src/test/resources/aere/registry-v3/n14-ecdsa-wrong-key.json
|
|
new file mode 100644
|
|
index 0000000000..1c69cd6382
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n14-ecdsa-wrong-key.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 1 claim signed by another validator's key",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-14",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0x8029e6ba97e0cfbd9ab4ee6578e3ef471375d5e3e592955eb6b947715ab035a31e58951dafe664e6de6e5fc6aae761a26890e81114e2c4429c5da4221c0e283701"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n14b-ecdsa-missing.json b/consensus/common/src/test/resources/aere/registry-v3/n14b-ecdsa-missing.json
|
|
new file mode 100644
|
|
index 0000000000..360ef92ee2
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n14b-ecdsa-missing.json
|
|
@@ -0,0 +1,58 @@
|
|
+{
|
|
+ "description" : "row 1 has no ecdsa link in the switch epoch",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-14",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n15-transport.json b/consensus/common/src/test/resources/aere/registry-v3/n15-transport.json
|
|
new file mode 100644
|
|
index 0000000000..77a8a6b43b
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n15-transport.json
|
|
@@ -0,0 +1,62 @@
|
|
+{
|
|
+ "description" : "row 0 transport is 19 bytes",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-15",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0x11111111111111111111111111111111111111"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/n16-declared-hash.json b/consensus/common/src/test/resources/aere/registry-v3/n16-declared-hash.json
|
|
new file mode 100644
|
|
index 0000000000..2fbca8a3c3
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/n16-declared-hash.json
|
|
@@ -0,0 +1,63 @@
|
|
+{
|
|
+ "description" : "the file declares a registry hash it does not have",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "AERE-PQC-REG3-16",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ },
|
|
+ "registryHash" : "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-a.json b/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-a.json
|
|
new file mode 100644
|
|
index 0000000000..f92d845f50
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-a.json
|
|
@@ -0,0 +1,71 @@
|
|
+{
|
|
+ "description" : "epoch A: 3 rows, falcon-512 + slh-dsa-sha2-128s, the switch epoch",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : true,
|
|
+ "previous" : null,
|
|
+ "expect" : "ok",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 1000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09501c96d2f5cf0b28fa00c726e5359c5d36a1fa069971f854b7d914fb2f1295e68b2c6fa91d82f7d287f55ad493c87320bf7ca2a5d5e79d7212e8a540c166b588dc03f73b83be060525b367d9f40f5e77e7798c60b6499767586770722820b3b9e6013cad3eab5fe5de96089a29f34919a2e9ebcb3fa03a3e714593b7a3356d11ffb3441ab40ad94474da662a71aa2419dcd50668cd5d8a9017662cb60998b34ab5b7929c58a94d5e133ebbdadb2b0279543067f76bcc4cb6d7e0a5edb7625467e3ddc92a01206e1b8dce69be31928687d8af4d26633a07e73c2830d5299b878977691cf65700b65b6ea2463e51b6136888c544545e59fe8cf190a7944e215a785b682623c95a79eda28e25e0e1b91b49ac89deaec3b14a3c431d9046a663170111ee541d81b43aa91f29dc147c6fc97739b3a63fad1ca84843d0a65b8d9396f28e9b11f9a41453ab18a2309ae8db03253a09fac8f0cd634c76a5e938a44719660944a95dff056cee43ea99592c3899c2880d7181ee3dd5c04baeb60e1369a69430a66031e3cb10e392622f5246a71761760cf417dcb40ad65f60704fb74ad26f26c3af7513a42f806895e0298c25c049187aa536e0eba21998912e621846c2ca0e323744ba930a29850fdb385c8241382296ba28dd4df05ddb1e61fe525949034b59929a784406de240f8086b4074825f419d5472a28a0b157500be37e9f64897db2b645d3807c48dc143266c99e7cc1638ae278772493a2a4ecf74e526a514bc9119d7129c5a0d115a450ccf4dce05b76d4b6149fdab028006df7ec2209923117abf7578a082128cad42aa66b69eb63acee4456bebeb537ca57bb3d3487f95e4f06c5cb29f292d3b6284e5a162cb83151cd9ae56aebbfda150b7edd5065302ccab70892733a1e096ba0da5f51b42764ad23060eb197d5460425fd9c7a26e7dc3cfd40eac3643539feea72c9ed41569111a7976d2c345ac2183fa2271b424526709fd9aae558a23a5cca29f4e2f31629746a71d904612e95ad9977bbe74fa32e90fac62625838cac49f50e5aed4e8879e2ce2e5651c4f4ba0c96583af9e1612b5ff1a6fac5027c0a308815e592308170b915b4a2de1e8d48e9a5730680ea9db8f3326c430241153b3b218d5347d5c843570cf80ee813871ae10f6b8ce4ab7e4c5197045e85b1cb4977f44c33eb85894b6555b4bd288a50c1b656936841048983c00a01631f10a84522cd613fed0d4beaa4aa4b3e9f30c324108d909e59a80150",
|
|
+ "slh-dsa-sha2-128s" : "0x47a0b70170dda85f843607f6c6fcbe6e6acc7c22980c108996a3fe72dc9f61a6"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39c8813cd3b34be58eaab900555a67486034b1923e0b00e435661230cab85f07690a5958a5f5e9c84f033a3dc2039a5296443093fb7fe8d41895fa73be3fb34cefc6cc36750d534e6a3c47307294694729d6cdedb633e8efe8979a9aee486eaa66136e342c578761241192610185feb2d3c196bea0e79222437b6a8e08cb09778d053b29552df96507b1cdaede8e9aa7abc18902f29937f30e7cee6868f349f7ae33738237dcaf86b8e8e01238f3d8ea6fd4090a8161db65dabeb5ded5499e8cc8a5b32607abc291b36a4b34b327d30cdef18c1825232e69a2b09d539ed84dd2a4756efa64f864c563943b3db825824f294c1bbfa2157347b0fb0e7f8a56ec253b39ca9b6cb1ef7d3d7c93a6cb220a7dc50c365905ea5a71575c3aeab25b33523e4fefbaf66137f45c3d96db719a12d2e2d42fbd6cdda58c5a1b958b28c2a8f2cca297871a147dda92a7f008a359027a9288e42ebcd6ea9542f10b66dbbce6e7bb914206122f866d9adc1c89cbf8bbad9bc9517c2ea9018b61d4d2df9abff1dd9f3a0a6faa72a449af9c97e8c4090f3bbd9824298e61599c13c7eb89677c0e845ca2907c728d9296c24e96b6a348dbea7cac62671c9a78a531463614ce321e28ca2f093094ba5f69881e6cd766874622ca769ea556ae757cb7f9546d99f5c90c25e7b8e14f3b7f270861398800b0604ec2a3374659277a23cf6131c63148a41b05b3c06e2a98a268f1b9f0df7969addef17179ca2261d3c229ae3db0c490834564c45f7b8ff6d3bf70784779d75915fb2e2d5bc147bc941b9e249af188f63f39b028547cf080b7674b228e20a600e3b167610f814daf105226f3c1ce5e07834fd33dfe46315546e926fd5be83fd4d47ccd5bb8ae736ac745daabb59c87b9edf9a45c9a1d1617ee84e588f27d12235c59ffd9",
|
|
+ "slh-dsa-sha2-128s" : "0x0e8f9bdc22cad3613ed07fba30ed04219b9528f9b657119e2f0886dc71cda4afa7d462fe8bb108feb58d998b370b2f7e162390713d1a17eb7de781a604041cbed13d00effd3b24f2ff87cac74f61e7b7f7aa6a259dc283485179ab4bb966793be018c4bbf4475bf7a69e600a37246908f662813813d4b0f4f83757f4064c5c0713870a0b98b5bb99025dace06100497fda8c73d7385d123afd4953961066e7c8544de3fb620ef5e23174327c2b64089b3fe6df3eb86e83b12634a0c9cc0d7844c894ba6d83afed6becb6f5abcfff397c5cea8064e5e153ea4253abe599dec1614b449329ebb25861b69a9b22228d1a03ba51532ea64ebe7603474a15a2806d3dafa29d57d27c5fa894da673b85b4674ce835fcfbd391d328ef83504101432bbb0c83d7be462b265911aad862118af6f4cea4df0f1dd38969c69428fe438d59d22736fbc7dd5faf6758905b26ec4c99d71e4b8fcc562a694ead91569c9a916df5ad693cb2ad0b7ae4c4f3c5b7322f56612c5449e0339dbd367460c76ab89b6f44942cd33f35eaf33c2ddc0c6af793556d5202fd1fb0f9fa1b7ed45c6ca68d904e476477b71a0bc6ebe248c9b4585da0c7bb186600691269bb4c836667a6d73a455b97127d898b7fae17e1acc6dcc3bac3ecb14da131d5f8adaa64b054e2f569d9bdb164792038e107848882de9bbeff295905c2af68d4c6dcc8cf718c2de872ab6b3d18e00d527166f8ced642281302e2acf4cf4489072a2dc3d55ff8716619cde494be1763dce925438b33ff1b91b35eb511645832720ed92552d4880ae53ff6516cfaeb1d48c923648e502e4038676f7c82e532ea713c6b9348c80ce3c5735f437491d3a8b1765294868c14123af2e9ff61e394216e630c71ff976072d2a1c50cfd8ee1ce27aba5bcf9aaed4a51521bad5e5d5e66abc7a95b215fc8004364aa4df2b8b97b14e3950f521b6327a55fdff9139fb0bd35237b022e3aa128d36c8a60f4621d25d28c59a97418c7dbfc15d900ba626d283632732631ec4a948f66dd9db3bee8c2cf60dfdacbb5ad4c0b2b31f8428868cca035e79c95bcacaba40a9351b2b44cb29753b6b9da0a751bd5af84c9094d5fe91e97501d4f075392290e8516ed5e41b41b00e09793353707fe5c1d942395074637f3ee0a0f105876d6f28a74f9558c5f360e98f047a99af35ccedef8d5cd299365e81e7e91f28a01eb265219e21aa7f7ce56b62f9d2a61560f9fa39f2765f5b50920658100a638aad03482a687905cd27dca02f1deffd1bc49a1be1ea7ff1a505da74fd932937d8f6a8bd75ef456d5f7b71ca5357bc66db6cf14368c4faddf4996363251e6a6113ec64d642c319dd85830d8b4c7ee1437ebfefe01f27709ba0c412c266530f5b6bbb005994774e8935f1d91069f9e7a8cd2bb7ad6527768473affe24709c10294eb588aafca85b379bedf0b142b109e1b186e635b0625c4e59576266acb5f71040c44035fc9480b13932bc657cf332b12da1cd7d5c3977f51d5fa742974cd256e8e3662dc698e0516d615d0a05ea9caf12338d0dcb6151e07f184c9cbd5e59bc40b12ed6372e2d6bd42aa0eb6c3c888f264a8c0d3332631d4919c921cdada6bffbd01ca5445de0779f9723577ebd7e33ab0e5f577843aaa6cb8cb5f0508c33b63913a44d02b76bbb1eabae325581738fbddb5d4fdef8dcb8597bd29c6ecc631839118c44f66ef8dedeca65e58941c30e0423c40bf064b8d19d28dab3787238781d492720236a7ae0695ccc867fbb1cf207ebecc64f84daea66b6745515b9ac9b725061bb9958ed79ad6161318a262528004401633d47a023c645683e36413b8653fa4864fe98c501197c10226b1732337842a1322bb788a00a0de86758139c2d9ea3c5b26bf5d7a4a92cab4cb686c580e3e6cca488136f0da9279073b3dbef9519168ba02588fa29cc60d02273805b425b919a7e2e89c9086609982163e09d5f6eb9c66267ac7be363aadd4617d398d4bdeca37a838d650b0919faf13b78642a058b1bb96b2ed1482cef9bc6e8b2e061e6815936e15a9c754353aaa786ab141e95e5f6c464a41b8bf29e28e764abd638abcfb342b54d08c15ba7e24e6fcb69b844e16cdb5cf4f50db60ff0699f969d8e68511fcc9e16a58e100f80671af6b04ff3edda3a4f05f9183c0c3bb7c1061fee2d3f04e33fe75f1354e6de54f582da914da0138e8565ff45ef52f638cbc33a24bae863fe91e58d7c5da34273438f15e10d4f59db16e505620d97d3fa4862a4097a659925d0e5f4e073103ed29a600b051b83b1f3a21381f4b871c18d262d7e43842c34ed80661438c064aa2fd858a8f3bcb035b5e942baace7b50e4de5a73d5c51fc0843cdc163958a62d333078f4c7d883bd7055a602e04c853f9215c9d7f798403c007fcee124cf6099322629c449ad4ef84b7356110798dd87aa4d98ebb47abc6cc8748dd381d588b77db7f4e7550f6ee1ef4360dac6d6c7037a65297d4a0ea7999a5632b90ad48fba0a916846a216941fbd13d62ab36e1066e24990c19592944078435c52d7717b3556595b645cd2359ad151dbb67e92b14168cac12fb2cc5422582a50bf6e99f116751171c9b78744ef719282f1b84bf95b4092514f4c68fb82a1526e0942ca50e186632cd9b0b8b8d91e84f85e35f30f815601798fcae676da6a2d38eab62f22445099694804a36a34142150fb795afb445e78c241f0b645209037a8871cb5487c975975ac997a540b709e3df6bf208d9d8017f9688b152c9ee2b934f65393de8403244b7437108e6d8c973aa723285555d9eb92509b1747977105cbac7fc33e658fd51cd374d21fc2bf229928948292c1698db7934d0f9be44b137514d0a5fbb659bba83861931e03698a61cd20a449d0358a5fce7f288e18bb3eb62b7ba0ae75feeec634fc90fc45ce45239c5e3179309f0c202cfc53d9f42a617f7aaae586e7161a0723ccebb7e8586cd40e1fa12d3ee89b400dba8073b0080ffaab1182e8243afd93318df15bbf3ce179f21804fbb8882e855ef9e0739ce1536d8ebfe9856aefa9874b4e102e705a40ca4c3ab0ab7df63ba525189b518796590035ca780d348de49f0ba8f28456ca6f3e3cff7e761d961ad98b8cf01e855797c88fe2f811e41e787f3e4becb0ef42ca3b9979356020b447294ef295543e0ef512a247e4d356bfe3deacca8ddc5255e6ad047121eaeafe61d71e7f31395cf78890add4f8c688e4eb065479a63ccb3d0c09028bf60c700fe9d19195c26fcbd4130e6feceb52e192a2aa2343c05b43b276f51a7c55dff7233ea512942291900d93315438a96af08e25ea5b9ce656c54e71ed60d1eeb1665ddaa9e42378c930e21d93484b9a4099b7ddd71d983b4c42c6b1f62907ce84b24321422b08b847f1ea97befaa4ec30a794ad7f340210c800cf185ee2c6c72e844cc5671964e1e1ec58953500f149f0f0f25c34d5592de421c2e31535040020237b907e86d753094dd4532e1ab9d821e7583d4a21e1041fa7ad711f29ee3721a2aec6b0c46866a2de71ee850d8122f722898e533848e2bb851ed24cff9ca83badcfad88a171b4be064007aef4d759d93ae9b67b446f3c6fe504f5b4fe851b8312fec86b46ec3cfcb36e0f682e65e117702b888ab8566c9cc716a3a86106d2323c0f7f20fbc1fcd110bed4492a750befbfcbbe16820077dee281bcdf14509b93137a3998b2fdabc2a375b38857bed12bb8a9c67bcae7934d02d6ff89620fa8946c8aa524fde99c12fec0e25bd79788e2c15fc31fa3f27502cb952b9f9482580cf18ecabd92c55113ec4c4470c4dc06d8ca27a10474594eff708209e8f376b6f17915c2966dbeb0e35ac2f02419692c0d232e133b3907059d3a56ff169e7e61915c8b1067e183337b40bc1136241e862eb3ab3f2c6a72b18511c4107ed063d1e2303d0fe6842fb01c204d1bffad7e90bb44a365e62945a7f631811c9c37ffa5ac39c16b4835798686da5baa8e1eb6aa76b42f6b86863c30669486a175d6b3bc5bc47c5eb05b240bd921007fa39506c6605bfbefc9c8c493973bf3f0767817fd8ce126a301c5b8fba79628a9b3a03cad0c491a5f487dc5e89269e5d3bcdc2998a136a012486c5bce2e6c6dc595aeee2ebd5a36dd06919396184aafb2301d1889b668c4d701c7ca01b95f9508f47d4c411cc0397c244ed4e3e3ad7f97d86b6f8834b13b1b2df0625e6b4eae9e439815e65baf2da767d3b1700fc461fad6297fe4e8ed02bfb65b750c2d2801b7308aba9657df3c3ed7d548687f55e85c22343d1db343bc2dbe222fb76fbb3cf490cee7a99ab3a337c626a148fb303b2f8651651588dd4859fd65c95820ee2af85adf4e8fc2c03828ea7427e7c6b0d4a1b0ccd424df6d1450ee436c01351d8b6bffd4ba072756315968845ab7976813d93d0f0f2be1c00faab3ccafa71cd26c5837e87292870cf768c7837e18ddc3c513820c660870b339fc42c5211d33d892ef22b475cea3be20f5e47206efbfdbeac208e26e97c400edfd41f063aaa6b85a0cf86e23fb11274b405f4f796eb10cb97e70783909ad492ad9207ae7b3d204e59d69c886f91bc82a107d0be3ae85797a7cba747b8e2640ec49384f53c785a84cf8de37dd4048dd4b879c58768bd131ad7226506113c446fbf13d769794f1535d58e9c52e23c1bd55e13c647d304e297d968c759a378f1d594897a026e3271aa6b4daabe174d6a35665b35193379f0ee465df7827299c18e1012ac69913a0a5bb5142e99b051763de3e98d5af8b62133e25b32f4f12b787bef7e21dec42de8e4d99a0adc8f365d8cd3e6a5ff3064ca18965ffdc6b383f7ad08186d735a099bb0ee14506388c1a37f7a766d286d748d404457226b952ca6cb3f317b0f4399006b5b8c6eb89f6b8cfa023cec4d2dedde3e31b9a633c0888989b44ab182a5aba30ba78640f477ef1202f6496fafc2a18e283b2e4e8bc60415a1c9a7fd68f15cc1ea0299e3b26f5755ad9f13481a0563a524c6735942f5069dc1d6a070b3c3698e9c503f67a11efe59413e937062668d3439a5dbef197d24ebdc79944b17c549b0648af9b1349cad83c2a0a9e55fd893cffe2aff4626662ebc5014e70baaf7cdbbdfd3f92fcc5eed863fa8afd87f88873f726a0a2eafe41fa81edd5833f5520cf93b0fbf0660e48eb0258d313bafb87dc9b0d0d9349f22fa2d960238f67457ad644bdc60fb5eafd1c88dd2a74db4da0f723a03df08af6c64883f275395020341d9dd3c7fa049ab2bebb4d8af2bb8dc1340d1a80088c4b2c26bfe7314926ee64bf239306c05dc2ec6e6c5e0ed4f6dbe51f5ee09533f558d29ca6fd27092c20dd892c89c83223752006b23e5abecfdc733aaa59c8549e89e5ab0eae1b44189f58cf9cc18de0c2a2f46a9235fbe42c641a890039cf6aad820f1f844edc24e69bc3bd0c22cfad3804d876edf5491e88cf891c347ed5f24464f2df439bb30742e1f9a4a7eabd9346c6a5f93af22e67becc494cadac82cf9cb693acf44560672cb9227eea2575f90b0e28431684ae12ff2e86fded0be3a099f9ddd32a7285531de8963c9a03355f1d9cef88d7ed9b842d0066ccacdb698d42ff9f8a4f000b9764a9aab1f3146f9f95e6636fdfc9ef91c4d060a54ed7f32167e7ac50590dae3a2904d5d2eeaeff2930bd4cad7166fc17edd2c30e6738157eeb0b441491e5dfdc17a7fbb2bdc6426b2cfb26cf2a7e20013f1b3e33a6d6821928443cc7893f7e4a5268a8b94a6ca6097d25be17b214ea4301e9a723194983bbce286f4363a53afd9e94dda9c761481d9d20c7687a2ff85d42436b9d557d5dc6c5e24ea21d5231487df9fc7986100664edbbc51ad4921c5ec9fbb407ab33ef5c3b3bc81f113e68f38d73f0db0261b656fc344d2d23b93446845d69cee1704834d98737848d405f52f5a7bda3dbdfcd3af3881484579d2d2f3ef976cb35c9cbb76252f2e00019363273489b39943d212ccecc647413c56de69e0087532223cf9b28ce3f77fed30bc3ae6a0842b546e0e1a8b6f6ee1ca0ef1b78c3ed829af817099426f94a447f67229cbca3c07b7a8ce547c5eebcf168248e0a0b9fbeb398e5ed2d0dcacb441f95f9e30c108c725507e459d34c1ec01b67065e5e202d685502d6ff015d46c20bbeef1db38c29df7df585b95d79f5687474e71fff162c0ec0c96c94c507f8a0292a8c32168dacd2fff78b5c7dc145e10fee1b25c478172af8f3ea132fdcad75dc22856deb2576a5ff3e8911842c811d1d57ec203c77b82da3658cbfee18d140ac341d38a30f1af298cf60f2a88d0dfbd3e079ae64a07abb4947cc042925fd5c64bb5d4467589f8c495b0097073c081517bc4504dcd7442bad7e7acafc894fcf34f535979364cf5e908a84e0e141ae47e2ae4dc95462b4f345b12b0629502c7bd65579ec66b2d0a951302ba6da1d1176db6aa0c0ea1fa88195dd2248990fa4aba88490b1da4ea405649203f6ff6f734693f40deabdad59ac62e3296cdcbd74061474dd7b63c46bcfe6ea2b0ddb0f7e77fcff3599892c82425b05ae7aa1a2ac1dfddfc67e11921ff4f2c8f6297881dd5e38ccc4076cac8015c59cdd6023ffbd62b887b33ef8d917446a8941d9563acb66a6226fa4d3f2cc21604c080b3f83e73c093d8f2f7067c392671020c7a7eb6fd0d97af0d63032a3116c408b708d4b2f711c1134b88a91aa359608550f0049af2bb97688afc4352a45c4f6d30d4634e70e82515ff1d5f77851ee857e42b486d5e1f3e0406227dded6c5f47eda30d94f44d978322891dc729eb6ae95d29d22c8a5d649193d5d2aaba782fa16ae488f645a7ed90a566e182f97bc62049724f4cb5fc71f6bc7be57f07a7afb9933f6706cc83483cd7dc4182768cd35bc42f1e9b54d5454d3a17e734475ff58fc66d75419d3d122eff05f7b0548188682f1318ec32c5bbea87c8624cc1e548bf18a6b102e7a43e6bafb579e4e84275fe07d8c63ace449a44cace5d9305ff756cbf40e5a6a20334d5b4a74ab0483e31593f2277e90341fa8036496c2bc6d2b7b10b0b354c86d666d65cacc593d1d7349e71b0360d823453011ee16b6280f5c048111b99b185af99e9d901d4eaffd8a96b1ff394b66208ddc1e7e53420fa965bfc4e630d73ad97b9c5c6ea884c619bc24ac3f46234e7d8d35a12b0cad7220d7a0945cdc64fee9d8852bff872c43f359e7aadf8fa3de3551fb716704af68a18f79d03b3c7d90cf21eb4bbdcbb4004f8ba15ff0bbd2d0918ee78e9bde980e4f3cc13558e6fdb40ca71ad2c10f5e5587784bacc6b925f72da12528216895e0ca4b350d078fdf534fe01bc86b45e0c8e2b35799d268a457f8768ed782dfb56abecfd2b9db00cd10e189c6164f82f5ccab423277e3465ec72d76b696cafc1cfa9a7fe47d142fd6672d9c5b77751b40801af07fc53b1c9da0fe6981ea75e066572f7272baef8fc54bfa7cd71cd0fbc5d6cd717e9aa07808496ad2b4b4005a320c9312c73385afd61193581dbae99df6c25f1b9da17093ccfb108b0a26c5ae4963183533ce2f0ade01bf5e818af613416433578522b1b1e5aa7c791570c8c8b26ded266399116f5789a8233fee128e54ca8ce63fd56c1a146c3006316d200e05715993d1d97907ca83d7fd42ef7e7222eebd74f9c86b6cefc82e614a53976272c8801bdcfd882e34d86b39142ac05088a4c47010a71107bc72a380bb3e5122981d1795256beec20a0fe568002d79a4b1577903fe8682f268eeeed0a97861337ffb6861bf378eba1e0957111c7f9fcfeb55a95238005b40e13ce40efe846ddb86d14c9ad2c46cca74baa364ed08da3a3079fae3a36346ac949e2174c661b8801a051423e95dcab6a0f9c965e8744bdd0e629bd3c1a1241e99951ddde184eb8f354209f24c04fcf10fa8f4e43cb55c922c28be041213ddcfad65c86e1ab9b615f91d5fb11e4cdec5b7e25f8e9811c82c2ed457d012e4967b555f228baf4f1648854c624e0525e36e5f4d1961bfbbc3621d79bd6bea72924d8e0146d0965c239a768b417ea4c33237a60fff2760a9dbfb1113a37b01b598f3e06987d99518bd9f1ec96cd7050863898c8664f793ef29114bbeeb9afab8ed09358d1227d7de2aaac0ab2391cb2013028ca5f4d1de6425ec5feb17d95df358572fa27fcd51d14c363a36bc37c7497a0f964a6c004561f68349f828d30d4633e87bdce6b6d92384c9c1c540c8295ea621e9a8006a8d7c163b988853071e06c78f1b9a0246db052e8484a65cbdced3a587e45d9e2b49a5501590cf768d08b6a043971110e9c9dc96abe855abbb7aee2c38bbb77e5c68d61f01f2376b6122450117240532c7c840e3739395dd6c9e80a432423fc5e3a6dce9dcd58eb418e16d7aa507b4d67dd6fe2af4042a5c7398ba4f87c650926084efbfdc9430a4bc2be544880ecdf7361aea06a25e4f592104b0d74312f2729a4db5876b675bc0fa68f6e41e014b7caaf6f49b8ef704b6243df410dce94ad2c51d328fb90b9cf2f5df645015f489a262f57a5aceba40a56d343403b660928cd7a9d165f4a5bc289c0d28f33dac85c9c2a5c79b5ddd22c744a0388a5daf4bab84d7c77685053c912c9a24b5a0664c6253febbcf552c4ff38bbaf2f7e0c9f06e69a91cff9138c2745b99367e00ff6b6a920b1812e17ba44175c033df0e58d1b5c0b7d146f861b62e812ecbe99d638219e0dba4dd88089005977bcc90634c4dfa95f87370d905d32f613358fba2efcface0b9a414ce33b09e271a647b911843933c5d1008fb0717ab59739eb8eb844a4b34bb1a8f635c5895afa285ddc43720e78dc81eee7db822896bd9bd6ae3e7fe2988ba560d58f02592870647b94aad1dbb0d0cb60e28135ceb72e0a6f4b7893a56eae83f9d9a4c549d53d17c6a00f5d6c266d23e7a1d13e22a5fede3a7082dffb34296f8fe9f3bfe525ee1da81efde3aef9b6de8457a10fd4340809e1dafbfb9e2719c327a3c3a4c51d4d5600e8a01ebd5c537a4cd7c4519e963de06de6c83a9b968b01f79e08b5415c5a9d6a92a633d6ae969b80cbb2cf4d6d1ab2c3b94e7c12df27ea89bff4014d92add41a3e961006a194ae3ea4a6b38c2827f6185ae636f6846b1c8401289696fb10c765fa93e58d068bdcd8c9dc95df572f096d65f5de42bae639d41ce7e1ee0f48ba4faf856c0cdd728956d7e4babd6d9d6389ff41d76c5fbd6380f351b05a37022dbce0a6a47ab7168c82c77a2810c80b1882f825ebf86cb7f6d0f54025fddc9b9120802514c797d1d3968631dae95297a857890ff1dee408909223d012925dc08b7d1119fefca7466392a019d4121ea76c8b4c3bd103a820557e4b2283e262af32f1edbffaa253c47d5873bfd0219b8be86c7e64ada2d87ab6b7f428a7d8fb3ae09b05aee71054355eb83ad76c05d836a9f1a65511b1553927ef1b19ab1576d7185af61be6104de1df218918179c6321846085a83bd1217aa63d0b03996ac1fb4018a8ab54fcf635f7d5a8ade95894f0d407e5d4691920f21094c6f632f1661402a0b3351f168f16a13d3a31ad48e89230cffad272926487f36c7a2584c9387623df6227be8c96088db4a21c93b1c88ee756e960f60e614b30bb6ff757c20f3674a7ae7f6ff6a9115a0a6d444513ccc0be5dcd557430e0ee8db3ed5b3e8c405110500b9bf7f6eb7748de4988a1db94bcb16fe33479f64762c53a1e2965363452063d7bc14386ca7b4d46ebcf08489c64ab413ec0f1ddee8719f5fe978d38438ca3059961ecc8480908cfaf139d88db2facb5e7a88a43a67dcb0f97a17f9bd5b09b8369803ccc7ab6d41238e59e43762965814c10c36fa4b6e61bf2e83c0243f20ee8aab62dfa9827aec06f99c5c565c1bc75291292d3113503a202851c26d1a8bde54bb30f0301e555374b71e278925a2afb29b0209c08ecb89601bf612ce811a493abe2bff78e7fd02ee13c5db6b3edce7c87559410b9be3be95465468e33af224d6508a44728cdffde4cb14fb96a0d2ab9c7f597541f9963775c32ac613af9beab89e0ff7a5e35613751061b0511532b10b3947802901505c8e33bae67ce0e28da760af7e80b730811bdf17abfce39d35def51d73a084119449038c2b0f1c86d844123c6e71f28b7038053e279dd11c088dfa11c547a4ce13b19453e88e5b74962101412490cfb68e21d8952db509cd3a814387b67339fd04ddd2163177589146409934f0eceb10db2d90a9e3f6691eb75e84d5e66bc3228baeadcba200f3d11e0cae090ffbb800f5da7032c35ab572de55beea37258bee6f191addf01739a26efaa612991cb2a3c6d1bbb03de0ee1fcf9b7f6c51e452b21c0819a9aad93162eb2dcc189bf355ecd2c3e504713dab24bfe3ed86a4194611029f7f6216cd469fe1f7d35d56b6c8c2045011e238f9cbc0a19b8914d74329e2472f15d0b7d60511814ad2736d6be168aac01868c2a675549c849fe05e05a76f077130b46896735db5490277b76bba43545de6b8ecb53fd20398eb94dd884951fb48d5690ce4bcd0b836615cd9340ff0cdee1122743accfef343811a71c7d14d1369fa49ce47784a6ff8adc26c151edd4969dba513ade6a9b1f009e57c3d6aa845ddee275169ce58e1f04b564ffb6d0eec75f7172e5e8fb814cd702c9fbea8a783bff637db8667d4b6b48a264135bf60acf335936105abacff0351ba9aeac88e9522cf7ed80069822a7db1a5d8221d9492e02ca893e1f15965fb82a80ee2ec491027bbc8906e71cf931fc21e1c0865ee06a79c023929625b4d232c7b3e2e4a4e5dde28fab675391befe583c95dadae71dbaa43e09d8d65ba36d148aa85d1a2a35dc51719ac0311ea72c1237c78a8b1542c59de3b743087245e54d3111c585b5e5e7642f625c8d44c6d9cff50d8d071f6fa573df937d9e7457302d8b293d8fd94ebd3023c55f8b260c3454e93f58f16d0f451189bf41c9f9b91d3c3918adbf98e4ca5aa0eb6314041521ef880ce18f0ce296721a06b329bb5fbb3024e424b46400e03caf0105877465285fcb41a93844fb90b7fc1924883ace6ca8a37c9905068c633761163affae39d0ba55b67fdc6bcf0908ee3a42af286c"
|
|
+ },
|
|
+ "transport" : {
|
|
+ "secp256k1Address" : "0xe23c5bba38d809fcb2d3384f210e9a6405beb498"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x48fcd978ac4d42ff52dd81fcd17e93190f35e5e0",
|
|
+ "claim" : "0x2dee91bd2cbfa906aefa3a8ae6e2de773f55dbd28e77bc329d28215183068585601ab9a7f9ff0c48095407474d502a3af3f059a666e5ed1e27468466d69914e801"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a6d094d9a3a0865864e9a16b477236f1ca26c888fd0c918db331c87a478519c41085cdac7e6cd0d89190a41a3bd6f4d6300995d591f5e22a7b7147caab1f9c7a85a4ba74d47c7b227326ac17535de039a7e604225d3daac7f75b9544654b73f79f5825825ad6e6c45d13e6d385a644633e1c8806d3a0a551c98f032583c95fb13997e52a6b02192d26b5a47fb22ee52999ec92b75c70774a4ae0481a79113ac72346263e53d5dcde708668d317dd00552d5a40ad47e59a501b10a50bdc52c5c2b2c920fa0e3dc9b8eca54b10aa5ab1168c88287dcf80ecd880a8fdec85b6d63a15b9f453845421a5d9b898e6149b60454828eb9dad6442ec62ad27ed72215014f3d17539085ea3f668b0a9183ab96e9db996801c72a0920b02a249911924f181e8dda515d114beb83b075ce7e7a0902a6971e31420ee4921f5cfc123f29dc7775017aefe99a7e326119cb925f6f603ac3bb137313609498d5a2000c426cb332c82500dcfd80d70a5e2d156844a683b313266af6d60216bd9e9998bda53c0028f387ebd21a5fca6c0607d54b1e95724746d15f25f16e45845926a83c7598646a0a0d3a8f8307c1a401b823f1656ca41e5499684150a954318da076af9131fcc93361d9bf0ae035f617e02cb5e1224a982b3591b24013ff80dbb61160d2ba4ce85a4260c8a3a3218e0ec869796b1b04a82079cfc0ac26da03b04a11950b2a3331ecd0026ea9737bd20e6ea3045b56e3c71278d2a8c72c8014b769da9319e19dbe762b1943e5a4be15aa84d0da831eddbb10bd05f35d55b6211d02a61c5d9247e69cab6c112acb568ea51f345a5bf16f84782e04220e217722da71d634e1a68b796376c8a49a965c592b87d06702fe42dac12da108d24ee42a109e8e4cfd3bed6ada5e3de50301696bab0564292864f1b9f47d5a53cc0c5f9cc3d57051065fd57064d08764892ef4c4a92b475184a4cb4ce1f3a0e6da0402414db5a9db34632b9717586e799b06e870b81a330da7be6a45ddfb000fd337a24a29e164449f96be015818c53aaaf09b9a565d7d9d735b9493885e7cb49a5f1985977cd6824fd62f51d2a1e60289dbaeaea148a44dd8876cb58b8ca2f29f6455f354e4e76aa13290f2979b78b22afa0e65c696c21497e94bf0141ac6298aac70b5ea843848a2264fc057abd3593cb17465e06d41731b7153b71f8f0f7a06d362fbd09845f0815794050460b41ad003c9396a86eaab240555ac8c75f85c0ab972c1a0b94b67b1aee2fa3",
|
|
+ "slh-dsa-sha2-128s" : "0x2b2fea4a0edd5dcc2f653eb2dd000aecd87deffbce8818aae72d7862b506bac7"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x3968f2999d69a9c28ae792a90a47363e689bd4b349e75c5f837181fc7b16d3d04489bbc32252d750d750417770630c5b65b88cef918ad23e33892a58458e9e63ea591596d3b898f65e1a5be3d36650c3d9834e1ec725426960d337b8f25878525ee3c3798b5afc9add5bec82c8e139c59738aba9ed5f42d11c886472e81cedfdb5b910eb73e884e0d4cc218b87cd9bcc0bc107af586c65b3949460a25892d9607efa341f232e478f3c9fc2d05f324ee6eb7bcddb72af371d47c36856f488872249ffdd322d3de7d12b62b1ec595187b5b363e36cc714b765f0ad5616488300f6e56811e88e359365d5698ab123b917bb32f56566958b154f6fe052b894ccc1fcd99d65d19e8117a8ca4887e01f36f181461a433fb9bbc1790d8b14e34a097b149f0c5c075ecae3501944935f3caa76f0b9370ebe6b90390b4d059f9029ee4af98dad33b9050877d49c3d4f2beaa4b5861a21af95b8c52f9ab4b0eb115357f5b1d25fb66a36b9baaa4d6cc5a4f5fb5462432bd82734d7393cd22c68f52493eb3434c3b88fa255baae5c46c650cae17ebe59827cd6645c6d377b3cdee3aa6a758ad3a96d103bf6ab8ae03b72b53f3aebdda359288c32ff5461a158962924a97a24af29f6c976762e8de9363485ada49c445566e71ac75379aaf7bf190a81c671115e842b5280a05bfb2ef3724bb74487068d5b5ab2d089ebea7ffb4381a7e96233f0915f295d3b71db872393bb990b9c74717bc3d72f6271bc248e54828a1e090f6da56de3643b083e9695db7d0a32bb42355e245e5cc2ed57354d82220b449e10cca1cbf6fbe796d141591d6f71e4eb6770a3c7dfcee509c3c28f2f1988eeca61833b6681e6766790c2a6f043b4f67e145b908ba7f03361cd9d435d054e11edd9667e4f9d12c2d74f2832b619",
|
|
+ "slh-dsa-sha2-128s" : "0x39254afc16b1dd8d4fbfff766819460253653dfc6a8e29abed55ffe91325afd578ebfa2dbe74d46b48b381e69d269b5bbe24ca1b85767bd71c744065fa47c646e3603b44261731b50f2d20a7a327e98b84c5ece73697739c8057f99d6ecbc54cf891649fa78b7bcd824972f3b27820ffda3629f481b1193b922cefc907bde3ab1c78b5ac97ff26986f3a553556d0b158e936450b4f41bf006c90a9758e0efb327f67408a7b803ede993522cd9042db4a672c89d4765a0fff8c6e8bf6882a8de432229dee08ae13def90f9fd0a40c99f3d93873a41d74871aaf407b0927a817b476eb93c645254bbc77d131e0bd35a2541248172993b1064d5b26b921396c8c1664178051810961039b15790862415338806329a45a266aece5904312afb1cfbeac1e816fb96256fc6e2b059c25af1966b0bf261bfb72afd8652feaedd6e0e4bf829a75188708ac9c623d4d6699281913bb563b96818f9307b66f7cf4aa9591e30c65a0b0885c22b5d17ff610f40bf2e0a9a32173b2fa7d66c14784402885d84f33fc75afd8f743cd10f5ad6dcce5b33a8f0c0365de2ce1b69aa86df2482a2c2d3746c6f0ee4e6fdbeef5738d809f6b0ef3cc703b0d29e93e198b68d62a5be657e69c33459fe4b163a5ecd72a90f1e53fc00bc8c698af7ae3cc5b07e36cb74088066a54138d6df4ef6e159ce5924b6903346a5fe115272cc951e8713d4b6f96f78d67a542c3bb402e69bdb3c2b06e189186c227927b2aba52b29c14e837b37798321fd000ed3bc0e386ad6e5d3a48494f57109322f0a87f7dd752d862dbf772498154804b09eca84c305595cc1e6654b1b2e94d5b88feda176aa144d3895a249754bb2ea99b2efb4f61b828f265638866a49dd3437c70016347d5aae64c79957ed394a85cfe06b10b98b6e83801728645529537a1102bb04ada4226688594cc28aefb24fbb0d1a60c7b826dadd23f301517e862c67fd88d0f6a5ac08e7f966ae375b468e57f01521b43fc24c761838c174ac106c4e1f435b7ead5e79aa1b303222f6b45c5515d497d8e7b05901bee96945652d304ad9ebae2153321885f19e7ad08c9da73ccc22a66c26c4cdc9360c36e307310714ac44c80887f42a2575305ef649378d76d297dc6faa904377b2037618f23b8be496fbc680645dfb80a76bfc060c6b2aee4ac5537e79b7dc7deeca0ca38041dc877b875cab1a297190269c987dcc46ff34e5bc154e2572695e463542be79d61fd5e96a4be2b07f5beb71b882f99de317116fd0b36131a88ff9707eb25594fec74cf76c2859ba6ba2b968d41479adf8857f4b0f4a26f49f0f04fbae0e2f3c2ab6aefdf01855a7a5a4b8bf516f4551a393a33d3920ca3ec403b4d37c2106d777e3d5dfa768614513885d857ce95b9bc3b992808e7ad71575e5e91b8107c5802043b221c74d73c7bbfa7a191945bbc5ed69e20016b16e2e2987818cfa80695e58950b0c1bbb8c474f861d1447161744c75d99dc8240338c43a5c19a8a9f46d80f6b4b6c1cb57f5a3350bfc35a0522f89e3470ccd71a458968c629c93336af6b5b091f569d1fc9492eb6b976376b8ff19ad9318f5cb1361954a0471419b4207dd9dace8c0545e74dfbb19ce3fdb5d456a1c1bff7383c6fd96dde3a92daf0ff5a315714c74711e3c05e0c59ba525c64ebd17fa20f8e143c5931b3c77da193415e6506c2db27e0e773a6a5b5d47ad95760b8d471d06d5dfe000a2d47e6e4e6abe7219750f1f7892f4e09fe88d13c2e3b53dc904ad58eaed856a4abb0c10830b96bfc1b5764f9e4b34b0072be314608fdea8c5005d40ef99806d4d3edb72e73541fb828d4b2adc38855e09e974293de25da6907f5ea97810eff1be37f88ea879e545bb5a70d2187edec81bd57a95c0314df4ad08a864156579d50826d0cfa511d335ff722e246151a7afce94126232f6bac89b13c142d29e7521479866e35b17c15f16ee89d798ee8bfac5868e505031586b81bfadef4aafc2ecdbde649f63e07eb6026d09910d9d3613a9871b5d1523cf5958124f96b5304d5225b4bbb03aeeef87753d0b6ab51a287df1e9031f56f755d3fe5a20f79b7f0f467fa97eac5bc09a1adc6ec285c8f80ec5c184b8b5eae326300a5bce0b1d757c8e4f27ca2822e73745009291f0d9032051e15b567511908f3ec68840cb6ec6018a9a0e30f2e34759743ef0bc9e12c9b32f29f4b70a998cb8893af2dcf17e0eb4f48e7ba367f68aea5516e7248c8be1d1f896d7e8446fadd9603012dc13126878300f0868bc512221154a5104882621f831e60b49d04fa8a701256b3a413b9db4abc5af10a3f8f4c26cd0b3c2f55a58c9380143d835b759bac7fef824515a18d79b6dbd361541047c79653ab4af5473b7b7e67a6755add78d5c14c0a9edc6c7dd42c3d0359d9f2f6961f8930458a34c4f12478ae45c20969c4c18654d31a7ae73902757b3b8a4eedfd16d6c0d22548d7b8ba77aeb4c1e3f3766b6ea802ee9bd92c5f98d00be80c15e7e3a82eb0d100436c398781607dacbefa98c87b3558f363b3ecb1ff313655838f864c1b2e0f6d6369bae4eb8cef98f564108ab2f763e590a9e9201f4e28ef1971438c30f4376c55cfce9b9910f448e31d06c2e456eb798476d56a890660e45616840377ea0574d1c066ae2fcc46f41cfbb511e5efc4b5c60e00e4846e157bbee5fe3bcd77408e3bf721bf871c05971a70cf7a13c782bb4afbdb1ef800a414260243fd828b67f49007eaf60b3e32f4e2b8186291075a0b1c0a528abb9da7974b3b1e8b20d337161ce234db66ce82a88ae1dc880933343961267cb4932b36aacc5f136cb474bbdb5e4c4be4cd74868775d80317bfba00ca4e58a39d04e63bb797de366c45efe2e356672f567ed1f7b2741df7543d6faa7227601eb7cff367d5a1ff320ca71fa2a1a42866239cc3fa5eba400ee4060266a05b8fe1e729908b95ba6aff8fd76b5e7df547df62cb89f0605c1207c869d7214e4e6972ea6e47b18235855d6f28265a737b4f64f0d215943f13d219292036c1cfc46bc61679f034919e4fea80d882a5121cb3096a50f2112eab265ebf75b607b93e14ceda4e08152221bd368cd1503ce375188d23514dd0936bf980d4282eaa6fe8f38f5eb00c34e3557ae363538a2c15b560b9f9322d1f17446e8f3fd317126986afc2c5e9fbb96f8ca7148f53cd75a4b845a28034c8679baf1f5406564b6e4b8fa8e681b5a9d208f3a1b28e84d6d52d4baa152524908d50d71d9c0d11bb5665c8a6bad669dbf303027bd0d534434f9e76f2c300326e25d00bd8d3bb1debe1c3984961c0ea8dc547e8cb83a8f3b044b673f4a08882d103d6eb143a9645a9a00fab6f1167a2c09015d6ff2dbe4aa4025f604a63eb32330f832162b6dd9364f4ad6afbd86c8d26f56d7d9028dbb3051c85a0c86ec0d7961fd6008f87dbe8347fd5ed1dc4c27285364f63650f161321daa83ad41fbc3412bff800c062a78cc5caea330cd58e63ea9a9d6de2ee069732799f52f49d513c658a44a2122b8427a405d706f740600f855130a0ea720f76b3111dafddf0e2ebbd13f60640379993889089ce508b1343f485457cb8e0c09760d3199b4ea940d584417259e41f2c66853ae4235b6f010cceca3859952b3daaab55da14adff0e421e862f138872c2577637b3e12b00384cd32fb3b9c97b0d59e51f2488e379065d79f5a834b076ab5b35fe4c47f2c4c4f43e622527abb8f682fe9f262d2883fce5c9f16b7566c4e078b67611abf72cb8a0263ba12a6c23b1a04458c759f2bdf6dbcc460bc5df48146468073b61aa5ab4a9c5f6c006f54f1bfdd85373f33af29d68580eba4cb6dd88054c81b3bb7f2be8186e380bee0b32a1b84ef6319798079828080361bcc27473a9634c23652ed6b2b2c8f8d5a6721551c780870f1787726b121263e74c9464a76282dca27249b4532e49455a7485e2cda4ccca823f62d3b2869602197a6f1ecfc9d92ab6e231996e603e81e3dc648aebdfb900a3d929502ff0bbb3dff813660c9d5a417d857c19754ee04e50f1241831517fc2d2a71c5e238a944992cc50b7106aabb5482fc7e0a2e6b5b11bb6845f34ede98a18d5f07759e61603de502b5eaabe59a4d2c69f4b0f8e73a9bc85b8950a54bd91bcd0366dffaa0df736dbbbc35d6accb5ab8b22a870374521f2035c1878718d7d3b025838da75d8bfa3ff36b2a10a3cdef1b150abf3b6be95a5c096a921a3eced20f509dac4ba43f2f515af2b65d3b2ebd0da2d7a58500157a666b387b1814d0a3e84f64d0fc44507b0b6792c0c6bd90ab62e0f75b66d50b6f842cfdbecf1fd043d642c5d5b5fe5cb68af62e6e23cc6f0f9b1cf3cbd0233ce48a996296b6609be1c9e7a027cf76615dd11208f1fde119099352cc17e1c9a22f4b71c3e628d72b620f3cb4bd40e4294ff8dfe19480b5b758b874a737e6092254638a222c83aac52fe0f66670454c313adb0dba2b4e95741d27104bbff159e999e23103c00470a7feee6f4a35f764ec81a8ef520cf1e8623fed3c06b63c022e40e7638db269b8add119fec50456b33224c14486f705e5b3339c6f38aa4ba6dec8b098c27447185ca50cd70772e5389ba703a4a9f8649946671a238e1f005aba0b3a18c8ceda9daf4cede6782d27931c638af3f6083b2bf10ff0a632ebd4dd528da3aa2b7a8bddff2901d902b26d518a058921eb0178ef08e24f7075f77ea0c0d0e72f29847ac7826230c0ddb5e7fc8552ff92c007e9141f51384a12e218da4fbfa9a7a4a1bf266aa975949e120db1b6755ff04adb07c66ba9619b40396072e7cc01dc3dd56f7a2f928a82c8906be416f6d5c41354881f9a6c66a927292f8cc2887aee86e90da32fa3bd9d72bc26dfd334f943305fbe4b645df83fb72c565f61860a480dc0f2f3360368ec3715c2c4a312bd2653051c8f29fc14e0c3d1f515e04b75ec02cac2aad8d411306969d9a8da08c3477eb6201bd54c6ee643d87a89c78a5c8ad48590b7a499cc44ccb812866a4c48ec2da5f1e0aac741464b26988459f3724ea4cf103c27e4a43e5a5fbbf94908878894f8b62995aebc20e632d924c82d9669f64b2093cfe023cdd1542c8f9d19e5e7ad6ed7920ba6834cb0cb91bce48fa94be47c1833c6ada4090509ba38defab7d56dde8168bac8021fb5a2aead00809f1881d53d26fa9cbc824488e16062fd9f68726c837234a82d518e3d10c9931295d20d9affa5fd18c0b2dda299cf1d6fe0c6e6959440af9b397f3441bb9881ba1d2df295d12686ef6b0bfe52fb2bef06620721374328551040d2fa434b161648b058b74df2a7ccacd7609b93421f44a136079c79a3e63bd3b4f79717f3c121ceec2c3918464f5619b1a2e83a7709fdf6d1004b0ee51c73e740b20e329847304a82802e02170db386e360dc6027aa7ba1ee35d7eeddb41ffde093073d92899d568bedee914627c8c48427376e7b5d5ebdab30e58147dac5638090e9c71921431f025f1d4e3ba3c68437555357c651336b326c9c519544363d5f4faa91914195314cc873ef97068d928a6b4e5c6ad70ea7a7b09b3108fd5696aaab800eafe463ee52a3f29e1bbe8a968e84b762484a13714ee260759b4492b749c46ab6603c13ece34e301c13bea57d9de706edc839f55b432b9299d2d6643817cd9d32d0d9ddbdbb23acef51992b62db024365ac2db4c432c531cc1ad18c807cf1ee39dcd842aa9a09b232cfd09bfce33277a8ed09953ab3b5d24e5a8a02fb4a02ceed705185880ecc47cb245665cf640ded4015b4afda053a5d1dff77e390c8105961cb3a954c28ddbb9efd759080dea99e94e69b03b928c8667fa4797dbb3cc6ed093bed107c817780f60729036f13346f05491fb837ef1ffc61be7b61d0b7f8dabfd49ec24cfcee088de38daaae6b4e740ab4faf16eaebf89962331a99f17ca5955b15dd1fa493b91e7cd218aebbfaa7d348b1ceea26951209137448caa93fa466ca32eda497a5b9a4fdbd23a10d9742e74c511a1648d00bca3ca23abcd4f18b7cdeb362e020c73888b76b83e70d26ee358c06933f77d1221a8ff0647200e451e971fe45c23aff60a88baf46f59a0bf94e99ab9337b0336ffacf8e79db92067d2b744134cefac1241dfda288f5c6ab293df7469ae0926c166e999ac99c8871e571eab03f82de73e9de2d8f4deea3724f795480cd47e304f27f2567cd94cbed52e06f1f1cf7af2feaeba8b95927eff950bfc26aa0cc3e46ec7bd5d4aa43374500f8cad4f153cb586620b9a0deeec2cb12ba48bbc8655c7fa70ccf94aa6891b5cc8a3c98b482d906d72e9d425301d0cc6fb4ec9c4a5bcdfdd74fdcef68f05fdb78f2a1c5ae32c28c43ee900738f31ac1fd337ce95966b3f557a727e0c3ada6c6aa61219d92fd5cf68fcd9b444f6b4fb6178b9c74238d2575f442a298127f282b5ad416cf6a365a214048489139918f93ec07f2cd864f5482c418c7336ca4590a7da8a20d33ffb7be19934c80b64f4b982a55b129f4896685534b83251d54e46a2971c0bf49ded9b13a77ade3de9a61f2204a46ed9cd7bc444801381994c8ca5a66abd70936f8d11e2a2fed78fe9fe8889dfcb979c9a3f11f2c2c1aa371d1e98c4fbdaa95d58c6b22410c0d3d3460077dce654a1decfc829f117bc407d06ad9ee6aa06bf818ea2f25312b1cbbb5de527ce9b5c5ddcb0df21e3442ffd149b24af5e59eb4d7e18f68b02b26e57fdf23e7af4fde3e672990295c37186ca67b2abdff6b46e1ff106f041279b61560ea2eae64649c65be22f9070c3239b0cf7929b0778c43dae5391d8d3b8c335ceac672376588a34d3b9c61833578e8d5a9e6e9f72748d860d7af98f7616431d1ae1ca20db3db6ec99d59fa98c25a1cf478e1b4a643c2fc9d3e482d56bedb1b7a1fc9c3e788d9de281c7356b82e3c9e1c9414a0d14cd07fea5364b6a22dcb3b69b6f447343822098548e3ca7e88a83187db145bda17f7c48cb00e6ce36d53e2d1e4c169569ee3fa03620a7131bd5c033062bb82cedd0d0ebc1025937b2d85a3cbcf6ef4458a57525a66244be3a62b582bf2b88549431cdce09f6407e1bee83d3fbe205f585cc7cf9c1eaba047a01f51e13bbe0715a9112c451f1daf6074a1af051d8b98863b6fd03238ebe295995d60e7a26d2f95a2b4b0d617af299133bf357518b84e942bc36a88b4030d91a7067e7a2ed7bbf4e9abda8c6887ecdfebda04dedabb9ea833123507835e0357ca1513b471da73102605ed03297b5e3eb7d3bd01c670f992a7f19962b706e8d0ae0f073638d633b34a1229b6979b8e90f2a536cb6024c644e1f7ef211451dc509e061b294c28be188c96246614a1fbf52db8d9a99f7100c878c1b9da98ee9e9eddf7fcb386061ddf46807c60b24d665f0fe7fde205f91021bfb87c8f4c89b5da254d185bda9cc2f48303b483ecbf934575aa45d0d58cea64662f0fda4d97790bbcfa237984cfb45a9cd611b533dc0ea997d191d14d307c68db318aee8f99544fd48fb86f041fe249a14263e6657a5ee732f7c5c9c97a8924bfdddfd75dc67da65042e711a3cc144f46d10a1a9fdac1b1b321eacd235299a1fab390df24acb739d61bd60c6907b9a3827958198e6e2b5a1c90cb9b44cf8db9b6e45f710d7a39c230ec9cd855af797555fb1d73492e29d17da0b6dac59c2ccde0715565efa1f62898c9b26438c60fc3b9f859bbd33a8e05e1d3d5a762bf19bc7c32cf7d4c6bce26fec6e5c8c537608a1c2aea2e1e5cca5bdbb45a8ed048514ef3d298e7dfb9c5408d941ded6220a44c184dc90c922a3ae31c9248c5f31627389770a59f9431fd0139c5ac0f08f69151a75a5a6a0355b7beab6be9829146ada371aa5791c861dc77598f09448af20deca73cf98a399f35c36f1167ba426c6cf4b8b9b8a22b961bca83e45bade098e20782a9f70bd54fb8eb6eda3acd3a5bbb553438cfe37e1f7fabf15729d6bd562cfe379d586181b71b3d3c4b360852003c4363a8d473198130642972eb3434c3a5ca9b497ec7000e821c3419aae75866496bb1b0a9ac6cf92f799071e06809f1f3f904cd18f32629e2093664755803f62f45942f5a358cb1e925a8694998cb14cfc52733c356cfd739c3976712ca7b007e08841639da14e429c102a8fba3191cd36c1c56eb06bf69afe3f2afc4ebf137c617faacda6baf5cfdcc6462ad02f63e8a5375288d0de5700d0f9f4ca82a65bfdc405d3f96fc663658f0aad91305b86ead3b21bd6561a40db0f2c5b0937ba5e1ecbe91e9c50b1dd6bd83a8145b033a7bb6a4ad4896e0ab160e8a52d39d2756b1c8d8570f7081ba217fd8803954290788882befde24b4971723b0ecbeea14d23c92eb6a0d7022a84aca072729d7ab1a88927a25f19a2086f846a44a2726ea26cf1b69c58243e219c756d06c361e1e161bdff0eca10bd30d23782b3374ed421f50cb66c9ee063ca622fa78c8cede932848f0f8f91bd7a0eaa324377c109808bd66ff463a72389c4b49f2e349be70d07fcb56b28549fca65ad853d70df66b587390febdf6b1881cce6c1ca9e9fdbc9f1ad68ccaff97234325d3c972b57ae5723fd73f975ba640f90e717e9284c111b76367c6797399452d37df6b8b8d22ed5e7dc1481a415fadc06673ce4eb6435d31acb6af68775436629a57db7a0aa192310e8427468e8e310bd3426b7ffab00110324c0c7e04ac6649b6f167fa8b928b3fe12ac162db3f2bc355295650fa2d976c64df69a8017034683bb4bd4baacf1cd8502dff20430d48c907107acfc4e29c584cb497b7a471fbde90aabab25290d853b8ebd2c0d49c2c201eca42a68a15879cf391671946319427b237472cd35431128ea7ab6d545617321592c07b09fff93e71596da30689b3c15368a1c3a57890e0ee5752bb4356290024fd1bd2ebfa19f7f3ca57c36d296ae61ec5581ceb77618dde2821460553ba0dd6dd68026b911f4af1be3986198966f90ab757aca2f5143f1937d09c3a08047b797781d1639db4030f9e59f8c5b71a71787cc84ade5a385ebceb1946177a056179aefb49e1f69ed0aa67901b2d6b2152b6c1fd1db67f358093180fcb8f96483fd35a87fa14825d3849dbf479be493bb2d1c639674bd195b5ea3caf49c2b78eb0e953dbf8fb909910c87efc6f9b6592c020333e00f83bea4bdebef4e107798f9a8e89fa5d063d69f88f31a53548ba2406407251f18c3d1ca6e392fb81a46107191e6d906b487469d0002afdb0f32c39873872a49eee649250d4d5d3a7687fde2952291c8ba78fd9b962060df12d212033303691b05eef0ae0e7f31b7e395576708d211d70281e9501618673afac20a93e82f060135e51b29132a0c9244551814bdf399b746651279ed135d162e366f39d40e3a49e907f72bf7c66fcb4ba75b1f447fbc3ae3f390ab4c10963d755ee188a9b0129416161995adcab12177976208e1c93ef48d3ef55ad22bbd97781dc7035c9f5fe25f47b703b1ed50dba311d24154ab05dd88ccbb5a8cd96d4665829c4dca5d5b22affbfd7e842ffe5e87bf4326f957392229bbc893b1fde9e4b2191a3345490d418e9298179661104f70bf6cf9a0094f9d37be98b82d98497573512d8f6fb4b0b0aa334a9120a5afef20e0379197ac7ec78da3688d2c9b590e40fcf866acbd1d857546522788d1f3ae73f330aad045c5bfd59b8a399ae626fd67d9797b32d6a279d42eec3ec8a2888258728f7c329c4efd0f71b730e57f9bd87204d40ac1ea6032a4b8ee3a338aad58c2f3c9795819af4cb652dedd475e5662d9c0cd23e72a8f4e86f1a63e5683c814a99a6595b779e5d715ac91ba62c1ae4ca1651581506ba80c2ee0d3f97b979758cfe93f373873f4775c882fb3b5815b9274595bf50488b935c82e0fb4ae4d078d30bf0843c89e484bf5a24d5de602649e336fb2b79da6131f96ef1b5f82cbd668f4599fc9a92b4e9ffe3468e39e4c8bd90531952327da74a522e479c66b7b1554c9a72a2e6db58fcd45588c9ff4f48be5ddc994913833b668c275174b9d862dbe8fd01535ff2bcff6ea030842ed3a4d105ba07feb0098e39f61a4cbc06bfa153c598c10c5de57caa413752878c7599e5db8482b6f275db2185c505bc0c9670fa0afe37031eab994120acb935bf9dbe6cee6ba336dce1b44732c4267ee77f5db890041e547bde486335b9a0b85d6640f6534d84b3729b3436ac1c0551d687ddd8da9abc18689e7e932d5d0e787ab5ee5f36eb53789b9ba2b71d7a4f7994e56b056d4a042bd2cac79ad12d87726ef8cb97342e616269e9f87493e95dcebdd91763b134019c0a76e8b12789b026ebd1d9caf1930010aa1a5c348ae2e6273c885ffdf8731b34d87c293e77e9ef14709c2e3b739dec85d5bdb8f5ebc9eb610240576435c8d222ae0c8ebe5844980560bcfd45cacff143a5c208add9011bf9770b7803fa90bbaa10f58d856250b37e481f325c538e473dee7863957121374bf12172321b9c99975078e43a0e1e40138f9c31d6dbe5e06fc881de840e64899c0cf342a806916147de3cc342832a9514eae9550d2cd1166e823f404a05b418e5f9ffa84352cba3007f9d37e5b00049d7c099346257fb53e86b919b45a9c6cd8b67cb3c4e383fcfd5789f2cc087d6b459e2a7dc96d08c826c43410b3df22021855c7d413d9cfe7ca79fa860918a74941e08511595fc9a3bec2e2e0c6dad05781c0a0d6b6609837ca8f78b0368b1217b121cd6ced8fa48dc131709434eed65523269abe95f338bc5e3fce0046ecb24dc1ad8c8fa68b5f9263361e4952ca1aee9229811a5ea85c9c4452235639d1eb8105ff88c048beddc0f7efd3690da8b9bbccbbcfeddcf3e3c9e3ea7b46a5b40098fb85a25842911e42a714c2dd0fab403340ddc1af9484843b33c7f5bed80fbecf68180c9b397ed85c51d39cf08c5c0336b149e6d1747360541e84a93224ae88c1b62384b938ae25ce17d656b9ae52fcd9100a40dd7793ca67357f3fb00621863a490373f0db49b1aebaff7284d450922f1e5243bb7fb5f7230dd7cb8db1e08893696908cad4a45711eadfce8b0b42a9aa937cd011bd5c4a8c3a2ec771b3ee4959eba5e4a17545d1c86acaa4805e4aad"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0xa16c987b93f1b3c51fa8a9833c8932eeaa566ce0",
|
|
+ "claim" : "0xb0c578f123a8a0c96354a13f98c4c2cb8a67541f5ccecfdd0cb6e61aa77f7768157dfb3ba59aadbc03350577f6f31b4083bec30291a61ee98ecb3db2536f788e01"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39cf29ab9b80215a9947b975d8c6097e53b39d1483c885ff7527d7fccdd2ca3dafc32bfbc0a19c857fa8be7e52e25064d69c3b7dde6e77eee96ec77011fee440c8bca99a45b432b5468715a0aeff9d61375393b3ca40b9140e1a2bc2a52c3c8a85292f4c9e87d1e0c12fbe4d7236ba7921b8b83bd10ad554179dcebf0791c4b593c8a1bae836883d5094499cf2ba41b00c8c36c77a83466c263a0b01e773f08ec66d46e97caf0f9785943f98e159e353f0d91d5ab526279477a5509129f7a1b8b07ba82a1ccb4acd5be5e40de088f2600e06a8bcf35f54663279f04c74838294048a8f8692904d4f9eaab49635068df74d1f5ed238f6b895acf1364544747bb10ce333a957599594d766ac5d1a3ceecf8a6696cdaa95f824ace18cc551e1f4ec12f345283b366314515849feb5bf81fd203a6c73b5bab7c01b5c1131d442dadcb6bce32d6e13c5a3e77b66eb8f5b2912c0938d89ed9e20a455066d151a973e4509b03f5d66ff7ffb8b362e0c09b969e21173693d9977ba06d48bd3b85657119f9dc3533c91965ed81d1eba72b46cfcff285131f84306fec7b271a02dd22982cb6399a9060d286aa18a3f97666810937f8a5667c94959a4c27299d55e94564dba27ea3d98cb3a9db6197c842eafb237649de3fab72a9d56098b5c1228e70dc062617a8a6b44d46b7899dc1e53a77b700925ed1b438c59458c15e9b91fa2c2164b9661a976720eee2864efc5363d90beea9789a6d3b0628bf4695a853251c7f70ba1ebcea06cb35cb47d72d2340bb9412edc49626d6c78be644c4ab1c539d1469d1cc63f092ccac45f66917d89274af9c84d7f1108b1bd738408e499efa63f1a87c8730400ec19f9a59d241032e9ab78670e85e8da24310b13e89ad521ad4fae3deb9d438dd7eac72b79496c7b65061314ae",
|
|
+ "slh-dsa-sha2-128s" : "0xb8f14bb6630512c51d227c12a04ce7b316bfc0d255f5a5d1dec3e1ce5f5cc92927070079430990b4364200dc6d389fde89c78649e21d8fd3a17dd2de7444e77ac3e8c70eda15f2247300fd8e37e1e3c2afcc3e8dd674823106b4297ecedc924ca948a9f80afd7ca1bb85dc0e60e1ccd5d97eb21062b2fabfe94827b4ce5f0e396e5a891fbfc61bb827cd305012515d0a182f163c1a5ee3827aff289ec526cdafd2874c457947e8a6c8332ee7172197cde7388303992be248892e727b559c0d74a2c65d46b6686a48f0b814bbf031d1bde17f55b888e7cbaa7fd6dcf428b13ca43f77d80c3804bd2840e5768c2aa17f6dc773b71f83eb7803fd9e1f1a2e3e158f7e823e9667cebe136d333316fc670442a8c662930a00f72dd2dbda9b19c3dcfdd09c60ba55d9ffb5d5b3384d719d153566bc0b6da89d8dd869fb8c4113258014cd48a67a3591d37f9ba767ad70a554ec98bb59275ce163364915051411db73833a88cab0d3fdb7c491b8580baca2bc44a7bcfc3a51c28ae0a1fc12bb53b2b948c571397a348e664522ea749890d1c7ea7e9561596a3e930bca68377e4d4c0e0301472c8017c1fd5702cd6dd4c3f5881ec4cafb98967a57837c3869720268b61f37836d0c9c5ddac850a835318b17758a6f97df4d4966d516ef100b7e61271c45aeb89242ac7d2b8ee45a08f4081727d54cc08ec0f8af9e16bdf6f6d6797b9f5fcff9686f15efc4e8e34b363d562dba239908a3992b3548566a30cf04c424383b5bea0a5011ac620ee384f6363fca87daa30fa88763146bcfe0a160c071d79dd8de0b11e034fddc032e522b7ee47f318cc6f3f2b6c9b6efa0aaa9b9a9c1243750ea31ac01f087d5f4f5fb97b8296b0953a606c49025f5bedba6773804b15fb3638e72ffffe38ac20486e18eb21059f419b0af9071be12e309a953ac82c0a5a620a7b5c850027b39cdeb5d728522a15c1557e4ebc3f4f09914b3a99e291a814504ff7171c23eb825d2df1bad1ff29144f8a3babcc882258e8a6060272e95c4393fed0ad86698554515e77340ae806746ed859ff9730cd718c767e320ef54fae5e0cb8ba331bdb920229d6047a6db8bad147b75d376c3e72e06fbc6a542f51a312ec831c704099b2eb0f801b68631b464ef484eee077cb7fd9ea951a0307e08dc5fb4ed5a6e62048b010ede39efc5462ccedef2a4c61ffdff63fb3aae19b28ca48593532f051c716835a61f2fbbd5c25883f4a85b48d81658b6d7cc4227f90a81e961c5fd8a388c9efb78da1c9bc50d53a41d2d336232e84e3eb3444389caa3457ef9e3560c25033ed45242d0b4bed69fda4a4f1695830c843e63147b6c2d3f9bc2608b0671e59d827dc1e3876e5fc6075bcdf95223f73dfd11d64399333f7bebdda7f5c2838c072f7baf753a36a1ae8987773fd0ae5acec41d7666c84c1125190f432a4d82ad9b78e22d6536a8135d80a3d1715d17a673033d37104857278a75c2cbcbfe0159343dad8e98e42874e2b001bdb469c9faf79759c4cb3e3f2ccaa16bb29d3e4dc81627441d07469dfb9f545ed83d9c20ce586370be092f3a90b18f30866336c6db9d53e2e0fe1f98c655f1961997e41c25089a518f05270ce06cc115b6c2e9c04f6ba9bf7ce3abfedfada8580ef89f2fea98e8a19c58a0f3ffb89dadb05dbdf05c44b79ad5e1d259d5aa6086cb295341dc40ff800b460a5ac602a687d6feaf66393dd2be22264498509c9d39033aaa22eb248780a3661ecf0a05cb6629ea3d91eb0f68465485e8fa3fad3fc4315a118e4eb2ebc6e9b07284697cacf0257edf67c20b7b0311d3094f4647da567385a508addc9b25a66db1f1544dbced87886946989682b2f2db1363dc635e4cc3c67ad83bd311437d22d8f60a2cb7833c952bab293c9e20ec2b44e1f1f42a797421eecb2e9e9f5e47105b9e7f5d7bd796c360ea39dab45ad701eef0a76b7773c55e7af7909d456c213b0db14f985d0f73652bdf39a6402cee104a168749466e477d8a399469992d65656b607fffbdf73ca1bf4976d3a0c0c64cf5d260d6d3e0198f0b86c451b9ff5840968a2b60a8ec286c81fb55741d7bc9714177c9a77219d3a39dc1d6d7adecb7f8f85af366ed653cd81408b509d0f56b5dccdcd1d982d115754364ca3f14a6f100c54ed8ebfce6b0dc3de4435507acb0c4d974ae3f2453867a70d5ba078a17db34844ea410af4f842dd4a9879a7706b18ddbf94c7b43ba137f7f9b8b3924b4d917f8e0262ad10d083c4dd3b99b70560377ad31784a587cf0ea1f99d6faf0f04a909179f3f93c96aaeae014ea1e74d9d7ccd0eb5ab466a6caf8ed0fae75cba902ae05244e0dde35b8c0bdbb3354ac60875c454ab11f49e47e2d180db319a113a5869bad3ef4580bc7402b0d6bac10a7a4e81403634fd1cd272076074e714b14a6efefc902126df6091330ae387e161789198680b0258c341b6f3ec0b09c7674e9ae8f88699fb7b2f88fdf2461e11ad483ee11fe4e3ddd48ede0ef0a1e54a318ae12473993a8456dbbe8b5ded40232b8d2474a90424281830da7bb36091ebcf591947b04739846d8a600946c2b892e2bf3353b09b08e3a141f33f6ef83d022666d380da43991d3eae4e62dd3f9432678e8be1cd4b9569fa2fa84e95195449716423688aa920e2ba1cd41cd5538907ebdf3ff15df27900ba7ee09f3e9194e1d8cdc0703d6f38b2b887a89b10787986013f688f9a355c6a362f4797576ba022e4f1d1d74e2e31dd98f1b617b99516c944bfa5bb474857fe74a09976cc29c71a7f5b6fa529f3e0c00c33c2f0700064fd507461535a35c0dbc5b69d413fd6ae9af49ccc5d02d7abac88ef02bbd40475595176fa3b68d602469a89afc03359b032fc1f0ae255d623fbf9525bfa36ef98467d5eb2f80cf7c72a04b557e40995471c7adb8701409830b232693bf2fe905ef8b1a32c4b8fe3300bfc5654acfcde685547d5c1b0c213294235b31417da91464619822f3535c93549ab4649a59dc3620e7f4a3327c0e421c5d1a28a2b4c3ba8ab02950631ed54690cee35bc4147aaa8477cae505a1d1757d85251bda5fc91cf65772e1b543bccee1a2cd0c26cd33015533a0e72c815be8634efbb50ceb0ec3c8a3bc6c84638ae371809ab87eec54b934343ee9ed1bebca488d9399a1e347b1647d108652243cf2531a4685c282e0b9e526688a3ae1d10060a78467e6804b705c143d073af664cb72ce657a7d210240011d539cb3144e9411758a211238a872eb4be615d4813b64b8df446d2741db7c9f0af2cc4dc83c0febc41adb5d8413b7ce54ed564e899c0a5a4abcd1cb44c84505915afaaf93751b11bc8e96610216f71cac8d3c9ddb7282f0f864400bdee42c3e5645aea1aa5649485435ffec9e43d43e4341d967c9a89eaaea9cca12e2089f3de222e1a5034baa32372582023b5564909fbb67acfd2a40d5ba40de2d7a31cddac717f5702648c0346e197f99598dc83edda7ad335f9e711a0835c75d4c32e3305e4db9dfafe171181551a8dd5bff89f8a9fb819eca7a171d1be47fbea0e2838a1f1d01f4e68c3d0045da0ed7d3689c17319ef5f5d178e6cf1628402c40d2095c91f7bfe6b837d8f86c5b2585653beb650fc29096f13617ce6d36fd6107ac83c7d7f5a8639e519b161581dd58018ace297bddc3421d358be70179b14bdff66f229a50a329bc30b054a95d0f43e7914a9137055f4dda000357fdb5e2afa3d61b9816c03697168cc022f0418ee5ad7aa71617103fe17e7f47ecf7ef9bf779f157eea74c3caf3821791ab628fe8cba64c12d3226877c48b746d725c46b0ccf5a18f869e6680f1e5ef3c5e7fc2a18915dfd8bc12676ab94ff4401ed22133ac1e1ba0c0352a30156bd80b63eed4a7fe9c948921e1a9843127f1191751312180b75f06e33694853a05a24ee30cae0b02a0be49db16f6f06630ced9b5e57cad548dcff70b1620ffb17e8bf8c247a962d6b2a6fbd4fb3c89e3aa4381e15b92f7245ea700e76ba99678f4b0c998ac90bf3e4b9ba5b52140e15e4b5a38e25462c1b61953cc2068d0b9ebe014db6b8fbdb2fc05751667659f40ba1cafcc2055c364116a058e286f084c2bb73096d46f6736de541b750ad437c27a92ea51baf3478837e99faee73f2a2745918f81547c45f2b7083befc6387a73366c175d2be22314a1fa73f11571395c7fe9df062740c58b56b4982240c63b8a0d5886a3ddbf6ffcbd705d3bf3713a0e1b74497b8c1f34e204ad81b63f27cfa5215d275597599f60d02bbf6cbb229088b56c96d73d09fb3c36fb3f05f4266221984fe8559619da67bb7314ca66405cef4bd3086940c4a7346243776a6fa128cd9b6181d8f584f482c502fce3339f87e4fc5e3593b7a0a64c19fe76c51a29ef776e478ecdd5e093b2aad0ab3cff0baf73f4e09d63e9ccfd4aeaaff147ddf2e9f1e3e6cb3bc9757c57072a1a8076e179e50b0a03dc94de86fbb99f0e92338f26b6ed7c863830f325d3606189b80c8df5a763f422f26436f753168b53bce965c562c2554081cb4eb42d48daf8573206f818ae66d62bafd151e9784d6a9304996b4b82cef081af9b106b42ca4b6b0b2401dc21d8875f9801591234dec266f1f218959af60351178049b487b2784183349e0a7ab361f575fd0237d9f483590a23401f9085b111ac3d740ff4c3eae0b7dca3d149243e3b1fbabdc7431a579652d522bef7023e1c6579d2f6852f1acb9b7f20e3956af8dfbf14617f14981f40b1b2430920be14284dd5f2771f73091adaf9179b8396c6ad2a3579befa1e323177fa2598a3ef80ff5785dc2677f87e9299c6bb16ef2b2080e91f6fcf1b9189e256985e631a05cbfb6427eac995e683f494751f7ae888bb0dfd23aad7fbe942b8100d4daf62b6b8e4d647c818ee7edf0d4d64293edc3b7b6e08a8b9b71a7c38f55ca76593d35770185637fb473da423069de005363ec25235ce816f4df3070ff567f919f47dc4fcf57c168032ef8d7e3fdc5a6a1dace2513fc24f0829e8e4b964d37333febb1eeaa7b81aafe30d16fe64b6ac037ddec2dd9b372c657120df4372504cd14be89d3719c5aa6d545030423fc50e277eaa401e8bb02d70b6614e9768a7e42ba9b35af8f9e3f7dcf175609f7b91a16fdcd65a151c0e85d92dc8a06cddd1ff77d150ccb62c612c90abdad156ced839e837c79b79f456156a28c45f3287cb86a9ca664a13313332a1ed9ef4b3a3df864eda7bd55a6d8705567bd8d1d732f65a324aa6c77f6dd82517d5274343a4e16fc8f41f5a3809e9f2cdec445b88309c9d1de684032a10f8944157a3dc3d4d8d59721f4f9cc0b0e1e7a97b7b066523f7498e0902ac5aa462d9bd096e13c14407bef96b59297391032a4aef8c543cc8b60217ddd5a5d815c4ea1e21625b52e2323b42b4851b0bbc461abad9b71805e8b1b2a16c811be69140d3a6d32d7aa9d5321adb57570fc2e62618cac60a4cce2b011a4c8ddd4dd521b6864c7c4562d8270dbbceec91bf1cd7be926d6b66bf370839bbb22856d1f0c7b2b7119ecea6278793186c50b045d09a1aae7c5bd2ec54df1087cbd1d8094293392605321bd39ffdbbe510f0e8760bd35074c4b0453604ca1f5bee056175ae7943183212ad527e125d2ae113d83c5a4ca1e63e8d89ba07ce8fac8257fe1c603031a1fe2e41bf922d7ffa0a610e0b91eb8c3147262fd228a4ab54fb520b49c91ca268d3954029be8677229af3ed232628e7d3a752e66c2171d1746b7e31d2dc8d1781af454822f36b3ff40f7683fcddc5aec46b13890a6c7c9531f30eeca923f198f4b57112a94e34673c88c70bcf80ee115de27ef5268a753c6f827e71254b5bea2a4f27c8e0e2d0c3f72d051558700196e80abbdf452bd70116c24f635d1850f9466282ae761f1a38a8a0fb5a02a9e1b99df55616f0a7c031fc34f190dfe5cdd4f2442d16ccb49187823fa90f3f87dc0966c4cebbb7472d8184e37522acb165f5d3b508f6a62623def48edddeff361d5ff37fdfddb2b324c4f545bfd5cb98d258edee6ee6170bd41135ddf4c9e358433330a5b590b25fbb276a2284b2df18550270b32b65d9b483fc42e9610537f27715e9f451bccb73e1ce017aaa39b65db4e86c86a50d0379398e57e0c34fa64f73acc0d2b4e953a89ca2f8c01b10135c2af5c234dfaa17ef97941aacb7cce96cd05fb246b76f15275e4d2a8545e52726a48f269d1a558aa12588cc78919a5edf6c0e9e576ed58c92b67d00e4197905d74dbdb3700fbde85d26de20cc652581608ce1d1084b507842a0373fd8830c8d3f68dabe93fb19e3189e486840715f92ae4d916a9ff3424b45ded24780b31fb7f76d506339d9f9a545fe0547c675bde44a3b490bd3b52e3b30842624ab5e8986161be4ef9da785bf537954d3c716da5597a859ef7adb40fd8030611d3ac6581e424ff636aff72f4dcd9f315744a3dae6cd386b2f9945140071a5a49f05e8f979115678eea7d6d884a92e4f14ff94dc102355c3aaa93e02723a92417ff49fe8cdbefee7e6c5e952ad240fa7eab4c7941f6ae8d2a1086e1f2ca73eb8ca5fbe3588ae51bdaf18646ed04bd185a19bdad69394ac15d130297c0fce9d8fce8ea2729dde117facb274f9865ffb4f2c7248102dbd96767483cb7fb764fe667d484a3143db514f08577cad8bcf695b0d953e2a3c8710d8979952929d59c8b8ae62ff678815130e68c85d4714e832733da40b933b7133725a40a12534753eb4877c65fe4c75542f28d6f9e805789995adaaff6fce3929e6027338281c6d0c33aac092fe0eb1797dcd953fc1f815df794249dad7b28407c50371a8c81625f6e7e08ed59a98758a9859c41f7436f937885ad35102b0eea85f3dc4bb9a6260f4e091ed983b1009275d43e4960f9422dddeddd09e9990d545cb67dc3f1061238dffec3ce01376259262b4c32c6173a6f1e239f4502cfb0900bbb7e3b4883ca3c64c8ba91cfd80b2bec6aea25b01124ae11a56ab3e4d448038795ff62e9d5ea5cfdb99c5901a8b8f8731c772690dd964cda343bfd020e920b32910a68b433ddd01d117a833242fd695a54f33fce28b506d931adba499373b0a6182e54323f032f1e7b8bad58dabcffdd1cae831c70e87b2c6fee3494dedaacccfdc93fa23ee1a4273f16adbbbcc21f5d02d8645951b93287732cbca4c61a0d0549345160537501b8c0dfc97128035875e73db7eebec24813d03d11cbcc089929b0f6e2440a26d90cffb6295e8fccf65b4d676abb8ff66709913775e611bc843302a475488c9a9310c0c8885b78d5db5cbb1a919683cfd9bd010cf2f1206ab327122ac87d8e2899cc1ac684e72c91f2d36c7bcc3491b768aac86e92aeb106d22b3e85112a2a871bb8c9d0a0dd15c89d113910f8babf15f27a13b10200ec7078d362773f17286228b0d5a58d6654b0fb4f60c81ee581e507f17a044e6bcad4bb6ddc66bdde7d311810d79ac031086d7b0c334cd3a8a496591aeda23b2c0097cefdb6894b352395dfc79b74a6e4d086656b0cd9c95a48640cc8b3d188189ec0b98c8618b0def4b0175f11369cb2f107e89c4a67a75396cfcbe899334a5d5df5927fef2eb8bd836a27a2834a7ab94813d30fa8431da3178da4ae56caaeeee66cf545537ea260ea6af56d4ba048076ace08ff2a446080a6b688a916a13b43b933e506ad187b1f829a1d54ae261651563874cae19c490004205765b43c3cca4cd8a309fb1bfd7520bcc07794cf7c03d9b1d1ae0cf646534f5a97106925ee96dcb7fc1f74e62c01d382fde19fe027a4b9b7627c08e690abe3ab076f184210acbb4229d483f7471ad551eb614c35e019a8a894b5f92f5371fd6c457f135ae8377c5781a8f3a6dadd2c00697bd8399b6f168dd64b2d2d66d5aebae90fa5f904af9f950f450d8be919ae3f02cb5c0be9687560cfab2d2161db61e978ef46304de248383dc3a99e30573bb66f873ef1e54f523ff8ff79e8c05e7f8143cebd1bdd9d2186ebdbd3b66a0a3dee79475cda2890720ac5bc33f8cd3e817d82bd7c52c34d491e1e9d1d307eec17c0c7679af3626e7b96bbe6ba2550f44de7d1d88b3e4c220b8f185b459f1f882a97248cdfc3d42209ff44806837750b3dd21ac5891254f6c7f6938aef3caca6c55b633770772c2c06734f84612a59aa8cfd4f347267e631658cfc4ff89cea84550bd43699c1d8840655f39e3449ea0d2abba1d81196413302719bc9b39cea85cb7db6ab7f00683842cc480503004c1c819ab80e121d9d21f46f362614a5f2cf80cb2c8d3fda82447cd0155fd7e0ec7589a6df2e6614671071f0f956143c762d51172da46e9f61e588fbf74cb3ceb74bf2ce4ec4ae26a28245f98ae91f09cae77c4660d6dabe7cad33ac506db3000d742f683e08bbd0a7cb9eec72a1a976546ec926b9faba5084e00d66475a514a73f01fbe1e79c0ee0066f4b724e4977f3c1518d28ddc918c573693e9b3fb69b426df0640c5ee42cd5533655f9a82c6843516298d05cd970f34dafa886995545c37b3b939e0dfa3647fb3f330bbd3e69307be3d469a99c24382acdcac76c6cb71decb4b7b11cb5f2e63d112767a7d6467c51f1c0c27900803180337f463e64f507ce245f606f8c1f1df836c7fd02502bd3127424804c69f1d066ec3acd9c4374e857c4607b711f532867cef2c1c8a7d7051a440eb7a8507500d86f11567e2fc812a27e63e5599059af1ee90444497f69add7862b93ea050f100e48df7a578d55b6d6321e70ef7a7625ed89054ab010850912088fdc21551b89397c35ab582aed6c215e00d398a857090e2f7cac21c7b51f34054a45f36157edc603b5d6e76ce20f2dfd2c20158943efd2349560666ca38505cc6af776e0720af2d5f6a7d98f385854700fc0c749dafb597e94d7ac54aedf34840ea778e8873d6f1fd7f53de7c06327d08d34a03b38315efd8eb52683ec1f9abbe2bcf096fa4f379f41e09b8bc67ae4685e68ce456465b38892a238b18358714fee41da0aac8dd729e2c3f17488470648df81040272b2e927e896a4eaf6a11c457938421288ff074da8db60d37c6d022e86952341f2b8d262cba0c5a6efb51925517a8c817a152499ae7ee56d36df86253e6b2d93079c89fc922014b03da3941509e979ff8dede44165ca4cb698924fd12bcb02a35deaad608ff3358d455a49e12e944dbb11ac7e9571476bfa856f3bcf90ca9bac6d57d5c1755104b348d2924ba9b14e9ffb750cafb6edeca6dfb79d73b9839092032035ea700d81f19d035e38bdde754a5098dae1c163f9c473b0681858004ab9d9c2c57282ebd7e57c474b8f7aa091d1048b95e7ef887767f49d2a7f6b410922da142ab8605e735ff6ea9e3f36a29380ec43dd009d98d8c20f4052d81fedfee6cb018b2da59d63b5fc153d5b0948d613415a6b8a2b7338897188582d2930480d897d55bec899723b285dec9abf819ac7e6f39d8c35c484ca13f129fa4b334979bac7715bbf5e52a9926568f359dd3e3e000958b561527bbd52025918ef75228c423da41861396be4f829aa4bb6f94f65e662e6ac91e828d721b741d7333a8e3050f136a463af537ee97af4b42456d65e1e2324f72267c07acb88c91d0cd602ef765f858f69fcd44ddc73dc7c5f8825f3fe04affee769f3ab5486232e35df8fdb75db79721906907ffad83c57a364ab85d93bc03ace8998ede749d88985ae41cef163a3d00f568d43115992362c581745f723a2955ed925cfc7c83c5b5188812fa2dc016dc21844f923b2362afa5ac5f2a6c9355b2eaf724606333f152a01c330ed88f7028e716043330a280c5ee458f2032c8163f5548428ce4c529d487a16ca0e58cbf41dc4dc802cc5ea7fad6a50de0c0f2c2be49c3dd2806911ab1322a30acd4fd8937b8930069fc1a6de86f9ef90f407b2563594adad581b49ad1d19b30ad13efb0ddd8e6f26dc43a36ff8d14d1c99b073f5f1ce8923d3100bb04488b86cd4e89f7b9f5b9cbbb3f86ee03b498ae255e09eeaaba3e4e4d68f1ee4d50f699e460a922e17ea8f0ceef9794e944f128efe835f281a7662f959054aa994afa3982f7a310f46f53d5ffc07884aa91bbdcb3f3779ebdd7f90801e96222f56df39ed9c2bff5d4a11be1da7482835e494b0856ea7c695cc1b53acf3b2e2d1846fff50bf55be65e16548c4fc436f20c50c119ca8eba4cdeda8c7e4d33734a0355586629ca5a7c3591ea4b15428a81b6d91529485004cbbf60e75208579ac354dc705edc7bccb32f23030e733d3f549fbb841329a01f5c5d263ce635a57aa9c69432e5213b155a07c34fe19cee737cb993fdc82ff38eafbeb734f04f58d367e34df15dd6044591983b9b45d4ffd87e2a6b478c7d1e86b4b974991b930370d5eaf5edbb53c3dcda643fb992b5fb0725a8aaf8a9e7c4012311f197179cf1293884e2356fc5b624cd46358d3c7bed1fed6b0305114cd11675aa49c1b9e6569817d34fd60c1105833d78dd00117284cd1722074a60655dfc428072b0d2eb881b93d6c367952a4bd59eb902032cfbf9189bf65f7bff592032c77d61dbf778986b491e297ad0da5b367c8a10c9071b8d509b246393fe04a290b3e2291f04eb750285674ae3e9c7b76a01b679787a4006836dcee956185d3b0ce16c4567fab862d3634b93079305008e2f99ed425489bcf5447699b7a7212fe2196d3999b39191e750fda742c6ffb5509e3806f38edccacbb8bc73c96cd46f0f400c4012f1205813d69a48bbd1f55724c7de917ab56d4188716b96653ebe4fd1b6d5d252f5599f9c53a4683ae60c8c31b86982f32bf73401a328891804daab93a155140fdd41ec87e392c8397c9ecbc48f26acee4e3cc279cfd67d75b5e0b6484274484c18f72c2532b4064cdcc309df796c802c17480428c3b5a5467b38aabce03de2a266c8a22d3b0158beb913d50615a1002fcbaf91edc529b0cd38f35138bd71dcfef1b6b90adb4e68a594de40199724c158db9c85ca78ce3a19378ee90dac98b23e1515324fe18472a4ca93b004295b7abd3c146109da707f5ef37886fe1a8966ff1e96375fd64536eece72ae3433a697492955cb182331ce72e8f1804efee93b1929338f"
|
|
+ },
|
|
+ "ecdsa" : {
|
|
+ "addr" : "0x5e13d369c8adbd8079272b624343ee1edfa4a560",
|
|
+ "claim" : "0x197e55da82eb1daa23a5478ed230c6d0452d3c1920df15e10a8d37a7430a7f2b69eb474bfe0c44a6e4a55db9d5a0e0b74549c044ae22778ce30f47a9fd1eba4100"
|
|
+ }
|
|
+ }
|
|
+ },
|
|
+ "registryHash" : "0xe17a14762fb5a1d59a9b5cdf2a25414190c81bf697435e751a50540fa74ca521",
|
|
+ "root" : "0xb78edcaefeec9a1285445fc4fe230e0fe656f360ea839d9c7e31396543f99bdd",
|
|
+ "rowHashes" : [ "0x6134be442a48790413f81ba76b4f258529b161988e4da2c03977b1450e16129e", "0x5f62516dee6156d0814cc7ce084b8902d3acef529b2a68f7217f7d61e576d28b", "0x43231e1c19e422e6c2caceaf1a30094e26f2e1cf19d572e94a4791b332928570" ],
|
|
+ "merkleProofs" : {
|
|
+ "0" : [ "0x5f62516dee6156d0814cc7ce084b8902d3acef529b2a68f7217f7d61e576d28b", "0x1b7dabd6159a5070e03f823f438a70cb6057b20a9585848c2d6841bb1f2f301c" ],
|
|
+ "1" : [ "0x6134be442a48790413f81ba76b4f258529b161988e4da2c03977b1450e16129e", "0x1b7dabd6159a5070e03f823f438a70cb6057b20a9585848c2d6841bb1f2f301c" ],
|
|
+ "2" : [ "0x43231e1c19e422e6c2caceaf1a30094e26f2e1cf19d572e94a4791b332928570", "0x68df066c46127a7540204925b00d14bb19bacb4ce19d65b8d6d0504337f8cb22" ]
|
|
+ },
|
|
+ "ids" : [ "0xaaddb4dde09de5718a906d83be7db3d58e0ae32a", "0x690a7fd66157e5b777256ea5214f634f61b3a72d", "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4" ]
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-b-rotation.json b/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-b-rotation.json
|
|
new file mode 100644
|
|
index 0000000000..95d2a953f2
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/aere/registry-v3/ok-epoch-b-rotation.json
|
|
@@ -0,0 +1,60 @@
|
|
+{
|
|
+ "description" : "epoch B after A: index 1 rotates both keys under its id, index 0 unchanged (moved), a new id joins",
|
|
+ "chainId" : 28001,
|
|
+ "requiredSchemes" : [ "falcon-512", "slh-dsa-sha2-128s" ],
|
|
+ "ecdsaRequired" : false,
|
|
+ "previous" : "ok-epoch-a",
|
|
+ "expect" : "ok",
|
|
+ "manifest" : {
|
|
+ "formatVersion" : 3,
|
|
+ "chainId" : 28001,
|
|
+ "bindHeight" : 2000,
|
|
+ "count" : 3,
|
|
+ "0" : {
|
|
+ "id" : "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x099202fa37d5e165b88428d963d2a224b8fc82ac0e4b3f6a02376f18218d1aa7d0e910e71586aeeaaddc2a557124d6ab4f9a44b9cad02166413cbeb14b364e13956ea326900eb2900802644167639045d76bbc4e051654cff404dccea94402141ad9fd992cef7a8fa6478b3e6f8912886e9edd1b34c29385b7e964f360e0fb1600787934486f461c95d577d2bc74c4dfeb969b4798565ce0225ad27aac052290a44f844ae233e082c97e4498a31117ac9d02f3605c856e2dde6f611812161f89cb3a54dc936ca1e740a6c659405ed586a9a963b11c89b01746325e39e645c72b0c7e4491b36a17d43ffe38d88c601a5976f5a9636c964a012bfbce5f9b371e7c3b38580d81c6e12b8e8f2aac219f96245d35b4f4afa6c94015b055703b8c4dabaea4ce2577482f5b34fa49e56a912dd58d74580b1f94e1d2056594ea64bcdb696b0baeb33c86b6544761a3ead9ba9888cb1ad51f7027ee52b21e46c5eeaf3f77bc0af7efdc87acbddda7dca00b6acc665002c26447e5b0e0bb5ba261717c68dea7f1576462776954d7249c2fd0886f615ad50d53960ca02d581a4a25517c050ed467c7a820bce6250a9ba2e44fd67fb21bac843bb134c95360dc1c50d54b7280a94440d018181a9d6374bc64d782c84471b47287d8ea748c36cb83cffe053cb89a9e4ae71df497871c2a728ef210903e5b7f39550d0331e15637be7e28b3a2fc05b0a9b0c5a06f9fe81263c3a94403d6c288a561288ebaf788bfe271a578a1a795a85e9d452b61ac204b297090617286922376bf0a8d67dd35fd705b81260b7aad30132b965e39bc3cd64d154c4175951704873992a814814dae5c6bc1e89a83dd91144cd1b88f6ce449900058afdc53bb44bcab63d30cbd6df115a5ee8f5380a127a160e922bebf7b408de82514b2e2550a0931e065565e8dfc389d454823a55b03e5c989b09e3791f656794e8379b7b4b1617aaa9770366d63a657f71ff40c69b1d5da518ef1e2aa42366cfa38e448563f6c2db5e3089bad5520ec26105fc885993630c10db357883f588a5a384cd6de688e1bc3b1200f87ed66ba3d4a4b671b2a500a0436e0955904030d76577aadddb8c1ed21b027f198c072f654c3abb086e7f185980f49d0e109c1a82741809f8afd15ee56a887b392c5b172ba659144a7e99e25ba19792d2a3c0ccb481822839c8c70c65c0943a2994ec9f6085b7ac64ce2b35489a72dd6693d25f2329264e063db26ad4495e3ad00f12df8cf914fd846",
|
|
+ "slh-dsa-sha2-128s" : "0x686b5dae4aecd5618b95c3b2a5792888513ba49dd366ac39b7431ef403e04963"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x391de378d9ee4e1d810e6ce145b1819f1b73dab7f6dc2468fa65d1ddc8e2a7e6fd8f185f8945700a938cc0c5afd87bda48c1b8167c3e6607ac864bb2b194a368c33cf8ab6a5eebb9a704d4160b068184264c2e59c4f82b9b4eaa9197c3ba5289c429e0f4c548769279daade1286d354212b1ba2ea4818c974c17770dbb59b65b3b9f891c826721f51a7ce14f94e2ef4cab868cf852ed9bfb17cd33ebdc4d688d6ba12c74aed2c8104d117574642af25e9bc91ba3fdabfdf1ed13c6e59fa1a0a4388925d2254195c666a6c235174a73125790bbdbed463617757fcc17cfd32da7c7f89e755f051aaee186665d9de393a82508d15f88db0271495c959bda6651a81a04dfc2103364f95f5464effde48f3b7ea80af9c1bbee99c9d39b0627984f09ccc6a4c888d121ca34e56760b1c3178e48607325676c484f4d666681f0d2454f7fdc59cca37136c5c06e746987e6a116728f8b0ae1ae9a32efdfcc956fefa55577ac670bc3d66016391bbb833d97f91d3a78696370a6f05efbd77cd50d4697c3df5699277eb1cafc1883776d9ecc72a763e5b65dbdd184efb9696cf58360e73f2d4db5e8bc6ad65bbbe7a8a994f5073fb4b12ad9b5196c450e27a53d8ca231f670966a238a6223b47d90990b1f6796f93eae971d4939d99dfea29d4ba2e3feffb97c0b27d6b6d2ee10751e75c658b44ee71abe9230f74a0d7f232329b165f5b2a3e584dfedaafa9ab477c0c516b6553c58797421f8d1e9236f992b61963c108752b1c43278a9b910926b396292fba67211e9a16b88aa9bab7b6b6db29f30ab5b7ef1568d46a010e8a27144a5e958022be5cf6bf4305f14e10781323acca3bb1d6b567d3fe5f652661dfc54d71ed9e3969289c29bff0c8972899993505cde2fca11c821d9280abfd5c20d4fb53380",
|
|
+ "slh-dsa-sha2-128s" : "0xee44a0de25b75a42e32080200c89b82e2f89551d44da272720c816fb144aa42ca29cc7a0045d97c82676d36286a9f1bf4d5b9e44b6855d90f25e03e3370cccc7665f3c7fdeb6f9565b76745a7652f70b7cb18989582559b81160fa32c7db7915f14c657ca37224955d174cc69de41774e4ac576f362306f3383733b322f8b333d9d0dee44d80e36a86491bfb7441a3c66809bc600399ac9788b4d7796604d4ec423c40dc1a6fb2b02db9a0d35072cb5aa617ef769006c504052596186ac0d504561c815617067f669b29757aed1de7a03c9c0410fb8b040dac268aa95232533eef1f69cc0100b33c9726d55af73b5d608b501b0470c4e9340b68251fc645bca481dc2d375de626580faa7b7faba8f8a596f795481cac23240854839a1100cd92a6410291ccd40cfdf1f70981c568b32904a0ad649de41b32299dd5a8bf50c35e5dbbd474c258946881b49e335e01c72ab6654741e657bcc5109fbda7297999cb4b272302739ee07cff0d1c9ef454a5dc5403cb7c170337336f94d56f6ccf563af44bcc8382de301720076a7ac1edc1ad95dba129760d7e9cd4df609bb8f7b389e7ab1e85e1b54fa5e3f2163afd7e24c5e5eb61a9e8e79dccefaed30f5fae83bdbd8a1673b36ce894891720b476652a26401e7890af9199bfc74fd0aeb6622fed8e488b8151a6c51a11bd808702f945ae9f9a016bdd94f45279d4765bb376df7fed5506b52b74c867c087c3386f74b130cacd7bcb4e832b697b50c796fa8fe4881c3f994820799417885af464f4f1a85989e5e3b54c3bd878a7ab054bd08c1ad850c96f3c0105380323908fdc94771609b10e489a8445f751f75a9b617cb1aec4460be2b53920e52f7d85096065fecbc6f19daae458f657dfc894758f3d9a6519fb4276e16b38aaeebcefba89a7686546901c57a29b95266d7ab87155a854ba9b269ac94a279e9c4bb38e6a4928cf6fdc3984b4363cc44e0e3cd7a7edf08388b9ecd5a04c55ac26b98f98cda79cd3f402caba28360899cca559be68d7a825022f9010e65f9a6564fcd0ec1cc4c0f4029086c90288fa83656cf2ca2cf30d5c423342cd15b9197905e9ab30a9d147aa2599abae71070e40058f0787ae39f39d6e5c1a8184b2cb3b1e6e45c40c61d46af8490cc9af6422a439f16adfe93a3cbe88f63df5eb8fcde9ea111ca96ea7be416d030500f2c7cf967dcaa4d3ed76a613b2bcc034ed3aa84f35556e7a65a8798825b576236798318034204f041dc59a9f9c407d34c2ca2d77470700ed6442cea5282ee99ceb71c6bf074423dc0785a39b89b062f89231af868812777536d0b144212d5b4b6fc7b87ea04fcd6f94438704f985b746a13dd519c57260f87150db4dc483b664944b9e805197df797be099940fed468b1e214ae99a68e99c6b5cf3d30fdbb1b3cc009ea58958eb4c4a7b7bad6b34fcea2a87eeafda01dca5223458affe54422ca70ef541ca8437171943d5bcdb70eca8de02b93098653160cae52f4d72fe5a6a7ad51c6465388f0362e6e72a3c96b9cad2248e8d9a2cdf89747444c7e51e2f89eb19daac76da37180e4133e0dcab15fc72c7bb90c1024d03eb2e630fc6d2537a101961b388e32ca5019a626b5a23914b06e7822905a5e3c21369b69fa63fc9f43cf7ecb6749c668c7a940b82f88c71802ce6e3c68b5c10c9249ba356bb3bb0539b581a8bd6ca141e5dc2b5932251746c1fc1c3da475581f3e3717f5d905f5ff3c83f1523f57cb750dabae0404beb55aba1105b995268906131835718cd43240bae9aecb30c794a8b186436cf752179b1de65b2a87917147612e3c95288a3e816238b3fccccae1da8041b4f784ddcb3d37ef3f019ef997bd8a4e172d397106a5adebb166c5f565016bb1c5f7f1a0cbb5bb22cd642fa4390ea640c04a968fb5a49ef929df1cafbb69c124ea58b31bf066be388d7b6d4c52409581da785d6447fd72b54949e4c1ad08fa64b520f2b8df83bbfa417952b87fbf802652a65df0d388ea32dfcab3227f645b6b28b66087819b4339ad171a48760e2bf90f1a01184389e23e7df583eab7c2dce385bb7a4d60ae5573966f916bb84aaec6cafe710f839b103532f9a7a556bfa116a05480386ddefa2858ac7ebdb58664a0e633a53e1685d71d5aad11f5eeb3d9ae30ab120fb88f96f383bb86917b72e02768f071ffca7e3fc2ac79846a36f6bd72c58aff03f9e87fdbeb65c8ce5976255227778cfa40ce0eee943b66a382e172abc814ebbcb0bf49efa75f87ef8621d227224b7be51b73a928c23a8937570e1a046bf1fd4c6993a9c14e552915953776265f78882ac8302f70900f9d612d2e7b7dad88cdedcdce7e615baf89ef249d6d535f92a2ec90a7435785f4d0c7a75812b875ec22e638f4af1705cc362ecf52c67900c888d068dc6f72a161013c30dcaa49cbf25c56e8937aa4897451061dcc7579ca99a25348e76ff121983444553419e820a3d1a41744f4227dca054c454a6497e0762155e2a06d17acb44ea55f54e4d6d2e1631a63d9494cf69c38ba66deb9d95c0ee01950dff8e6a5d1c46fececc7027997b8ec626f8405ae99ac20600898fd7fc422e6cd3f774b4009f371ce38e1f089ec93ec0a48d6bfb90ee79c3bcff321eeea33a44022ab910458984b75c5089cec0d8beec20c4c39311b991154fac7c0461b7d667488dc9f0f5497cf66166782e2dfb69a71031fd0251918e4c1243aa4dfb9fc2b6123b4f02f436c0f8737a6663af2b99fbd22c6af539ca9389bfb4e55da2c9ad42521ca6978f71991f53fc8cb227e228a62f3e22d7c3eca8ecee260e55084ad3ace0d6379d5eaf82bf6d3b69c4e74fade4210114d95b41a4c004858119a9a9b178d5a0cc97386bfed0dc6edbac5281c2842951a0c4d7da10207523973c676b8e6887a087c1c2f156970cc6db9cbd3c8ec1c9c1bec41fcbfdb4e8929b67e6c1939bb990ee2cfec3197b4ce824d25a7b4c765945e85ff2b096037adc4dd763b87850fb39aa98f1d395c9353ae3b5b53842a7056c011fb690e856401fc6f67b1c0a5414fc229284e74c230ced260d4fafc5fad153a5154d35c3bf9c559239ce18ca9810a1254a0a6c2960a53d838431447739261dc3b055a0b115914af263ac9fce2b512884620451156c40cd84b7bb2d449aad243a8aea3859412476ddbb5eb73028bfc6b2a942839e363262f94795aa45f6579680997d6acd7a8c8daeace08362fcd420f2f8a96801c002361b942493cc5ae79884eddee989af9832d55319ec033956660c5f11b9fbff9f1410a18c0e9a38e9261bdd13bc392a18a3df97aa33e7f59c125f88d78c86058f3c7e9a9d3b37bdb1e05d90375de0090b418de3ca761560f079a6ddf328e72cd89dcb63c9dd0357ec736782696241e2095aa6107a8bf7bbcde26d5d14533f28ddad7fe1b3f0c181c0e6d55204f6ce79cfc557cfb2d54cd2f33adf17a837243b51705bca7ad8cc452e5340732e678274f9eb532bfea122cfd2959b2499ad25a18db7dc387e976f8b5510821cfff778be799b80505cf38ab1ba6b01561ff81ef17f7735a1ed6a319a7f571daf92afb7490fc17064ccb6a8453ae6e66a2afdcded0c7359461278c49d342df84c43a0607b7327853db675e4c9ca95c52ae013461ca0763d157ac992e219a6683a547c32374631b53138676f50ae0d30588fb25de808e1d9efd5fb9485192428477c2f64fcaa862761c7f5505cc650910224400e2a2db13fbea0b0cc358d163c6d4a8e6296e4c9554078a55f23e60de9bea12ac199cd19b97babe61b2a3b853860b4441ae8dcd85d59695393816c64bfc074e945452080e15bcf6776cbb6b251c13be63932702468679b2bd7e1693a1d910e1b62be91e177a8dec8e4d7642e88e513e3a871ca502854ab0fb7fb8a099d0e0dfd73064012051af337abc78bbbc6fa2dc7169ebfde2d40167048d78f12cb5e7c130a2137a0b26922553f43aefdcdcec55bdbee0fa752a4787ea9d1c75d1bcd9d28135515a0ecfa9735901a0eb89f915d036e21263f90606f65e62f6e5c8237db14d570612611b3ceb4d026ac13f473e5706cd7975c95d49734253757f9c1e6aca9261cd2b95722098c5f7c74daa6c926ea4867ab54e4605a15bbf7ab94348d9b45c31a1fbdc7f420cccce25abb4249cf413008a01e53296318414dfac822cdc0bfc4298273f65cda3fcd61236e255dedd879fbf20b8c4843e27ef413c7a1ce2c714c88358091abccd7fed337a7d4f725ffbf7856ea4694113d605b1ff7b2bdbaf60f7abf7d43eebb1e82f4b6b7f3f8fc23ae27b09f78a7a3b324c7790431c800293e08fed2fa49aafe8f5670d4e6bff4cf6e7924993d6e18ad87699da99a2f2ca9f3c7b44b3b61dcfa5f041f7a6df94131b8e5c04069678541c87872daeb2943902afa6ff4798e45a75659568a02471afde44f8e116fff4eb7c16053a7aa370bcddbf5229c231ef8f2e642c1a88f90e0a309d24a3ab28d3adc176665e522cf5bda0285baca5bf2a0fb4c0fefff3b8ea1522c9ef29342ea57eb4f16d69bcf948d66247ed2f2cc4e567476f736d170c98398ac7c0d158f294ff33ec8d2794ec1929c57ee6d7f46da8e40337a2b380717227ed82eb13a14d129069e98cdd65bc34472fe1a52dfa7e466e559705c53d73d97239e38bbd600aaab107ced36fe7d8ef2387a05d8548a48a684fdf02b984022aeb28e8c5eccd1941ae19d2cb12a31de296b4fd1409266c43118848962e9e59a41054a52bf2f20b09eb4e77cca72df70cdc4d712d5c0313ddf9ec8df2d901145341b3ccfcbed77288ce3e4afc677ad8681c746eca02e7f7538d0108b68a922a21d6a8c2cfd67d8849ff5779de1c00588133309d4158d1738e508a1a2ba3351a46fd3f86339d66b1244bc2788de3fc60144d03c08b0ef08914088f9ce947d2b230ffb9ce176a4bd45b0c8b100e17ec7829eb1ce10b1a514b5e33d4f40792f0a300a4c3ba7a912db8e19cb72ee02ae8ddafc2caf116df905640d0cb65cd0c61d38e0a9741d3dc2b7677e8ec051d329183c954ff9c0c2d8771182d5550a742ba8147ec6571bde519c2f57f10aeb1c8900f8324f017f3b1dad92fb0d19a76de75c0c7cb67d079c8bc0bd7355fa25752d5d00ab00f9ab332aa23aaf8b5cfa4d2723b2020c9e494208c61a76e18c9a583172d6ddf544a327c931e8b908830e46f184998fc0d34ebe767e4f5d06f99804759c7e2b76a8baa302d6950f90194b0cc694a0d351374cd028ba6b0414377a850ca2f209d13cb7daf43d14f606a0e549ce14189023fc7b45e2b095a3f45930a72296eced3e2da24bf237959c0b966bb88a3a9818932b1cd41e8ee002df515ec94901902b2e67545dae53e08810b99dade7b579b847a6570211687a62a56dcb324bb442c4fc22f9d85e54b3f939937daba84c86fcc36c83ca87de70fc7f4afed335e8f9aae027e854e3a022a053c3b22be3617240f1355be9af3f4c8e9481005cbef07bf1380ddc012412c31b221275b56c3ad52cb2f7a9b340526e6128416025d4fe497f2d502070653d36f924420c0844b5560a8728e4a3be8b1ce67a1541c00e97aef9c808bd77af5aa280690d98f5ec218bf5c9d135d85069405b82c221d834b8285402f481b7d51ecdca91c4c2b27c12f486d382e0c14ec23c2bdf33ea8ff693af551fbe55e46bd84f335a68646bd092f914da4954c57201d7e812f4974a553f043ace9c6ce2c609cb4d90dc1ceacd5d610cf4723024538cfedc1bb22c9663ac541f89f97b37d2e1b4d8073ada1596e684b94e74c2c2f0087251f1eaa6789ece436b2940d3285f297cb7482aa9b8c47118a0b1d2031fc311689828b64855bc17306529e4b0a3326438b42698dd4e2e0c2f624aa510a2363583cbac47fbf9974925d81af9534d0ccb41e2b445eb19569d703cd8ace661139fa344a5e097290c233114370831d4710676f7e93889ed533454928333655b06ac5ae67f301f2b7944d769892ed76374a1f3861c8624b2a302df1a2f1a60d41e61379ab3681d8eee152c251e1b7b0806aab2f287338b752918cb989d864e9acaa92944f5194f8eba19a18a025157d2c3988163baf8b7ca9060edc2227ade8e05348d86d18f9eb633e4f06ee346e4c2912ed1c763a75fd1baf32cffd0c856ff9b44f1470136c0a8ae0b88175a7e7f993d8469cc8ac3f643aa7db36992cc97011be0a42ff1df8aa7cd82e260e05fdd67304644335b386c7825858a438c51b63f877af005f7d95202b54a2130a1f652ff7addfb798daf4415572376fdd910cd099066e8d2fe251a907e41bb950e960fe5116f4a4fc6037273250569b41ac07002ecf3b4b63f8b853f9693badd2e8bff695266095f4b2f38ee4d60428a45e7586d9d47c01c12c5e18d1ca9afedca6f03384567ddc730fb8fed27516eb7c54135cc7447af831f0c37727997ab2b01fdbc5e12c112aa987e95cf5aaaf44be14bf4882f49cd84894d555655d17aff21f077b2cca1ff0922afbcbf4781145cfb87df585e6af1955db04843a763fa735d33b3df836585c5894e5125d500673d5e4d0bdf6708d8d28c80298a9bb47c7430ae8ec52285a4c14371b3f8ac1e21306b34bcb0c1e3aa7a8dc8955cd9cac32a0f69d0fa0aab30abcbeb2c21d655ccdbae1c2040faedfc7a5ef29cd5d9227908335ebd257ae8c410b1916b9a5bf0e72902c2bcf701a18c1fe13695a8435b0d0129f3db883f428acea8b7f274a629865f1849d4c263a1536421875ffacf058f0128f0d012fd60f2b3fa6b71fbb96f3e1e33faa09b1d20b0919018e91a6bd9595e9c16d4fa6665c4d0adbd77a59cbbbd587029a4f306c887277a7a27748a6f289edfa16c7e4042fc81355b85a994cc6784f5fde054f188b9775836594abd82c1309a66db4388ad49f60794d8c8e1fe279f8965312a1e23c2956427bd6e289e55ec728f66c36526d40aed7c44e5352fa3e2b5d27bdc1f7b3bfc4f095d002bc8e7b2df2032daea9bd3e0bed2733e7ba13c6d8b45c492becabbef0e8c62c257480faaf6aefede888ce1546046f04ce7e06936cbda44c5f33c71c07b53fb3ac7a72c3770838471aace69f7ea454d2980fb5462173aaade7964b888606741270f92bc18950284d013b692bad63ec3726d8f6596788a032eee6eba08eecc836202b06ca43fcdb062e65f8ec91f7400963bbb8094de4b4e1042e040e81130a3ff037e1b7e947b0c3e8b7ab5b539f8570ec2cf08971a1bf0d4f3e8311b5c625b7d032fe2e0603ac1a4824432b4c7bb5afa190afa30c36f168d196fc89015aff8229fd4b299206e8183897229e95ba06324edc1a9ac81aad786d5c9d38c87c48fc6159934a8532489f06e1aa314a057d91c0f7218861ec241dfccce63d60bfa624652795229fff21cf5ca61ce05ea0ad6a1763173675377d1f2427564e397683428fbcc4b97495735d075f84b289b73389a1fece959f9d9b4932f4d33a0907202c650ccf65327d24cc24922d0d675fb59621e2bcd2eb31ed1ec5fddc96593d4f936ad42731a50f164e404b93920283bf9fa43f8be5878d18e07cb8813914508532625f71d02a615bf47018e3b3efed72d17e0c974d33df18ae70e3a4a743ac3c955d1c366bc94d789c90a8b3771969210c7f0c4b9b12f9fedca5d2b71b6c04e7024a0a5e3d0d3c7d30cf568a659cc17309b223399b39ee5efd0cdec3a34b0735df8d7e0bafa40a8aefd742b3e0157fc89d113af5fcb0cd136a9cfb82acce406054aeda30b83ade59cb6771c366c86b5d9b016a74f220a967b83254db3e24d3e1f5d5e23b21354420dfca6bd8454575c6b0e528744f44ff8e1b9679b084d083b9ebeff09df273a476332dfa172cb98c79ecbf3ae4a722c25be71a3b206d848f56b02fd04bd32ff959e6931bf6cba042f9fde027d832632cc40d4320166f9644296d2dcc845491ed780cb609c0432408d08dddc70fa2d52884df47a55a8a3e706a24ac6ceb375a894636e1ac121040561ef486ffeebed3c5336d123dc05a5cf221b9e895f6d3ffb24b3674039d50fec114d3648d6dcf4fbc0b503658672d675c4ac64dac4db4615d011e82bcabd9573fe9e2af224103f99c4e6e5acd2196f1eb2260fb4aa61c298f99c20c4ac1c9e70a9a9e28db441c3adf2f2b3a00ca3f1398b5a112126fc3f0e2d11d40db36d0aa47d59cf8ece36df8daa854509e546295bebf92465f32a7edae6af4218b49781034329c22ce9e87258216b4a901b823a227e46f2938df336d3fe03fdbff4efc7b8ff8142b4bb60592abe508675d04081e5eee99468971fd49989eddf4648d3948266b08133b8c22ce3523757821a05f254cf5691848b1532655e85fece5eb186e87fea61936fa63aa047b5cb77c08aeeb2991c26619139b951ba4c2ed487703a6123c9c16d7b6cd3a17ad108fbb7c79fc3706f654be77a6cd8a5213d3976b1a4527144e788b712f37cbfd5f4ea5aa5fcc0f91b98d74ddcacb83fb33e039e1b88811a2138743ffc0dc5eae46c688f48c0be92a7094f92c2d4bae0c1dd95d40ffa113f27b8fd1808178be0c3bf77b677df2a17c9443fb6023c9e43c48614fd7d09a904e7a064125f8b7671fbb7529169138feed4bf3e6c215947efbf44fdb5eb1e3a5700fc8bcd1cf2a393ed438e68b607a1061e6cbd46a0b4f30fb4a492e786c5cc6d4f80542d64d0d271308ba072deaf7b1ff1c5200a2bb24c68aa2a5cd07052ee5760e0ede484e0a9c482cc74ab564654787e1698bef1386fe446106af25cf2fd950a78f4b521d547c83b6e4b6ef652444af342e90bb5761ea0dbf6b8c315996ed3d3a1a9d1e5f2b75ab18d0bcc87ee639299a248406d9deefecbb6883fe81ad12f20d80fc9b3c8962cd84e5da215b96bd457d5146aeb36d08185b2ee021fef7fdd43d0555c0fd16e7b66d1f534ae0b87f6299fc3b8e70236f39c91601564a5c2b3abce248ecd5450096e65df8b69de8b5cd963127f207f0df538f990bf29ff0c2930ab8b378b86d2619b150ab4dde82469e40e9e6e503182882b03442f92cf7449fc2c4b2f7ab91cf5ec57b8b0ebc18b27ad9125da57b6c139edbe7495defc73d68e71019b2b808a1ecb89fde58ed9dfce8b17e072170983e3dc3551149108582b95b2e4bd9552faff0bc7fd13dc0130f62a967761928dd62c9cae970ee447842a15baac31a280b443390bfefb7d4115e8d1c6458e1920485985635b75bf84b6af5226dd9b36c94bcd1a5f3ed99fc3e5adc6f3c4a592d2eaecce02d0e5ae97e6c4c7e101d4138e526fe3f090123c6df8596505b4d28c1be9e0c3f83dd4ac07946617eb553f7688f6724c8d8d34281a8c094740170280cec80b61b07eadb2c63427690ce73233f18593537e07266a71523688e6fdd36943d015c1bde058ebf5fcd12ea00e6b41565d062722941ca346b5949078421cf1f32fd38ce1be52fd65f2e9862bc5c57b45f33581eb72d387f0c212d68f85baf7e42058e41966429b0189da4eb4e58c1104e59d34eb0678a1385c38289210ac86f77cf8bef670b9ed04414875a29c27b79bc97e7febc40c39cc8e201ca56b25cd8c96f1a37ff688fd5d55cf5232d216283169b51cb41c631ca323056f2e8f74d5178a83b3bf43cfbbbb40f2680f338a89b294d4b611b0f275cc60e99bfcf270cb761c1c2a6773503a3c0e03b2a858d0cb5f81b032012bb0e15add080cecf19bedadc4d0c7e9d81fa75b97e7ca5e1c9eec88bcd10afc0d8e48f83aee498633bb260d731e0f900a9b0ae3f0d6e57346b8d3d8019bf079b4f909b6dce5718052416de8b61e9ef317ecf2faec5a64c0ce4bd5aa72b79360ff9b58d4a5f3e0648000d90a947933b0fe71d81ebaa96cd4c54c5d42b941e73423efb1f6626767f0e6dde52cd8796b0db31cedaad75b4ff72b83e0e9ece164c4f4dac170cca65e42db8b7ead0fa6e2f0b2d9576c79d1d73aa4b7ce4b954958dea381a65d4287bb1e02b7b88b33b2f1872d92ec6bf79fbb726aa436434fc7f2e79f0ff8bf243e19c08f680a5012c3c3d0501abb46026c420e485166fff457412a075086266b854aeaf5ac3a300ff5501bfd7ae96ebe56a5df5b7abb5fe2d9bf7ffc0005b6aae9dca8380a66c8c14e884f9f3338346ef1daad62042d09cd774b43016b0339aa208c5d6c2f7373797202ffe680edce71d684030e5841edd57cacb0cd596c63515a1b992de113fd2c8330840915d3409f608c8d43601f09dddeda6c504352e4d8ed932d8b5076a557fa2d87914ccbb0fed61c1f4d9950be0900b2212a82abcc4d9f4466d1f5469939c1e35dcd2d124623e2e1aa2dbe90ce09b958edc4e60d7e7502ed16a8a1d08dfcef84eed8a93d6940441ad41e493ec09abce869a8de0a778fd8df55cd1d9d7f053a72314e786088abdf968a3b1d1427e52427c2313182f51b5556466960017468a35ed2594280ad8493a5d3503ee4c479fd4c8db0141fb6b77331b46fb228f94e213ad372c09ebfc8bbcc79eb074162b4694b7bfb8444a4938a80747d2c15879e28e3cf44a8ac2ef8c5d9f93e9cb42f81cf88035dab96b6c078bceb4fb9cf293dc964b0cc9b722a84f3423bd4fbc57ad1f68a8166e86da595fb3b7a4dd87190dc65756e0f7750b68e3f605def2821619fb4fada9cfd1c41343dd4f5424a1911ca709ca745962a484d981db73a23a85c046a3eb73cb48b085d3286738e689437cd4976cbd3e2c5a4a4e385b3aadd09b08859bcf5506164db33d414caee679c65069543f1db8b242dc424af5a45bcb5ef9b939ce94e4dfe56ca25702d7912c38dc44d94670d90109ab685ccd59988bb7e932ffebc882b7dab274065578c041591d481501797b4039da17684a7242622f4390544b05023d3902949d348a44d9ff421d04a55395cb4248c7cb0f13b697f1423be1342d31fa9b85aab70c16bc62eae5660256d2472dc908768ccb7ff02cc84ffc6059752499711338e41d37f8751d84eec47a51c7daaa273e19c523d3d97ee5f71571def6f7268f24afaae71eafc84986eb8a0bdd50fa553c815939a4b56380b22b650fbb989b525d2862c5d420c83509b5c76b1a9a2105b45c2182331ce72e8f1804efee93b1929338f"
|
|
+ }
|
|
+ },
|
|
+ "1" : {
|
|
+ "id" : "0x690a7fd66157e5b777256ea5214f634f61b3a72d",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09a89834aba90aa88f605981578667395d730a408f3d112231997200c28865ec37a4a1f044c8817949cfc8a4fd9028832fc406f1bb919789f2099629c2c8d6bd128de4f51c02a73c49dbf17883ef90a9dbc0350aa67e024a893e555b4f989780a45320af4858421346445f66aa86e4954c0bce0debc896f21bc960e4fbd4eebed93e943a40387210ecda652c36b6da73570500adae1a2a03284dc47f1e370570a07007d8c5a64089e81e2c4d45eb6ca01530884070d46f4605ffe139457d5155c8e9ce8f201715ce7b9d18755304ddb6871551498985ab400cdc4349c6b5ed10b76b425e70376e39a6167622eb5d4b7cbd932aeeaca53b3e28ea06c44780b01684e66eed712559543cea677f1d9807e2ad0312c42e43d399302a0c4c506da7cba37000c3ecd10b58922889e5c8d31a9882ab8ae4b69d3d3d3abc6450881e9b79d9e2ac51085f61ddcfde73e57c1784a6a766ee2bc434d4973a9667c1c8e00eba0c544a36c593a764f519de83251ec48fb45a63e00ad4aaf01d1a295eda0eb95b27fc364c33e3482f4e5256cd622242840d0630194316033219c3051258f548a23c08d205a7b15199ba8d6507565d06a1f20db367183d56d9dcfd2e12c36bed83d239ddbda9efe8507451542942033282bce486f002a215c2ef599a6619247888a81782b005acb3d550988c1f22c6b186038bbfe1c583d165588e00c7f0f7e462a778e6a8126be71ee0dae7b5cfc6145aa6e65c8c136d34f7b45252652995898150cbf177f47ca8d16b583ce5b0e809567c08b99c06095c879b4d945b13c8a62429966347946b606dd78803a3c8113a431761dc868ba2e2541c66b39f30ee21b0ee3fba5eee922d56f49ea60c25a1094381908a69b351e325357d9b4b9e2d040d8be7795891ad46a334a057b0aebdb2e5a9cd760b02c774f60df240e05ed3708840b1663cb435adf9929c138b9fd15461d86328d5895d8778ada79d9b567386a6302b67b4b99a37f4362dea36fa2fa1f1ee2f4f8293b131c57595468aa5ba62a03dfadc9784c8190559887603c4b50b7487e795285705f07f90d8a9ca50e4abf0905d7487f04549132cb3a62ac2e490d6d5bfde20568290b693681218426fa0458eb356b198b41bc60505afdf7219ce5959124e4d1a56ba63345f91ab39afd970997895689c8397c023b1c8b774f92f0e5940c764abe3bd609a0d50a98dfe291e1677e6232896ccdea3d047f35c558daa130ff53cc66aa03ca5687a2006cb7c8c3f",
|
|
+ "slh-dsa-sha2-128s" : "0x3345627b00d77c13ce3ebdd12964c45d0bec4dcaea60b64fbf6cbe7b897b8136"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x394f68dbc8384822df8d4fd86c22e55256ce421178ceafde6e1a5f6437900ed2a86a72cd648af5e2ec15c79027aaf194847efd5855472b428c647a7db9d6e97dd15f70c3992480431ac6919e5b11c9154ea5dd9ac630f866c589a54b84a4c9fc57b86f2b5c835d3f6fac9de77d1f08abd507f514df6e7ba1c33518d3d1e447638eecc8a4b7cea388c2a57a6640fc599e73aedfb4ce6b3f147591b9bdd10fc7539fae4b2931eec267fbe70a5c6dd8b24bc98276db5d8da487bc38298d17aa7fa5facef7cddfdfd6eecbaf7e8086cab1df3c8f3be1913d30892aea7bd03d7ec1296247593835d8a74f467806259280a4e652f7e1bce11aaed31fbe2e155964f7c37243a59dad5c8d19c3c6b9d0f62d59ac39578dacf29d9ac2c0d5f160f7bece5902417ea82a0736bed8a4d078599134506a7b0f8a3ea8d6749fce0d749722f7c5198c340f53af2b4e1054fd97239109aea654bd2be0307a2d868570fc34f56a95ef5ecca1995681cbfd52a0e309e9db779ae71aa921796ba86a2aabdf6a39250bc71cdf8ad4d94fd6a758f29c90a7dc44839761f4a1a9c6d1905dd18d0532832867e48e91156ca67f2e2731bcc949d8140a850a8aaf9dfeeb9aa339b453bc906fe07f0a3e30f59a941d9f4f7b723a639e5e10f39cacce38936fa58e36746b0cbdece2a9122a110099104543f066515aa7750ae0080462d9254f58b5064a55b23a06dbff5875966598a7ef2417a8f32231c630c7b3d574584c2344e2fb38d8bd4d9437aecd68dc690b8f1e93f0109ee3747bae997419d1255a5c14fb1ed17b112ace324a41dc34a5ab81630fdb178641536da5268d928d19daa49507a5c81aca3e061b4b5c490310b13292385bb341b0550cfff7d8c72de94a6462defd1e6596b351ef32ca474b61c951ca5bc4f919e4",
|
|
+ "slh-dsa-sha2-128s" : "0x6e16547734391aae71d29745c3ac8cdfbc98f07ad9a8470650f0a0085883ff970643e21b67d6ffe83653a99f2198f821cc080dd7f0cd1a612ab5c6f18d9903ecce34a5cdf069ac66483448219c06b131b377900b999f9aecf637713feedd8c7d4beb03ee11bb297bf4a97959ac5c85c0c83b48147fa9a3be7543ce1050394e83ed745f9ec0c555328d3786da46acac3074c0611667ce5bb4613436dac210c2e9cb186e9540d7d43ceed7f278363811083368d50f6d258a46a32c8df5d62c42c4f6f34c627076169428e646774dd6dfe6924e2240e720fd4d53dee8f880c782862de1ff96fc5204a17625ca008781cb120f74caa37a36dd20136567c05e8e7723a2e21569f065d4fc631811ed0b2d9bb67d2c82b755d14cdeaccb797f207427d572419360af1c443fa68064a653b1e21a2b83fbd93e38c7cfa5046eda9b86c68f3855c61cee9f799ba02e611a1b7df6a15fdc4b4b09e51b3b5e1101d0dc90a213cfa0522e93808fc4ab3d8cef74d279b98069988f6b8c6b4c8d3d62fe2a5a62f1a7fb0fbac7fb36529dd85416a330f35a7e4e161757a83282ad50ddf92c6096cc1fe071952dae4540e0c9d0507d4b61ad34751ce17fdf2e99c3e54cb523d3ffe2cbe8a5c58b84bdde119175e9599df6b2666a7721e246305457cdb5ff5ab4ec9d04bca439d59989253bbfd9a91cb10a9fac3134d85ef28f1e4d4f884aa195216a4811be7617c0d6004c7833088851fb7758aa5aac838ddc5e3a51d122fbb03b0b5d0a3593b2b97eb69c2266eb236bcf3134414536ff36895bb081e9fdd2e5a9f9ba71310af0fa126eddac07ca67020ddd4caafc9b102afd4d0bcae2a957bd65d0a15762b98f4dc7b548cfb463ae10ec3da3b5a4e9976b8f05405904aff74d3d536f9a321b41e0c1d5e4fdbbf61b42d868602e112b53552b8199a6618723e5638273822fe0afc5e6fe068d117bd5af3a1c1e8bb4ea9ae639674b51a523d19f950629a76e9a52c673dd153915863d0ad166d357f8d23b85010aa0b8263de0f253a0ec29b0973af15e4419d965164b5fc6a0e782716d86bfeedfabf4d9705e7093373819a814a45b245cdd13a667b31f1724b5cbffe3b5ed3087118715a0ee68af333bf26f1ac1ff13eaad6a5edd5e760e89518e24a982af4f44386c6d92db7a2229bc9c4df23274cb0f10d348f2373a79f55ee05e3dcb256df464c5f3e54ab790f1fdc585cbacd93c775e50bd02f451b69972728bdce813b46742ebe9e45d45c8bc23d4b298b5956e03b48c0a11c602ccdebace8f92e2521cb346f291717cc1881b0fe3a2e23d4ac694b7f1cd296b32b7f2f139877a129079a524d7e3c4f9c36b5836346a6944c49967796d8564ac8d2ed5e804a14c655ef235fcac5a8cf0372f7df952af0de7e4319089b54ea3f718b539a9bca631ea0bcc9259c64626d252245d541d90179364072b081d70da0a7e561ba2902e8ce864a398dccf55a4f583df7b6f6ad6738813eef6815f8f67936b7b842ed7dcc48808156d236d70a9ecba41994bc0296c3a236f2772c747db6ad62723c4457bf8a2e526f306d8012e04adcff0015a88167d199029ecbd333a6ea35f5b9dc2eaf11a14fd09b35bb2842a4e610da4afef15f332d5d1e82c7b0b452b7564eb45193af060595975d496ee59151e3c0f1545ef2694eeb1a2e38d4e008c0943c8e7f181a258c35e5068df39376aad6ef356e0010303d9a0dbcab91dc708b8e9482f50aa18f88f45864d539dc0818148149aa259eeb270a474b0a117de91b6834672a5cb4b5fb7c2ea0ea7e3bc9884163887986aff1cd89c49a6ca417dff067da528dd33dcd1f7db96ed50820bd72dc41984ed5c767478b79d8f61cb7b417893a3a4451129525a915b1e999086e6db74ef627534015206953ed3a5e2bbc5c629b00f3f3b22a37519426c20b2a10c60087ea32fe606d81c6457a02bdcadd8d56360dbd278ced2d4cb9af64af4ec77989475882f3c1c0b9f9e0b6528b9834e34024dbbd64dc19fab35f3bfda66c086f4c0ff06a29e9fe881340d1c0719ef568e3f8f683282b963005e93620c01de327adc0af4ea7f968fa987cb8f38350ebbb3b91192ebb009f9fa85657e06cca6f71edd3d0dbcfafcc11b908cfc38a08ba288910fcb14f97746ac20ff6e6c43eb099d09a717ac03f5e0600f0bb611d6972626999f5661e048476aa999c83e3f476e77e7ae09c6fb7c343a196e1846ef061be75fd8b662932fdd2c7d8784c6e498d4d828c910eca00ac199957fb44d572d4bd2c599fa6c7c2a166d96aaf4959c561d1e9dacf502f76b050c836194fe1897d54a017944a973f49b2ea59b66c24d18f13048e093e83af249854da9fd6b4974b4db3e8e65684b3b6a0a11d942ad5bb667460dd98ab54319cc2ab704a7a57c1583b8289477f5557d2da684aecf66eec3a54da742e2d24a6935ffc4f439d4a8abc21921087df93da2bbdc3a0f61729b397faf12bfe59c85a6af75c9f4ce4af19239840b57c3a4ead6096f2910da23bdfd02ee4f3676897f475d625d0e9a9cc930116bb2327232dacbd0ff32cfaa40aed89024b9ccfacdb76bae77a87b569582442ad2230c8fb3e0dca3937dea5685c46aff9ae6e16438e0e9ea8ba299936a42d68967926edeb3ef955d95c5a0b74a13edd280bdcb462dfc2d82e7ec89377edf6760450e1ebc61f035fff661173de5fc80dc66b8e3d38c67f4ef8c25c2c5626dd2875e10d870f12b3f36f749eaa0c82e94b2f30686cda1da606e0c815a35fe6fd671915483e1b2b48fab000ae560dca0119be7a0a3dfb347ef95c7fcd9a78e76911cb5bd438a7e96562e437e32eb399782a9498ac992716bd9f3d7d4e35a1f1821f9008f547d171ce2b69b007b5e377a3244092396acf958932616bc5cb95059762f48468a94f9f897736b11bec2ce0af9ebaed9add43bf5c262106a96083ad967b7fcb127012b1b37970a6be14cd9088f6ea927a66a76c35e1320452848bf7496fadbc613b2e122e55634f0491397ee5d211d780971998244f303802d7630837d05f3dcc588d8ca32e02f16d2297aa577576ea5c1b90d6d330a18444dba772d7aa94d0bf2000d598a069d03e7873f114cab9174af2f28e257ef2c0e44925da7ccb593d6183fdd37a1abfd7107ce02c655e7966286b72d65394f312d72505803bd53621a08100a041210cb912d5aef260b84e39faa7b5d8a539b6392b32ce6287e1a619804677b3f69ac46fbec010e726f3eb3458433e68e6417ee375dc70c2b2ee16b2cd9b228d6a46f92ba66a8c5b08cbd284dd759478c9f690c5e1e16d6332b5a0b9aeee43ac8ce3eb0c3eb6940b61a65bf7c3348d8dd15302b8b7bf6b6257e074d0af3eda088f7c22e6778c8cfef1f15d9f86c76a4b05c9afa228bc4f116ee8adb959b4ed9afb2307f2252b10baa436795028629d05277ea2722ffc14d9a5fd56e6cd6f0ba218675df025e50586e46429f1c6028e305d22b5479dd045d98a93fa30de08bec1576ea692bfe6b657b4be65578fa2dfcc197212643ec9a1a8de5971c07023abd8767c528025281f9854145e3d9c47e01bd37dc3a35b76639e4716465b862b705ebaf674a64313641de333828d75c16d4f6ebc4193fc2c92e5a3373fc79dcdd8505a8ea7ef8be6ffcecbb2e80017b6fe401e49193ab31e67a56e8163cce767abc393608e7485f41983ce27b9b1de1a0281f237d685d401641f860f8f11d10805fbf0c7125deaf583458787c6f2850b0cc8c62053e069df241192c6af9018158c27e30574a9025af5af73bd956bc008efe84b31fd9a49c110b803947fc939faeb773cd3c33d1b6a96fca0c079f2eeb4e3ff768bbe1cbada9ad22c2d97928389e5f7145a346931e4138d66319f0154cdf3b28cc9bc04139f92e421efb522d0639f02935e228d6eacf3ccf0356b32c163dff6b597d51b64a13c8c93f60f150f445271489db644665ed1208c025b35dcebe82e73034561704c602d1b24e04c08e4ca8fab21c5136b6d4b7af05cf8ed62961b4bc1c2883154116a0ca8933e36042eb98d851be695d8c4de2c2530372c606c93bab254d6b00e59fdaaec98c56415da26ea8449061e12bd22743a1a0e0e1e117a4a9448d75b3a9dfe6f213460ca639632d404af60c764d91405391137ab9ec4e8519d11e3dcae18dfad0404ce14ea4dd36dc3ee24b7a15709410818ed0a42091a01ed9b7f39f7c87d60d2b3dcbba880001a519fb7de152ec06c73d35c08b3e375b9186752931b6108a4b84189fe07a7165e18357a94962dc2761f4eff0df829427646d2210b55915be710e2a1bb413df2055e7aa0b0b9a4067d35881f22c08e61b587a59ef82ed4df267afbcd4c62f22435167f2d7a4a939eaf28a6f1903c8c046b2d7719b7134834cd56964ba860e60ebb6fbf4605a11b52aac2d595cf3b6533fe2452b65dfa0fff71aff39124a88e3e02977d6063a8370f98e3cb8c80f35260a8541b9584b1d2bcb315b394d7641ca56539b4ca8bd9e4fbc594b0a3bf1ed678be2f9a18d31d610b55ee175514738717d47e4821150a799ebce655d0c75228c2160aa1936dd42f9923de2ac97d0dc3ea062d41d5beffdd1d69672b73490d6a5e14a655228bc39ffc8f1e862fd39dc950dfe648e0ff87807e543d02c40411ddfc6c1f8eed733750557c9f68d830c83af737c9d8c3ff0d23987a8e09e6293d707940eef4cc838365775046af35dd26acfbb4264a9ab84818a71c5a13d8e615c5675656671e5fc2e91b682e91eca76ebfeb1c09334e962496f583affefc56dc144873c79d4df77da394845fa29ff348007c8ee7f23f2944c121ee3177879e6938eb043a0abb75991b3e789571e3eff009cf089acee93612e97be85e1cd83da9ff5006c14151afa67fddbd9262667f98df52dfded25f28b36fa32ec662cd5a6b0f844030dbe1c87e9e2d435fca1a81045b8de5b8ccc411a839064bfd133731f55ee2ed2ee727d9382d130ced8a48942ea295bcf75fc74e24204b808956bfc171392f18554764aa80e75a539941d90a4afbce1f981f0c35bcfc78330ecf3d416d0683c7682cbca066a10c43273a0f85495cb4916ec0eee9952431a11717cadc95c7626436953fdd5fbfbf9ffe329159d1bd79499807796d75c458c3e3914d1f73f656e9fa273244615710c3eee84553a7ca0250e97a0b8895695bf86408d2f3cb2fbffffd62c8583af5b25b7e2a38e266c9623429f8d80ab8fdda6774df598f966b86ac228639af66cd0e3ee7ad7714b4ecb42876c31eb2608fab0c6ee26e97fca305aceeee80bbe22cb5e9819322aedff05cdb78b1fb3060ef18ce0385ae0fe6803b414aaf0b340eef94a7517e5cc3df4bd273f92120b8ce73281cab96821ddaab08b41b97708dbc7d0edc49cb362759905ce8d42743f83a0d75878596c4c5ca878b7aae6fee6ca7b20f2ee60ea773499a781b958f4353ceb078e5c04b0fef3e0112dd0e3a7ef19e4c63a202fdcb8ea56d15b2fb0deee4198a19c9aa59c1ef2b3de73f291445c248779eb5fc76953137adce5dff20f2198cc9e729be4adf385e0f25f67f68c04b4cc26987c133b987f477d89977621b8313d6d18a5ff6a76c73ed608f5e4adb860e2e8a6cdf237d4871a98f0c448668bb42f29ccad560fc1e571f8abb3c75665a65a212fe9d2c1c48eae9b92bd0a8b7b3d2fef99ffaf7942f5834533a592423d2cd66aa793e85bc8351876946a1e49e13ee374609932ec1af8d4d3f52e00f783368aa2bba882cc91c5fc6eeb657f3682dca8e9d63f319df3bd1cf52c511f600a6c815e4ad59426d9e1f32831dc5d8b0673c7c58e8bc1601d241bcb76c1306ddd5aea847dc903f376bc4d8e73a55f0a5ad331f57bee70533b29e6b8493d9f11ce4f27f9605f693c05487bd43882ebe8a1090a95abcfc186d74a3708ce3351ce7226183a21c08497dcf52727b7de08ad6a970b2c9f314bc7b33995ffc77a9a36ab46c7a05f61315d18b3f2217703be5753b4ee1670eba3af00e90a94664039aac93e89dcaa59d4566bf286f33c740feb763d0a385855f4410052c52abcfc972298ce03ddcb2e65dca251afbbb75c516ba77001dcaad8470f61e3391c1c68b1b7dfac9e50d53d2ad12876ba96419b39d7f94fd88b58ac1c123790bca733b12dadec6922384c6f3b7284334bed918acc06ecac7674428d56496e9d2e8f0175b3c7e384218380b6d59dc93541ac0a7419eb0ced7ca8c12a487fef9ea50280b7f7067a8855e784362e85703f6b848ddcd4bd31293baecda021fcaa7198b27d37900ac192d71de4e5124089bc1c8234fc455fe71171fc44494395b323fe3575ac720af5cff428326cca56ceb0c47e20e1432018a769f467405f5a8b71e15e0bd32f027640212d893678ec6fa16e5c00bf5c0eaf2de0333126ebba6b2306211cbc731a6baa8fc5a64a30141a8bde237c217161e384af3355b4a253d35766a55cc69be97abead95dc2ccdb4d243f64aa6d74330cbb2fc9fffa79fb6b6baf99e5ba9abd7966efc1586e72bd25f6563fbe125abec67f24e3510bcaa34c49499811ad2425c25593ff362c90c5c4fb3c4c45a4c63c46cae8cb1759ff2d82ac2726b60b4f094b6344191f3828c78d369956b7a28f650f63260c2dcdfa66d1df4731866efa6a335281d1cf2ce3635eb4294c8b2e1d4b7ced7b4b58a10d693e9f5a269b9d3451198735697af3a7b4b630b835e3b56e252f71f9aa6dcdfddfae13668bbbe3538d5aca766dbab6655c4aa906e0106640d21c30f1a241f4f5dedd526e8f579848f1b64808afb54bd2737a18d9a0e4a078705847b59a1ca4b2b554d03304daedca50726cd23326a6507393b2dff27921b5d7d322cb9901e0efce9bfd95039bb3bf6a99282f9dfb1e90289e986a657b3aa212cec6e611423eb3e4523f4723302b1b4ea5db2cc3fe3a7f0f3add38eaf228a6f0c02b9237e4078b438c01a0856d64053427af9f84eb04f022fd12986287b48cde73554b014f75a04d01f7d3fc6285347be643ce214b72c911e6c5360909ec590ffec8b4395fe271e97af852edd3801ccf04d3ed6684c66c67278cf331ac7c9b748e2dff377cafc7fc6732352245aabc9f5f25cc29d8f7f211a88a7aac750e488ad0304b7907bb063e29fccb16dd7ca0b78fc3962046a83f9c7138d49df3b765df47829e5f56e5155dba194d5128648b92e4f5c11bdc9232725faea4b87d6d940b9bd7cead9462736c7ef605336c40c9a053a000ac390b6340dc85a6905d35dc83c2d13786d233952ca8777b5981b761376f4ce2c5bec0587c2b28aecf39371b8899d227dd58c054aea7257dcfd838c32d6053362842a0baee7f967b6a4f5e1cac240896a8ec8fabbc4a551a55e674dc8cede1b9cee3874ff9fd3b91db433a12e78904aa3ec84d57a0169f1719297b467c46b278f671f74b8bb3c2c0cc2a093cf93439c1267e3be38b12e9b5881c27ab47bb01397c6470b80174ede3df34ee51ac116bad6fba58f8b8e2c7e0d1dde184460a5bce9e1d853d11ac017001fccfd5b767afb69691844e8327d39660c06b8916e918f5587f5abcd0f0bc45328ac01b1ace66405ed6c7a5080f5795f2ba0c0d9e5d05f462d89aaa230f240fa47c5c0de0b2099e93ae8c0f94a45f0513ce2797cddccb5216bad88333f6fec5805e0b9474a18ff562e78dfe325c1a6bb3648b41595690cab5ca9805eaa8e13526d036f4233f8181aa8efc76e14031d343bd5d9023fd6cd6b32947e173807883b6a964d398d3fdf9f34a44bc5fe41c5d72ffe5fedaa13fa1da68e19656ed70771529cfe822fc694be1445c79a041eff9753cf47a48ebe9f2c9f1546117b97a1c2bd6e375b957fe38cfcbb29f8eb726f18bc6131b1e27316064980e35d95fd913583b9735c6bfb03ec86e935024e60679a61d972b4aa296189fbc268552acb6cd890c68e50e325719d2f2c99b8105bc92fb582eafc1d618b4e88070e6d8df4924a1780f63ee216c0e937073725353b0c97acae72ebe521fb05fa78a4d6ecb7ba2b860190b6a5c340c83249919c26466c9cf4a9b774fc823141f65196df32edddad59fb05ba24738d81734004c42a7f92f5234b7f4fc0d605b032b08eda4cdfa3b03a3b805ecf5e4ad667a8cf399efb3c1d6822d9d5bb5eece6e08a515cd75c4485537eed6cbd55efb0a3d393d2cdcf44846f0c27cf6a664c70dbd54fd56b20bcc482de2eba84163375b1bccd43da63467557828b791dfb0a976628206e26e9eb10f1e9b9fc34571cc1a38f54909a1ee0b097e0f22f3ca58b56c631708e9baa52d7eb551bd327a6e0014fe98f04d7b0544fadc06c16a5652ea16b6c92a014bdeb2c070843152847293a0a925cf3c22bc9ac23464919ba6340cf233990690c94601876bc30bd5283f97cfdee757caee7b7b41fc265fb2ca9751e3b523e8498d665151d1c67624a084571f6c29973e624703d2e87f1ae5a5e0dbeeb96f46698223e063d10d85fd13fa0deb3891359844ad5e8100036d9b70b3b7831ae78c927a5e2c2ec62992cc424894ccd6f064e9ac307e6a2dd092deed179cf60b4bdc6c56c32a538d477d7917f7203f898659104ad5aab3e520a9f21d9c01b581cc968a68a77648cd95f66b5a1eb1b9d60b0a73c2eb05873f279c4ce43409853df2c8db254fd5b63af900c764ad4a0aeb4641e1a4e4089967e83603cef0317d06d1b990354c11b17c83c2a78cb9152615b9eed33e20f61a83179748ed4044a65edf285b155d41c735a883a481fa07c4941865b86d3cbd54c345d7933e32daa90a1291211191e0a3a5015f0f60d2ff07782606c164485aa469bc97f74dbf1345ea631bacb972be00547074759fab2b98a78cc43b7e4fee587e40e23d9f8ecaf03337d47d27bce633ccd97c0b18509afe35d54b1761a4ecbff6c44dba5402f3111eb671183b5e6bdcd69398056b980c35628f03214e0cb4ee5364e51de27843ad6c24b1e972889d54ed2a31d74000c32fc90b3c96dc3761c9649305c5f5e75f5b5ab7eaee213dbdda1039d4f3f450c77e6434752b74a55c42c98719836fd91fceb27be449d65c89a823218e882b987277622ce62fd0b46130760f10be6b49ec57e25cf6584a99433cedb1ecb1ce25cbf5e2b6eb716c12064f2cc45f4989c4c1b6c1ebd390c44195a16da16340d3a8588754ae676a990df1eaf04336b3252a5177ca3b3b2afd8e7555e92be6f6d7e64bea52c8d25adce3c580b5731574729107afe0e1025e6da2f2b05d6cc223778ac7de1202566098d43d0e4db6df8d242b57353cbadc0711030c6612cb92a9f9685c88856a0739e61d08c8fc5864fb9d8f41b27b43152ec15b3307e2c6f20e00254984e6284763acc977d9e16ffd4ca8be3ba7a289e3c5863371c132b8300f59d50f9efd344d1cf51c5ac64f29210740be2dfb720397941e2ba939e31c9ed563a674628b6ec3c8983be01e41eca61f869b920bf08db3255cc04a1f459653a4a3c204e6ec5496af1984f5e47caf56993bce1124bbfdb5d7081895a96170241307f000ed22ba92d5f5d920ab39d3ad1e288abb76ec3acbda6a7779be4c65e99bc7d7d5aa57d08ca1774e0fb146cd3a894beac12715bf322febeb256518addf26df507db3c79cb2883e6bb1e4716e185026cd760c76038d52a2e0695d76b3bf9da7df9f4dea5323f7dddc8ea1a0031851928e354e703651f7a21df505a4e7f9f7a8a398582aaa9f504510c0bc6f9af8942601bb3a6df3faf2e97c9df28268e1dd466857d413fa0bab4ff017f12554dd317455d6c716f9449c5273ffc959f147d7e0da0c2eab432b83f96f7d2de7b1ebc41eaf2128f8eb8f9c09c7b3fb4e95bb3424b216232406b81abd4c0afe11835a8425304376b08a4442c6eb0e88a51bc67a49b143bb35416c9ce613538483c091bf181d322efe10b2204aa0f0e01507a7cb809cb54b5cca5f44c20da32b2b7ec52098e53de672795b68a44ba667bccac558210307ac27bc5c203a2e6a264e7cf3028cb4ed41e29bc46985c1440187155b8bd737fbf9480749d62481d805463d75ec17c7ba83c60cc7020fe4b110ab1a248f6fbfda3e5b8a688a280f87a53ea7154311951c2001a7894eee171a64cba9b19a21e09540dc5ba85b1b2880efc39c8886dee72e64f045d00d99a90ffc81fc957ee65b7bb93e113717e7e7a275814404198f9e9d33f45335908f1ae917e0322b3d12c3d298ee814d22f8a57304faa93c18a14fdf53f05499239b66498512a6856ea194705521857a1724bc2925ba34f0e2707c84ee234c3436b4d3ab46cab863a28a011236e564ddbab3d49baf77be49ff2f5f2ca75252971a421aa2d4975aeacedba6cd3629efef8b2322b516c60ecca2541112b59d73b88177cd3be06163a463306cac2c0c1b11f84ab9b2fb6ab776bf0dc0fcb381975e4c1a0198b41bf6c1587bf6ca7272d8c722a581bce4494be5431cc5e3038ec33d843b9049b018fffa03cb3ff58e5da6bd6d49ffa6f776a5c4fee3cb258c4bf92e5e4079e38437f321e0c29d608cf5f69129e705e66a7036d67d43fd4a2919271fe07052fd30c049b793d2af0dec2431ea687077cb7a7a5badc21fcb0c2ac10bb37247207596d33d1c2232fc2a225acb9f30be7fe6da19514def9b595929c1c0c4b146099bcd980356b601ed0701299ca1a5547d62badd0475bc76fe51d0565b95b52a801f14e1f1ca62526cf8931f0706e3a478d20ce7eb1b1088454beac15277a72c90dd95f6146f961e41caccb2cddb2cd0680760731bb6db221944eab186425b0c2caedd840be5a2575d8dfd5810c4db5403d4491304130bbc564cb578d814d952706570e56641e8ce6232a2d4b18941c35301cd5c29211237c274dfb1aae379e25efdf827ff6e41cade1d57ed229a6ba76bf98de6592e5ae3ffcd481b53071e452a0b25f12919003474bf4ad2f36138d3d7c23c89b5b41a25c3622bf1dab6762cfa86a5bdeb6f2baa9cb3ea7dfdf9bdc700f4062ce8fdf477a17088bb2bf654e2eb9ab943472dadd73e3b63a4fdcf90fffa98983130e16d512b54aa0d4acbb1604d00fb2adc4a88e87d466237ee7b0fb33e5f384656a8759143db4c377e2cd264259"
|
|
+ },
|
|
+ "rotation" : {
|
|
+ "falcon-512" : "0x3981b03586d7884dfe64c33f5b7b388f166ace48916b895ced22b34d428da6cb1bf0b0f292968d77e45343982d586dc6c556f8ac4afea15682ff6aa72683367a22398495006bf5ac0e830f10559bca255d2149a0740e61f05322d4acfe3a86645817823db5c1524f27b71c99374eaaf72ac0f59033a05ca55c563d1d2b58ccff25c58e779666306e18c1a9a4bcfdd7b47d34f68a96f3c18ab227b263566951271db2b7d6e20d9febc759c0bff4189c59f6add4708f3d8e532d58660cbc12ff5ab24a6525d98e4ff50f2a2b14f041e5cd6f0b1c4be47ae745ab7a59e8a220e5fc390c92ea8b085334d6cdb33fdaf1d7cf3c477367f96a54c46f9aa448cc53ae521bd73dd8c6a652f69373c3c7fb18af3211b3969ae922a3ad33babe49c88116a97125ae74780644f6c2d31dfc5987f550e2ad8c798d4f0f5a05b356dae5a73949b876f37355793ae6b0c6729ea2d70b12c74c2884d76844faa866ac685de8c74f0bb2f5ee9027d731aa55b2e9b1ef5a13dd33656699333004392ca27769c6a91d5b26f3ac3d65d74f9219d938f2b02f5fab2079e2ebe905915224480b53e2a89beebe3ed153b1bf1f8e296b6128388a5625ad48640cac171c30e689dc6593eb24b8f575e09438162d4ed215083142fd8df2f1a67770ba392d92a11fba399348aec782c16af5a41168b17eb6104fe43b49a7dbc01a4766fb962cd20eab637aa3e420a6f9aec4a2f9697ca26ceca1718843fa445abf3910cd92d877cba165d6bbf86aa5536f5ebbe450e62b06f2a3a8cb03dc5c198f5c6d90f5337789924ea67fbb0a07c8a06ff158d72f86daecaf9c96f12bc0b30a5e39c7e926bbe241f0ab69930aec2ec3ade0746f55fe3b18c536132cff870ac4f9bd0efe7d84df72fa1b6cd5334e8e2324e18da66ba979091080",
|
|
+ "slh-dsa-sha2-128s" : "0x563b16e5f93863fb9479ecda8e51da4c5e0b8c2ab218e682251dbdc02341a70a0bc0a8bfcd7fe676b4a88ed00ab7bad29a5226e6bec830015cc98a88e82d8907e4b66e4b39fab840bc60df099fa85f9e079a4afc0fb91c1ff5f8bc18679ec741add6e6a35870278fba0fb69e912c6dd01dbab121ae9568e4fb8d2be66f506b4094ad1e4a249a01fd55d6956780c0252f978308118de5a33edf8b1de9ecd158c4c1be63cc25aab2b1137868c2cc9e5c5bda02cb50e7a5ac5cbd6c3500c755bfad4f65bd913f3e8faf204a3851410354c9beaf9ac2b69ac726a1b61a9bf625e9bba4d3ece8511f6f2aeadf08fca28d772bc1511a4f3b659b0a8f3c6c8376531540a9866870faa1b3306ad1a8d26022a08bc2a90a4dae1a3b67491357c619df90d0b25d7329fba316d7e845f1c324f99a3f4dd60a0f58ee0f2f0d28efc4642ec3374bff548d20d150c31bebf560805bb61b8638fb8940def864a2e38402257a0fb446cee1e38e000bae954fbf1f4f26db7631bf01089f0d81d4bdab306e142bd1e1f356de670679e7d0f3713216064b14bb0f85a56e9b90dfbf0b1c81aa4968a855fd9d60cdf4ad35090e2dbdf8de9224d9fe53902bc02abb46bb568a0ad2db5a73673746ad968780621277519e39053252c9e8fb46d44fdcbbc973875ef2e3c991eb5ee02671cd1580d2ec9e8c8035638d2f5409b0343173a071b2a72a237f8bd4ccb5d080fe6510ba2b355b9d39b3ca12ae06f2766d634457455d72d519bbaccb2efd04a142c7ede443d0db7b44c2d5cd0a3a468932a9a5370853bc475c622bb5c8c52eba04325d20a396ed36e5d4a59e1c00861f3d0b0e08a9f778c70c7e8ceb448ca4a52f6e0bef75b34a5471a3bd668d5d693f370048c93657adb1e5bd768b5b38f6efe11f315b3e6e62358c28894ad8ff475f98584ae32ca9c56b39f4a9f3aece99d8e3ce5d2443441e183e479964a18d53aa867d07ab6f6d9d019160421f283678a0e7774820005020b98fc058076fbe1c65d188c4d5bdea7cf0a5d67fc39820c80726e72837bbccbe1c396a79ee29c0c23ef9871795f25afefc81ba91aedc3d6799a093a0c0d533e094d5f1fa60c6ef72a4122ed34f3ee5ba6992b419ca1de2a9585bbbecb2a705386096e929e7bff99ba7a5e33805288c8ac315f1679e7f055d1c63d3229a206736ec1f7585653c0bcdcb2974d9bcf9fb805a89aa2ff4f57e98194ddf8bed97e4c985313b6487ff4a4131bf0a3e86837eaf9caac911548f3a60a3e1bf04d6720b1e4d60685b6db4ccca66123d23e17f2f004354bff43c4d61ceff52748c197296ae3c8c6380baba17d00531bea8f4c1becf6eb6e9fd50c86bdbade0f4da4015f486f970a812c778fe413841f0171743044d6e77789f1bafd6abd4234aff922148f3dba40f3c194053713b9b9a3d7047bb849cb5a806740d9424288bea002261fddc12a6123fbfc3c8dfa26753e92e2f6fd14e4f1895ec36d90f572198427f65e92a1ccf92bed4f56cfaddd747cb2a0a6237325eefd74da45cb52df13c7e78e2c60bdc332d118fe51e3f17cb85edb9d5070a8addaea082767ad40a9778e46a61803c733d1f27e36a4d1810d4cc77757509622ba4464ebc3a2f8bc9c9e49a650450f0ea57619c179e94eae7dba9c66cd079f160398a0ed40f685bf1a405752f9b2820525dbf697e5c198905f09106dfcbca5a5bc62a72b2dc8b85e991871a8e4d7091fb097e0ef13c63f59a939c02b94c58ed9ef9cba75db728d88c81619c86d95710c5b51733a84b9a8cf068869464c35d27bfb1daaf140d65afdee9b7ccdde62d5d4e2d83ce670dc49ade7b85d1d8167893d0c68faa29d159ef95d4381bdc6a4234ead47a472e7f9740db9e1d8c5a4c66a84907a056d625b6f8e192a89b10f6d4b655e74ca6b01e6fbb2b187ed75b0da052713862e7cb3457df4202bb8df95fe309b8eb87a711767afb1a3003ace4cb01cf3de67cf13e24e6d166e763a8962ee7f47d5ae9a82b951362ff226ec3bfe12b188ab659d8fbdc38e0ac6d0a8c68c5ea7a273cde1b53d5063c5c9bb6b80e803261ba27bd88330cbe619a580f2554171173f046ad43e2e5be710517889ef08cc9ba4018b68edf3e843ce09d0cb226a2f84ef49b60e0cf97b70dcb84a353adc79bf8dd7682bb18ace2282b0d78ab1854bc7294e3889c8eac041dc31ddf581e9697256428c469fe3d2c68d6ab627bc9e8e730632c518837a25d4e89aebe1cddb015b57a88ac7c3c6a2f62f2aed77ad8e19edfed15551941e87b560f05b24b3f261230ef1c3566b8cf121271611632e111756ce0346ad9ff9ce3c8caa1796641f5e019420273243dc1ca62721a62c7f182a53eecf09acbf08afc58907814f0ef90675f634b6c4e565a157bf4acacab2c01e6cf62f0d47eb3ab93ad79f2d1661b1aff34065e6d7e39746b3d94d92670c7c78e04f16b63891675667b83fe689d18b348d640cd5dc302c0b7a149eb562f29ef317218d5958763685bf2d86f756853538a5e699bb3f0e58c1934892cacb9854e25211ac4dc4fb6eeb2f59d99d2dae281f2592f0ab8f1f4e59708751da251342bdd5864e7a9b563e12c74e7ea762fa2db1bb5cac5c2b02b680f27f7372e7bb7914403f267c0e5a8a8e7f59b4f28fd0254b570c158917245d976bf85419d8778a3f03c02f99f853185882ad19d3aeb2382185ae6ce0349ff3ab4b7b419c6647b0edf74588365339b4c22c54bae1522c82318225c44aff5341b13a09df32eeed978da9069fe9795cda0763c78ff688c1c456a550ff450bc29df105407859dfb13655d8e6063eabcfb209a9af22f4dabeba0e151563ee2a20605573c3e5bce979c420928688be7c5ca0c66d6c4760299fd0699a7b96be126bd16c8b57d2b3da3a31e44ccb85626c1a5845926564305db1575137fa505389c17c736d648c96f1f529b100123d7535cfd9e6636d167083b1f2f6462ff227116ceae90240515329fdfd232762aee1d9bbd50fbae995cc4c27f34cfe21c924a603564bd3443ae0c2a6a78599705cda7d8c1224adfaf1cb0f1b7cbf6b2f8e1d3e69e200947a8cbac5704613c041b9eec1a947a5a45a855651275c63bf96d0bc26c964cd283e5cc2e81f7b13db18d58fe5c31da90bcd5e03ccbd9b7cf4af67897e031a73f7661289907c57455bc2e77237d6959328445b2c666bfaa5073914220324c8ae9043548f2cb28167d6d22d919f6ef05c0b71704fbf0e6ef338290b043319013eba466edb620c14c27ec65c853d0f07e55d56e12295e7e0b2c7d0cd342a428580645511780193dcced94a2dadfaa90e789775f42a5220f13a7757b966219da9ebddbafa76281fb4e4f10fad3b2c59bc1279e7892cba7c78f0492b683d6ad565ce4cbcc8678cd7cc8db72b2111bfc5881042c1eecf57ecace2a45e83dd10b60deec32830a8edba51a31bd72abaa26e47a59d7db74612a52544f05e3989d93f0c25a3a3802d86f025afaad0c8f9383b02bbd671d5b308f7416cfd3caaabc7875241e5f13643022e2e80eada5895a48d2d4fb5dc190f197837463b6ea5d8cda125dce4e9a1c20dbdaeafd6d5c14220b49ecb149848c9714d41e9324226e6daff80949fc51cd0eda6290a75d757200fd1832fe20a3fcac026cc04bc75f91310e6959d417a1370cf88e132333439d5a71c9165ff1a6f1193b2335eacb42b5ba5540def54d6d0960fa1b37b655040b594c57ec6984b273c58228a9bde8614b8f6bcc874e7dbde109fbdc41684051fe05c4de5dc0bafee37fb2be501e36e4d8ea55864432cc554a01c4c202531edc612f41dfbd0c220ca5b603c7ed47e9be4145b1490161e31a2e6c82eace746e62bb8862a1b85d35af5286587c3ea6bb72444dad67abee707a9d583455181c0b246fd0c33d3522458ca4abceaae209ea5464d294837e7678150add9a37f3405a76baeceb0eef3f3fe7038980e96652c5e53d77b15dd8197f304bab443ca94d66f43d69f4c7ec1c7bdc57093893a67d20d89e587a9988e873457cef966d9270216e65f1eae2ad0d3bff25650d884ec197a69e5c76d39d77f7e5e1c623bd664645ed7df0b69e8dc3aa7e6260ed481ed07cce4405de34313561fa30bd3a78a7bed156fa773c0405cf20d4b0fd1cb60d58a2eb136dfac1e388def9e81a9d1f1f769be49d1627f206364c61c5a09d9d35d7ae05f8eab1d0cd633cc4d92fe1fb58ec4845c16e1578e80c0702471577e49dc9e106dc59c02b534f59b0c449a2ddca0f5590d4c34c5f877503094256f017c9a4a0ba613d136e07d7eeb3a4cc23121a934ee84249820bd64987ec55351d3602cc7afd1ba272557e531b3371b99df3528dec1f8d1d4eb6d49ddf94027b9390eae72f740ff649a4438448463778df7d5a0a5f764336a2efe509afef92610de6dbf22cf51381a3243171cfa9ca8caf6ac9f4e0ea6238cd7ef7bbd5fb06d3426aafe2bc94c8776f5ee74725b2f7f1e91b533ad9ebc626cfc5d2a6eee2c792602be3e838f4fe43e1851940a1e21d2c4fec3fd672b0c7d3e266bec169315a9960c7c433517484693894f71328b5738127fa6e51a6b0145f7316f5677581146028bfc4a6e3399037e6cd038cb993bd1e63b7c5c9020ddb57dd78da6b80b9593eb0252b499e66c0d3526ae41d19f9430ea7de2c8dcff825ab026e4bdc2da80340d14415f22a009bc7b325d615855a98b403a22939ddefe7d82f9b48814c09f4a121ed92575cfe32e04df38cd041fcaf0b1e572fc18992c182cc8ebe05969d90970ca0ee9b651fd65a4d002490f04639bfce86058cd1ed219457242c4c233e5a4b84cf3e62f45cf2f2e308b43ea17839640a7e93570a4ae3760ac79ee0a61290944fe47ad43c67f01be52d639c85b3b5b07a9aa98b2e7cb3dddb82d2a0edf88c38b4119bba29cf812970bf79629d295c2764a3d3c8b20743e939102f6584458ddd1da577b5667dfdbb350b596f565d64040eb16e6b00a1c76af2e6ccc18273c3075b5bad660017506a24b8fe728cfb6531c16c92f6726127e93e919bc4a018b29cab8b098ec0390106d37e73e14d647c00a723191ac447819457e1882e7930e147aa05c6a6648d073baf7e0a379cf4a079cc2aa7111ea0b81b6737a50e2a02c3e862fed198020f295b1f0a2fd42a19d69599f3ea4263b01d0899cf13509bc2f0490c78c69cc8182d009bab3a84d12287890ce43424ec7fbbfd0daa76f08fb3e0bfee27688ef5ffcc366701539cc87446ae2a0d910664626992cfb8cef95990e59ab088db3cf5d8303820ab67a3f463c8a38c054e1791c1d07e9f2e14ee8d1138ba4b2f9763fb9faeac3679a777c60048341a9c3f370b855d4125e9597db28248e3d38313d18e5ead92def8d04f7b286c4f05064a0137a1821f5e5da38e69297b9fce7ee55b595ea05272509dd1dc96fb28e35547e2179808d333aa357fe87dabe64cf1c3fd4dd75bf30b9bc7d4135d3432df069f5b60e152b287e3be28f552aa867b58e47574cbc5facfee6dd2f585356bfffdf2abfbb13cc957a56b0e47225b9df42c4bc44f7da0cee1b64d4bea4d7142dc18851a86eba8ca3a632820088d1d0f277612181d33e66554a538228cfbb163174114fe8b5b143edee891d6cfc697b0dc486b384db8cbd20d1b48d43d254a5174adfa368a793f060c922a59bf309954546648d174ad56f045f9712d2a064ab37b05f92b71f3e11cee5d6709e8c79b501b103db8261574533fcde6bc4c26b257ec4f0a3a237b9ef488e17ad5af95fcd176452d1b7e20106a2119508d9e74de932ad79c4c608f1ac76e95b9ffbf9637cc0267b8ced6d139103528fde29e1df10e5adf50882053986d1670d420bcaa3365fb662e0d433508db556ca2a5913eba6cdef737e856c2a24be7007aed60ed10fb77b7e9b339a1c7da723b3ffc12fa12a012cac3b0be1e4a317b17247b5f1102e006c745fda650ab1ace51adbf3bed3c15281ff975e2e7cc58b7998ae0dfde1e0c1376343d0dd0aadd07d8919c296a7cbd4c8265ab3e0a4f5c1f6da51d946f9bb2b00bcbd134335691ff4e797e9d07779493d88e1e91b033479207e36e76f1d4264f551ee2a9a95c33f4c588e5f3d366e2f187d8eb77ebb3f9acd757d7384aadd90392aac2b230804502cfaafaf2328420a41c173d903996cdd87366a33efdf9d565cb0ac0078b2f40cdbf773b86ea3f44eff5b86e822b536dcd72006123a4e11b26d21120d8b250b8dec716b091b1eb150857bc64759f31d7add4b058841193c58417c33e9238f4741804f9f148096b15ce8cec22dd2c4636a39e86eb1325dfa7ac87e58d34950a309b4c513a7e14f00cb5c8b6bbbf3487b3bf9f29ce445a9cdcd1eb402724b2f092ea52ffcc3b24a482a24d19f89d44afc6e166082bcebafd24d54bb5022a08a2469e1633edd7832e6c74e5d9976beebb6928620c9e865991d093313f4f24d7e8d7e63bce3e4bc8ef79be24f2b7278dd84e80801d304cf3d775e53e8f670fb0ad4dada5fca06536f31ab452a7d1dbfa032c2bed87b66d0a7fcce064a4a28b60a7e626605385b44fd54286ce871212268ab65415f69ad0f60062f8f7e46702d5f54895d9b2e7c219c30f1a32e061fcbb5875af955f73f2bb31db7b282aa12dd0fba2c8e469aacc6914c230d499c8b7ba92572b19dfbc2ebaf4ebec1842ec54ac05d95cca796beb8cf14f5fbdd8e4baaf2d59833b5a329e4fc3f32c730d5fe55124b1a7e4fb7f64f63f74cf928552e4b5eb1f2976a99198925c0ccf5ba8ecaec313d216e7adfb1fcca3693b9e74b326551a0528c5097e1f34247b5eda7bbacbeb21fe6491ce67c3c7764cd798b1fa813454bda9e017b1c8981d95b3e65782f89514d93a0ae33ed10e6c8897a3cdb9d01cd0e0e12f3b398ec72409a4adcb18c7f6091823079782cd68ac017edd272464805f3e831e06f02ad1e1da0acb7cd6807a9b80c29fa3b2ae5b1b75b43425041bc26cffd0c9bd4372925f3ebca751480063084a888fc9c0bb5243dfda4b4a9d4f8dae59f4eeb768788e4db8a601082ffd3e09d9336d5f339a825676c3e3367b161ceb3a6cdd80ce650fa711452e886b1aab4f4a92f07141ea3c28bbffce0bbc4b4587d4cbe42b3dc7d92d0d3298dc751aa71ff7aaf353a75ae3f23363cd925247660562bfd43348a7fd2fe33b2c46196a0b7f30ae843f32c3141e7cd523963162eaa726a8ba34b6f34d8980d8a69df2a103e0462d9d57faffd6c1bb3967b877b9e319ad357fa05c25c27c823025f246086de0f60d668930a5ffc304a026dd3c06a1ca2ff6328dc9046c28664087cab513358de893da3fadb740618b5e0086ae17aa8ae59c2a31592e21287e600fd14a4c57b285991398298944729029d979811d3784484e2d09a883636be1cebad5ae042187b62fb858e47ee7b66eb0303c3ad215f3f1877e6298bd439d10dfe2055655c68527efe9fb5188a3345959a36d49e3fa5f05d1bf880cba1827de4be26ff650daa1f0a4727383b2601168996303c550cb8ba0fed5d739905adf7ca5655d34a953cd6a6f47110fe9330b831bfdb79213a898f1e1e719786407e10bea78527c94799458c64706afc3931426326bbcf2490db4fc85960da9431b9028eac16664559c32e55ceb99c020126d65943eb4eaacf0fd642a1fdc2885a749a53e27eec2dd4927ca58cef7be2fddbe7e3c6a9b7f8a1a047e1720b36f92cee110c5cd35fe4e5fd88902feccb964953059a00c783d7f8e480955bdaf448170d2003e14ed223c2b9938744e1c14a619bd67c306df9bb00620cb300882c2c48de11e512fe4e249ba69aa527cd718faae2989b9306144e63ff75543e2a8ebaa92b19754a32ef4d4174c8c25648aec0336af2ea17f85096dce5affd0a6da6079cfa04c1acadda7f91f1a15f4d2fae5b3516a69c4bc0664066ba697de2de4ef233143119f5ff216c68d9a37b6ac5d24f334851c147657f0de1926c1b026b7028d54578e46383b4d83feb0fd1e366e682aedd5eef12b35ff8e192f82d59db1e82adaef5f0e3138d5b408e5948048df66f20501013b5cf09755484236c6e20e98e9deadc7c6280c463c002c274243b85fbf8434200f8f6621e754a8b1dca5a366bbab3fed0e22cb235ee6d8756908fc49a72cae7800e9cbbde623963e12a1b1c01e2129d65ff53d6e363da80b47323d15cfe7f45bb9f3c1619c59053584cc4d68d586c35540a907d590b7e076176609687af7f06f811c6393436ec08767fbdfe08145165869dca0ad295de1d4b170bb30b0184e92f40b3b0225aefee2ff8d3a9a94827bb185d48bb9dbeb2169a377b9a9ea40666eb61009a41756c7190cff6db52152119e97c919f9a327bce47b0c8ed157207cadaecd89375155c9ede0ec95dc336e038cfcc3fa6a14ec85371cff3a5e28086437c5b4f343faf76f77980f2f35d9592b9549eb94cc402855d1a88bf04a67484e9a7b7425179ffc5d5f8eb6474dd76d5f64c7cdad8e002d65bf34b9a7f597a515e47060a21ec853eba88bb8152ba22e682ece98da7b90b085a80dceab5920668cbebed0acaee891d7b16c5a5075fc007a63f954a5b8ecad07ef54ea9ae6d67305591f6042fa1fc5d092300da6c97492653d2a4b1fc3611f9e7222451ebf33a836d153869433466957717d5a88abd01f94783102efd01116d4f25a5a64d8ad5946f4e798e9c4cf7ce615aeb0bda6f7c9deb632f3be4283fe8e7a45a920e15824b8f354144b71dc580fc6c1d5eb5768417eb99149a177f07dd61216fb1f85e100bf2e8c5c4d73055d19ce09e970085d2213617b738ebeebfb386b0765e2a5d0de3cf7cf147859cd9b5e28e388f2b9d1de6987fdce0fcd20ecc563331290fe28a4e1de9c327829c4c69bd18745a8ac8f9a0a8e4ad65b07495a63b20f4b2f4c8dd49cc43d9474072781ca60637837eef9a2c9596701b607aefd8c679a3c714fcd9a85f73108c87662a37376f67e623bebe30995f02855d216a4493315ef3ebe9160d9ee0c05cad991f7f42def8d662a144d5222a1f3cdcffc0ec111b3ea555de6726fbc4d0893bc87ddff378628049f1fba03647d13ee4f98815843c619b9f02faed2d3fe3da8bcd4e839ed749e3c5834597ce1e2892ed0d443d8d983aeb8fc69ad80184e69791cfeb634b98949a17ceabbf7cb2e85f7d3d771d5c9a23f327c4ebf8ad8495830d2f2f43b0a500476c5a37ceb9d475a23f15c69e07d03129265dd70a83ce8a5cd40e929c2494830897e41c62de0ff8c8dc9afdff4844b28d4acc376abf59dbb0d08a2f01e7b622c702dc514bc277a1129619cfe00cdec4bc9a60383f43b79587efd3eb9bba9637641068430ff7e7c62ce572f1679962ddc524d200c07d427e6db62657ddf872200751be788d462723d1712e06017f6fec18ecd978ad377d8db8661478d2cf60847baa34dc43e1910482d42c02c1eabf8f3a3fa7fa8566dc61756c246c44a2bbdc6378ffd6dc8e35242a057c7b2751d8f537f6596426be24bf89cec38c7133fd1ee024e53321bd787aa1d253b608e52328240618da5d45af03710cd1613211f87768ab518bc4f1cd01254cce9c151b2ab653c1451c72b9530142fff1bd6f409d8f4b4cb2c589b7bd65a73aac8980d9dc807856e37edb7c31e27fc7eb812d5c39d8f95ef26626ba580b03390c180fbdfb2a3ab2d6fb563c51f49e9a10f25f46289e74981e019e02775918fbe9a8cef65586cac7b9020bfed88ff27d60174f73570053b1bfda473050b015427b14d561f773c2f5b4ff4e7eca0e4e7177e811e6eb60bd72b1c0459d1ef6615e5038d7fe06847ab24a7f41d1593acb4b54d8c2fddb6ef23d62b0246cea17a1cb2dabaeda2625b1a64b9da3b88496349c41b33935e39700913b23ca60b565d961442cc8c7a8991afe7734965774eed9fd267fa62ecec64f32792d9d0fb19d8e666d852466da5a73ce68275785b983d16ff3849ade8adfa672743d923858e886fb344f653a0247d40c7b0b87a7469c48d6056c340eb8d7e2a04b90930801424c6b9b2547486595f505a89e1492d015e082957168fb103d11bab79cc4852638193a855fbf35294ac690bd295f6fbc28aaf194e13e4b76c6d05772a6b2f8513ce2c03d884fad0df46228e19b940398ffb09c3d5300b4ece8e71bb25485d0d44bdbfee6655bec314759e46e8b826b98692b31bfe2c817e4f5d6cc87e4964770adc9c60178e5590b31e9880c80ac9125a972b04f4e24b1eaad78a691f70823dea467f61a7b308f8191f2b8b7c006e92d950ca5b8238f20ef75c28f81180ce3ae09e72db1700740e7a252ca957ad52c4a74eb8207d3eb9d053febbe48b8640585a2106857144a1c2dc3d12af55a97bd93db5dea31a28bb94a64a54947f9443c762eb8efe68499c9ead28cdeadc913828f00c82fc4bd96aa32ff31975daa9c61b4b6349496292d9b75a6f0012280eadd9853ee4d0130cc57b0d24a0b8115fb5241037e91b93142810ba2daeb6e2ce3647f367111082dbf7083854d395b47999026d112aaf90db3109aaecf7ce10e72ca13d5f6da166e9a938fe439230abb58abf47d72f39ea60436f0b8f939d76832abdf58f07d90776f29101b99c808d44ccc7fb60ce155cb3d2a38e5d4f215a7ff552cbcb64d964f1c9e32242bef9175437cd507daf55dee7e3d48f4c0c5799f2a692005c7783d11eb84a533e79a1dae908b2e8b8924b0c9819f190b3f8ce61bd3236b2d48025b2e707a2a64401a821603b79329d390c3a75aa4de23ecbcf7d90d32d6a42c160e02843ed80134c3c542e16791b0a60ac2d3df46e9079d3eb37b7d220513a636c9437945022c8b9305d90953d478bcb956c28556066200109faaccb090c4084ae2e8126bc01c9d07a7f6cc2407d0c4a56f11b2d69780ad0c6295cefa259169800019908cee9d52804c16fa34b4c5e7feae98aa5e1ce7c7365ba499fa1622bb5338b1fd951134e48e4bfabd055263bccb2f204a710dc531c7abc412c92cde71b096c9d4d2ebf98d33ff42c3a30699d14f111062a78b5090bd27f3cf3f6904d81d4cb8a19a924af0dc45253d370c5a1e7dce7a2d1457dbf59eba5e4a17545d1c86acaa4805e4aad"
|
|
+ }
|
|
+ },
|
|
+ "2" : {
|
|
+ "id" : "0x41f547a71d1404f147606491f3b96e49f67d4658",
|
|
+ "keys" : {
|
|
+ "falcon-512" : "0x09b3f618864123704b78a9552a0b068f395444870c2cbd5d741a0c565554bc2785a691ff502d6ed0e14c925eaa24c075d20949d12f369848e178d50b085e87c9b251f68b61ec506435bf5b53a49d299409f54e906daed0c1a25a63563090f6660380321e786311b492bd7ff684a2650bec34d5bdf071c49f5a050415b2c3579b2994fbaa9a97b7f24a30e7e8bba68145196e0424471de31775aeca732dad506b16ad4f61a325136a6664f439e60687e764a009db3218f706785b98b154a625c168fa2ac541b8dce39682172b95e19424b98ba985622b2a23d8db2d46a7230bcb667372a924aa4d1a9e9cc1a8dc1ae11fe88081d74d857bf63e9814a08c9ce059a4b1ccab23a2fba765086b15bcba135d0937a064b90663ec69ab521746600610bec0a6b3c705277f90d588a00e908dd075059de6c52fe05fd8fa8ba1b3c2cf151cc810225db79aae0328b8ea1e92fc67b7bde405a1442128023128a5f7089722b954f15597ebba3aa3b55ae947be1e659be52af04c3205492387b51e72746a904ff13ae41964281ebd81783528269ccd6d2a7845d790fe4cda8ee58d93de3a3ca28bc4e6e18e812c313452a4468049a86ae39d5fe156fa2a43d29161bc911d515f4cb6b625f4679e37d5b55064a16c3e48a7f3ae10a09d9ab7f0ea4dfa2fba9da412af1978720fc47185c7ae16474833c8d278dca65b822c5526bd4da67c0700166cba95e3d23691e6e1e86ea4e560cddd59af18a689c4dc2b6dc0e114f2a84754498a8e299ac17a12fd199d1fd8d5c31b0a40ef4b2fc9627d16ec11241fddb4fee6c652d0119f7d60e852decd3489cdfb75c10a18f562154e542614427ee7cb0e96b99d74eb9585223760bac37de51697d86403ac877f823451d8c60e84188a8fa6804c3a8298f223169c4c61fe443434a76d6a51ccc1d06df3b962fdba9e27d7723a8390f4672d66dc2f756263ab928d9d14f6d550acb286647ed6dfb091c462cf4756194ebac9c94bdf7ae4ac7b5093ab9cb94455dad8ab15b134d31947df478a1aca5e28e98020dfdb6d4ab750911bb2690104b9606e78c8659c2f511bfa3254d32e65aab180ebb74f9848700a8cba3a1a546b77678a17716f232e57b204157761161670bf654f182a14bbbb1c16b14b652127241167e898e097b6270b062f0607a50bb040868768a24312a8da316dbc547237ace3a160b7835c805061f8f2723386929835251945908058905f625cd9a91eea83c0f693523128c68613038e",
|
|
+ "slh-dsa-sha2-128s" : "0x9fc24e59b10d63d59b6c448f79d029745c4f27a31903ad2a6f6fdd09b3abebb1"
|
|
+ },
|
|
+ "pop" : {
|
|
+ "falcon-512" : "0x39916580739423a110970dbfa8b6f06ebfe827b6503b1629f4008d64024e63c71af7a932f3f29cbf08eae4cca92f36f670de2f3a0a461999f431bd5da16b868d2230d6403158010384f0f98d2b95936e0a132f5b86f5d11e32ecf3cf206ab9d26c1cb7fc93ea3468109a59163b15391795b76ce450813b28d28510767270c1c474632bd6eab70174350d329d0039ef8fa6739b2f665fff021cf669156e3797da72e5913d08c94a48a16d12b5ad7e521b730bef92d7cc277a92b3e4c9f9cfff7cb3896f93dbd495637c2a47835f2afde4222c8dd36d4d6d9cb419b5b5563bcc1a61b640e70bf2c4bed6599c5ec50643fa302c227ae56adc3d4b044926f4bc4b26d58d0d0778e2b8ec5e18b5cb9ecb6d7a26808962082bea23a932afefd0d483a9952f98ea11b629b0ad74c367e09cc016b817b624547ed8fdf360a8a06acf7b5f0d3c92448d9f7e9453a4e29222611490a7188dcd0a8568b67d333228454cd9cb99fdc9d6d945a64d8d96348120295b8f2ea9e95f92d9dddfa2a91b6ea2c44de7b605db8e3e1019dbe5cb464e0b211713cdcc32ef3631caccb48b6b0c968492a5f1288e99ada3a4d8287b5c9f46236b4b3fcfa55135f1ee4b13e3d6765866a316d8cb3ce80d67a518ee974976172f91eff1cf973631ade2a2b81134c39d0f3c72bf4fe546a7bc7d3f1142aaae3f5b4e8f3932d9b516ff1cfd827e7395d576d96cff52f00e76abe5ba3f1f0887fb064ee11096e52d441d1b4dc7a69462acb7296c489f498c456b2336f2f112391bd7e545629697bd096ab373a34147643199222b8f1b05a95bba5877aeed29c43bddecbc814a6f2bb38d1dde30c352e06f19bf52717236488848599eaa1ef17873681e91064430aa2f4a23445fac0a8c8231c8cd7c27f928ca0ebf7ab08feb53",
|
|
+ "slh-dsa-sha2-128s" : "0xe922917f6a5d9d49338e445586f4b3bfcdd92b89a013edba38e598aad56f8d10875fa62dddbce6c66865eb7d14067931d640a3b7c5dc448bf7cb6309943c2f0930c78c03fad2cdfa1c21689c6f621bfb1cba1968dd28e66ceb6cd5cd4f10b8797a53a8ad54e93febced4dc1c48fc4bf768b85a811866f86f004fdc340628ccf44b295fb5310898614b6a0341a2456b94930d086ee75f67bb935e62c739fb87407975f78f372ec11c0bf8bce5144abbb2678711850174134e6e5acc3b87f14022d158a57dcc7916a8e75341488af6b1d9c0af90bf2ea86440fd1b8001d7fdb8ecb8cf392498e41f8be5c7aaa81841aba7422c45fcc0caadd52d36d1d56cd02d027b6ed9d122ab3d53597507079bd9fb476105b12e3406c1873a8bf6a5b9479b5cab9c370b79425b1bc7616e2f1f66a398c2e38f7a9ff1077918fb3f7e65f025d4feb8b13397460a753b1999b3d351c5b77ece3751686c02db0ea4ff23727527cdaf038ff060a09689a13fb7dc902cb82844b11f8092625272d8888090e60cb1040b6cc5b0ceb6854a7fa769a77523e7a718a1a9cf56b94be12fe8fc4d319b335757c6b4807e17e9ffdbb486d9910404e675648d069c55e96894c7b2ab17d91aff88f44ad609142ea3747117596c98831338c616cea7439b1754390604188018818a5fd2cac7522b2df5e42c14e77b7383744234da5fe1a02a60e18a178751eb9c0212cd847317d64dabe4407c4a4d2ccb6965eb33699c37c733d42e66f92b01cf8b0ba2c8d737711439de358756ab4ba374e7359f8ec5838f531c984e2903026acbce89ff2935855ba5e5f3d85c82bfc3975ba3d4a9721ffaab1182035bb7526f062466895c5900f854fb52f5913591828cef55cd07d70c5805327cccb9822860f32a8e8f78806e39d36ea7be59186da6ab5f1739b6716323b9379446ce6e50345cfc9b769162ba96929e2cf0693b77a558e5386945fe5c6410a2594805695a4cb602fb25993a0359753f4ecea67d0a1045a80054664a5f589dd823d11b1e440813b3bf141f119c38f9595c1eec85ce74fd0cd69ab783ff7adf32746d3c4db1153df20ca1ff94acfcf3c8ece27b9a7819f7751028435730771a0d7eee4d5a05627e9577de7a1c0d16400a81c6d93fe48990d8d4eb942233b6e81f2606c228423d52fa012ba6de7c24ef446f32ba1e1bee5ab78e79f40ddc3f8279277735564901682f03ffbae6176aa8c2dc6871cdea56cb875f25c88d955ad2e5f560fa25acb5d2130327aff86a324aaa721874c4276667404738fffa534f26e4e0dd67a9d0e5d447c2868af3f5b93dad621f528509fa6c3d2b9a391275396d3db6487ef219bf42088433b79d34ce793f024380319f1a0017c0cf821d998871fd35d2da47b774f6c6664e54090d74d087fa43ca622417314ac0a7f2d23da0e9be5242191b9096ab0e200bcee276a787ecb770a60f975c2935f24600869822ce96462d97f34c23eaa50b443a504670923b260e1698eb12a76a094b9a8b9bc2fb07c38b03b495a70e4976d05477ee88b58e2d66729a91f0fc003e56236c5285869a6eba073b36efdac3999ca0b91408282f83b179629bebabd5355381c4435bb173598ce3496dd8616eba46505a64d29a166b51b1033cafccc0c6cce63afe4f2dff7a2cc62a909853b14b40c418d3a180a922b02243637700c87bd0268e3ba09730a2e2e20065a7310d8cb86ae6b2174454ee4c01fc86c0441cbc51f1801a021da1f1fa4ba6cc0e8e35a11a0e55a4aec60d5c98330ea1822991083deb2a80efaf382d29cd0b04fc2b3289e024814281aad94ffde1a837da103a0022b23f223e63b852ce8bb89d50271b29b5dd805edf1f4339bed98ad4e4fa42cd726f3f70c7c434035cd9180a02ac954a1173c2694f0cd59942291c34a8071803a69552d71b8191c4299add494d05e838803e5e9de4e5a2d7b0f8b4a221ce677b5b365e57284f4b74c973c72a565422b2233a5b3770cf28645a18ce1bf7cd0e726566c382d801e655829a7c5e2aa149217075014492b80533bad2c8013c382aae26cf4dc39a6eace929903894f85c8e97e4be1df2bbd53fc780c46ed384e01fb40c515e88bcbeb2005df6c152f0d169a90ce3a43c2c3469a85a456991996f6e9ffab555233598f767b38307fab61336a8d57c1f6753749d46e1b3032532a5ef11082cb30e12bb6b292d0f37806e6208d4bbb7c7cba1b3b410ec1d29dd35af7d38ba79059999992088f06b587bd9570ad0a1e2352a6133a50a3a45da27fcf63cb7c6fa98e6d3d3d7987447fc596edd9a157d72d0bb60441935481c54f9c163b985c708ea1dc510f35f9aa8768e73843ba5e8621912f43383365f534f3ceef986e90664123079f7355e5a5193b0ca1bce0443e01adc00f18f8f07a9038cfbc672494715221c0b8c5dadf7a66875ad67300e5fd662ae7b4281f2df29aa0f5b7f9f70fd3180d7875aaf784eb3da36f9fd8abfcbf2f156392cd196ab952669a531bf941b48b7d2850cb8a66addeeb1447d89daac2079094bd4163d9e0d8ed52e9a93e31a7d4f5d2afc4b7d2c0b988d41c3e247237363dc05dd16d49d159005b42ab9def7290a51beb7811e9f4fb9961a7af09fd4f291f797f8eeb05bf76884ca340af07f62f587dfcbadb344c1b350960686aeecf772f59d3f5c9f6c01240667d1fa5c3d84dae1f0dc9562543e4636d81a3f0407bc29127bf4b4527d0f6d7815a941fb53e6527d5940739bd369786e710f6b0f69b05b2e0c49bfa51411319b9f7b172fc11d901e41ec54887a0fe5748b1d2403d23ed5494b96639126c1d3fde11d85c8c717fe8b01319a9668b109e2d34a6ef5911aeb31c88b71c32a6723b0ad2a28b2d8c75087a546550b0971dde64d3cd69434914d5544a8828c6e7775cc802fd71e467e0327d692cba302f681fdf0c7425ee580c413d1a3904974e55e7ddb19de793541a7a4310e50990744b4655e72b4eb5a3a8c5fcc09a545198c6475dd26a43338753855ae4dbd845d3122b16063b9d4f1170b0fb1eddbe15bf6a0f935565ea46bbbd6c00491a9ea8288822dbfe8788aec3eb3e5e42140fe3cdf16328587b736242c2aa85828dc84352bea3c6d985ac48437bd72f12adc7fc08d03371992547b91a3061c9f9bc6c32a8555df262c14dba813ae8e2f9c732bf7360b1e94498f5a1248ca4a0c020e381d8c25f4924f91bf0c649207b1314bc0088d2f15f662a2594962596ea66c036677c451e77f051cf9c5f6b83ada58109f68b415af541dff5d6cba732a938ef4d425243a3571f475af0a456a7ea5afc7c78fa195780b270ee1f4d69fca7c93087e103595af8757afa5dd23ed17bd723c1edf8701a1b4bcb2102ab2aaef2df7cf485370d310651f6e897cd2d687375d29c7f101aed941cbbbc12ac7ad60c3147e41fffafb766e548f0e96bc911f38a6d1864277c170fae28e4b06fee1d1925923432bbe28e41f8cc19271f68196bf4724278f8492a6d5c0826e03d8dc1232c0efe5c7598b71be7d6c468ccb1077d7c8bd4630bfa4a108d58d5498e40584f6ab690e27ec8152c1c39bb70ccf7c5f2c33e48af63d536d9e7ba90db931783a9cccc05c22dbfd90f84f75d139aa22b1246a15534f1521ecb9031ff0686c39b728fcf6e0323cda56b641561a88c6f78cb1d880d102d26b20213d03af41c91ba6924a0ae17a92fdb375492fa0b514ce2fe88fb95d72e5b1b11bff99d1b0ea0832a0d3472b5880b3ddef0bc0891833adec1f7797f86fc549b22df2a0a59390a900e588cdd2405e5afea987db98554585c85fa2428cababff59c17713cfb100084192cee9f4ee3855163ce76fc59ebd4b23766b0ca7c2d59754ca42ebe3c997cc4cdcfc2ef455d3afd488474b4da2a6ba278c196616f995c4398710c291efccbe36bb724bff2d097095f440f79917229a6fce31dbd89e58696c4571dce1e535adf5e1b0942fb5d59a13f7fb4eb17647e83e587acc50d920db2951bb48e1495256e10a62a8d43d3cb7719c54c24f546ce4937e2ba7b1911f5684068c365398e41f7153cb1e2b9ac014bb7395a36efff14ee94373dd128d725dd6ae6af408a5da12ee540fd8d2264b24cc7fffdb2859ce5227ec3c3d5e0bae49b5f495a39e5d6b3baf7c967b21a55e3528fb0bda0e9f2a3cdc37904005a76b07d044ce439a345f5ab69a3db8c711d478288df2d4776d53ccfbf49a06d0d0332814d34053c98ee3464bbf46309b763114ddf1073100c34466cbf3414b4bc7b8ee73c44d76c46435c0354a71fba7d8ba8b0248f867cee79a4beacb5dee9c45577e5b423582fd261b6164de192e98aaabb47179a6fff8827221a70c77df46d01357bf27392d4dfe3b8e24abe9854d3109b533edab16f495eaae07562dfb4428cefbffd748f144329f7653931a9f65a3b024bf19d2fe04764d53730df662469a19c4bd966dc925b1ac52d9094ff7dd7268697468135000a8766d8292f9079f9bb5601193df637f8192812a9a97f604015ec15c89fee9f700509cd745da588a86c7c756bc84745c593bcb7c7d9d34bea98d505a57b31a90833e3d1e154c3b686d5d8a20375111bfc6964bdf2f815e160754b56c59fec8fa533cca9e21d4f688ed94cdab427f9e179fd308856ab7f7206d13d65cace5f8d65c8b95270559a7d33c76c81794ec38d75e2b3f9ebd1351e07da0540e3981d447558d6c21ce6b0c32bf61a3f554cae9edac7a92e2e25965037830c57f30a021953d91c8349b94181ca8c3bec9f33327caa08e437e542d4cd9742ea16801aae94e19442030e8c95bd4f23d88ae9a1f1cfe4a80b046f2e54885c54572a215f17bf8359db4edc830c48941153bdff79a6777a67a9ca0ee3c5d2e4497871f4797974c1d932fa3417b909ca5b29dfb315bf1590829f1cfad84b9e068213b8a6e9171c1c41757e262d371b7073d1b90fde5bdbafab76426f486581bf52fb2a53df2fdd0a6d5065afa6148606a3dd311b155dc0dcaf9f741a50d105053225f1c223ad0fd8af47d27db808cd32f733fcc8e2655523fd36a906c6e6a1d6eba56311424458b446bc1b77b866af76be210b9a417e87903a1ba2e431c176a82cc5a71a4ddf29350efa6dd8d1707d3884b31b9b52bc876b6599f40b077c43d815d2e02ba043505abe7ecd7dcf73818ceb77a09ea4e582616f4af11133a80429edc9a434f3cd2b41192edad842b433ee7936fa5c7680023f0727f4337c53912fdf6fc7e6d5c0dda2e0a8722d5b0565ddd8f9349815bf38e8615b5c7ae35622d7feb7907e6423c8aa7bdf57355c0353da377977e180b88ecb1faaeee2d7142f342263e636eb99c78af9cd0ef0314d9b57fe1176bf8b13c221b5a05c1f876194ac26c35b0ddd91a2130276ac402314367d99c2e300a33073c06dc18cdf5361908d58a9553268c6d0ba19ef6f6d0bfbf2b1e2f5d284c74695189d8a3236e927d9598a4be253d0492f98015851be3693b0c1b3c4a73a95ea57c20699240887d501db5d3525e787dd1a583c2a831a9b59886c873b8ea5dcec376ff37fdabfa21b74b3968008dfd9784fec35696779217b4f5507ea15852f751af31243dbf857d66cdbfb2e290b52f67312fe5d93bdba25b1b7dfb0f3488974a7ff0e437cea09d0baaba7bbd2506fcd182cf0dabe7c262a823fa1dcfe00bfaf7cb5f54283763a45134dfabe9927fecacd648ef767fdce12d570693ca6aa10c74c41761f64f31139f3aabbabefe6c7bd79a6a3334cb465f4203604c0288c49db25bd25c6c4c113e09fbd65c0f271f4a373294831c33f7b2ef392e4a4b91a3973d38473b9f3a485cdb04b7f75a833e2c0461c6f27e6d8f518d3a4366ea3bf37f43e4408f00c4c72ca8d0a9fdbf1ac7fc9fed47e8a3f3f33ebcbac25fc2e70bd39a85519181383597ccc3503e597a734c98e98a15be8bf4b37330f585ea138e5a2e4104ec1cb6f5a23df7ad83751c32432033f072e8ee3cdeaae4e7de98f9e58633bcdceab69ff60004cfdf51b54e9a33232e1df86ca9708811a69b8759e5b2daf57eaa8f1f74ae6aedfd9106c105a6cd715b66f561c0a0500a501a9f3d50a0b5540ec96d24fa5f6157f5465d413b204a224e2b752a49322a90aa340e4422e60a449cab5b6106135ad34ae309ada87ce9a99cab959f6c2502b2da99d8ef296884f4255fa88f38908e4294f799afbf3d664900c5230ebbec54328167495caa99942c13e834da5c488f2dcbbe4d2448eea2657a2f82a91a53d09b2b5445de8c8c8ede11f028e067620f2ad83be80d19f3b9a9f3b81bc8a405c233b2b17ce8ee5e0ef05847aeb36f219817d735faf6092d13569cbf069696bcbc50cb50cbef921f8fe76775f1034e73bf04431b696eae4943efd78ef6c19436c76ab389825e57b23f4529fb848233833afa418d85a92fc865e634357071bc415da56078f44bfe306d3b00574c04b2e94d6b801d5e3bc03686d1bb27dc2753112b2c22a43610a4dbe1e78c9f4f6f2b4ca3ccbddc2ce0e78fa34cac5935bf0867bf14f40648c805876e61fa841292ef2d2d53ecc00319a6df0bb6347dc865e39d9da574ad93f9cc910a9eb920986d5e6b331cb29b45ff32ddbc9e09b71eef73c8673307d6684a34ce85ff3a4208741b205d31011555b17b7c5effc210ad9309468a007d76983011b88c818eaeb3d3815a02d76f735433192f1bc99a6c7dbb57e107caf9e986248ebcb2e9c28279ea1e19a8f8027bd6f8728c9aed0b974322254e686526cd9ee0c6720de4eac01cd83e5705570c249856ebd7ec76cddd98cc096fb93db8ed86a5aa0736c36d978c09b915f7b9290cc255ea1a4b355888fb96e506cba34683c6a890c77d92fb01bba6b69f91efb3e4313111dafc3a189db063195bb650e0cf353dd975fb5c286f86b8f7d982ca5f74a78fa0fa3d693980be09298bd41c4ef38874ddb95e928494b9e345525b00e4760a1d6a4d54675e39b1d955e20a58f3ee65ffd1e249eb3558ba348a2be114f396c422c57314ce6df0ae9406dc6bd0bf5f1db49f012a03834b3314dec7839860867033643aa7dab3fe17ee025812ad2c05484abd0bdeb67043be2a57533d294aa03f24ec8afae512537343eaa16b07eabbbd2cf6755261ee473dc457ec36775102e1c8150248e4e51dcaa6abb7753920bd5247ccf6dcfed9dde98c9f37938d1c824fce116f39f0d67ab9c1fbc79e034e8bee6f79715433d485edc70e5c098ef7bcf2972171da06cd2f19cde8f824e0f2bbcd816f7eb87b7bdad659a900f36df708d3446d8e412b92142d8414f3a0508d106473e809a0831953e2064c655519a8f22fd0c517df7ac44d72a0e7b6fb697b188133fdea4d16e51c6da3109f7cec1a43fdf47957a35f4651454ae04da9e9d5a1668f46cbc58422c38fdf204f4e9c0df3b1f0ed2e14d0e008bed642353ede25a5c25684e7d593eee9d14b3a5a81429b30895ff5d1f7f4a124d2fc9bc1eda61e8e4bd73b57ef1a168cdfb1ce1d70955567a3d949bab203c379e3676932f96c04ddd0271a6afa0bd55988134de26bf5d6c725c09e04aaa03d393a82805a366e0d98e4b65bf45e05ce45f4dbdc1f8ec052102df08f5852630b706dcde9a3efebca3852e85cbd7fb6e6e00b4bb397004db1602b7f8c0dd365eb2d946d00eacf0ecedae83d26555a1bef8be88eee9de9f9811074151f0cc747f36d45ea7290d53c18fa8ce73f77f54226e5b1719a9bc911c9d7565693836edeaa6cdb7b2e2f9cc8c86b7c207cc14c261793df6c4c623355db04d5eac01c011677d26b764e9048bff8d76e2b6bdf792c57e044eea4307f5a3a62900df3f57ae88577644e2121134d61bbf3100fedf83371438b7854d06340ffc00383a0a4789a6a85062aaad3761dbb3c77e61c5926b0488f711a77735dce429b6e028373dd341fa2db5394867242331168665b4d7fc4ef96b12a571b8b25d44fb0de64b9820734e5647821a038428d67dbe95885526c3f2b8064e8baa5144b7fabbbf5a133c4b8d7a2f950a4fb69f9cdb37ac28cf0421894f0b771f80db988e25fb4ba9991664c93116bab82ba808693d583a2b697fd2b5eb673f954255da410df58231eb7c89b8257c5a68ca0306d088638b2faecbe3cacbbf77725e1685aa81d965f1ef663f1e474eceecbd52943c2e4e0456b52aa0c7758cd2fe67f3132176113a16dc9bd11d6dc03ee643fe8bd6677f2ec0ea754ab499e00ced482d78147ecb2f91d3154e03b57dfad4e4cdab98e134a609a7512a5a0e7c3c4adc9db444238e0fc3c3586b389d8d090ca46222a9533672eabe4fabcf61beaeb59c507f2941ced1ee4cd2afefee5aebeb354ec33cb85c9695426126f016929b471b9cc07dd6ff787fc2d682cc1e80657bd656acfb865dc91d6b032785cdd7a1d66d4d5463e142b6f028e8fb5bd6c621109e7022818b39197f85fd6ad4785efe48c4509e9a537f10d4fc9d23f275fb9e684c2f827868c9ff3baca8faa59903c829bbe1992541d15d538e64329e886ade0c5517cbab3b15fdb4e82506e27f449e268b488de32fd036fcf80f6c97505a5f33e4d3a004772a8970a3fe54049513cbc57131ffca1c82918a81bcb879b8f48d4300b11cd90069912ec9e59d10b6bebbc24ba1061c62a8762156df586a4aa758f13cab5ab59a3b1ef7d038c68920eb0a3c8a673c27b6fb80e5e8741b3b7fedff0c068a83e72373da07c8d73abbd9fa0084bdc92866917b546dbf7a6304f04b18d9bcebe2b4bcf5ac7ec526abb4a52a19094c8c231668d063c5558bdef0436ac418f42c5f41f2df996d19d48f8bec412de05a6a3b079e5b6ac1be0773814acc3d20166874ef64a6cf27f7fc72e0232031ddef1a6a4ac9897a86605550dd635c995626fe985aaabdd937bafe3e2a4082f0fc875ba7ea963a8e5987ad400423967bba1c0e369263ddf16fefc88901be069fc617ba6dca90608cd4a9d86476f8cbb41fc8197a9ee6fb331aae55959d107bef29b4f6f064651964999fb8dc904b8193dc7582fd47b0b0fb912f1c0c3838dd489c374ba5ea614cc80d4d196291c4a54989ae628dff5beb61612353ea0cdfd75962ab057bac887ce7f5df01861c769b88c7e1682f0ec6f7cea63598c3e6f41093d845db95377654fc56702a4110810917521ffada7432b7b16a64699e6a955a4273fe9220976f8b1ae9ea79678a3a74344a44c32454e7bbbae9a1fc440811693f66d63663c84bf847e0a2e8299fb0a6413194231a666a2efe5ae1c41db1cf12dbd8d58408cbeb1a9507b5b09ebf416f712b0040f8300dc5188e673c5ab1f13156718031f25cd5156beb8e77e95b48f42d1361da25a94cf1bb4a2a5c41f8da5c3f6a30c00e7d0323f7bc14583fe20815f468928fb69a480673b6c775b2d1af6a176abe5f6c679aae41ee1d5c89439a798823b65ef718515ceed5a7ec87eff54479a9afb48d0fcdb9a240e946719598512220d2afb20840e3680689cbbbf096e7d7505d1d854faacf024935a672278c5dfad333373015b11571b2a7329a0d2fa792d838ba3fcbe5303f84cc6d0454b89cf740bb0f83b79c98b38fa17dca42c5d57d8e86cbe16d46c4c0caad1f55ac4a399d9755067b642299b6b023e47ef74343b9d856545a51907f86034397dc1cdeb0856ea9fa753ba82c5f7e44e4423684f1b03ec59e5cdd96c03dbb1421e89bb0d1dd570309d92519e2b90fc83ece91ec6b13134cad1272f0fb1092a21e0066cc0a783e566167b52856fa6ef12aca963dde340e94f04980279f67a1eaec339d0656c09a3fe91a2b1885f1c09e831471ebe78f2af2efa1fe5821034ae172082de7cf5fd8599f7c575311d35248f2b0e6342cf7ac4bbcd19942a74ae9a9ea3ef5641f70ad1746406ad9bc24a1a3ed17dfda75ad54fb920ee9c92b792b76d42cec2c22fd1bb0f7acfa398d82b5f016f2943dfb44ca1d96b2a54ceb7595837379d62feac76dfa610a82ec947047176aa74fa8d58aef3d34e79768ba7b213a8c44c6e9739f05eb197148b2d2f3c5a1dbf0d4ddc4ae2bf0eeb93d2d4d0990c2c21ae34300a3139ccb5cf216b4031f5be4fc61b137a952fd516e45236dc791b692910a09a600fce9c14ce9e429ef1ae3ae737ebe9921d10522a4507d0794fde66f639189cca95923c51f97cfde4d57c718b6e0ee709227fef69a95a229ab54a4ba9d858115ac04dd0a594ee8fba7d29a23d8df53c131dbd6f7f47c6ec482cb2da38e98a8bb51a2878950877408f0892199ae4e94c4c8eeb614eeac1435b2947ba67c30ff52ff4c958eefd318814a17f53c8ae691d3fd91ea8196bd82d4af9fa216e32636d6535d5c68f579d3066654f2cc067873fea5d56f9676800892f210363fc790086a778fb721854a0abf9a2403ac6de964c2eee9011a44cc0d66ced8bb0634cb986a12b0d5d875db0f26f008555f7ff57f42a441250dc5d13dc5342ef36c288127d46b4a2cd85e5189877003589579aa787c46843e47666be2ca6e8aa84e065ec77f0f77e5cee75785e2358a5e1fd7d540ba1d36052964d7a5de9d1598cb71b238c6a6f2a4b6c72d8c5b0a4c2f17342747dcfb2bf7bc52256fa21741e1f8e7c2b749005ef240296ff9935f75e943c2e725e9f54636c3466450a49eadcc6f330558f2146426fe6786f4ac6fed1943d616474f7665e8ecc2612479eac464c8313066de5fb652beb42ee17c0d9eac4496b5a732c3df31d90e24ffa8eacb12b72dc1d393d0880959e0ce9db8141ae1490bb12af9bb2d12da5809a348714024d7beb73dbdeb4d7adcb68c59ada159fd1855ddfaa33e0b985d7bc3f509e64ee52b5057656295dc669939c45d89a07f03c0062e20e309a0388725c993f74cfbb8db38b85f13bae8b27a4da755398f228d79eba2ad5101d80c75eebee608dae268dac0c3a1c63e311fd82cddb78f06fd576314ffbee8ed598818894fffa54b56e7a7be5c20ac553d106609f4bc757acfe7b116f695fa4ac3ac93bd0de4bf87aa6aca5535e467298aa934c11143bbf39c464db663b97ad416b6501daa12fa8d9aaa31334851f36f654356467cf4f42fcf0c4cb239c2acf7c7938c0760a6a8f953e75471881c59293285241f7b73e4b3dd5"
|
|
+ }
|
|
+ }
|
|
+ },
|
|
+ "registryHash" : "0x05d68cf78b088d589f8b54243857a41c5a42958ae0e5807e3ee2fae9c6501b67",
|
|
+ "root" : "0x26da256a0280b55dada254313ab5cc4eee9fbd5ac2b37c229e6c044c73d3519e",
|
|
+ "rowHashes" : [ "0xea11f4ef69b54777a682922371576f1109ac0007190892350c1f2b156bdfd047", "0x97cb598a18b30f14e7769ab0a48af96205eee47a865c21ed1a27eff79f173f00", "0x15c5ae7699bc260cce7529044a732ef82e3827233ec01ae245b4ab39064b7fc3" ],
|
|
+ "merkleProofs" : {
|
|
+ "0" : [ "0x97cb598a18b30f14e7769ab0a48af96205eee47a865c21ed1a27eff79f173f00", "0xa6191a53104eedbcee8e72c8cdea7711bd0892700a46d740759f19ae4aa09c18" ],
|
|
+ "1" : [ "0xea11f4ef69b54777a682922371576f1109ac0007190892350c1f2b156bdfd047", "0xa6191a53104eedbcee8e72c8cdea7711bd0892700a46d740759f19ae4aa09c18" ],
|
|
+ "2" : [ "0x15c5ae7699bc260cce7529044a732ef82e3827233ec01ae245b4ab39064b7fc3", "0x78a4074ddbd4dda0362d2431f7629b0eb3dc490b4e83306f3e4ebe383d0ec907" ]
|
|
+ },
|
|
+ "ids" : [ "0xa5ea2fcff9e3cf29d0c6f5f147b67ff24aec3bd4", "0x690a7fd66157e5b777256ea5214f634f61b3a72d", "0x41f547a71d1404f147606491f3b96e49f67d4658" ]
|
|
+}
|
|
diff --git a/consensus/common/src/test/resources/vector-slh-dsa-noble-2026-09-03.json b/consensus/common/src/test/resources/vector-slh-dsa-noble-2026-09-03.json
|
|
new file mode 100755
|
|
index 0000000000..b5d70db943
|
|
--- /dev/null
|
|
+++ b/consensus/common/src/test/resources/vector-slh-dsa-noble-2026-09-03.json
|
|
@@ -0,0 +1,10 @@
|
|
+{
|
|
+ "scheme": "slh-dsa-sha2-128s",
|
|
+ "form": "FIPS-205 external, empty context",
|
|
+ "source": "@noble/post-quantum 0.7.1",
|
|
+ "nota": "AERE-SINTETIC: the public key of a test vector generated with @noble/post-quantum for this cross-check; it belongs to no validator and no private key is in this file",
|
|
+ "pk": "77868c8946cf36281f0bcd8a5b299c4300d20feb42aa7a08893f402ce0c7b64a",
|
|
+ "msg": "616572652d6879627269642d63726f73732d766563746f722d323032362d3039",
|
|
+ "sig": "67fed7799e0b273a774c759571734072e3465b9b32becf6d334392143f72f49039f3f2f4e342a003333d1e1da2deacdffe2f52f3552f79487e0e0fd35e2e657152f6ab027523f4eec039a9b22d661efb90c4401d4a008693d862886ca038a1539fc8827667c85f81ce364b2dc12aea515786d606df7db8f9fcb7d1275eaa07051b481be40be4ee4905eb491c1509b2c755af8ec43d6bacbce519a39f19c6cce3de80a0488a3e724a33327ea3e85cbb9165e1395b744f64a637d79d287f17c4d61bb60b9e5bb03e88f73e19e0e81e3ea4a44d482d4f649756e3d0cdda173c372ed55470fab7e47c78fc7b189814ead0024cee40005b4d5b1a0e2729995c003e7c5c0843c47dc9f726ab8d0724377602e79fcf9f8b8e8cf52297251576079fe4d984f758e814c71e88352bf325239a913ffa8b14a3b94124d3ae14eb3c61326f8f1fcb8b7f70b1208cdc509a11a33d86c8d3284b760364f4095a333678ec856abcbdcd1f30867281e384bc4c9861aa82497d5b6bfd05c4c5ccef01d2d6d897aa9987f393916a2fec108e26108198f68693d26989bc93694ce191c00104ad626ef5c1555d38e08758d9211159aead1283e5276365f1e3c57df0d8f09526a8c6543b086f2a4d9ff6ef34333f2ffedb1a7a18f590b349eca3563008279563e6149bc8a87cd111b5f567636e0ba35ef93c6d97aec4b7e319aa9216eafc73336454161c35e31efb6d4c30a200b8186d8e683710ac01d330e3836f2594b5583b00f10ace8d607a3f3e53fef09d92c9ba46648acf78f72d74f6e9a7208b4eaa5a9e152b33c3f27ffa81c0401b399c33feccc21d373794973c12100443d59d71e76f37c8a688fb7c3c4f73a68ebeb204a45dde88d384ab2ef91974f8ef970f2c376107a05c7e4691522481e6ee6dbe478525444231e2bc53c530e652844c2342410214d401f00b5cbe01736c55f0a473434764d568d941e556deed1bd2678e646b41f5c7a6fa11a259849cda323dcf6e64dc64cf76e6734561bbc7dc0b49da4598fc79e2672e1aea7187c2d39a93e50052558e704fac8d963fc7cfbc424ceab9aabea9a151143ae2c25c945cec0d6a696b696ee4c8ce5c4f10248117f08771c002dac825c807adc5395af6ced8e8c687775137dc17319c0b235540f9dd7f0855aee37b1d6cd1b5033eeb824c0c6b25208827d1cd1616b829bcc266d4cab18a90a664c15d24f8f71cb4b744ac1f2aefcb72f9c1dad83cf48a6cf5f0f38857ce139c5d546310778b73488850c0c55354f5ac8649e715c5426fcab890f7c3be3c558e45adcd1bd44e37640a10519338a50f48fa394d9f6669a143821d03abffa7c442f36f09bb83811cbe4999e1cd2cf1276470d7a169e3900fd6e4399df2fc7e6c74d70af5cbe3169ee977f6a68bd29225b775f95cfa7a39bf513924910c194919f92f3e72a46e420f217648bf0492310f1bfeb5e41fb384a4d40988e83418e2e193745cfda92080d755e6d180b922df1eafb440c431d92dc8c6750f564df1ffbd4dbcefc6f1b7fbc3b931726852af11f18e58d4c998d47f985868bd74bc45159036704730db0b279222aab572ff762a6ffddad353cd9149118da44eb732d8fa7e462449ffdd0be5518b63abe26f360b837b5e97f41009a7adab94da2603fb3b7fbe902ca56d4f4a4cf6a2fc426dd75f37c620cf27f18187cc59fb23518cef5450ef0d6117ad5af77d7a436c58b90b9b1adb7aa8accc6f067b598ea2e2a12b1b7c4fca5331133bcdee7337450453548d704c4f35f1a9489413bed593fe90b57434fc22f51dff6de52db277dd83bd157de23106aa62531035ff84daa0dc71b330c84920ca14a922342437e0bdad4a3fa9e8c42639a759cbba77dd49b2a4e19a55cb01ddd7e2a680e37e2d844cf7e25c367009bb9596ed3dfb95d9dab8b6a8ea56979e776945f6ea4af3f4ae474d16c04acb97c8e003be87287d2b1d7a06f680d4419b537d67b20fbe377cbf8401f10eb7e709298a7f06c63b80e818f25b96c862b20327f228ee78178af3075280aad0b216cbca3b3d984c972a3df1984296368e9aeadae0f5604b0b556fa2e4e4df4ef812e5ada45562f3705ab82429506b0667e5015f8ff92b5a7e9f738c1045cce143657ecbad7b61122d7e8392012277e2f2ecb8b49ebb67f34c277004e085b4730d17eba1c1afbafe43f32ee1ea15a5e19613cae33f4dc2970ac31eac84f017622ce2c1ef1f1adf7882861a6f02cfa59c1c19301c628725030c0b43094a6968513152737e0af2f2fe1f1a27cf3a87ea7be403b12e7cfd26930fb0eee15f60048b62ceec6a322d7cc17b53e9bd2e93f22c78598f778eab003d9aeb2bd14ef38786bad3fba86875145b203a26229af48876916b1982cbac1c618d9e084d8eca8ecd0caad4315044126dafa9411af94ebc1f25d97cb27abc75d13eebee3b2186504957c24cbcf004e9b7d22de9dca8d215cb0c43818fe98a69a0e85d40e9892c459f498c8bcc3808724f3cfc8b0094e096cd67d6226c9aa3c4d3510cf16397881ad22fe6e2d9c87bae75cc40f8003b69f78f4676af2268dd982e982742a0ae85951c084ab14a9e34dc6ee509add0d8c6a0a2274135f0eb209652033912e15c28c9c291c30e33e4e2ee423208c66effaf2f4ee4d74774e0a6386c57304fedcf2e3e1044da478a3d33ccfe1cc9f925f2a1ffdba7d2dc30a7fdac96ba2f3c46b52dd8529844fcc8fce29a59aa6ed496b9b50725dddc63acdef7364d11dc6e1d3e04991df87859a304095eca35eb9dd8ad02b890863faae4edf085c8b9f9de3efd898d7e4ff8781121057e3dffd6abaf983266626b205f590903a32027357034d718fda15f8facbe82cfb8875c6c8b6649c2813f315d845e2d430ed0e9011f6493abc58fdbc2043cc592fbf2ed202a3c6202997a71d5ce4c6d746cb9219c32204e276309de853dd37e2eb4be2d27ab24970e2f87a1db15f132835735b66daf7a114428359e982294c82865fd7badeade0a2baf3c2c8f61ca3a22c83a0fa6c09f187a0cf5f70f05586e23ca5b7f648d20b9fc3215013d6b0005adb89589535d79b264acd4309b035c54ff87d38c22c02959d5110ebd80960a0dc2d2416d276278219690acef13f298a19b887b29af6a0cf38c30cecc7a73c64da71bda754ed54ef0cec5208604421fcfc3a79e20d871db9a2a60605cb98d081b965ad75580e5209b1ba9d94c2e626da3caa998e43c72a9998f7c0ba1c521ea3939723fa13cc1262ccf4628ff00ab2d778e99dc125a16c1d894b3cd4bba4bd02085458559a22632aeb9cb2e158332e8b6012a4415e231df0792fb931e2e2857210a3b1af79517b6fa55f6c7ca6dc1c056daec11fa22666c404b1b36cd7f46dea36ffe10ac71100986db369e71bb1c378f77e401eee32ae0e48965fd8b500ad3efac1effbd3c053ba210a2a58a25e7b9d5f0fdf79d58477455cfc0b2604492970885fba5ab2708b2e676acc61642889e958f23b5212e119894b95a9aafc904986db219160de187b0ef33f07f0b598c7a44dfe7c6508c403a91dbedad5dc26dae9bcd21903e4ea9754c42b3f01bb57cc3639b55d3aa40ca3b60591b26ebc5f1e225632d2a8f0a3b20ec1c13c8a80153f9c286f34c719feef85fa5f53ab42bb2f7dc4f02f3e706501bf3dac0d452a002a73d948d04a232439d56568c8d22991fd178ec94dfaca8f1fcc54d9be92d7acb25e27e45a9729b903c80cd94b806ade21db010693923bb45900c55bedc582ae27cdfe2b665dfe6bd6868976035dc85a9e85a7010e457736d00f7c685b0393d4daf163164d76f3004917f0b88417d32b1e79d4006cee735c4eac9fb3e6acb5432fd58495de8d314652fd286f36ccc424f7bffec59df9b9062ca6a38ab8adaec902f7d1b48b5ffab4b5384ed7be957bd2795bfe2a9caa72e69b9a4bcbd106ede1021a8221f47c7f41509c3e3d32fd1888379fd7cce5693ca33bd8810ac0a55a6a771c995d2fdcd2e94e84ce2ad1ab3e490ae9dedd2403335a9925f5f827922e3140dcf347f42f1fa6ac28b5e7afbde06fc100f95a1ca2f8aad4d1bbd789cfe0f0dc9ae8b1d453ef3253435539c9c01146fb60a93323e619e2f7fdfbcae40ccf84fb09633db41d284b2fefe7879a8aa57c8d3d0a96eb287ea865a4e9a15b8004401d6bb3139dd5ada82b2eaa0b44b16129568ef70e35844bf2bedd7cd9d3790b57e6bcbee06a2e9371045b2ea891a82fbae78e13464c6dcf3ea574328d265548f95bd507ee3c0cd5b3dcd3a5f344a334ebcc7892f6bf5f8a63110e148baf16344b09dbec02dca4f6ac5c86d6e1107646150a2edc785d798761f35551196bfb70dc7eaae2bb647197b946d7ba167d0f6e366fd633822fd1188b3c8bbc3a96da6d24d62ae5e85dd07551324c73a6a650c75ffadc0ad9737f4cb214ffe72ab6cf30f2a4aab57c25e5a99eb062e54d7e0aff93adbc2e4767a12796650c6f5b2db7463dbe4d5eef59ef13a0337cd38543d9d95bb66b26e6c8f55844fb4652582271206ef0250d38bbf795c5188a5a82755873871f0211e4f9207a257c5fcdc467913aa644cb9bb7eaca94b3ccd1a6191e94fef075aa482c1f11ab042dcbbad46c796241ab79c2f86bde9dfebddb270ebe7d8bbff3e614b98f54c152a54c7e75f68c8cd0855032e0c206ad25d7519ab3bef49e3fef664d9d0f0af5ea316c983d4a4013743b07203e039ce6e86b35e85d7ad383925cfa8ee6cc44fb5f1601e303657762515905b22ec2bdadaffd109f807667bb61b21162b6b2196a51b87303f8fd968a19426bf92e28d661c52efa2b58d0726539ba61813a3a14ec7f8deb5d13098cd03b1d7b545cfc91d1a2202c7548ca9f85d2ca888107ecbac63981d3c6084a7643d86c0ce773a0f023fad67605bd8606c0e5158879859488d9ba3c056c762fcf13695172205919c71e53097c3404f8566d9903bea68d39d5dd5c5ae04ec9afc682574f488a7b358f57906889fbfa02d451398f8bf433f2fdb0d9ddfe7a11c9fccdc58b9521ea6adaf31c78334decfd7f6a445dd5c08d71292d12c8f58d356cd0a4755a2f205bd1f833aacf31ef9374c30411a470af9d52707cedbf5d7c6677918b16ece8b44020a0ad0108d3d06f42c56492036a16f7ebc1ce146a4ff061c8f28a3393550be8d02e03a753a4de0e7a2c1b034eeeb7dcc25e36a1b3fe8be79032da57fd972c8d460c841315c55aaf47a1aa4118766bc20c5be078f8636779bca218a7b3c67eb231ec92712eb0583dab001d774fc41edbc59d29b66b63c72daa73c7da82e619ae92df376dc5048d484410a42270119a390255cac3bd48509201351cd0975933c402dc2878282108999bf9f0803ba69c1fab3c79dca5d1c48069b6609732dc5662c76a39d5a87bf0238275519bebee2a6843d7da2223e864cadc64e6bc35de75168eea1a4c76a956a5cc38075f019e4ddc9293e1674798913d0cb6b622ec2518bf384dfbee4f0e6530217bac4144bd3481173c37b5db7e25cae689eadeb5e35a40e1c4f33dda61b38bc066fe665e5375f04c5ffd282dd707a3ce8f29094075765de4d199800e38226dc95c91984afcc89a853126be1c747307ba73544b82c7b18b97e717bae81fa61fac001e2408ceac060a6c94bf40f3242bc9782b7f179ece763c73f21b269e7b79303b9c28b08278bab462e017995d9d4b488184af420292c8f08d92e630b34d6cafea52616f0f405934a16ed6515290869f1e853f60d5fa36453cd09c8604f8384be27992200095c3ea208a223de8930dd3248029ef196257cb40024da46188d925d3c0a19b3b01cd96310489b26262361320d8735838691dff538f54f685396fe780f1d3831311a3e77b57113a3a23f747aeb4ebed6aa7c1c16bd92766db04253282da0339fc49e61f1415dc788b8d31db4fc37a79283020029470eb5797fc50d5989f38bd9f46e35428e56c3622eeae2659d427a561493f9236bb197031bcf556825ee30ee98f4f271b8b9846633878b07e2792eeb4177d0ae2e77a6d812c7c8e8e2b7a88a0edcf759958e17789079c35cbe6bbd3114a5682bff4c005e642d3be071d9c07f00339f6bdf771d2d46d84a1712290eb71cd36223fc0fa3d64d6ab0b44aafdb96dab69c490c4e68acab6b228fa528efe7c41b09a93a2827ae0405cd011bf9f516bccf508c995588daf2cef1ea3fe792d21772fd8bab223d740d554fa7fbdfa0d7c2083b6442fc3ac849cd9dd0c13fe031e8b656a2849468b70745eea37fac1b0369959e93675048dc89f6029a378a014c5a65de94c7dedfad0ac0a2b2e6da90a25427fee681ec0e06824e32d9a85db98738ec651b60c71b45c22810d74fd93748c786bab42f8697fef5292ad518af07709dcca4ca2d677a187eeefdb3db719303c2cc3fd1f74e30f882fdbf44c89661306abd6431a22c0bbdf3d1b5f97799ebf29c05e62a5894c12538ea8de88567db9421d2a4b1c7faf0f039d0ace438a7165b989ae86e8c8699e3ce10710b0a04a09335dfebefc7217f3e0a919b57a1db05f81f7baf9443f2d71917eaeb52529c1491711b355caeb821d07238f7bea601109eceaf4e1503b4e0758826454b44357dc1269dc4f4757d8f5c8b2be605f7d7026017523d8b3580b72e43df61ecd5aec07baf3393a8efb18cd7333b1945da07e973b8c5bfcebb053d4b9c73efff86e3c1ae424d2cf3d48b38b6e345c74b8015677da947338276250c0a21db95d5c293966eba2e105acfb77f718845ed143693f6bf39974481393616ac8dce0e9014e07442e9726b3b5f258c6510842b394559e5a5763a19d0847e910afaf1a6dfc5b724bcc9c05c130ad37c1d967b1d07c81301dae7df61b5d62c0d1f7e24b6967cfb673681f1f8e91862f0b53c7b82096e37084772da8398c2f3cd0c704fa3519bcb2aeaf18193d1a8cc8c7ee285878dc665d2eecb857776bd8984a5796703a659effdfd67a1c7c758195f310baef4353804c197fe69b2c53d664e7722a1838c0719a462a4411262b3bec89fd5e6e3e4f1da598154bcd0fb12806903fc9656988f1f7866ddfe3d2d1224cd447422b91479ad69d48c9472f7a669850150f1129c88a8c09ee744169d6c550fb3742b2c225e4a01ce1a12e9affeade7e1df3b865a94b8522aaf79ce42628e3632f41a9d41da0e42b24dc80454a3d79f8f45f83a879acfce73658fe7d447d1f029e4966dccf4bedab315e6b7e265c698e969327042145b981c828eea5f81d6bfc3af770b0ea9ff412c640ce78ee297e0f22db7f71e701215920c7dde71d08060aba05a8c972bf804a4e743d3ad46cab8105ee6a6a718467fbe7a10db8032b611951ad158762436dd373d1d1c033d1b7997f9bd82ac08d12df4afd2003a9c8f40f3b29126e45c05dd325ee5d60f96cd73ef915f091beefa7ab35d39983b3438feb3f56f34bf86d258b04bad97f8b9c2299f1261b21bf2b7daa15a9f0b3c92c39569f71ea198a18115a4bcfd257d4ba98658ddd6a50623bad3f6a5bc1bc1bb665e4a1ea4ab99794515d1daea397420cd53cf2dd7c3002702d1345c2b8c861794bcc27df9e7468ede1608aba2c1504485cbc021698eb44ad5dbc4316ffc4de11edaacabb3904d036e02ed7a728cd29fd95b733bd2b0d0a3a7e0501f57bca4e74f8de6e412a9e21c88b209a9e3a32d3846d12e8db08f08b415e53eccca3cfac362a5da2437dcf9b5c9f89706155fb260bbda8cec5b386d1186daaa1c72f4940e844b3cc9fc7a60ab4e22d481790010ef36be8b8e025b7307d70e1ca3e11e755f4039a6d0ea55ebf86d309e6056d6e1b6732560026258d7b6e0b5ccebd59ab7ad5dd48dc41668b223d1e2d078aa7180176c33cf96bc466719b7fc8d444510e5fa3661e8ebc74d2b515a8d08a280b419ce245a2dad9ec876ffaa02d0474ecdfed995e52e880011a3d5febc5c520aadff075a4f9975eae6c3610e12719ff87d9586a029810dc7d8d4cf1f0ebfbaea18ee6b2ed19e387c18954451a943701d1f3376c9acefff7a841845af834acb99b54e8d14e341ce769242d6d6b558b42e63b62fa55c7ad7482175c81d11d700e1196ae0e3798b4e8893fd194fb0885a9d57c309b3b01a0c7ccc5f0594d12ec1c21eaf2af3ecf90cd5cd364a2edebea6d8dd3865c7cefe2ef66da644a630f955f472c859bff21ccc2ad778c8a6a1fed8428cef29d4aa13c6dc5edb7aef44fbcbd3374bf2ef5a439691929f04054ac5fdba0c564ca98502c5532fd1c8d2aba91788c71acc95f434b93dc4fa7b468a98465b70e766787ce5de56d7d539648aaf2671d8682eada24231e20c55ef7d2995674863ddca495ab5ff36ff2be4e18d20209098ae792e44348ce6138d22a407f1ba24b17b88aa470e889ae4c629a31014c97c8fd5a34042bb548dc90f98332962f61e7ba32cce11898807c263ee68eac042b71a7fd30faec8d462b05a9d9af742de2dde1226d70bb23303d58f0fc5bf072ad7d63cfda8e17be96ba9e319870084c916bc465b110422e5e64134ee5d2e6ab79122e1e39bd7413ce131ec915854e08716d4525849430b74953ed216eb880fb8422fec1c9edfe4da15fbc985ff7e7a4713a71cd219bf20c5b13da12d0e366d6b7542c72801562b383624d19d78bfaef312a0941e925b741460c7dd059e6536d1c94271a660f4311b0fda9a28fc6074bb942ff41f37cf30491db436695189b7aded4b9a7f8f9750eca3521fe64396cd8c0a2543c88d0646549c927c1e97b6663130376d33000542c5ce44b27d9e2602457339d598beed92b204c34645fb5a8e688d08cc32315d3e80b39639e86e6b002a2aae39a22b8eafa742d9cfa62245a60f8b8c72f9e55564b60ed4e557bf862668b49e521f9f61c4364cc9a253097fd1496121e63cb3ae444211fdd29a5d8a7ed2135aa993af4177fdeb424a6afaefe2171651f5aa25411c903bb15e91f829af927ec0feefa7ae7febff1b60c8b39fc55c3fa5baa526a8031a96641e896be98e6436146decb2ff20638f4d0dbb06e0cab890a7bdf9dd47af158ec621312624345041316e65c79e70d714bab7d0ae923772754081a0344f0cd36492c137804de093c2949f0c6e644c26105a6b490cd4f55944129a87c23c6c172be09eabc71d804ce76a8bb092ab05b3d5f563144d40bcc2ebdbbbeb3a185a2ac2c66500000456391574c613b36b23ab7021beaaa702803e01d51074e9f94838c37e4a9f48ffe6544f7f223b33924ed3f8bb096d3927174209d76cec40743ac7a7c45b5697081204b61b7d82136f5c84c97e01e66f98f9abb7e44dc2bb1513574bc2c0a8b96ee8f88520adab32c486f42d36dc62a00bb015fc6590b053295c161868cedb543465d72bd199539c81870bcee27c2063e20ada168c47c9b11f4d7ac2aaf62dcdad0b9b818ccf17d170abb8b0eee17205ba20c4ca128f98d092f4fa8f54a24defc3daaa2fcc9876ba502406664725589ce4392b1888d314a076b2e8bfc9f64cb2ac94b5c868dafc98bcfa36a38a77ea1d4a650b05b3e0c6be7906579f32dc04b8cf4e37f57e64cd0ee5248637c2a034904e9b20428745768e3ddb47dd7efb5e27b02a6008c3d57b3f5d99fb39526f8457e0debb5f170756a2ebbc2a66a5e1396ff2a92376e30a74e7acceafd4c92b04ceadb3c000af2118f2ef3c6ccf7e0e124a80c91916e5b225ea88aadcb4b3e36e62f2f3528d609a942fb08f555ed0c5e42614cf9fcf701d911d956db61449e175ddd1b0bba1b7ee300c7a34e54b42acccf6e7a3a47701a15b4082583dfec947a0ec13749c4435e8a1b44e808a0b8db4674e7ca34c8ce23c593a764a4882f42f0455799767e7a1d75a4419f9c429cc5dc6949cce4c70f90e19fc7942dbdf7f0e3a857c17fb336ae1779e738a1eabd7760546a215e7b419313cb1f8060e2552bf990c3123c6d2764f0b5dbdfeae498bb6f09bb7221b88da1f225c7a9f5a88c19d890a3740e0fdb31738ab32e12b16330fca9457eedd03ba61765f60f39536ef301f8b864486aa9a5b908d24a00abbe4364a1ffed84822906cf7edf72ccd16fc4112d309120af01f7c4b90a747a5536cf57bf94ce530df6e95873f06e42735581231f7f1f312a2bf14a325f1582a9f9dc5b11a77f166966e0cd90e86b511649fc293b50f28cdb4dda769b3ac7d190c7bbd470fe81383973e87a4cbdde34536fcf30ae9ea51c6ee907e6505311c0b4fc854aff34bd22b31c71a02f7296d950a13710e2d62161f97af62a5d92afe4c9c5ae69611c57acf16dd100b626b9230c78aabe2d500e87d427706ddfb5063426a2e8d6b521f671c73935c0d9961925c78111bcb0f421420dce466e5aeb380da9f037e9db535f50c2db0b27f0c77f9ccd0f145e7dc4cf28f600a2cd42728aa476b3c10f4d6580af0ac773410cc3faf34ea5a9a387a1fe90a7885c938f984dc543a1c4a6fcd6760538bde67588963eaa56305368097252a014c01db5ca15d8acdb4fc0b84b8599d82c78907b5eee0c6f07b2c22bb76ed072648ac9ff835f89704dd3f3d63fc32ea03513133e39f9c75e64957d1aa7c5fe7baf0a978e330ad62546c035a8e453e0fbf8f21990bea65f9d33852280f61224a79ff4c8a33138d50bd2bf44f5017ecdde038dd252484bb34be7596b35e76badbb11b2bccbd29869a00bd8efa2410864b661b347e3fa9e89404bc927c81c24c1a218a3d543a7b3b2453565bc55ecc94e86cfb46e28f698b7c47ef5e1d11e9c51d5e98b3936838c33b056dd377c75c661dbaa0a63c1eec52096477912821974ff06f9cbc499d0ab71922fd021ae460bdeaedf6f3cf5f260ca6cde4ca7fed26f99b59ab3113107c686c3e512a3f781078294ba870c911f05c0bde3d1931f62ecf44bfc73038220053db0cf0dcb5448f7e55addf7d65e03eccdddb647a2b28296070271d187a89fb108a03a4633a9c3c4a984034a609dba455116b6e299733dd80e707d8286bc47ef938ff78a64cede408c47efd6f3e4892d79fcf95de4fd284803341868b3af24235d9db7e1cf6455c5c1efe49a5d4eaa6f8f751a992b79595b78e68813e60ea8e72f875b2d82aad56f53281fe5f",
|
|
+ "selfVerify": true
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/Proposal.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/Proposal.java
|
|
index 73bd09f3cf..64ece7de19 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/Proposal.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/Proposal.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/aere-bft-bounded-message-lists.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.messagewrappers;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.ProposalPayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList;
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLP;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
@@ -102,29 +108,29 @@ public class Proposal extends BftMessage<ProposalPayload> {
|
|
|
|
rlpOut.endList();
|
|
return rlpOut.encoded();
|
|
}
|
|
|
|
/**
|
|
* Decode.
|
|
*
|
|
* @param data the data
|
|
* @param blockEncoder the qbft block encoder
|
|
* @return the proposal
|
|
*/
|
|
public static Proposal decode(final Bytes data, final QbftBlockCodec blockEncoder) {
|
|
final RLPInput rlpIn = RLP.input(data);
|
|
rlpIn.enterList();
|
|
final SignedData<ProposalPayload> payload =
|
|
readPayload(rlpIn, rlpInput -> ProposalPayload.readFrom(rlpInput, blockEncoder));
|
|
|
|
rlpIn.enterList();
|
|
final List<SignedData<RoundChangePayload>> roundChanges =
|
|
- rlpIn.readList(r -> readPayload(r, RoundChangePayload::readFrom));
|
|
+ rlpIn.readList(r -> readPayload(r, RoundChangePayload::readFrom), MAX_LIST_ENTRIES);
|
|
final List<SignedData<PreparePayload>> prepares =
|
|
- rlpIn.readList(r -> readPayload(r, PreparePayload::readFrom));
|
|
+ rlpIn.readList(r -> readPayload(r, PreparePayload::readFrom), MAX_LIST_ENTRIES);
|
|
rlpIn.leaveList();
|
|
|
|
rlpIn.leaveList();
|
|
return new Proposal(payload, roundChanges, prepares);
|
|
}
|
|
}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/RoundChange.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/RoundChange.java
|
|
index 6c922b101f..5d7cfce849 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/RoundChange.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/RoundChange.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/aere-bft-bounded-message-lists.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.messagewrappers;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.PreparedRoundMetadata;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
import org.hyperledger.besu.ethereum.core.encoding.BlockAccessListDecoder;
|
|
import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList;
|
|
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLP;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
@@ -126,37 +132,37 @@ public class RoundChange extends BftMessage<RoundChangePayload> {
|
|
* @param blockEncoder the qbft block encoder
|
|
* @return the round change
|
|
*/
|
|
public static RoundChange decode(final Bytes data, final QbftBlockCodec blockEncoder) {
|
|
|
|
final RLPInput rlpIn = RLP.input(data);
|
|
rlpIn.enterList();
|
|
final SignedData<RoundChangePayload> payload = readPayload(rlpIn, RoundChangePayload::readFrom);
|
|
|
|
final Optional<QbftBlock> block;
|
|
if (rlpIn.nextIsList() && rlpIn.nextSize() == 0) {
|
|
rlpIn.skipNext();
|
|
block = Optional.empty();
|
|
} else {
|
|
block = Optional.of(blockEncoder.readFrom(rlpIn));
|
|
}
|
|
|
|
final Optional<BlockAccessList> blockAccessList = readBlockAccessList(rlpIn);
|
|
|
|
final List<SignedData<PreparePayload>> prepares =
|
|
- rlpIn.readList(r -> readPayload(r, PreparePayload::readFrom));
|
|
+ rlpIn.readList(r -> readPayload(r, PreparePayload::readFrom), MAX_LIST_ENTRIES);
|
|
rlpIn.leaveList();
|
|
|
|
return new RoundChange(payload, block, blockAccessList, blockEncoder, prepares);
|
|
}
|
|
|
|
private static Optional<BlockAccessList> readBlockAccessList(final RLPInput rlpIn) {
|
|
if (rlpIn.isEndOfCurrentList()) {
|
|
return Optional.empty();
|
|
}
|
|
if (!rlpIn.nextIsNull()) {
|
|
return Optional.of(BlockAccessListDecoder.decode(rlpIn));
|
|
}
|
|
rlpIn.skipNext();
|
|
return Optional.empty();
|
|
}
|
|
}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/network/QbftMessageTransmitter.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/network/QbftMessageTransmitter.java
|
|
index 18437e30fd..236b6cb35b 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/network/QbftMessageTransmitter.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/network/QbftMessageTransmitter.java
|
|
@@ -125,44 +125,44 @@ public class QbftMessageTransmitter {
|
|
|
|
multicaster.send(message);
|
|
} catch (final SecurityModuleException e) {
|
|
LOG.warn("Failed to generate signature for Proposal (not sent): {} ", e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multicast prepare.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
*/
|
|
public void multicastPrepare(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
|
|
multicastPrepare(roundIdentifier, digest, Optional.empty());
|
|
}
|
|
|
|
/**
|
|
* Multicast a prepare carrying an OPTIONAL post-quantum seal of this node.
|
|
*
|
|
- * <p>Sigiliul vine GATA CALCULAT de la apelant, si asta nu e comoditate: semnaturile Falcon sunt
|
|
+ * <p>The seal arrives ALREADY COMPUTED from the caller, and that is not a convenience: Falcon signatures are
|
|
* randomized, so signing the same message twice yields two different byte strings. If the local
|
|
* copy and the one on the wire each signed their own, the same validator would produce two
|
|
- * valide si DIFERITE pentru aceeasi runda. Se calculeaza o data, sus, si se trece prin amandoua.
|
|
+ * valid and DIFFERENT for the same round. It is computed once, above, and passed through both.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
* @param falconSeal the seal, or empty
|
|
*/
|
|
public void multicastPrepare(
|
|
final ConsensusRoundIdentifier roundIdentifier,
|
|
final Hash digest,
|
|
final Optional<FalconSeal> falconSeal) {
|
|
try {
|
|
final Prepare data = messageFactory.createPrepare(roundIdentifier, digest, falconSeal);
|
|
|
|
final PrepareMessageData message = PrepareMessageData.create(data);
|
|
|
|
multicaster.send(message);
|
|
} catch (final SecurityModuleException e) {
|
|
LOG.warn("Failed to generate signature for Prepare (not sent): {} ", e.getMessage());
|
|
}
|
|
}
|
|
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/CommitPayload.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/CommitPayload.java
|
|
index 8b788f499e..cdfaaf24c6 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/CommitPayload.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/CommitPayload.java
|
|
@@ -5,73 +5,76 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.payload;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealed;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorV2;
|
|
import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagedata.QbftV1;
|
|
import org.hyperledger.besu.crypto.SECPSignature;
|
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.StringJoiner;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/**
|
|
* The Commit payload.
|
|
*
|
|
* <p>AERE hybrid PQC extension: a Commit payload MAY carry an OPTIONAL parallel Falcon-512 seal, so
|
|
* that every validator's post-quantum seal over the commit hash is GOSSIPED alongside the decisive
|
|
* ECDSA commit seal on the same message. The Falcon seal is appended only when present, so a
|
|
* Falcon-less Commit encodes byte-for-byte identically to upstream Besu. When present, the whole
|
|
* payload (including the Falcon seal) is covered by the author's ECDSA signature, binding the
|
|
* claimed Falcon validator index to the sender's identity.
|
|
*
|
|
* <p>AERE FIX-MALEABILITATE: this payload has exactly ONE valid encoding for a given value. See
|
|
* {@link #readFrom(RLPInput)}.
|
|
*/
|
|
-public class CommitPayload extends QbftPayload {
|
|
+public class CommitPayload extends QbftPayload implements PqSealed {
|
|
private static final int TYPE = QbftV1.COMMIT;
|
|
private final ConsensusRoundIdentifier roundIdentifier;
|
|
private final Hash digest;
|
|
private final SECPSignature commitSeal;
|
|
private final Optional<FalconSeal> falconSeal;
|
|
// AERE HIBRID (2026-08-25): the NON-Falcon scheme seals of a hybrid certificate. Falcon keeps
|
|
// living in the legacy slot above, so one signature has exactly one home and the wire format of
|
|
// a Falcon-only commit is untouched. Empty on every commit the live fleet emits today.
|
|
private final List<SchemeSeal> extraSeals;
|
|
|
|
/**
|
|
* Instantiates a new Commit payload (no Falcon seal).
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
* @param commitSeal the commit seal
|
|
*/
|
|
public CommitPayload(
|
|
final ConsensusRoundIdentifier roundIdentifier,
|
|
final Hash digest,
|
|
@@ -306,44 +309,55 @@ public class CommitPayload extends QbftPayload {
|
|
* @return the digest
|
|
*/
|
|
public Hash getDigest() {
|
|
return digest;
|
|
}
|
|
|
|
/**
|
|
* Gets commit seal.
|
|
*
|
|
* @return the commit seal
|
|
*/
|
|
public SECPSignature getCommitSeal() {
|
|
return commitSeal;
|
|
}
|
|
|
|
/**
|
|
* Gets the optional parallel post-quantum Falcon seal.
|
|
*
|
|
* @return the Falcon seal if this commit carried one, otherwise empty
|
|
*/
|
|
+ @Override
|
|
public Optional<FalconSeal> getFalconSeal() {
|
|
return falconSeal;
|
|
}
|
|
|
|
+ /** AIP-22 stage 4: the commit seal's signer, recovered as CommitValidator recovers it (empty when it does not recover). */
|
|
+ @Override
|
|
+ public Optional<Address> commitSealSigner() {
|
|
+ try {
|
|
+ return Optional.ofNullable(Util.signatureToAddress(commitSeal, digest));
|
|
+ } catch (final RuntimeException e) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
/**
|
|
* Gets the non-Falcon scheme seals of a hybrid certificate.
|
|
*
|
|
* @return the extra seals, empty for every commit the live fleet emits today
|
|
*/
|
|
public List<SchemeSeal> getExtraSeals() {
|
|
return extraSeals;
|
|
}
|
|
|
|
@Override
|
|
public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
return roundIdentifier;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (o == null || getClass() != o.getClass()) {
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/MessageFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/MessageFactory.java
|
|
index 11426d6a68..24777b59b7 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/MessageFactory.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/MessageFactory.java
|
|
@@ -125,44 +125,44 @@ public class MessageFactory {
|
|
final QbftBlock block,
|
|
final List<SignedData<RoundChangePayload>> roundChanges,
|
|
final List<SignedData<PreparePayload>> prepares) {
|
|
return createProposal(roundIdentifier, block, Optional.empty(), roundChanges, prepares);
|
|
}
|
|
|
|
/**
|
|
* Create Prepare payload.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
* @return the prepare
|
|
*/
|
|
public Prepare createPrepare(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
|
|
return createPrepare(roundIdentifier, digest, Optional.empty());
|
|
}
|
|
|
|
/**
|
|
* Create a Prepare carrying an OPTIONAL post-quantum seal of its author.
|
|
*
|
|
- * <p>AERE PQ (2026-08-28), pasul 1: firul poate purta sigiliul, si nimic nu il emite inca -
|
|
- * fiecare apel de azi trece prin varianta fara sigiliu de mai sus. Ca la commit, semnatura ECDSA
|
|
- * a autorului acopera INTREG payload-ul, deci si sigiliul, ceea ce leaga indexul revendicat de
|
|
- * identitatea celui care trimite mesajul.
|
|
+ * <p>AERE PQ (2026-08-28), step 1: the wire can carry the seal, and nothing emits it yet -
|
|
+ * every call today goes through the seal-less variant above. As with commit, the author's ECDSA
|
|
+ * signature covers the WHOLE payload, and so the seal too, which binds the claimed index to
|
|
+ * the identity of whoever sends the message.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
* @param falconSeal the author's post-quantum seal, or empty
|
|
* @return the prepare
|
|
*/
|
|
public Prepare createPrepare(
|
|
final ConsensusRoundIdentifier roundIdentifier,
|
|
final Hash digest,
|
|
final Optional<FalconSeal> falconSeal) {
|
|
final PreparePayload payload = new PreparePayload(roundIdentifier, digest, falconSeal);
|
|
return new Prepare(createSignedMessage(payload));
|
|
}
|
|
|
|
/**
|
|
* Create commit payload.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
* @param commitSeal the commit seal
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/PreparePayload.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/PreparePayload.java
|
|
index 727cbccc81..dea9b70233 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/PreparePayload.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/PreparePayload.java
|
|
@@ -5,73 +5,76 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.payload;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealed;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagedata.QbftV1;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.StringJoiner;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
|
|
/**
|
|
* The Prepare payload.
|
|
*
|
|
* <p>AERE PQ (2026-08-28), step 1 of PREPARE-SI-ROUNDCHANGE-SUB-PQ-PROIECTARE-2026-08-28: a PREPARE
|
|
* MAY carry an OPTIONAL Falcon-512 seal from its author, appended at the end, exactly as
|
|
* {@code CommitPayload} does. A PREPARE without a seal encodes <b>byte for byte as upstream</b>,
|
|
* and that is precisely the property that lets the binary be rolled onto a live fleet without a
|
|
* flag day.
|
|
*
|
|
* <p><b>NOTHING EMITS SUCH A PREPARE YET.</b> This file only makes the wire capable of carrying one
|
|
* and of refusing a malformed one. Emission is the next step and has its own gate, following the
|
|
* rule paid for at commit: first the binary everywhere, then emission, and only much later
|
|
* enforcement.
|
|
*
|
|
* <p><b>What the seal signs is NOT this file's business</b>, and the design note states it: its own
|
|
* domain {@code AERE-PQ-PREPARE-1} over (chainId, number, ROUND, digest). If it signed the same
|
|
* bytes as a commit seal, a PREPARE seal given honestly could be pasted onto a forged COMMIT and
|
|
* the enforcement there would accept it.
|
|
*/
|
|
-public class PreparePayload extends QbftPayload {
|
|
+public class PreparePayload extends QbftPayload implements PqSealed {
|
|
private static final int TYPE = QbftV1.PREPARE;
|
|
private final ConsensusRoundIdentifier roundIdentifier;
|
|
private final Hash digest;
|
|
private final Optional<FalconSeal> falconSeal;
|
|
|
|
/**
|
|
* Instantiates a new Prepare payload, without a post-quantum seal. Encodes byte-for-byte as
|
|
* upstream Besu.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param digest the digest
|
|
*/
|
|
public PreparePayload(final ConsensusRoundIdentifier roundIdentifier, final Hash digest) {
|
|
this(roundIdentifier, digest, Optional.empty());
|
|
}
|
|
|
|
/**
|
|
* Instantiates a new Prepare payload carrying an optional Falcon-512 seal of its author.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
@@ -154,44 +157,56 @@ public class PreparePayload extends QbftPayload {
|
|
|
|
@Override
|
|
public int getMessageType() {
|
|
return TYPE;
|
|
}
|
|
|
|
/**
|
|
* Gets digest.
|
|
*
|
|
* @return the digest
|
|
*/
|
|
public Hash getDigest() {
|
|
return digest;
|
|
}
|
|
|
|
/**
|
|
* The author's post-quantum seal, when the message carries one.
|
|
*
|
|
* @return the seal, or empty
|
|
*/
|
|
+ @Override
|
|
public Optional<FalconSeal> getFalconSeal() {
|
|
return falconSeal;
|
|
}
|
|
|
|
+ /** AIP-22 stage 4: the PREPARE seal's message, as PqPrepareEnforcement builds it. */
|
|
+ @Override
|
|
+ public Optional<Bytes32> pqSealMessage(final long chainId) {
|
|
+ return Optional.of(
|
|
+ PqAnchor.prepareMessage(
|
|
+ chainId,
|
|
+ roundIdentifier.getSequenceNumber(),
|
|
+ roundIdentifier.getRoundNumber(),
|
|
+ digest.getBytes()));
|
|
+ }
|
|
+
|
|
@Override
|
|
public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
return roundIdentifier;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (o == null || getClass() != o.getClass()) {
|
|
return false;
|
|
}
|
|
final PreparePayload that = (PreparePayload) o;
|
|
return Objects.equals(roundIdentifier, that.roundIdentifier)
|
|
&& Objects.equals(digest, that.digest)
|
|
&& Objects.equals(falconSeal, that.falconSeal);
|
|
}
|
|
|
|
@Override
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/ProposalPayload.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/ProposalPayload.java
|
|
index 813e798a97..ada90e3cd9 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/ProposalPayload.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/ProposalPayload.java
|
|
@@ -5,82 +5,85 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.payload;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealed;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagedata.QbftV1;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
import org.hyperledger.besu.ethereum.core.encoding.BlockAccessListDecoder;
|
|
import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
|
|
import com.google.common.base.MoreObjects;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
|
|
/**
|
|
* The Proposal payload.
|
|
*
|
|
* <p>AERE PQ (2026-08-30), the hot-path step after PREPARE: a PROPOSAL MAY carry an OPTIONAL
|
|
* Falcon-512 seal from its proposer, appended after the block-access-list element, exactly as
|
|
* {@code PreparePayload} appends its seal. A proposal without a seal encodes <b>byte for byte as
|
|
* upstream</b>, which is the property that lets the binary be rolled onto a live fleet without a
|
|
* flag day.
|
|
*
|
|
* <p><b>NOTHING EMITS SUCH A PROPOSAL YET.</b> This file only makes the wire capable of carrying
|
|
* one and of refusing a malformed one. Emission has its own gate
|
|
* ({@code aere.pq.proposalPq.attachBlock}); enforcement has its own height
|
|
* ({@code aere.pq.proposalPq.forkBlock}); both are absent on every node today, and absent means
|
|
* never.
|
|
*
|
|
* <p><b>What the seal signs is NOT this file's business:</b> its own domain
|
|
* {@code AERE-PQ-PROPOSAL-1} over (chainId, height, ROUND, digest) - see
|
|
* {@code PqAnchor.proposalMessage}. A proposal is an offer, not a vote: with the commit or PREPARE
|
|
* domain, a proposal seal given honestly could be pasted onto a forged vote and counted.
|
|
*
|
|
* <p><b>Why the trailing element is parsed strictly:</b> the payload is AUTHENTICATED - the author
|
|
* is recovered from the signature over the encoded payload. A decoder that silently ignored an
|
|
* unknown trailing element would re-encode without it, so two different byte strings would
|
|
* authenticate to the same proposer. When a fifth element is present it must be exactly a seal,
|
|
* and it must be the last element; otherwise the message is refused. Messages of the upstream
|
|
* shapes (three or four elements) are read exactly as upstream reads them.
|
|
*/
|
|
-public class ProposalPayload extends QbftPayload {
|
|
+public class ProposalPayload extends QbftPayload implements PqSealed {
|
|
|
|
private static final int TYPE = QbftV1.PROPOSAL;
|
|
private final ConsensusRoundIdentifier roundIdentifier;
|
|
private final QbftBlock proposedBlock;
|
|
private final QbftBlockCodec blockEncoder;
|
|
private final Optional<BlockAccessList> blockAccessList;
|
|
private final Optional<FalconSeal> falconSeal;
|
|
|
|
/**
|
|
* Instantiates a new Proposal payload carrying an optional post-quantum seal of its proposer.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @param proposedBlock the proposed block
|
|
* @param blockEncoder the qbft block encoder
|
|
* @param blockAccessList the block access list
|
|
* @param falconSeal the proposer's post-quantum seal, or empty
|
|
*/
|
|
public ProposalPayload(
|
|
final ConsensusRoundIdentifier roundIdentifier,
|
|
final QbftBlock proposedBlock,
|
|
@@ -185,44 +188,56 @@ public class ProposalPayload extends QbftPayload {
|
|
* @return the proposed block
|
|
*/
|
|
public QbftBlock getProposedBlock() {
|
|
return proposedBlock;
|
|
}
|
|
|
|
/**
|
|
* Gets block access list.
|
|
*
|
|
* @return the block access list
|
|
*/
|
|
public Optional<BlockAccessList> getBlockAccessList() {
|
|
return blockAccessList;
|
|
}
|
|
|
|
/**
|
|
* The proposer's post-quantum seal, when the message carries one.
|
|
*
|
|
* @return the seal, or empty
|
|
*/
|
|
+ @Override
|
|
public Optional<FalconSeal> getFalconSeal() {
|
|
return falconSeal;
|
|
}
|
|
|
|
+ /** AIP-22 stage 4: the PROPOSAL seal's message over the proposed block's hash, as PqProposalEnforcement builds it. */
|
|
+ @Override
|
|
+ public Optional<Bytes32> pqSealMessage(final long chainId) {
|
|
+ return Optional.of(
|
|
+ PqAnchor.proposalMessage(
|
|
+ chainId,
|
|
+ roundIdentifier.getSequenceNumber(),
|
|
+ roundIdentifier.getRoundNumber(),
|
|
+ proposedBlock.getHash().getBytes()));
|
|
+ }
|
|
+
|
|
@Override
|
|
public int getMessageType() {
|
|
return TYPE;
|
|
}
|
|
|
|
@Override
|
|
public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
return roundIdentifier;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (o == null || getClass() != o.getClass()) {
|
|
return false;
|
|
}
|
|
ProposalPayload that = (ProposalPayload) o;
|
|
return Objects.equals(roundIdentifier, that.roundIdentifier)
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/RoundChangePayload.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/RoundChangePayload.java
|
|
index 8804b6a46c..736b9e7299 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/RoundChangePayload.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/payload/RoundChangePayload.java
|
|
@@ -5,80 +5,83 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.payload;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealed;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagedata.QbftV1;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPInput;
|
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
|
|
import com.google.common.base.MoreObjects;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
|
|
/**
|
|
* The Round change payload.
|
|
*
|
|
* <p>AERE PQ (2026-08-31), the LAST hot-path message: a ROUND-CHANGE MAY carry an OPTIONAL
|
|
* Falcon-512 seal from its author, appended after the prepared-metadata list, exactly as {@code
|
|
* ProposalPayload} appends its seal. A round-change without a seal encodes <b>byte for byte as
|
|
* upstream</b>, which is the property that lets the binary be rolled onto a live fleet without a
|
|
* flag day.
|
|
*
|
|
* <p><b>NOTHING EMITS SUCH A ROUND-CHANGE YET.</b> This file only makes the wire capable of
|
|
* carrying one and of refusing a malformed one. Emission has its own gate
|
|
* ({@code aere.pq.roundChangePq.attachBlock}); enforcement has its own height
|
|
* ({@code aere.pq.roundChangePq.forkBlock}); both are absent on every node today, and absent means
|
|
* never.
|
|
*
|
|
* <p><b>What the seal signs is NOT this file's business:</b> its own domain
|
|
* {@code AERE-PQ-ROUNDCHANGE-1} over (chainId, height, targetRound, prepared metadata) - see
|
|
* {@code PqAnchor.roundChangeMessage}. A round-change STEERS rounds: a quorum of them opens a new
|
|
* round, and one claiming a prepared block decides which block gets re-proposed. Its seal must be
|
|
* transferable neither onto a vote nor onto a proposal, nor between a bare round-change and one
|
|
* with metadata.
|
|
*
|
|
* <p><b>Why the trailing element is parsed strictly:</b> the payload is AUTHENTICATED - the author
|
|
* is recovered from the signature over the encoded payload. A decoder that silently ignored an
|
|
* unknown trailing element would re-encode without it, so two different byte strings would
|
|
* authenticate to the same author. When a fourth element is present it must be exactly a seal, and
|
|
* it must be the last element; otherwise the message is refused. Messages of the upstream shape
|
|
* (three elements) are read exactly as upstream reads them.
|
|
*/
|
|
-public class RoundChangePayload extends QbftPayload {
|
|
+public class RoundChangePayload extends QbftPayload implements PqSealed {
|
|
private static final int TYPE = QbftV1.ROUND_CHANGE;
|
|
private final ConsensusRoundIdentifier roundChangeIdentifier;
|
|
private final Optional<PreparedRoundMetadata> preparedRoundMetadata;
|
|
private final Optional<FalconSeal> falconSeal;
|
|
|
|
/**
|
|
* Instantiates a new Round change payload carrying an optional post-quantum seal of its author.
|
|
*
|
|
* @param roundChangeIdentifier the round change identifier
|
|
* @param preparedRoundMetadata the prepared round metadata
|
|
* @param falconSeal the author's post-quantum seal, or empty
|
|
*/
|
|
public RoundChangePayload(
|
|
final ConsensusRoundIdentifier roundChangeIdentifier,
|
|
final Optional<PreparedRoundMetadata> preparedRoundMetadata,
|
|
final Optional<FalconSeal> falconSeal) {
|
|
this.roundChangeIdentifier = roundChangeIdentifier;
|
|
this.preparedRoundMetadata = preparedRoundMetadata;
|
|
this.falconSeal = falconSeal == null ? Optional.empty() : falconSeal;
|
|
}
|
|
@@ -98,44 +101,61 @@ public class RoundChangePayload extends QbftPayload {
|
|
|
|
@Override
|
|
public ConsensusRoundIdentifier getRoundIdentifier() {
|
|
return roundChangeIdentifier;
|
|
}
|
|
|
|
/**
|
|
* Gets prepared round metadata.
|
|
*
|
|
* @return the prepared round metadata
|
|
*/
|
|
public Optional<PreparedRoundMetadata> getPreparedRoundMetadata() {
|
|
return preparedRoundMetadata;
|
|
}
|
|
|
|
/**
|
|
* The author's post-quantum seal, when the message carries one.
|
|
*
|
|
* @return the seal, or empty
|
|
*/
|
|
+ @Override
|
|
public Optional<FalconSeal> getFalconSeal() {
|
|
return falconSeal;
|
|
}
|
|
|
|
+ /** AIP-22 stage 4: the ROUND-CHANGE seal's message, prepared or not, as PqRoundChangeEnforcement builds it. */
|
|
+ @Override
|
|
+ public Optional<Bytes32> pqSealMessage(final long chainId) {
|
|
+ final long height = roundChangeIdentifier.getSequenceNumber();
|
|
+ final int targetRound = roundChangeIdentifier.getRoundNumber();
|
|
+ return Optional.of(
|
|
+ preparedRoundMetadata.isPresent()
|
|
+ ? PqAnchor.roundChangeMessage(
|
|
+ chainId,
|
|
+ height,
|
|
+ targetRound,
|
|
+ preparedRoundMetadata.get().getPreparedRound(),
|
|
+ preparedRoundMetadata.get().getPreparedBlockHash().getBytes())
|
|
+ : PqAnchor.roundChangeMessage(chainId, height, targetRound));
|
|
+ }
|
|
+
|
|
@Override
|
|
public void writeTo(final RLPOutput rlpOutput) {
|
|
// RLP encode of the message data content (round identifier and prepared certificate)
|
|
rlpOutput.startList();
|
|
writeConsensusRound(rlpOutput);
|
|
|
|
rlpOutput.startList();
|
|
preparedRoundMetadata.ifPresent(prm -> prm.writeTo(rlpOutput));
|
|
rlpOutput.endList();
|
|
|
|
// The seal is written only when present, so a seal-less round-change is identical to upstream.
|
|
if (falconSeal.isPresent()) {
|
|
final FalconSeal fs = falconSeal.get();
|
|
rlpOutput.startList();
|
|
rlpOutput.writeIntScalar(fs.getValidatorIndex());
|
|
rlpOutput.writeBytes(fs.getSignature());
|
|
rlpOutput.endList();
|
|
}
|
|
|
|
rlpOutput.endList();
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java
|
|
index 3d0138d9c5..8dc438b412 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRound.java
|
|
@@ -5,40 +5,41 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.statemachine;
|
|
|
|
import static java.util.Collections.emptyList;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqHeaderSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorNotReadyException;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
|
|
import org.hyperledger.besu.consensus.common.bft.blockcreation.PqAnchorProducer;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Proposal;
|
|
import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator.BlockCreationResult;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader;
|
|
@@ -87,40 +88,60 @@ public class QbftRound {
|
|
private final QbftMessageTransmitter transmitter;
|
|
|
|
private final QbftBlockHeader parentHeader;
|
|
|
|
// AERE hybrid PQC: guards against re-importing once a block has been successfully imported this
|
|
// round, while still allowing a retry if an earlier import attempt was rejected (e.g. a post-fork
|
|
// Falcon quorum certificate that was not yet complete when the first attempt ran).
|
|
private boolean blockImported = false;
|
|
|
|
// AERE ANCHOR V2: the ROUND-INDEPENDENT on-chain hash of the block this round is deciding.
|
|
//
|
|
// Why it is not simply block.getHash(): a proposal block is built with the COMMITTED-SEAL header
|
|
// functions, so its hash includes the round number and differs between rounds for one and the
|
|
// same block. The certificate carried by the NEXT block is looked up, and its message M is built,
|
|
// from the parent's on-chain hash, which excludes both the commit seals and the round. Keying the
|
|
// seal cache on anything round dependent would silently produce empty certificates at every round
|
|
// change. Replacing the round with 0 in the committed-seal encoding yields byte-for-byte the
|
|
// on-chain pre-image, so this is the same hash the parent header will carry once imported.
|
|
private Hash pqOnchainHash;
|
|
|
|
+ // AERE D-337 (2026-09-28): the post-quantum seals of THIS node's Commit in this round, signed ONCE.
|
|
+ //
|
|
+ // Two paths emit this node's Commit: accepting the proposal (the local copy, and the wire copy in
|
|
+ // the rare case the node is already prepared) and becoming prepared later (the wire copy, the
|
|
+ // usual case). Each used to sign on its own, so at the parent of an anchor every Besu validator
|
|
+ // made two SLH-DSA signatures back to back on the consensus thread, the first before its Prepare
|
|
+ // and the second between "prepared" and its Commit. Measured on 2800 (2026-09-28, import times in
|
|
+ // ms measured at a reading node of the network): the anchor-parent slot 1,036 ms against
|
|
+ // 599 for the other slots. The message is fixed by (block, commit hash), both fixed for the round
|
|
+ // once the proposal is accepted, so the second signing could only produce another valid seal over
|
|
+ // the same bytes. It now reuses the first, and the local and wire Commits carry the same seals
|
|
+ // (Falcon is randomised: before this, they carried two different valid Falcon seals).
|
|
+ //
|
|
+ // What is NOT reused: an attempt that produced no Falcon seal, or no extras where extras apply.
|
|
+ // Those are retried exactly as before, so a node whose first attempt failed keeps its second chance.
|
|
+ private Hash pqSealedCommitHash;
|
|
+ private Optional<FalconSeal> pqSealedFalcon = Optional.empty();
|
|
+ private java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> pqSealedExtras =
|
|
+ java.util.List.of();
|
|
+
|
|
/**
|
|
* Instantiates a new Qbft round.
|
|
*
|
|
* @param roundState the round state
|
|
* @param blockCreator the block creator
|
|
* @param blockInterface the block interface
|
|
* @param protocolSchedule the protocol schedule
|
|
* @param observers the observers
|
|
* @param nodeKey the node key
|
|
* @param localAddress the local address
|
|
* @param messageFactory the message factory
|
|
* @param transmitter the transmitter
|
|
* @param roundTimer the round timer
|
|
* @param parentHeader the parent header
|
|
*/
|
|
public QbftRound(
|
|
final RoundState roundState,
|
|
final QbftBlockCreator blockCreator,
|
|
final QbftBlockInterface blockInterface,
|
|
final QbftProtocolSchedule protocolSchedule,
|
|
@@ -411,44 +432,46 @@ public class QbftRound {
|
|
|
|
private boolean updateStateWithProposedBlock(final Proposal msg) {
|
|
final boolean wasPrepared = roundState.isPrepared();
|
|
final boolean blockAccepted = roundState.setProposedBlock(msg);
|
|
|
|
if (blockAccepted) {
|
|
final QbftBlock block = roundState.getProposedBlock().get();
|
|
|
|
// AERE hybrid PQC: compute the commit hash once, then produce BOTH the decisive ECDSA commit
|
|
// seal and the parallel Falcon-512 seal over the SAME commit hash. The Falcon seal is gossiped
|
|
// on the commit message so every validator's post-quantum seal reaches the block assembler.
|
|
final Hash commitHash;
|
|
final SECPSignature commitSeal;
|
|
try {
|
|
commitHash = commitHashFor(block);
|
|
commitSeal = nodeKey.sign(Bytes32.wrap(commitHash.getBytes()));
|
|
} catch (final SecurityModuleException e) {
|
|
LOG.warn("Failed to construct commit seal; {}", e.getMessage());
|
|
return true;
|
|
}
|
|
- final Optional<FalconSeal> falconSeal = falconSealFor(block, commitHash);
|
|
- // AERE HYBRID: the other schemes' extras, over the SAME message; empty on any node today.
|
|
+ // AERE HYBRID: the Falcon seal and the other schemes' extras, over the SAME message, signed
|
|
+ // once per round (D-337, pqSealCommitOnce).
|
|
+ pqSealCommitOnce(block, commitHash);
|
|
+ final Optional<FalconSeal> falconSeal = pqSealedFalcon;
|
|
final java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> extraSeals =
|
|
- falconSeal.isPresent() ? extraSealsFor(block, commitHash) : java.util.List.of();
|
|
+ pqSealedExtras;
|
|
|
|
// There are times handling a proposed block is enough to enter prepared.
|
|
if (wasPrepared != roundState.isPrepared()) {
|
|
LOG.debug("Sending commit message. round={}", roundState.getRoundIdentifier());
|
|
if (!extraSeals.isEmpty()) {
|
|
transmitter.multicastCommit(
|
|
getRoundIdentifier(), block.getHash(), commitSeal, falconSeal, extraSeals);
|
|
} else if (falconSeal.isPresent()) {
|
|
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), commitSeal, falconSeal);
|
|
} else {
|
|
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), commitSeal);
|
|
}
|
|
}
|
|
|
|
// can automatically add _our_ commit message to the roundState
|
|
// cannot create a prepare message here, as it may be _our_ proposal, and thus we cannot also
|
|
// prepare
|
|
try {
|
|
final Commit localCommitMessage =
|
|
falconSeal.isPresent()
|
|
@@ -469,44 +492,46 @@ public class QbftRound {
|
|
// AERE ANCHOR V2: remember every Falcon seal heard for THIS block, so the proposer of the
|
|
// NEXT block can carry a certificate over it. This is the local node's own seal.
|
|
pqCacheHeardSeals(block);
|
|
|
|
// It is possible sufficient commit seals are now available and the block should be imported
|
|
maybeImportBlock();
|
|
}
|
|
|
|
return blockAccepted;
|
|
}
|
|
|
|
private void peerIsPrepared(final Prepare msg) {
|
|
final boolean wasPrepared = roundState.isPrepared();
|
|
roundState.addPrepareMessage(msg);
|
|
if (wasPrepared != roundState.isPrepared()) {
|
|
LOG.debug("Sending commit message. round={}", roundState.getRoundIdentifier());
|
|
final QbftBlock block = roundState.getProposedBlock().get();
|
|
try {
|
|
final Hash commitHash = commitHashFor(block);
|
|
final SECPSignature commitSeal = nodeKey.sign(Bytes32.wrap(commitHash.getBytes()));
|
|
- final Optional<FalconSeal> falconSeal = falconSealFor(block, commitHash);
|
|
- // AERE HIBRID: aceleasi extrase si pe drumul tarziu, ca cele doua locuri sa nu divearga.
|
|
+ // AERE HIBRID: aceleasi sigilii si pe drumul tarziu, ca cele doua locuri sa nu divearga; D-337:
|
|
+ // chiar ACELEASI, semnate o data la acceptarea propunerii, nu o a doua semnare SLH-DSA aici.
|
|
+ pqSealCommitOnce(block, commitHash);
|
|
+ final Optional<FalconSeal> falconSeal = pqSealedFalcon;
|
|
final java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> extraSeals =
|
|
- falconSeal.isPresent() ? extraSealsFor(block, commitHash) : java.util.List.of();
|
|
+ pqSealedExtras;
|
|
if (!extraSeals.isEmpty()) {
|
|
transmitter.multicastCommit(
|
|
getRoundIdentifier(), block.getHash(), commitSeal, falconSeal, extraSeals);
|
|
} else if (falconSeal.isPresent()) {
|
|
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), commitSeal, falconSeal);
|
|
} else {
|
|
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), commitSeal);
|
|
}
|
|
// Note: the local-node's commit message was added to RoundState on block acceptance
|
|
// and thus does not need to be done again here.
|
|
} catch (final SecurityModuleException e) {
|
|
LOG.warn("Failed to construct a commit seal: {}", e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void peerIsCommitted(final Commit msg) {
|
|
roundState.addCommitMessage(msg);
|
|
// AERE ANCHOR V2: top up the seal cache on EVERY commit, including commits that arrive after
|
|
// this node has already imported the block. Those late seals are exactly the ones that let a
|
|
@@ -522,53 +547,79 @@ public class QbftRound {
|
|
maybeImportBlock();
|
|
}
|
|
|
|
private void maybeImportBlock() {
|
|
if (roundState.isCommitted() && !blockImported) {
|
|
importBlockToChain();
|
|
}
|
|
}
|
|
|
|
private void importBlockToChain() {
|
|
|
|
// AERE hybrid PQC: pass the gossiped Falcon seals collected from commit messages so the block
|
|
// assembler can embed the post-quantum certificate. When no Falcon seals were gossiped (Falcon
|
|
// disabled), fall back to the unchanged ECDSA-only sealing path.
|
|
//
|
|
// WHAT GETS EMBEDDED, corrected 2026-08-19 (finding D-235): NOT a per-block 2f+1 quorum. The
|
|
// assembler writes a certificate only at an anchor height, over the PARENT, and it needs at
|
|
// least K valid seals, K being the configured schedule (6 of 9 on chain 2800 today). Between
|
|
// anchor heights nothing is written. The older wording here said "a >= 2f+1 Falcon quorum
|
|
// certificate" and described the legacy per-block rule, which is retired at the anchor block.
|
|
+ // AERE AIP-22 stage 5: from H_hdr the sealed header carries no ECDSA committed seal and the
|
|
+ // accepted proposal's post-quantum seal as element 6 (the same bytes on every node). A proposal
|
|
+ // without one cannot have been accepted from H_fin <= H_hdr; if it happens anyway nothing is
|
|
+ // imported, because the only other header this node could build is one every node refuses.
|
|
+ final long aereHeight = roundState.getRoundIdentifier().getSequenceNumber();
|
|
+ if (AerePqHeaderSeal.active(aereHeight)) {
|
|
+ final Optional<FalconSeal> proposerSeal = roundState.getProposalFalconSeal();
|
|
+ if (proposerSeal.isEmpty()) {
|
|
+ LOG.error(
|
|
+ "AERE-PQC-HDR-02: committed at {} but the accepted proposal carries no post-quantum seal;"
|
|
+ + " a header from H_hdr cannot be sealed without it. Not importing.",
|
|
+ aereHeight);
|
|
+ return;
|
|
+ }
|
|
+ importSealedBlock(
|
|
+ blockCreator.createSealedBlockWithProposerSeal(
|
|
+ roundState.getProposedBlock().get(),
|
|
+ roundState.getRoundIdentifier().getRoundNumber(),
|
|
+ proposerSeal.get()));
|
|
+ return;
|
|
+ }
|
|
final Collection<FalconSeal> falconSeals = roundState.getFalconSeals();
|
|
final QbftBlock blockToImport =
|
|
falconSeals.isEmpty()
|
|
? blockCreator.createSealedBlock(
|
|
roundState.getProposedBlock().get(),
|
|
roundState.getRoundIdentifier().getRoundNumber(),
|
|
roundState.getCommitSeals())
|
|
: blockCreator.createSealedBlock(
|
|
roundState.getProposedBlock().get(),
|
|
roundState.getRoundIdentifier().getRoundNumber(),
|
|
roundState.getCommitSeals(),
|
|
falconSeals);
|
|
|
|
+ importSealedBlock(blockToImport);
|
|
+ }
|
|
+
|
|
+ /** Imports a sealed block into the chain (shared by the stage-5 and the ECDSA sealing paths). */
|
|
+ private void importSealedBlock(final QbftBlock blockToImport) {
|
|
final long blockNumber = blockToImport.getHeader().getNumber();
|
|
if (getRoundIdentifier().getRoundNumber() > 0) {
|
|
LOG.info(
|
|
"Importing proposed block to chain. round={}, hash={}",
|
|
getRoundIdentifier(),
|
|
blockToImport.getHash());
|
|
} else {
|
|
LOG.debug(
|
|
"Importing proposed block to chain. round={}, hash={}",
|
|
getRoundIdentifier(),
|
|
blockToImport.getHash());
|
|
}
|
|
|
|
final QbftBlockImporter blockImporter =
|
|
protocolSchedule.getBlockImporter(blockToImport.getHeader());
|
|
final boolean result =
|
|
blockImporter.importBlock(blockToImport, roundState.getProposedBlockAccessList());
|
|
if (!result) {
|
|
// Do NOT set blockImported: a post-fork block whose Falcon quorum certificate is not yet
|
|
// complete can be retried as more commits (with valid Falcon seals) arrive this round.
|
|
@@ -643,93 +694,122 @@ public class QbftRound {
|
|
/**
|
|
* AERE ANCHOR V2: the round-independent on-chain hash of the block this round is deciding,
|
|
* computed once per round. Replacing the round with 0 in the committed-seal encoding produces
|
|
* byte-for-byte the on-chain pre-image, because that encoding differs from the on-chain one only
|
|
* by writing the real round instead of a forced zero.
|
|
*/
|
|
private Hash pqOnchainHashOf(final QbftBlock block) {
|
|
if (pqOnchainHash == null) {
|
|
pqOnchainHash = blockInterface.replaceRoundForCommitBlock(block, 0).getHash();
|
|
}
|
|
return pqOnchainHash;
|
|
}
|
|
|
|
/**
|
|
* AERE HIBRID (2026-08-25): the non-Falcon seals of this node's hybrid certificate, over the
|
|
* SAME message the Falcon seal signs (the two are one certificate; two messages would be two
|
|
* certificates and the verifier could not bind them). Empty on every node that is not
|
|
* hybrid-configured, and below the emission gate: {@link HybridSealProducer} never throws and
|
|
* never emits half a certificate.
|
|
*/
|
|
- private java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> extraSealsFor(
|
|
+ java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> extraSealsFor(
|
|
final QbftBlock block, final Hash commitHash) {
|
|
// ANCHOR PARENTS ONLY (2026-09-03, D-329): an SLH-DSA-128s signature costs seconds here; it is
|
|
// only ever used in the next anchor's certificate, which is built over the anchor's parent. So
|
|
// the extras are signed only when the block being committed is the parent of an anchor height.
|
|
// The same predicate gates the enforcement (PqCommitEnforcement.anchorParentByConfig).
|
|
final long number = block.getHeader().getNumber();
|
|
- if (!org.hyperledger.besu.consensus.common.bft.blockcreation.PqAnchorProducer.config()
|
|
- .anchorAppliesAt(number + 1L)) {
|
|
+ if (!pqExtrasApplyAt(number)) {
|
|
return java.util.List.of();
|
|
}
|
|
return hybridExtrasOrEmpty(number, pqSealMessageFor(block, commitHash));
|
|
}
|
|
|
|
+ /** The anchor-parent predicate of {@link #extraSealsFor}, in one place for it and the D-337 reuse. */
|
|
+ static boolean pqExtrasApplyAt(final long number) {
|
|
+ return org.hyperledger.besu.consensus.common.bft.blockcreation.PqAnchorProducer.config()
|
|
+ .anchorAppliesAt(number + 1L);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * D-337 (2026-09-28): signs this node's Commit seals for this round at most once. A result is
|
|
+ * reused only when it is complete - a Falcon seal, and the extras wherever extras apply - so an
|
|
+ * attempt that failed is retried on the next path exactly as before this change.
|
|
+ *
|
|
+ * <p>Package-private, with {@link #falconSealFor} and {@link #extraSealsFor}, for the probe that
|
|
+ * counts the signings on the two paths (PqCommitSealsSignedOnceTest).
|
|
+ *
|
|
+ * @param block the proposed block of this round
|
|
+ * @param commitHash its commit hash in this round
|
|
+ */
|
|
+ void pqSealCommitOnce(final QbftBlock block, final Hash commitHash) {
|
|
+ if (commitHash.equals(pqSealedCommitHash)
|
|
+ && pqSealedFalcon.isPresent()
|
|
+ && (!pqSealedExtras.isEmpty() || !pqExtrasApplyAt(block.getHeader().getNumber()))) {
|
|
+ return;
|
|
+ }
|
|
+ final Optional<FalconSeal> falcon = falconSealFor(block, commitHash);
|
|
+ pqSealedExtras =
|
|
+ falcon.isPresent() ? extraSealsFor(block, commitHash) : java.util.List.of();
|
|
+ pqSealedFalcon = falcon;
|
|
+ pqSealedCommitHash = commitHash;
|
|
+ }
|
|
+
|
|
/**
|
|
* D-334 (2026-09-03, mainnet 2800, 125 s of halted chain): the hybrid loader is lazy, so a
|
|
* registry the container could not read surfaced here, as an exception thrown INTO the QBFT
|
|
* state machine, at every anchor parent, on every armed node. Three such nodes plus one node
|
|
* restarting left five of nine. A broken hybrid configuration may cost this node its SLH-DSA
|
|
* contribution; it must never cost the node its vote. The loader still refuses to START on the
|
|
* same defect (QbftBesuControllerBuilder calls it at boot), so this catch is the second net.
|
|
*
|
|
* @param number the height being committed
|
|
* @param message the seal message
|
|
* @return the extras, or an empty list with an ERROR line when the hybrid support cannot sign
|
|
*/
|
|
static java.util.List<org.hyperledger.besu.consensus.common.bft.SchemeSeal> hybridExtrasOrEmpty(
|
|
final long number, final Bytes32 message) {
|
|
try {
|
|
return org.hyperledger.besu.consensus.common.bft.HybridSealSupport.instance()
|
|
.producer()
|
|
.sealsFor(number, message);
|
|
} catch (final RuntimeException e) {
|
|
LOG.error(
|
|
"AERE HIBRID: extras NOT signed at height {} - {}. This node keeps voting but contributes no"
|
|
+ " SLH-DSA seal until the hybrid configuration is repaired (D-334).",
|
|
number,
|
|
e.getMessage());
|
|
return java.util.List.of();
|
|
}
|
|
}
|
|
|
|
/** The exact bytes a PQ seal over this block signs; shared by Falcon and the hybrid extras,
|
|
* so the two halves of a hybrid certificate can never drift onto different messages. */
|
|
private Bytes32 pqSealMessageFor(final QbftBlock block, final Hash commitHash) {
|
|
// AERE D-311 (2026-09-02): the form is decided in ONE place, shared with the verifier
|
|
// (MessageValidator.SubsequentMessageValidator). A second copy of this rule drifted once and
|
|
// stopped a chain; see PqAnchorProducer.commitSealMessage.
|
|
return PqAnchorProducer.commitSealMessage(
|
|
block.getHeader().getNumber(), () -> pqOnchainHashOf(block).getBytes(), commitHash);
|
|
}
|
|
|
|
- private Optional<FalconSeal> falconSealFor(final QbftBlock block, final Hash commitHash) {
|
|
+ Optional<FalconSeal> falconSealFor(final QbftBlock block, final Hash commitHash) {
|
|
// FalconSealSupport.sign never throws (any fault is swallowed and logged), and returns empty
|
|
// when this node holds no Falcon signing key, so the ECDSA commit path is never affected.
|
|
//
|
|
// AERE FIX-OPRIRE-CONSENS (b): the block NUMBER is now a mandatory argument. Seal ATTACHMENT is
|
|
// gated on the activation height (and on registry coverage of the whole validator set) inside
|
|
// FalconSealSupport.sign, so merely holding a Falcon key no longer makes a node emit a
|
|
// Falcon-carrying Commit. There is deliberately no height-less sign() overload left: a call site
|
|
// physically cannot bypass the gate.
|
|
//
|
|
// AERE ANCHOR V2: WHAT IS SIGNED changes one block BEFORE the anchor activates, because the
|
|
// certificate carried by block H is made of seals over block H-1. From that height the message
|
|
// is M = keccak256(RLP["AERE-PQ-COMMIT-1", chainId, number, ON-CHAIN block hash]) instead of the
|
|
// ECDSA committed-seal hash. The committed-seal hash could not be used: it includes the ROUND,
|
|
// which is not in the block-hash pre-image, so a validator holding only the parent header could
|
|
// not rebuild it. Every node flips at the same height, since the height is a pure function of
|
|
// the same configured H; a node configured with a different H emits seals nobody can use, and
|
|
// the producer drops them on verification rather than carrying them into a header.
|
|
// AERE HIBRID (2026-08-25): mesajul se calculeaza acum intr-UN singur loc, pqSealMessageFor,
|
|
// impartit cu extrasele hibride; doua copii ale acestei logici ar fi divergat intr-o zi.
|
|
final long blockNumber = block.getHeader().getNumber();
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java
|
|
index f9c6cf7734..a7979513de 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftRoundFactory.java
|
|
@@ -1,36 +1,43 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.statemachine;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreatorFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule;
|
|
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory;
|
|
import org.hyperledger.besu.util.Subscribers;
|
|
|
|
/** The Qbft round factory. */
|
|
public class QbftRoundFactory {
|
|
|
|
private final QbftFinalState finalState;
|
|
private final QbftBlockCreatorFactory blockCreatorFactory;
|
|
private final QbftBlockInterface blockInterface;
|
|
private final QbftProtocolSchedule protocolSchedule;
|
|
@@ -91,27 +98,27 @@ public class QbftRoundFactory {
|
|
* @param parentHeader the parent header
|
|
* @param roundState the round state
|
|
* @return the qbft round
|
|
*/
|
|
public QbftRound createNewRoundWithState(
|
|
final QbftBlockHeader parentHeader, final RoundState roundState) {
|
|
final QbftBlockCreator blockCreator =
|
|
blockCreatorFactory.create(roundState.getRoundIdentifier().getRoundNumber());
|
|
|
|
// TODO(tmm): Why is this created everytime?!
|
|
final QbftMessageTransmitter messageTransmitter =
|
|
new QbftMessageTransmitter(messageFactory, finalState.getValidatorMulticaster());
|
|
|
|
return new QbftRound(
|
|
roundState,
|
|
blockCreator,
|
|
blockInterface,
|
|
protocolSchedule,
|
|
minedBlockObservers,
|
|
finalState.getNodeKey(),
|
|
- finalState.getLocalAddress(),
|
|
+ AerePqIdentity.local(finalState.getLocalAddress(), parentHeader.getNumber() + 1L),
|
|
messageFactory,
|
|
messageTransmitter,
|
|
finalState.getRoundTimer(),
|
|
parentHeader);
|
|
}
|
|
}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/RoundState.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/RoundState.java
|
|
index 2c798c9e27..b7ba44b5a1 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/RoundState.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/RoundState.java
|
|
@@ -149,40 +149,50 @@ public class RoundState {
|
|
committed = (commitMessages.size() >= quorum) && proposalMessage.isPresent();
|
|
LOG.trace(
|
|
"Round state updated prepared={} committed={} preparedQuorum={}/{} committedQuorum={}/{}",
|
|
prepared,
|
|
committed,
|
|
prepareMessages.size(),
|
|
quorum,
|
|
commitMessages.size(),
|
|
quorum);
|
|
}
|
|
|
|
/**
|
|
* Gets proposed block.
|
|
*
|
|
* @return the proposed block
|
|
*/
|
|
public Optional<QbftBlock> getProposedBlock() {
|
|
return proposalMessage.map(p -> p.getSignedPayload().getPayload().getProposedBlock());
|
|
}
|
|
|
|
+ /**
|
|
+ * AIP-22 stage 5: the post-quantum seal of the accepted proposal, which becomes element 6 of the
|
|
+ * sealed header from H_hdr (every node writes the same one, the proposer's).
|
|
+ *
|
|
+ * @return the proposal's seal, or empty
|
|
+ */
|
|
+ public Optional<FalconSeal> getProposalFalconSeal() {
|
|
+ return proposalMessage.flatMap(p -> p.getSignedPayload().getPayload().getFalconSeal());
|
|
+ }
|
|
+
|
|
/**
|
|
* Gets proposed block access list.
|
|
*
|
|
* @return the block access list
|
|
*/
|
|
public Optional<BlockAccessList> getProposedBlockAccessList() {
|
|
return proposalMessage.flatMap(Proposal::getBlockAccessList);
|
|
}
|
|
|
|
/**
|
|
* Is prepared.
|
|
*
|
|
* @return the boolean
|
|
*/
|
|
public boolean isPrepared() {
|
|
return prepared;
|
|
}
|
|
|
|
/**
|
|
* Is committed.
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java
|
|
index c397cab98f..af124c1ed0 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockCreator.java
|
|
@@ -62,29 +62,45 @@ public interface QbftBlockCreator {
|
|
/**
|
|
* Create sealed block, additionally embedding a gossiped parallel Falcon-512 quorum certificate
|
|
* (AERE hybrid PQC). The default implementation ignores the Falcon seals and delegates to the
|
|
* ECDSA-only sealing, so existing implementations remain valid; the QBFT block creator adaptor
|
|
* overrides this to aggregate the Falcon seals into a per-block quorum certificate.
|
|
*
|
|
* @param block the block
|
|
* @param roundNumber the round number
|
|
* @param commitSeals the decisive ECDSA commit seals
|
|
* @param falconSeals the gossiped parallel Falcon-512 seals collected from commit messages
|
|
* @return the block
|
|
*/
|
|
default QbftBlock createSealedBlock(
|
|
final QbftBlock block,
|
|
final int roundNumber,
|
|
final Collection<SECPSignature> commitSeals,
|
|
final Collection<FalconSeal> falconSeals) {
|
|
return createSealedBlock(block, roundNumber, commitSeals);
|
|
}
|
|
|
|
+ /**
|
|
+ * AIP-22 stage 5: seal a block from H_hdr, with NO ECDSA committed seal and the proposer's
|
|
+ * post-quantum seal as element 6, everything else of the proposed header carried over (the anchor
|
|
+ * certificate included). An implementation that cannot do this must say so, never seal the old way.
|
|
+ *
|
|
+ * @param block the proposed block
|
|
+ * @param roundNumber the round number
|
|
+ * @param proposerSeal the proposal's post-quantum seal
|
|
+ * @return the sealed block
|
|
+ */
|
|
+ default QbftBlock createSealedBlockWithProposerSeal(
|
|
+ final QbftBlock block, final int roundNumber, final FalconSeal proposerSeal) {
|
|
+ throw new UnsupportedOperationException(
|
|
+ "AERE-PQC-HDR-02: this block creator cannot seal a stage-5 header (proposer seal, no ECDSA seals)");
|
|
+ }
|
|
+
|
|
/**
|
|
* Convenience empty Falcon seal collection.
|
|
*
|
|
* @return an empty collection of Falcon seals
|
|
*/
|
|
static Collection<FalconSeal> noFalconSeals() {
|
|
return Collections.emptyList();
|
|
}
|
|
}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/CommitValidator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/CommitValidator.java
|
|
index 918607ad2b..680c53f44a 100644
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/CommitValidator.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/CommitValidator.java
|
|
@@ -5,40 +5,41 @@
|
|
* 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: an OPTIONAL, height-gated post-quantum enforcement
|
|
* hook (see PqCommitEnforcement). When no enforcement is supplied, behaviour is byte-for-byte the
|
|
* upstream behaviour; the existing constructor keeps that contract for every existing caller.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.validation;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit;
|
|
import org.hyperledger.besu.consensus.qbft.core.payload.CommitPayload;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.core.Util;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Optional;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/** The Commit validator. */
|
|
public class CommitValidator {
|
|
|
|
private static final String ERROR_PREFIX = "Invalid Commit Message";
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(CommitValidator.class);
|
|
@@ -190,41 +191,43 @@ public class CommitValidator {
|
|
|
|
if (!payload.getRoundIdentifier().equals(targetRound)) {
|
|
LOG.info(
|
|
"{}: did not target expected round {} was {}",
|
|
ERROR_PREFIX,
|
|
targetRound,
|
|
payload.getRoundIdentifier());
|
|
return false;
|
|
}
|
|
|
|
if (!payload.getDigest().equals(expectedDigest)) {
|
|
LOG.info(
|
|
"{}: did not contain expected digest {} was {}",
|
|
ERROR_PREFIX,
|
|
expectedDigest,
|
|
payload.getDigest());
|
|
return false;
|
|
}
|
|
|
|
final Address commitSealCreator =
|
|
- Util.signatureToAddress(payload.getCommitSeal(), expectedCommitDigest);
|
|
+ AerePqIdentity.author(
|
|
+ Util.signatureToAddress(payload.getCommitSeal(), expectedCommitDigest),
|
|
+ targetRound.getSequenceNumber());
|
|
|
|
if (!commitSealCreator.equals(signedPayload.getAuthor())) {
|
|
LOG.info(
|
|
"{}: Seal was not created by the message transmitter {} was {}",
|
|
ERROR_PREFIX,
|
|
commitSealCreator,
|
|
signedPayload.getAuthor());
|
|
return false;
|
|
}
|
|
|
|
// AERE full-PQ: above the arming height a commit vote only counts with a valid post-quantum
|
|
// seal bound to this very author. Below it (or with no enforcement supplied) nothing changes.
|
|
if (pqEnforcement != null) {
|
|
final Optional<String> refusal =
|
|
pqEnforcement.refusal(
|
|
targetRound.getSequenceNumber(),
|
|
signedPayload.getAuthor(),
|
|
expectedPqSealMessage,
|
|
payload.getFalconSeal(),
|
|
payload.getExtraSeals());
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqCommitEnforcement.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqCommitEnforcement.java
|
|
index d1aa1be8e1..074459cbe7 100755
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqCommitEnforcement.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqCommitEnforcement.java
|
|
@@ -1,40 +1,41 @@
|
|
/*
|
|
* AERE full-PQ consensus (TOP 3 list, item 1), step 1: the enforcement core.
|
|
*
|
|
* WHAT IT DECIDES. From the arming height upward, a Commit message counts toward the 2f+1
|
|
* quorum ONLY if it carries the PQ seal (already transported in CommitPayload, live on the
|
|
* fleet) and the seal (a) exists, (b) has its index bound to the VERY author of the message
|
|
* through the height-indexed registry, (c) verifies over the commit digest. Without a valid
|
|
* PQ seal the vote does not count -- this puts post-quantum into the agreement itself, at the
|
|
* layer where the D-235 header rule could not live (headers between anchors carry no seals;
|
|
* the commit message can carry them all).
|
|
*
|
|
* HOW IT IS WIRED (updated the same night). CommitValidator calls it through the production
|
|
* constructor, which self-installs from fromSystemConfig(): absent property = null =
|
|
* upstream behaviour, DISARMED by default; a broken value = loud refusal, never a silent
|
|
* disarm. The core stays purely testable: the registry is injected (the PqSignerRegistry
|
|
* interface, which refuses by construction to answer without a height -- the D2 inheritance);
|
|
* the singleton enters only through the production factory, exactly like PqAnchorSealsRule.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.core.validation;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSchemeSchedule;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
import org.hyperledger.besu.consensus.common.bft.blockcreation.PqAnchorProducer;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.function.LongPredicate;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
/** Height-gated decision: does this Commit's PQ seal let it count toward quorum? */
|
|
@@ -96,40 +97,42 @@ public final class PqCommitEnforcement {
|
|
// receives it too, so from the hybrid step of the schedule onward a vote without ALL the
|
|
// required schemes does not count. Without the pair, this stays exactly the Falcon
|
|
// enforcement we had until now.
|
|
final HybridSealSupport hybrid = HybridSealSupport.instance();
|
|
if (hybrid.schedule().isPresent()) {
|
|
return new PqCommitEnforcement(
|
|
armedFrom,
|
|
PqSignerRegistry.falconSealSupport(),
|
|
hybrid.schedule().get(),
|
|
hybrid.registry().orElseThrow());
|
|
}
|
|
return new PqCommitEnforcement(armedFrom, PqSignerRegistry.falconSealSupport());
|
|
}
|
|
|
|
private final long armedFromBlock;
|
|
private final PqSignerRegistry registry;
|
|
// AERE HIBRID: null in Falcon-only mode, which is every node today.
|
|
private final PqSchemeSchedule schemeSchedule;
|
|
private final HybridSignerRegistry hybridRegistry;
|
|
private final LongPredicate extrasRequiredAt;
|
|
+ // AIP-22 stage 2: the origin of the anchor grids, read lazily so tests need no live config
|
|
+ private final java.util.function.LongSupplier anchorBlock;
|
|
|
|
/**
|
|
* @param armedFromBlock first block height (inclusive) at which enforcement applies; use
|
|
* {@link #DISARMED} for the today-behaviour
|
|
* @param registry the height-aware signer registry (injected, never a singleton)
|
|
*/
|
|
public PqCommitEnforcement(final long armedFromBlock, final PqSignerRegistry registry) {
|
|
this(armedFromBlock, registry, null, null);
|
|
}
|
|
|
|
/**
|
|
* Enforcement that also demands the HYBRID schemes a schedule requires at each height.
|
|
*
|
|
* <p>AERE HIBRID (2026-08-25). Above the arming height a vote must carry, besides the Falcon
|
|
* seal checked by the Falcon-only path, a valid seal for EVERY other scheme the schedule names
|
|
* at that height. The point of a hybrid is that the two families fail independently, so a
|
|
* partially satisfied certificate is worth exactly as much as the weakest family present, which
|
|
* is why a missing scheme refuses rather than degrades.
|
|
*
|
|
* <p>NO REGISTRY-ALIGNMENT ASSUMPTION. The hybrid registry and the legacy Falcon registry are
|
|
@@ -162,45 +165,68 @@ public final class PqCommitEnforcement {
|
|
*
|
|
* @return the predicate "the block at this height is the parent of an anchor", from the live
|
|
* anchor configuration
|
|
*/
|
|
public static LongPredicate anchorParentByConfig() {
|
|
return h -> PqAnchorProducer.config().anchorAppliesAt(h + 1L);
|
|
}
|
|
|
|
/**
|
|
* Full constructor.
|
|
*
|
|
* @param extrasRequiredAt at which heights the extra (non-Falcon) scheme seals are demanded on a
|
|
* commit; production passes {@link #anchorParentByConfig()}
|
|
*/
|
|
public PqCommitEnforcement(
|
|
final long armedFromBlock,
|
|
final PqSignerRegistry registry,
|
|
final PqSchemeSchedule schemeSchedule,
|
|
final HybridSignerRegistry hybridRegistry,
|
|
final LongPredicate extrasRequiredAt) {
|
|
+ this(
|
|
+ armedFromBlock,
|
|
+ registry,
|
|
+ schemeSchedule,
|
|
+ hybridRegistry,
|
|
+ extrasRequiredAt,
|
|
+ () -> PqAnchorProducer.config().anchorBlock());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Full constructor with an explicit anchor-grid origin (AIP-22 stage 2), for proofs that run
|
|
+ * a per-scheme interval schedule without the process-wide anchor configuration.
|
|
+ *
|
|
+ * @param anchorBlock supplies the chain's anchor activation height, origin of every grid
|
|
+ */
|
|
+ public PqCommitEnforcement(
|
|
+ final long armedFromBlock,
|
|
+ final PqSignerRegistry registry,
|
|
+ final PqSchemeSchedule schemeSchedule,
|
|
+ final HybridSignerRegistry hybridRegistry,
|
|
+ final LongPredicate extrasRequiredAt,
|
|
+ final java.util.function.LongSupplier anchorBlock) {
|
|
this.armedFromBlock = armedFromBlock;
|
|
this.registry = registry;
|
|
this.schemeSchedule = schemeSchedule;
|
|
this.hybridRegistry = hybridRegistry;
|
|
this.extrasRequiredAt = extrasRequiredAt;
|
|
+ this.anchorBlock = anchorBlock;
|
|
if ((schemeSchedule == null) != (hybridRegistry == null)) {
|
|
// Half a hybrid configuration is the shape that starts a node believing it enforces
|
|
// something it does not. Refuse at construction, the same stance as every other AERE gate.
|
|
throw new IllegalStateException(
|
|
"AERE-PQC-COMMIT-CONF-03: the scheme schedule and the hybrid registry are a PAIR;"
|
|
+ " configure both or neither.");
|
|
}
|
|
}
|
|
|
|
/** Whether enforcement is active at {@code height}. */
|
|
public boolean armedAt(final long height) {
|
|
return height >= armedFromBlock;
|
|
}
|
|
|
|
/**
|
|
* Decide whether a Commit may count toward quorum.
|
|
*
|
|
* @param height the block height the commit targets (the round's sequence number)
|
|
* @param author the RECOVERED author of the signed Commit message (from its ECDSA signature)
|
|
* @param commitDigest the commit digest the PQ seal must have signed
|
|
@@ -226,88 +252,105 @@ public final class PqCommitEnforcement {
|
|
* @return empty when the commit counts; otherwise the refusal, with names and numbers
|
|
*/
|
|
public Optional<String> refusal(
|
|
final long height,
|
|
final Address author,
|
|
final Hash commitDigest,
|
|
final Optional<FalconSeal> seal,
|
|
final List<SchemeSeal> extraSeals) {
|
|
final Optional<String> falconVerdict = falconRefusal(height, author, commitDigest, seal);
|
|
if (falconVerdict.isPresent()
|
|
|| !armedAt(height)
|
|
|| schemeSchedule == null
|
|
|| !extrasRequiredAt.test(height)) {
|
|
return falconVerdict;
|
|
}
|
|
return hybridRefusal(height, author, commitDigest, seal.orElseThrow(), extraSeals);
|
|
}
|
|
|
|
/**
|
|
* Every scheme the schedule names at this height, other than Falcon, must be present and valid.
|
|
+ * The height is an anchor PARENT (that is the only place extras are demanded), so the schemes
|
|
+ * are those the anchor at {@code height + 1} requires: with per-scheme intervals (AIP-22 stage
|
|
+ * 2) a commit at the parent of a Falcon-only anchor counts without an SLH-DSA seal.
|
|
*/
|
|
private Optional<String> hybridRefusal(
|
|
final long height,
|
|
final Address author,
|
|
final Hash commitDigest,
|
|
final FalconSeal falconSeal,
|
|
final List<SchemeSeal> extraSeals) {
|
|
- final Set<String> required = schemeSchedule.schemesAt(height);
|
|
+ final Set<String> required =
|
|
+ schemeSchedule.schemesRequiredForAnchor(height + 1L, anchorBlock.getAsLong());
|
|
for (final String schemeId : required) {
|
|
if (SealSchemes.FALCON_512.id().equals(schemeId)) {
|
|
continue; // already decided by the Falcon path above
|
|
}
|
|
final Optional<SealScheme> scheme = SealSchemes.byId(schemeId);
|
|
if (scheme.isEmpty()) {
|
|
return Optional.of(
|
|
"AERE HIBRID: the schedule requires scheme '" + schemeId + "' at height " + height
|
|
+ " and this binary does not implement it - refusing rather than ignoring it");
|
|
}
|
|
final byte wire = scheme.get().wireId();
|
|
SchemeSeal found = null;
|
|
for (final SchemeSeal candidate : extraSeals) {
|
|
if (candidate.getSchemeWireId() == wire) {
|
|
found = candidate;
|
|
break;
|
|
}
|
|
}
|
|
if (found == null) {
|
|
return Optional.of(
|
|
"AERE HIBRID: commit at height " + height + " carries no " + schemeId
|
|
+ " seal, which the schedule requires - the vote does not count");
|
|
}
|
|
// One identity per message: the hybrid seal must speak for the same validator as the Falcon
|
|
// seal, and that index must be THIS author in the hybrid registry. Neither is assumed.
|
|
if (found.getValidatorIndex() != falconSeal.getValidatorIndex()) {
|
|
return Optional.of(
|
|
"AERE HIBRID: " + schemeId + " seal is index " + found.getValidatorIndex()
|
|
+ " but the Falcon seal on the same commit is index "
|
|
+ falconSeal.getValidatorIndex() + " - one commit, one signer");
|
|
}
|
|
- final Optional<byte[]> bound = hybridRegistry.address(found.getValidatorIndex());
|
|
- if (bound.isEmpty()
|
|
- || !Address.wrap(Bytes.wrap(bound.get())).equals(author)) {
|
|
+ // AIP-22 stage 3b: from H_k the keys and the index->author binding are those of the v3 epoch in force, as in the anchor
|
|
+ // producer and PqAnchorSealsRule. Paid 2026-09-23 on testnet 28001: this check alone still read the static v2 hybrid
|
|
+ // registry, so after the rotation at 3,097,600 the ROTATED row (index 2) signed with its new SLH-DSA key and every one of its
|
|
+ // commits at an anchor's parent was refused here; latent while four other validators sufficed, it stopped the chain at
|
|
+ // 3,135,679 when the Nethermind validator fell behind.
|
|
+ final boolean v3 = AerePqIdentity.keysFromV3(height);
|
|
+ final Optional<Address> boundId =
|
|
+ v3
|
|
+ ? AerePqIdentity.v3IdAt(height, found.getValidatorIndex())
|
|
+ : hybridRegistry
|
|
+ .address(found.getValidatorIndex())
|
|
+ .map(a -> AerePqIdentity.author(Address.wrap(Bytes.wrap(a)), height));
|
|
+ if (boundId.isEmpty() || !boundId.get().equals(author)) {
|
|
return Optional.of(
|
|
"AERE HIBRID: index " + found.getValidatorIndex()
|
|
- + " is not bound to the commit author " + author + " in the hybrid registry");
|
|
+ + " is not bound to the commit author " + author
|
|
+ + (v3 ? " in the v3 epoch in force" : " in the hybrid registry"));
|
|
}
|
|
final Optional<byte[]> publicKey =
|
|
- hybridRegistry.publicKey(found.getValidatorIndex(), schemeId);
|
|
+ v3
|
|
+ ? AerePqIdentity.v3KeyAt(height, found.getValidatorIndex(), schemeId)
|
|
+ : hybridRegistry.publicKey(found.getValidatorIndex(), schemeId);
|
|
if (publicKey.isEmpty()) {
|
|
return Optional.of(
|
|
"AERE HIBRID: the hybrid registry holds no " + schemeId + " key for index "
|
|
+ found.getValidatorIndex());
|
|
}
|
|
final boolean valid;
|
|
try {
|
|
valid =
|
|
scheme
|
|
.get()
|
|
.verifyRaw(
|
|
publicKey.get(),
|
|
commitDigest.getBytes().toArray(),
|
|
found.getSignature().toArray());
|
|
} catch (final RuntimeException e) {
|
|
return Optional.of(
|
|
"AERE HIBRID: " + schemeId + " verification threw at height " + height + ": "
|
|
+ e.getMessage());
|
|
}
|
|
if (!valid) {
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuard.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuard.java
|
|
new file mode 100644
|
|
index 0000000000..ea85af1542
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuard.java
|
|
@@ -0,0 +1,181 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.core.validation;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import java.util.function.LongPredicate;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4: H_fin may be armed only where every post-quantum seal is VERIFIED from H_fin.
|
|
+ *
|
|
+ * <p>From H_fin a message's author is the id of its seal's index ({@code AerePqFinality}), and the
|
|
+ * envelope's ECDSA signature is no longer read. For a PROPOSAL, PREPARE or ROUND-CHANGE the author is
|
|
+ * given only once the seal verifies; a COMMIT's author is its index's id only when that is the commit
|
|
+ * seal signer's id, and what judges the COMMIT's post-quantum seal is the commit layer alone. Each
|
|
+ * layer is armed on its own height. With the commit layer unset, or armed above H_fin, a Commit whose
|
|
+ * ECDSA commit seal was forged (the adversary stage 4 exists for) would count with any bytes as its
|
|
+ * post-quantum seal; and the other three layers are the second judge of what the author already
|
|
+ * checked. So this guard refuses to start such a node (AERE-PQC-FIN-02), before the network is up.
|
|
+ * Emergency disarming of a layer after H_fin therefore needs H_fin unset too, on every node: one
|
|
+ * uniform step back to ECDSA authorship, never a node that trusts unverified seals.
|
|
+ */
|
|
+public final class PqFinalityLayersGuard {
|
|
+
|
|
+ /**
|
|
+ * One seal layer as the guard sees it.
|
|
+ *
|
|
+ * @param property the property that arms it
|
|
+ * @param armedAt whether it is armed at a height; null when the property is set nowhere
|
|
+ */
|
|
+ public record Layer(String property, LongPredicate armedAt) {}
|
|
+
|
|
+ private PqFinalityLayersGuard() {}
|
|
+
|
|
+ /**
|
|
+ * The refusal, if any.
|
|
+ *
|
|
+ * @param hFin H_fin, or {@link AerePqIdentity#NEVER}
|
|
+ * @param layers the four seal layers
|
|
+ * @return empty when H_fin is unset or every layer is armed at or below it; otherwise the refusal
|
|
+ */
|
|
+ public static Optional<String> refusal(final long hFin, final List<Layer> layers) {
|
|
+ if (hFin == AerePqIdentity.NEVER) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final List<String> missing = new ArrayList<>();
|
|
+ for (final Layer l : layers) {
|
|
+ if (l.armedAt() == null || !l.armedAt().test(hFin)) {
|
|
+ missing.add(l.property() + (l.armedAt() == null ? " unset" : " armed above " + hFin));
|
|
+ }
|
|
+ }
|
|
+ if (missing.isEmpty()) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ return Optional.of(
|
|
+ "AERE-PQC-FIN-02: aere.pq.finalityBlock="
|
|
+ + hFin
|
|
+ + " makes a message's author the id of its post-quantum seal's index, so every seal"
|
|
+ + " must be verified from H_fin; not armed at or below it: "
|
|
+ + String.join(", ", missing)
|
|
+ + ". Arm the four layers at or below H_fin on every node, or unset H_fin on every node.");
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The four layers as this node's configuration arms them.
|
|
+ *
|
|
+ * @return proposal, prepare, commit, round-change
|
|
+ */
|
|
+ public static List<Layer> fromSystemConfig() {
|
|
+ final PqProposalEnforcement p = PqProposalEnforcement.fromSystemConfig();
|
|
+ final PqPrepareEnforcement pr = PqPrepareEnforcement.fromSystemConfig();
|
|
+ final PqCommitEnforcement c = PqCommitEnforcement.fromSystemConfig();
|
|
+ final PqRoundChangeEnforcement rc = PqRoundChangeEnforcement.fromSystemConfig();
|
|
+ return List.of(
|
|
+ new Layer(PqProposalEnforcement.PROPERTY_FORK_BLOCK, p == null ? null : p::armedAt),
|
|
+ new Layer(PqPrepareEnforcement.PROPERTY_FORK_BLOCK, pr == null ? null : pr::armedAt),
|
|
+ new Layer(PqCommitEnforcement.PROPERTY_FORK_BLOCK, c == null ? null : c::armedAt),
|
|
+ new Layer(
|
|
+ PqRoundChangeEnforcement.PROPERTY_FORK_BLOCK, rc == null ? null : rc::armedAt));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Refuses to start when H_fin is armed over an unverified layer.
|
|
+ *
|
|
+ * @param hFin H_fin as armed on this node
|
|
+ * @throws IllegalStateException AERE-PQC-FIN-02
|
|
+ */
|
|
+ public static void verifyOrAbort(final long hFin) {
|
|
+ final Optional<String> r = refusal(hFin, fromSystemConfig());
|
|
+ if (r.isPresent()) {
|
|
+ throw new IllegalStateException(r.get());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE-PQC-FIN-03: from H_fin an unsealed message has no author, so a node that seals (holds its
|
|
+ * Falcon key; from H_k every registered validator must, stage 3b-ii) must seal all four messages at
|
|
+ * or below H_fin, or it goes mute at H_fin while looking healthy: a loss of liveness, not safety.
|
|
+ *
|
|
+ * @param hFin H_fin, or {@link AerePqIdentity#NEVER}
|
|
+ * @param signs whether this node seals (a reader does not)
|
|
+ * @param attachCommit aere.falcon.attachBlock ({@link Long#MAX_VALUE} when unset)
|
|
+ * @param attachProposal aere.pq.proposalPq.attachBlock
|
|
+ * @param attachPrepare aere.pq.preparePq.attachBlock
|
|
+ * @param attachRoundChange aere.pq.roundChangePq.attachBlock
|
|
+ * @return the refusal, or empty
|
|
+ */
|
|
+ public static Optional<String> emissionRefusal(
|
|
+ final long hFin,
|
|
+ final boolean signs,
|
|
+ final long attachCommit,
|
|
+ final long attachProposal,
|
|
+ final long attachPrepare,
|
|
+ final long attachRoundChange) {
|
|
+ if (hFin == AerePqIdentity.NEVER || !signs) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final List<String> missing = new ArrayList<>();
|
|
+ gate(missing, "aere.falcon.attachBlock", attachCommit, hFin);
|
|
+ gate(missing, "aere.pq.proposalPq.attachBlock", attachProposal, hFin);
|
|
+ gate(missing, "aere.pq.preparePq.attachBlock", attachPrepare, hFin);
|
|
+ gate(missing, "aere.pq.roundChangePq.attachBlock", attachRoundChange, hFin);
|
|
+ if (missing.isEmpty()) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ return Optional.of(
|
|
+ "AERE-PQC-FIN-03: aere.pq.finalityBlock="
|
|
+ + hFin
|
|
+ + " makes an unsealed message authorless, and this node would not seal from H_fin: "
|
|
+ + String.join(", ", missing)
|
|
+ + ". It would go mute at H_fin. Arm them at or below H_fin, or unset H_fin, on every validator.");
|
|
+ }
|
|
+
|
|
+ private static void gate(final List<String> missing, final String property, final long h, final long hFin) {
|
|
+ if (h < 0 || h == Long.MAX_VALUE) {
|
|
+ missing.add(property + " unset");
|
|
+ } else if (h > hFin) {
|
|
+ missing.add(property + " armed above H_fin (" + h + ")");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Refuses to start when a sealing node would not seal every message from H_fin.
|
|
+ *
|
|
+ * @param hFin H_fin as armed on this node
|
|
+ * @param signs whether this node seals
|
|
+ * @param attachCommit commit attachment height
|
|
+ * @param attachProposal proposal attachment height
|
|
+ * @param attachPrepare prepare attachment height
|
|
+ * @param attachRoundChange round-change attachment height
|
|
+ * @throws IllegalStateException AERE-PQC-FIN-03
|
|
+ */
|
|
+ public static void verifyEmissionOrAbort(
|
|
+ final long hFin,
|
|
+ final boolean signs,
|
|
+ final long attachCommit,
|
|
+ final long attachProposal,
|
|
+ final long attachPrepare,
|
|
+ final long attachRoundChange) {
|
|
+ final Optional<String> r =
|
|
+ emissionRefusal(hFin, signs, attachCommit, attachProposal, attachPrepare, attachRoundChange);
|
|
+ if (r.isPresent()) {
|
|
+ throw new IllegalStateException(r.get());
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangePayloadValidator.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangePayloadValidator.java
|
|
old mode 100644
|
|
new mode 100755
|
|
index 8fd9bed3e6..63a94d5ae5
|
|
--- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangePayloadValidator.java
|
|
+++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/validation/RoundChangePayloadValidator.java
|
|
@@ -38,40 +38,43 @@ import org.slf4j.LoggerFactory;
|
|
* performed elsewhere (eg. the BlockHeightManager)
|
|
*
|
|
* <p>AERE (2026-08-31): an OPTIONAL post-quantum enforcement hook, gated on height (see {@link
|
|
* PqRoundChangeEnforcement}). When no enforcement is supplied, behaviour is byte for byte the
|
|
* upstream one - and that is the configuration of every node today. Same pattern as the PREPARE,
|
|
* commit and PROPOSAL validators, deliberately: a second rendering of the same idea, written
|
|
* differently, diverges eventually.
|
|
*
|
|
* <p>The 2-argument constructor - the one production code calls, from both {@code
|
|
* MessageValidatorFactory} and {@code ProposalValidator} (the justification path) - wires the
|
|
* enforcement itself from the system configuration. That self-wiring is the security property: an
|
|
* enforcement that had to be passed in explicitly could be dropped by any refactor without a
|
|
* single test failing. It also means round-changes are judged in BOTH places they arrive:
|
|
* standalone, and inside a proposal's round-change certificate.
|
|
*/
|
|
public class RoundChangePayloadValidator {
|
|
|
|
private static final String ERROR_PREFIX = "Invalid RoundChange Payload";
|
|
private static final Logger LOG = LoggerFactory.getLogger(RoundChangePayloadValidator.class);
|
|
|
|
+ /** maximum allowed round (AERE D-434: ported from upstream 118f8b1920, GHSA-23rh-rrqg-wq82) */
|
|
+ public static final int MAX_ALLOWED_ROUND = 1000;
|
|
+
|
|
private final Collection<Address> validators;
|
|
private final long chainHeight;
|
|
private final PqRoundChangeEnforcement pqEnforcement;
|
|
|
|
/**
|
|
* Instantiates a new Round change payload validator, with the post-quantum enforcement wired
|
|
* from the system configuration. This is the constructor production code calls.
|
|
*
|
|
* @param validators the validators
|
|
* @param chainHeight the chain height
|
|
*/
|
|
public RoundChangePayloadValidator(final Collection<Address> validators, final long chainHeight) {
|
|
this(validators, chainHeight, PqRoundChangeEnforcement.fromSystemConfig());
|
|
}
|
|
|
|
/**
|
|
* Instantiates a new Round change payload validator with an explicit post-quantum enforcement.
|
|
* Test seam; production goes through the 2-argument constructor above.
|
|
*
|
|
* @param validators the validators
|
|
@@ -92,42 +95,42 @@ public class RoundChangePayloadValidator {
|
|
* Validate.
|
|
*
|
|
* @param signedPayload the signed payload
|
|
* @return the boolean
|
|
*/
|
|
public boolean validate(final SignedData<RoundChangePayload> signedPayload) {
|
|
|
|
if (!validators.contains(signedPayload.getAuthor())) {
|
|
LOG.info("{}: did not originate from a recognized validator.", ERROR_PREFIX);
|
|
return false;
|
|
}
|
|
|
|
final RoundChangePayload payload = signedPayload.getPayload();
|
|
|
|
if (payload.getRoundIdentifier().getSequenceNumber() != chainHeight) {
|
|
LOG.info("{}: did not target expected height", ERROR_PREFIX);
|
|
return false;
|
|
}
|
|
|
|
final int targetRound = payload.getRoundIdentifier().getRoundNumber();
|
|
- if (targetRound <= 0) {
|
|
- LOG.info("{}: must contain a positive target round number", ERROR_PREFIX);
|
|
+ if (targetRound <= 0 || targetRound > MAX_ALLOWED_ROUND) {
|
|
+ LOG.info("{}: target round number out of range [1, {}]", ERROR_PREFIX, MAX_ALLOWED_ROUND);
|
|
return false;
|
|
}
|
|
|
|
if (payload.getPreparedRoundMetadata().isPresent()) {
|
|
final PreparedRoundMetadata metadata = payload.getPreparedRoundMetadata().get();
|
|
if (metadata.getPreparedRound() >= targetRound) {
|
|
LOG.info("{}: prepared metadata is from a round ahead of target round", ERROR_PREFIX);
|
|
return false;
|
|
}
|
|
|
|
if (metadata.getPreparedRound() < 0) {
|
|
LOG.info("{}: prepared metadata is from a negative round number", ERROR_PREFIX);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// AERE full-PQ: from the armed height, a round-change is not accepted without a valid
|
|
// post-quantum seal from its OWN author. Below the height, and on every node without the
|
|
// property, this is a null check and nothing more - the upstream path, call for call.
|
|
if (pqEnforcement != null) {
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/AereD434ListBoundsTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/AereD434ListBoundsTest.java
|
|
new file mode 100644
|
|
index 0000000000..889e0e7c20
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/messagewrappers/AereD434ListBoundsTest.java
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * 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
|
|
+ *
|
|
+ * Aere Network notice (Apache-2.0 section 4(b)): this file was added by Aere Network, 2026-09-28 (D-434), adapted from the tests of the
|
|
+ * ported upstream fix hyperledger/besu dd4101c9ec ("bound prepares/round-change lists at decode").
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.qbft.core.messagewrappers;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.messagewrappers.BftMessage;
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.mockito.Mockito;
|
|
+
|
|
+/**
|
|
+ * AERE D-434: a RoundChange whose prepares list holds more than BftMessage.MAX_LIST_ENTRIES (512) entries is refused at DECODE, before
|
|
+ * any signature or author check; before the port any peer could make a node allocate and verify an arbitrarily long list. With ten
|
|
+ * validators an honest list never exceeds ten, so the bound never binds an honest network.
|
|
+ */
|
|
+class AereD434ListBoundsTest {
|
|
+
|
|
+ private static final QbftBlockCodec CODEC = Mockito.mock(QbftBlockCodec.class);
|
|
+
|
|
+ private static Bytes roundChangeWith(final int prepares) {
|
|
+ final NodeKey key = NodeKeyUtils.generate();
|
|
+ final RoundChangePayload rc = new RoundChangePayload(new ConsensusRoundIdentifier(1, 0), Optional.empty());
|
|
+ final SignedData<RoundChangePayload> signedRc = SignedData.create(rc, key.sign(Bytes32.wrap(rc.hashForSignature().getBytes())));
|
|
+ final PreparePayload p = new PreparePayload(new ConsensusRoundIdentifier(1, 0), Hash.ZERO);
|
|
+ final SignedData<PreparePayload> one = SignedData.create(p, key.sign(Bytes32.wrap(p.hashForSignature().getBytes())));
|
|
+ return new RoundChange(signedRc, Optional.empty(), Optional.empty(), CODEC, Collections.nCopies(prepares, one)).encode();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aPreparesListAboveTheBoundIsRefusedAtDecode() {
|
|
+ final Bytes oversized = roundChangeWith(BftMessage.MAX_LIST_ENTRIES + 1);
|
|
+ assertThatThrownBy(() -> RoundChange.decode(oversized, CODEC))
|
|
+ .isInstanceOf(RLPException.class)
|
|
+ .hasMessageContaining("exceeds the maximum permitted size");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aPreparesListAtTheBoundStillDecodes() {
|
|
+ // positive control: the fixture decodes, and the bound is inclusive
|
|
+ assertThat(RoundChange.decode(roundChangeWith(BftMessage.MAX_LIST_ENTRIES), CODEC).getPrepares()).hasSize(BftMessage.MAX_LIST_ENTRIES);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/PqCommitSealsSignedOnceTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/PqCommitSealsSignedOnceTest.java
|
|
new file mode 100644
|
|
index 0000000000..daa5ff1d44
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/statemachine/PqCommitSealsSignedOnceTest.java
|
|
@@ -0,0 +1,210 @@
|
|
+/*
|
|
+ * Copyright contributors to 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.consensus.qbft.core.statemachine;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.ArgumentMatchers.anyInt;
|
|
+import static org.mockito.ArgumentMatchers.eq;
|
|
+import static org.mockito.Mockito.doReturn;
|
|
+import static org.mockito.Mockito.spy;
|
|
+import static org.mockito.Mockito.times;
|
|
+import static org.mockito.Mockito.verify;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSealCache;
|
|
+import org.hyperledger.besu.consensus.common.bft.RoundTimer;
|
|
+import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
+import org.hyperledger.besu.consensus.qbft.core.QbftBlockTestFixture;
|
|
+import org.hyperledger.besu.consensus.qbft.core.network.QbftMessageTransmitter;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreator;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule;
|
|
+import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator;
|
|
+import org.hyperledger.besu.consensus.qbft.core.validation.QbftBlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.util.Subscribers;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
+import org.mockito.Mock;
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
+import org.mockito.junit.jupiter.MockitoSettings;
|
|
+import org.mockito.quality.Strictness;
|
|
+
|
|
+/**
|
|
+ * D-337 (2026-09-28): this node's Commit seals are signed ONCE per round, not once per path.
|
|
+ *
|
|
+ * <p>The measured cost on chain 2800: at the parent of every anchor each Besu validator signed
|
|
+ * SLH-DSA twice back to back on the consensus thread - on accepting the proposal (before its
|
|
+ * Prepare) and again on becoming prepared (between "prepared" and its Commit) - and the
|
|
+ * anchor-parent slot ran at 1,036 ms against 599 for the rest.
|
|
+ *
|
|
+ * <p>The round is driven through the real state machine: a peer's proposal, the local Prepare, a
|
|
+ * peer's Prepare that makes the round prepared, and the Commit that goes on the wire. The signers
|
|
+ * are stubbed on a spy so the SIGNINGS can be counted; everything between them is the production
|
|
+ * code. The pair of the claim is the retry: an attempt that produced no Falcon seal must be signed
|
|
+ * again on the second path, exactly as before the change, so the reuse cannot swallow a failure.
|
|
+ */
|
|
+@ExtendWith(MockitoExtension.class)
|
|
+@MockitoSettings(strictness = Strictness.LENIENT)
|
|
+public class PqCommitSealsSignedOnceTest {
|
|
+
|
|
+ private static final long HEIGHT = 7L;
|
|
+
|
|
+ private final NodeKey nodeKey = NodeKeyUtils.generate();
|
|
+ private final Address localAddress = Address.extract(nodeKey.getPublicKey());
|
|
+ private final NodeKey peerKey = NodeKeyUtils.generate();
|
|
+ private final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(HEIGHT, 0);
|
|
+ private final Subscribers<QbftMinedBlockObserver> subscribers = Subscribers.create();
|
|
+ private final FalconSeal falcon = new FalconSeal(4, Bytes.fromHexString("0x29aabbcc"));
|
|
+ private final SchemeSeal slh = new SchemeSeal((byte) 0x02, 4, Bytes.fromHexString("0x0102030405"));
|
|
+
|
|
+ private MessageFactory localFactory;
|
|
+ private MessageFactory peerFactory;
|
|
+ private QbftBlock proposedBlock;
|
|
+
|
|
+ @Mock private QbftBlockCodec blockEncoder;
|
|
+ @Mock private QbftProtocolSchedule protocolSchedule;
|
|
+ @Mock private QbftMessageTransmitter transmitter;
|
|
+ @Mock private MessageValidator messageValidator;
|
|
+ @Mock private RoundTimer roundTimer;
|
|
+ @Mock private QbftBlockCreator blockCreator;
|
|
+ @Mock private QbftBlockInterface blockInterface;
|
|
+
|
|
+ private final QbftBlockHeader parentHeader =
|
|
+ new QbftBlockHeaderTestFixture().number(HEIGHT - 1).buildHeader();
|
|
+
|
|
+ @BeforeEach
|
|
+ public void setup() {
|
|
+ PqSealCache.instance().clear();
|
|
+ localFactory = new MessageFactory(nodeKey, blockEncoder);
|
|
+ peerFactory = new MessageFactory(peerKey, blockEncoder);
|
|
+ when(messageValidator.validateProposal(any())).thenReturn(true);
|
|
+ when(messageValidator.validatePrepare(any())).thenReturn(true);
|
|
+ when(messageValidator.validateCommit(any())).thenReturn(true);
|
|
+ proposedBlock =
|
|
+ new QbftBlockTestFixture()
|
|
+ .blockHeader(new QbftBlockHeaderTestFixture().number(HEIGHT).buildHeader())
|
|
+ .build();
|
|
+ when(blockInterface.replaceRoundForCommitBlock(any(), anyInt())).thenReturn(proposedBlock);
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void clean() {
|
|
+ PqSealCache.instance().clear();
|
|
+ }
|
|
+
|
|
+ /** A round of quorum 2: the local Prepare plus ONE peer Prepare make it prepared. */
|
|
+ private QbftRound spiedRound() {
|
|
+ final RoundState roundState = new RoundState(roundIdentifier, 2, messageValidator);
|
|
+ return spy(
|
|
+ new QbftRound(
|
|
+ roundState,
|
|
+ blockCreator,
|
|
+ blockInterface,
|
|
+ protocolSchedule,
|
|
+ subscribers,
|
|
+ nodeKey,
|
|
+ localAddress,
|
|
+ localFactory,
|
|
+ transmitter,
|
|
+ roundTimer,
|
|
+ parentHeader));
|
|
+ }
|
|
+
|
|
+ /** Proposal from the peer, then the peer's Prepare: the second path fires on the second step. */
|
|
+ private void driveToPrepared(final QbftRound round) {
|
|
+ round.handleProposalMessage(
|
|
+ peerFactory.createProposal(
|
|
+ roundIdentifier, proposedBlock, Collections.emptyList(), Collections.emptyList()));
|
|
+ assertThat(round.getRoundState().isPrepared()).isFalse();
|
|
+ round.handlePrepareMessage(peerFactory.createPrepare(roundIdentifier, proposedBlock.getHash()));
|
|
+ assertThat(round.getRoundState().isPrepared()).isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void anAnchorParentCommitIsSignedOnceAndTheWireCarriesThoseSeals() {
|
|
+ final QbftRound round = spiedRound();
|
|
+ doReturn(Optional.of(falcon)).when(round).falconSealFor(any(), any());
|
|
+ doReturn(List.of(slh)).when(round).extraSealsFor(any(), any());
|
|
+
|
|
+ driveToPrepared(round);
|
|
+
|
|
+ verify(round, times(1)).falconSealFor(any(), any());
|
|
+ verify(round, times(1)).extraSealsFor(any(), any());
|
|
+ verify(transmitter, times(1))
|
|
+ .multicastCommit(
|
|
+ eq(roundIdentifier),
|
|
+ eq(proposedBlock.getHash()),
|
|
+ any(),
|
|
+ eq(Optional.of(falcon)),
|
|
+ eq(List.of(slh)));
|
|
+ // the local Commit, added on accepting the proposal, carries the very same extras
|
|
+ assertThat(round.getRoundState().getExtraSeals()).containsExactly(slh);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aFalconOnlyCommitOffTheExtrasGridIsAlsoSignedOnce() {
|
|
+ // off the anchor-parent predicate the extras are legitimately empty; a Falcon-only result is
|
|
+ // complete there and must be reused too, not re-signed
|
|
+ assertThat(QbftRound.pqExtrasApplyAt(HEIGHT)).isFalse();
|
|
+ final QbftRound round = spiedRound();
|
|
+ doReturn(Optional.of(falcon)).when(round).falconSealFor(any(), any());
|
|
+ doReturn(List.of()).when(round).extraSealsFor(any(), any());
|
|
+
|
|
+ driveToPrepared(round);
|
|
+
|
|
+ verify(round, times(1)).falconSealFor(any(), any());
|
|
+ verify(transmitter, times(1))
|
|
+ .multicastCommit(
|
|
+ eq(roundIdentifier), eq(proposedBlock.getHash()), any(), eq(Optional.of(falcon)));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aFirstAttemptWithoutAFalconSealIsSignedAgainOnTheSecondPath() {
|
|
+ // the pair: reuse must never swallow a failed attempt; before D-337 the second path signed
|
|
+ // anew and could succeed, and it still must
|
|
+ final QbftRound round = spiedRound();
|
|
+ doReturn(Optional.empty()).doReturn(Optional.of(falcon)).when(round).falconSealFor(any(), any());
|
|
+ doReturn(List.of(slh)).when(round).extraSealsFor(any(), any());
|
|
+
|
|
+ driveToPrepared(round);
|
|
+
|
|
+ verify(round, times(2)).falconSealFor(any(), any());
|
|
+ verify(transmitter, times(1))
|
|
+ .multicastCommit(
|
|
+ eq(roundIdentifier),
|
|
+ eq(proposedBlock.getHash()),
|
|
+ any(),
|
|
+ eq(Optional.of(falcon)),
|
|
+ eq(List.of(slh)));
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereD434RoundCapTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereD434RoundCapTest.java
|
|
new file mode 100644
|
|
index 0000000000..e719908194
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereD434RoundCapTest.java
|
|
@@ -0,0 +1,61 @@
|
|
+/*
|
|
+ * 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
|
|
+ *
|
|
+ * Aere Network notice (Apache-2.0 section 4(b)): this file was added by Aere Network, 2026-09-28 (D-434), as the regression test of
|
|
+ * the ported upstream fix hyperledger/besu 118f8b1920 (GHSA-23rh-rrqg-wq82, "Cap BFT round change number").
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-434: a RoundChange for a round above RoundChangePayloadValidator.MAX_ALLOWED_ROUND (1000) is refused, as upstream does since
|
|
+ * 2026-08-20. Before, any positive round was accepted, so one validator could push the round-change bookkeeping of every node to an
|
|
+ * arbitrary round. The worst round the live chains have reached is 6 (2026-09-04), so the cap never binds an honest network.
|
|
+ */
|
|
+class AereD434RoundCapTest {
|
|
+
|
|
+ private static final long HEIGHT = 5L;
|
|
+
|
|
+ private static boolean judge(final int round) {
|
|
+ final QbftNodeList validators = QbftNodeList.createNodes(4, null);
|
|
+ final RoundChangePayloadValidator v = new RoundChangePayloadValidator(validators.getNodeAddresses(), HEIGHT);
|
|
+ final RoundChangePayload payload = new RoundChangePayload(new ConsensusRoundIdentifier(HEIGHT, round), Optional.empty());
|
|
+ final NodeKey key = validators.getNode(0).getNodeKey();
|
|
+ return v.validate(SignedData.create(payload, key.sign(Bytes32.wrap(payload.hashForSignature().getBytes()))));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aRoundAboveTheCapIsRefused() {
|
|
+ assertThat(judge(RoundChangePayloadValidator.MAX_ALLOWED_ROUND + 1)).withFailMessage("round 1001 accepted").isFalse();
|
|
+ assertThat(judge(Integer.MAX_VALUE)).withFailMessage("round 2^31-1 accepted").isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theCapItselfAndOrdinaryRoundsAreStillAccepted() {
|
|
+ // positive control: the fixture is valid, and the cap is inclusive
|
|
+ assertThat(judge(1)).isTrue();
|
|
+ assertThat(judge(RoundChangePayloadValidator.MAX_ALLOWED_ROUND)).isTrue();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityMessageTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityMessageTest.java
|
|
new file mode 100644
|
|
index 0000000000..e8df550557
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityMessageTest.java
|
|
@@ -0,0 +1,204 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.Payload;
|
|
+import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
|
|
+import org.hyperledger.besu.consensus.qbft.core.QbftBlockTestFixture;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.CommitPayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.PreparePayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.PreparedRoundMetadata;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.ProposalPayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.RoundChangePayload;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
+import org.mockito.Mock;
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4 on the REAL QBFT payloads, with real Falcon-512 keys generated for the run: from H_fin
|
|
+ * the author of a PREPARE, a PROPOSAL and a ROUND-CHANGE is the id of its seal's index only when the
|
|
+ * seal verifies over the message its own layer builds, and a COMMIT's only when that index names the
|
|
+ * commit seal signer's id. Every envelope is signed by a FOREIGN node key, so a validator's id can only
|
|
+ * come from the seal. Each positive has its negative on the same fixture: another index's seal, a seal
|
|
+ * over another round, a ROUND-CHANGE with prepared metadata sealed in the unprepared form, a proposal
|
|
+ * sealed over another block, a commit seal of another validator. The runner's negative control plants
|
|
+ * "every seal verifies" at run time and these probes turn red.
|
|
+ */
|
|
+@ExtendWith(MockitoExtension.class)
|
|
+public class AereFinalityMessageTest {
|
|
+
|
|
+ private static final long CHAIN = 28001;
|
|
+ private static final long BIND = 10; // H_k must be the bindHeight of a v3 epoch at or above H_id
|
|
+ private static final long H_ID = 10;
|
|
+ private static final long H_FIN = 20;
|
|
+ private static final int N = 4;
|
|
+ private static final SealScheme FALCON = SealSchemes.FALCON_512;
|
|
+
|
|
+ private final Hash digest = Hash.hash(Bytes.of(7));
|
|
+ private final NodeKey foreign = NodeKeyUtils.generate();
|
|
+ private final List<NodeKey> ecdsa = new ArrayList<>();
|
|
+ private final List<SealScheme.PrivateHandle> falcon = new ArrayList<>();
|
|
+ private final List<Address> ids = new ArrayList<>();
|
|
+ private @Mock QbftBlockCodec blockCodec;
|
|
+
|
|
+ @BeforeEach
|
|
+ public void registry() {
|
|
+ final List<PqRegistryV3.Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final NodeKey nk = NodeKeyUtils.generate();
|
|
+ ecdsa.add(nk);
|
|
+ final SealScheme.GeneratedPair p = FALCON.generate(SecureRandomProvider.createSecureRandom());
|
|
+ falcon.add(p.privateKey());
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(p.publicRegistryForm(), 0, std, 1, 896);
|
|
+ final byte[] id = PqRegistryV3.idOf(std);
|
|
+ final Bytes32 popMsg = PqRegistryV3.popMessage(CHAIN, BIND, N, i, id, FALCON.wireId(), std);
|
|
+ final byte[] pop = FALCON.sign(p.privateKey(), popMsg.toArrayUnsafe()).orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(FALCON.wireId() & 0xff, new PqRegistryV3.Key(FALCON, std, pop));
|
|
+ final PqRegistryV3.Row bare = new PqRegistryV3.Row(i, id, keys, null, Map.of(), null, null);
|
|
+ final Bytes32 rh = PqRegistryV3.rowHash(CHAIN, BIND, N, bare);
|
|
+ final SECPSignature claim = nk.sign(PqRegistryV3.claimDigest(CHAIN, rh));
|
|
+ final Address addr = org.hyperledger.besu.ethereum.core.Util.publicKeyToAddress(nk.getPublicKey());
|
|
+ rows.add(
|
|
+ new PqRegistryV3.Row(
|
|
+ i, id, keys, null, Map.of(), addr.getBytes().toArrayUnsafe(),
|
|
+ claim.encodedBytes().toArrayUnsafe()));
|
|
+ ids.add(Address.wrap(Bytes.wrap(id)));
|
|
+ }
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : rows) {
|
|
+ hashes.add(PqRegistryV3.rowHash(CHAIN, BIND, N, r));
|
|
+ }
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(hashes);
|
|
+ final PqRegistryV3.Registry reg =
|
|
+ new PqRegistryV3.Registry(
|
|
+ CHAIN, BIND, N, rows, hashes, root, PqRegistryV3.registryHash(CHAIN, BIND, N, root));
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(BIND, reg);
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs, H_ID));
|
|
+ // the production verifier reads the same v3 key from H_k (FalconSealSupport.verifyAtOwnHead)
|
|
+ AerePqFinality.install(
|
|
+ H_FIN,
|
|
+ CHAIN,
|
|
+ (h, i, m, s) ->
|
|
+ AerePqIdentity.v3KeyAt(h, i, "falcon-512")
|
|
+ .map(k -> FALCON.verifyRaw(k, m.toArrayUnsafe(), s.toArrayUnsafe()))
|
|
+ .orElse(false));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private Optional<FalconSeal> seal(final int index, final int signer, final Bytes32 message) {
|
|
+ return Optional.of(
|
|
+ new FalconSeal(index, Bytes.wrap(FALCON.sign(falcon.get(signer), message.toArrayUnsafe()).orElseThrow())));
|
|
+ }
|
|
+
|
|
+ private <P extends Payload> Address authorOf(final P payload) {
|
|
+ return SignedData.create(payload, foreign.sign(Bytes32.wrap(payload.hashForSignature().getBytes())))
|
|
+ .getAuthor();
|
|
+ }
|
|
+
|
|
+ private static ConsensusRoundIdentifier round(final int r) {
|
|
+ return new ConsensusRoundIdentifier(H_FIN, r);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aPrepareIsAuthoredOnlyByAVerifiedSealOfItsIndex() {
|
|
+ final Bytes32 m = PqAnchor.prepareMessage(CHAIN, H_FIN, 0, digest.getBytes());
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ assertThat(authorOf(new PreparePayload(round(0), digest, seal(i, i, m)))).as("node %s", i).isEqualTo(ids.get(i));
|
|
+ }
|
|
+ // index 0 with node 1's seal; node 0's seal over round 1; no seal
|
|
+ assertThat(authorOf(new PreparePayload(round(0), digest, seal(0, 1, m)))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(
|
|
+ authorOf(
|
|
+ new PreparePayload(
|
|
+ round(0), digest, seal(0, 0, PqAnchor.prepareMessage(CHAIN, H_FIN, 1, digest.getBytes())))))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ assertThat(authorOf(new PreparePayload(round(0), digest, Optional.empty()))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aRoundChangeIsAuthoredOnlyByASealInTheFormItsMetadataNames() {
|
|
+ final Bytes32 bare = PqAnchor.roundChangeMessage(CHAIN, H_FIN, 2);
|
|
+ assertThat(authorOf(new RoundChangePayload(round(2), Optional.empty(), seal(1, 1, bare)))).isEqualTo(ids.get(1));
|
|
+ final Optional<PreparedRoundMetadata> meta = Optional.of(new PreparedRoundMetadata(digest, 1));
|
|
+ final Bytes32 prepared = PqAnchor.roundChangeMessage(CHAIN, H_FIN, 2, 1, digest.getBytes());
|
|
+ assertThat(authorOf(new RoundChangePayload(round(2), meta, seal(1, 1, prepared)))).isEqualTo(ids.get(1));
|
|
+ // the prepared claim sealed in the unprepared form does not author: the seal must cover the claim
|
|
+ assertThat(authorOf(new RoundChangePayload(round(2), meta, seal(1, 1, bare)))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aProposalIsAuthoredOnlyByASealOverItsOwnBlock() {
|
|
+ final QbftBlock block =
|
|
+ new QbftBlockTestFixture()
|
|
+ .blockHeader(new QbftBlockHeaderTestFixture().number(H_FIN).buildHeader())
|
|
+ .build();
|
|
+ final Bytes32 m = PqAnchor.proposalMessage(CHAIN, H_FIN, 0, block.getHash().getBytes());
|
|
+ assertThat(authorOf(new ProposalPayload(round(0), block, blockCodec, Optional.empty(), seal(2, 2, m))))
|
|
+ .isEqualTo(ids.get(2));
|
|
+ final Bytes32 other = PqAnchor.proposalMessage(CHAIN, H_FIN, 0, digest.getBytes());
|
|
+ assertThat(authorOf(new ProposalPayload(round(0), block, blockCodec, Optional.empty(), seal(2, 2, other))))
|
|
+ .isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aCommitIsAuthoredByItsIndexOnlyWhenThatIsTheCommitSealSigner() {
|
|
+ final Optional<FalconSeal> any = Optional.of(new FalconSeal(3, Bytes.of(1)));
|
|
+ final SECPSignature own = ecdsa.get(3).sign(Bytes32.wrap(digest.getBytes()));
|
|
+ final SECPSignature other = ecdsa.get(0).sign(Bytes32.wrap(digest.getBytes()));
|
|
+ assertThat(authorOf(new CommitPayload(round(0), digest, own, any))).isEqualTo(ids.get(3));
|
|
+ assertThat(authorOf(new CommitPayload(round(0), digest, other, any))).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityVectorsWriter.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityVectorsWriter.java
|
|
new file mode 100644
|
|
index 0000000000..b1a6776bb0
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereFinalityVectorsWriter.java
|
|
@@ -0,0 +1,206 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit;
|
|
+import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare;
|
|
+import org.hyperledger.besu.consensus.qbft.core.messagewrappers.RoundChange;
|
|
+import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
|
+import org.mockito.Mockito;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4: the WRITER of the shared authorship vectors. Real QBFT messages, encoded on the wire
|
|
+ * exactly as this client sends them, each ENVELOPE signed by a FOREIGN node key, each carrying a real
|
|
+ * Falcon-512 seal (keys generated for the run, nothing here touches a real key): the second client must
|
|
+ * decode every one to the SAME author this client gives it. Every expected author is asserted here, at
|
|
+ * writing time, through this client's own decoding path (SignedData), so a vector cannot say what this
|
|
+ * client does not do. Runs only with AERE_T4_VECTORS_OUT set to the output directory.
|
|
+ */
|
|
+@EnabledIfEnvironmentVariable(named = "AERE_T4_VECTORS_OUT", matches = ".+")
|
|
+public class AereFinalityVectorsWriter {
|
|
+
|
|
+ private static final long CHAIN = 28001;
|
|
+ private static final long BIND = 10;
|
|
+ private static final long H_ID = 10;
|
|
+ private static final long H_FIN = 20;
|
|
+ private static final int N = 4;
|
|
+ private static final SealScheme FALCON = SealSchemes.FALCON_512;
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private static String hex(final Bytes b) {
|
|
+ return b.toUnprefixedHexString();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void writeTheSharedAuthorshipVectors() throws IOException {
|
|
+ final List<NodeKey> ecdsa = new ArrayList<>();
|
|
+ final List<SealScheme.PrivateHandle> falcon = new ArrayList<>();
|
|
+ final List<byte[]> std = new ArrayList<>();
|
|
+ final List<Address> ids = new ArrayList<>();
|
|
+ final List<PqRegistryV3.Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final NodeKey nk = NodeKeyUtils.generate();
|
|
+ ecdsa.add(nk);
|
|
+ final SealScheme.GeneratedPair p = FALCON.generate(SecureRandomProvider.createSecureRandom());
|
|
+ falcon.add(p.privateKey());
|
|
+ final byte[] s = new byte[897];
|
|
+ s[0] = 0x09;
|
|
+ System.arraycopy(p.publicRegistryForm(), 0, s, 1, 896);
|
|
+ std.add(s);
|
|
+ final byte[] id = PqRegistryV3.idOf(s);
|
|
+ final Bytes32 popMsg = PqRegistryV3.popMessage(CHAIN, BIND, N, i, id, FALCON.wireId(), s);
|
|
+ final byte[] pop = FALCON.sign(p.privateKey(), popMsg.toArrayUnsafe()).orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(FALCON.wireId() & 0xff, new PqRegistryV3.Key(FALCON, s, pop));
|
|
+ final PqRegistryV3.Row bare = new PqRegistryV3.Row(i, id, keys, null, Map.of(), null, null);
|
|
+ final SECPSignature claim = nk.sign(PqRegistryV3.claimDigest(CHAIN, PqRegistryV3.rowHash(CHAIN, BIND, N, bare)));
|
|
+ rows.add(
|
|
+ new PqRegistryV3.Row(
|
|
+ i, id, keys, null, Map.of(),
|
|
+ Util.publicKeyToAddress(nk.getPublicKey()).getBytes().toArrayUnsafe(),
|
|
+ claim.encodedBytes().toArrayUnsafe()));
|
|
+ ids.add(Address.wrap(Bytes.wrap(id)));
|
|
+ }
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : rows) {
|
|
+ hashes.add(PqRegistryV3.rowHash(CHAIN, BIND, N, r));
|
|
+ }
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(hashes);
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(
|
|
+ BIND,
|
|
+ new PqRegistryV3.Registry(
|
|
+ CHAIN, BIND, N, rows, hashes, root, PqRegistryV3.registryHash(CHAIN, BIND, N, root)));
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs, H_ID));
|
|
+ AerePqFinality.install(
|
|
+ H_FIN,
|
|
+ CHAIN,
|
|
+ (h, i, m, s) ->
|
|
+ AerePqIdentity.v3KeyAt(h, i, "falcon-512")
|
|
+ .map(k -> FALCON.verifyRaw(k, m.toArrayUnsafe(), s.toArrayUnsafe()))
|
|
+ .orElse(false));
|
|
+
|
|
+ final NodeKey foreign = NodeKeyUtils.generate();
|
|
+ final Address foreignAddr = Util.publicKeyToAddress(foreign.getPublicKey());
|
|
+ final MessageFactory mf = new MessageFactory(foreign, Mockito.mock(QbftBlockCodec.class));
|
|
+ final Hash digest = Hash.hash(Bytes.of(7));
|
|
+ final List<String[]> out = new ArrayList<>(); // name, type, height, wire, expected author
|
|
+
|
|
+ // 1. a PREPARE sealed by its own index: the index's id
|
|
+ final Bytes32 pm = PqAnchor.prepareMessage(CHAIN, H_FIN, 0, digest.getBytes());
|
|
+ final Prepare p1 = mf.createPrepare(new ConsensusRoundIdentifier(H_FIN, 0), digest, seal(falcon, 1, 1, pm));
|
|
+ assertThat(p1.getAuthor()).isEqualTo(ids.get(1));
|
|
+ out.add(new String[] {"prepare-own-seal", "prepare", Long.toString(H_FIN), hex(p1.encode()), hex(ids.get(1).getBytes())});
|
|
+ // 2. a PREPARE naming index 0 with index 1's seal: no author
|
|
+ final Prepare p2 = mf.createPrepare(new ConsensusRoundIdentifier(H_FIN, 0), digest, seal(falcon, 0, 1, pm));
|
|
+ assertThat(p2.getAuthor()).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ out.add(new String[] {"prepare-another-index-seal", "prepare", Long.toString(H_FIN), hex(p2.encode()), hex(AerePqFinality.NO_AUTHOR.getBytes())});
|
|
+ // 3. a PREPARE one block below H_fin: the envelope's (foreign) signer
|
|
+ final Bytes32 pmb = PqAnchor.prepareMessage(CHAIN, H_FIN - 1, 0, digest.getBytes());
|
|
+ final Prepare p3 = mf.createPrepare(new ConsensusRoundIdentifier(H_FIN - 1, 0), digest, seal(falcon, 1, 1, pmb));
|
|
+ assertThat(p3.getAuthor()).isEqualTo(foreignAddr);
|
|
+ out.add(new String[] {"prepare-below-hfin", "prepare", Long.toString(H_FIN - 1), hex(p3.encode()), hex(foreignAddr.getBytes())});
|
|
+ // 4. a ROUND-CHANGE without a prepared claim, sealed by its own index
|
|
+ final Bytes32 rm = PqAnchor.roundChangeMessage(CHAIN, H_FIN, 2);
|
|
+ final RoundChange r1 = mf.createRoundChange(new ConsensusRoundIdentifier(H_FIN, 2), Optional.empty(), seal(falcon, 2, 2, rm));
|
|
+ assertThat(r1.getAuthor()).isEqualTo(ids.get(2));
|
|
+ out.add(new String[] {"roundchange-own-seal", "roundchange", Long.toString(H_FIN), hex(r1.encode()), hex(ids.get(2).getBytes())});
|
|
+ // 5. a ROUND-CHANGE sealed over another target round: no author
|
|
+ final RoundChange r2 =
|
|
+ mf.createRoundChange(
|
|
+ new ConsensusRoundIdentifier(H_FIN, 2), Optional.empty(),
|
|
+ seal(falcon, 2, 2, PqAnchor.roundChangeMessage(CHAIN, H_FIN, 3)));
|
|
+ assertThat(r2.getAuthor()).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ out.add(new String[] {"roundchange-other-round", "roundchange", Long.toString(H_FIN), hex(r2.encode()), hex(AerePqFinality.NO_AUTHOR.getBytes())});
|
|
+ // 6. a COMMIT naming index 3 with validator 3's commit seal: index 3's id
|
|
+ final SECPSignature own = ecdsa.get(3).sign(Bytes32.wrap(digest.getBytes()));
|
|
+ final Commit c1 = mf.createCommit(new ConsensusRoundIdentifier(H_FIN, 0), digest, own, Optional.of(new FalconSeal(3, Bytes.of(1))));
|
|
+ assertThat(c1.getAuthor()).isEqualTo(ids.get(3));
|
|
+ out.add(new String[] {"commit-own-commit-seal", "commit", Long.toString(H_FIN), hex(c1.encode()), hex(ids.get(3).getBytes())});
|
|
+ // 7. a COMMIT naming index 3 with validator 0's commit seal: no author
|
|
+ final SECPSignature other = ecdsa.get(0).sign(Bytes32.wrap(digest.getBytes()));
|
|
+ final Commit c2 = mf.createCommit(new ConsensusRoundIdentifier(H_FIN, 0), digest, other, Optional.of(new FalconSeal(3, Bytes.of(1))));
|
|
+ assertThat(c2.getAuthor()).isEqualTo(AerePqFinality.NO_AUTHOR);
|
|
+ out.add(new String[] {"commit-another-commit-seal", "commit", Long.toString(H_FIN), hex(c2.encode()), hex(AerePqFinality.NO_AUTHOR.getBytes())});
|
|
+
|
|
+ final StringBuilder j = new StringBuilder();
|
|
+ j.append("{\n \"note\": \"AIP-22 stage 4 shared authorship vectors, written by AereFinalityVectorsWriter (Besu-derived client); PROBE keys\",\n");
|
|
+ j.append(" \"chainId\": ").append(CHAIN).append(",\n \"bindHeight\": ").append(BIND)
|
|
+ .append(",\n \"identityBlock\": ").append(H_ID).append(",\n \"keysFrom\": ").append(H_ID)
|
|
+ .append(",\n \"finalityBlock\": ").append(H_FIN).append(",\n \"rows\": [\n");
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ j.append(" {\"index\": ").append(i).append(", \"id\": \"").append(hex(ids.get(i).getBytes()))
|
|
+ .append("\", \"falcon\": \"").append(hex(Bytes.wrap(std.get(i))))
|
|
+ .append("\", \"ecdsa\": \"").append(hex(Util.publicKeyToAddress(ecdsa.get(i).getPublicKey()).getBytes()))
|
|
+ .append("\"}").append(i + 1 < N ? ",\n" : "\n");
|
|
+ }
|
|
+ j.append(" ],\n \"messages\": [\n");
|
|
+ for (int k = 0; k < out.size(); k++) {
|
|
+ final String[] m = out.get(k);
|
|
+ j.append(" {\"name\": \"").append(m[0]).append("\", \"type\": \"").append(m[1]).append("\", \"height\": ").append(m[2])
|
|
+ .append(", \"wire\": \"").append(m[3]).append("\", \"author\": \"").append(m[4]).append("\"}")
|
|
+ .append(k + 1 < out.size() ? ",\n" : "\n");
|
|
+ }
|
|
+ j.append(" ]\n}\n");
|
|
+ final Path dir = Path.of(System.getenv("AERE_T4_VECTORS_OUT"));
|
|
+ Files.createDirectories(dir);
|
|
+ Files.writeString(dir.resolve("author-t4.json"), j.toString(), StandardCharsets.UTF_8);
|
|
+ }
|
|
+
|
|
+ private static Optional<FalconSeal> seal(
|
|
+ final List<SealScheme.PrivateHandle> falcon, final int index, final int signer, final Bytes32 message) {
|
|
+ return Optional.of(
|
|
+ new FalconSeal(index, Bytes.wrap(FALCON.sign(falcon.get(signer), message.toArrayUnsafe()).orElseThrow())));
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereIdentityMessageTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereIdentityMessageTest.java
|
|
new file mode 100644
|
|
index 0000000000..9124dc9338
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/AereIdentityMessageTest.java
|
|
@@ -0,0 +1,165 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the identity switch, measured on real QBFT messages.
|
|
+ *
|
|
+ * Four upstream test nodes (QbftNodeList: a secp256k1 node key and a message factory each) get a
|
|
+ * registry v3 row each (a Falcon-512 key with its possession proof, and the ecdsa link signed by the
|
|
+ * node's own key). The validator set given to the upstream validators is the list of their IDS.
|
|
+ *
|
|
+ * What must hold, each with its negative:
|
|
+ * - armed, a Commit (and a Prepare) signed with the node's ECDSA key is accepted against the id set:
|
|
+ * the author is translated to the id, and the commit seal's creator is translated the same way;
|
|
+ * - DISARMED, the very same message is REFUSED against the id set (its author is an address): the
|
|
+ * translation, and nothing else, is what makes it pass;
|
|
+ * - armed but BELOW H_id, it is refused against ids and accepted against addresses;
|
|
+ * - a node with no row stays an address and is refused.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Commit;
|
|
+import org.hyperledger.besu.consensus.qbft.core.messagewrappers.Prepare;
|
|
+import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
+import org.mockito.Mock;
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
+
|
|
+@ExtendWith(MockitoExtension.class)
|
|
+public class AereIdentityMessageTest {
|
|
+
|
|
+ private static final long CHAIN = 28001;
|
|
+ private static final long H_ID = 10;
|
|
+ private static final int N = 4;
|
|
+
|
|
+ private final Hash expectedHash = Hash.fromHexStringLenient("0x1");
|
|
+ private @Mock QbftBlockCodec qbftBlockCodec;
|
|
+ private QbftNodeList nodes;
|
|
+ private final List<Address> ids = new ArrayList<>();
|
|
+
|
|
+ @BeforeEach
|
|
+ public void registryForTheNodes() {
|
|
+ nodes = QbftNodeList.createNodes(N, qbftBlockCodec);
|
|
+ final long bind = 5;
|
|
+ final List<PqRegistryV3.Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final SealScheme f = SealSchemes.FALCON_512;
|
|
+ final SealScheme.GeneratedPair p = f.generate(SecureRandomProvider.createSecureRandom());
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(p.publicRegistryForm(), 0, std, 1, 896);
|
|
+ final byte[] id = PqRegistryV3.idOf(std);
|
|
+ final Bytes32 popMsg = PqRegistryV3.popMessage(CHAIN, bind, N, i, id, f.wireId(), std);
|
|
+ final byte[] pop = f.sign(p.privateKey(), popMsg.toArrayUnsafe()).orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(f.wireId() & 0xff, new PqRegistryV3.Key(f, std, pop));
|
|
+ final PqRegistryV3.Row bare = new PqRegistryV3.Row(i, id, keys, null, Map.of(), null, null);
|
|
+ final Bytes32 rh = PqRegistryV3.rowHash(CHAIN, bind, N, bare);
|
|
+ final SECPSignature claim =
|
|
+ nodes.getNode(i).getNodeKey().sign(PqRegistryV3.claimDigest(CHAIN, rh));
|
|
+ rows.add(
|
|
+ new PqRegistryV3.Row(
|
|
+ i, id, keys, null, Map.of(),
|
|
+ nodes.getNode(i).getAddress().getBytes().toArrayUnsafe(),
|
|
+ claim.encodedBytes().toArrayUnsafe()));
|
|
+ ids.add(Address.wrap(Bytes.wrap(id)));
|
|
+ }
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : rows) {
|
|
+ hashes.add(PqRegistryV3.rowHash(CHAIN, bind, N, r));
|
|
+ }
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(hashes);
|
|
+ final PqRegistryV3.Registry reg =
|
|
+ new PqRegistryV3.Registry(
|
|
+ CHAIN, bind, N, rows, hashes, root, PqRegistryV3.registryHash(CHAIN, bind, N, root));
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(bind, reg);
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private Commit commit(final int node, final ConsensusRoundIdentifier round) {
|
|
+ final SECPSignature seal =
|
|
+ nodes.getNode(node).getNodeKey().sign(Bytes32.wrap(expectedHash.getBytes()));
|
|
+ return nodes.getMessageFactory(node).createCommit(round, expectedHash, seal);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void armedACommitSignedByTheNodeKeyIsAcceptedAgainstTheIdSet() {
|
|
+ final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(H_ID, 0);
|
|
+ final CommitValidator v = new CommitValidator(ids, round, expectedHash, expectedHash);
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final Commit c = commit(i, round);
|
|
+ assertThat(c.getAuthor()).isEqualTo(ids.get(i));
|
|
+ assertThat(v.validate(c)).as("node " + i).isTrue();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void disarmedTheSameCommitIsRefusedAgainstTheIdSet() {
|
|
+ final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(H_ID, 0);
|
|
+ AerePqIdentity.uninstall();
|
|
+ final CommitValidator v = new CommitValidator(ids, round, expectedHash, expectedHash);
|
|
+ final Commit c = commit(0, round);
|
|
+ assertThat(c.getAuthor()).isEqualTo(nodes.getNode(0).getAddress());
|
|
+ assertThat(v.validate(c)).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void belowHidTheAuthorIsTheAddress() {
|
|
+ final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(H_ID - 1, 0);
|
|
+ final Commit c = commit(1, round);
|
|
+ assertThat(c.getAuthor()).isEqualTo(nodes.getNode(1).getAddress());
|
|
+ assertThat(new CommitValidator(ids, round, expectedHash, expectedHash).validate(c)).isFalse();
|
|
+ assertThat(
|
|
+ new CommitValidator(nodes.getNodeAddresses(), round, expectedHash, expectedHash)
|
|
+ .validate(c))
|
|
+ .isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aNodeWithoutARowStaysAnAddressAndIsRefused() {
|
|
+ final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(H_ID + 3, 0);
|
|
+ final QbftNode stranger = QbftNode.create(qbftBlockCodec);
|
|
+ final SECPSignature seal = stranger.getNodeKey().sign(Bytes32.wrap(expectedHash.getBytes()));
|
|
+ final Commit c = stranger.getMessageFactory().createCommit(round, expectedHash, seal);
|
|
+ assertThat(c.getAuthor()).isEqualTo(stranger.getAddress());
|
|
+ assertThat(new CommitValidator(ids, round, expectedHash, expectedHash).validate(c)).isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void armedAPrepareIsAuthoredByTheId() {
|
|
+ final ConsensusRoundIdentifier round = new ConsensusRoundIdentifier(H_ID + 1, 0);
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final Prepare p = nodes.getMessageFactory(i).createPrepare(round, expectedHash);
|
|
+ assertThat(p.getAuthor()).isEqualTo(ids.get(i));
|
|
+ assertThat(new PrepareValidator(ids, round, expectedHash).validate(p)).isTrue();
|
|
+ }
|
|
+ AerePqIdentity.uninstall();
|
|
+ final Prepare p = nodes.getMessageFactory(2).createPrepare(round, expectedHash);
|
|
+ assertThat(new PrepareValidator(ids, round, expectedHash).validate(p)).isFalse();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuardTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuardTest.java
|
|
new file mode 100644
|
|
index 0000000000..fffe7b61ba
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqFinalityLayersGuardTest.java
|
|
@@ -0,0 +1,130 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4: H_fin is refused over a seal layer that is not verified from H_fin (AERE-PQC-FIN-02),
|
|
+ * named layer by layer; H_fin unset is inert. The last probe goes through the production path (the
|
|
+ * four properties the layers really read). The runner's negative control plants "never refuse" at run
|
|
+ * time and these probes turn red.
|
|
+ */
|
|
+public class PqFinalityLayersGuardTest {
|
|
+
|
|
+ private static final long H_FIN = 5_000L;
|
|
+ private static final String[] PROPS = {
|
|
+ PqProposalEnforcement.PROPERTY_FORK_BLOCK,
|
|
+ PqPrepareEnforcement.PROPERTY_FORK_BLOCK,
|
|
+ PqCommitEnforcement.PROPERTY_FORK_BLOCK,
|
|
+ PqRoundChangeEnforcement.PROPERTY_FORK_BLOCK
|
|
+ };
|
|
+
|
|
+ @AfterEach
|
|
+ public void clear() {
|
|
+ for (final String p : PROPS) {
|
|
+ System.clearProperty(p);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static PqFinalityLayersGuard.Layer armedFrom(final String property, final long from) {
|
|
+ return new PqFinalityLayersGuard.Layer(property, h -> h >= from);
|
|
+ }
|
|
+
|
|
+ private static List<PqFinalityLayersGuard.Layer> allArmedFrom(final long from) {
|
|
+ return List.of(
|
|
+ armedFrom(PROPS[0], from), armedFrom(PROPS[1], from), armedFrom(PROPS[2], from),
|
|
+ armedFrom(PROPS[3], from));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void everyLayerArmedAtOrBelowHfinPassesAndHfinUnsetIsInert() {
|
|
+ assertThat(PqFinalityLayersGuard.refusal(H_FIN, allArmedFrom(H_FIN))).isEmpty();
|
|
+ assertThat(PqFinalityLayersGuard.refusal(H_FIN, allArmedFrom(100))).isEmpty();
|
|
+ final List<PqFinalityLayersGuard.Layer> none =
|
|
+ List.of(
|
|
+ new PqFinalityLayersGuard.Layer(PROPS[0], null),
|
|
+ new PqFinalityLayersGuard.Layer(PROPS[1], null),
|
|
+ new PqFinalityLayersGuard.Layer(PROPS[2], null),
|
|
+ new PqFinalityLayersGuard.Layer(PROPS[3], null));
|
|
+ assertThat(PqFinalityLayersGuard.refusal(AerePqIdentity.NEVER, none)).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aLayerUnsetOrArmedAboveHfinIsRefusedByName() {
|
|
+ for (int i = 0; i < PROPS.length; i++) {
|
|
+ final List<PqFinalityLayersGuard.Layer> unset = new java.util.ArrayList<>(allArmedFrom(100));
|
|
+ unset.set(i, new PqFinalityLayersGuard.Layer(PROPS[i], null));
|
|
+ final Optional<String> r = PqFinalityLayersGuard.refusal(H_FIN, unset);
|
|
+ assertThat(r).as("layer %s unset", PROPS[i]).isPresent();
|
|
+ assertThat(r.get()).startsWith("AERE-PQC-FIN-02").contains(PROPS[i] + " unset");
|
|
+
|
|
+ final List<PqFinalityLayersGuard.Layer> late = new java.util.ArrayList<>(allArmedFrom(100));
|
|
+ late.set(i, armedFrom(PROPS[i], H_FIN + 1));
|
|
+ final Optional<String> r2 = PqFinalityLayersGuard.refusal(H_FIN, late);
|
|
+ assertThat(r2).as("layer %s armed one block above H_fin", PROPS[i]).isPresent();
|
|
+ assertThat(r2.get()).contains(PROPS[i] + " armed above " + H_FIN);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void productionPathReadsTheFourPropertiesTheLayersRead() {
|
|
+ for (final String p : PROPS) {
|
|
+ System.setProperty(p, Long.toString(H_FIN - 10));
|
|
+ }
|
|
+ PqFinalityLayersGuard.verifyOrAbort(H_FIN);
|
|
+ System.clearProperty(PqRoundChangeEnforcement.PROPERTY_FORK_BLOCK);
|
|
+ assertThatThrownBy(() -> PqFinalityLayersGuard.verifyOrAbort(H_FIN))
|
|
+ .isInstanceOf(IllegalStateException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-FIN-02")
|
|
+ .hasMessageContaining(PqRoundChangeEnforcement.PROPERTY_FORK_BLOCK + " unset");
|
|
+ // H_fin unset: inert whatever the layers
|
|
+ PqFinalityLayersGuard.verifyOrAbort(AerePqIdentity.NEVER);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aSealingNodeMustSealAllFourMessagesAtOrBelowHfin() {
|
|
+ final long never = Long.MAX_VALUE;
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(AerePqIdentity.NEVER, true, never, never, never, never))
|
|
+ .as("unset H_fin asks nothing")
|
|
+ .isEmpty();
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, false, never, never, never, never))
|
|
+ .as("a reader seals nothing and needs nothing")
|
|
+ .isEmpty();
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, 32, 200, 200, 200)).isEmpty();
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, H_FIN, H_FIN, H_FIN, H_FIN)).isEmpty();
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, 32, never, 200, 200))
|
|
+ .hasValueSatisfying(
|
|
+ r -> assertThat(r).startsWith("AERE-PQC-FIN-03").contains("aere.pq.proposalPq.attachBlock unset"));
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, 32, 200, H_FIN + 1, 200))
|
|
+ .hasValueSatisfying(r -> assertThat(r).contains("aere.pq.preparePq.attachBlock armed above H_fin"));
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, 32, 200, 200, never))
|
|
+ .hasValueSatisfying(r -> assertThat(r).contains("aere.pq.roundChangePq.attachBlock unset"));
|
|
+ assertThat(PqFinalityLayersGuard.emissionRefusal(H_FIN, true, H_FIN + 5, 200, 200, 200))
|
|
+ .hasValueSatisfying(r -> assertThat(r).contains("aere.falcon.attachBlock armed above H_fin"));
|
|
+ assertThatThrownBy(() -> PqFinalityLayersGuard.verifyEmissionOrAbort(H_FIN, true, 32, never, 200, 200))
|
|
+ .isInstanceOf(IllegalStateException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-FIN-03");
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridEnforcementTest.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridEnforcementTest.java
|
|
index cf8c683f01..95b4b667b5 100755
|
|
--- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridEnforcementTest.java
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridEnforcementTest.java
|
|
@@ -173,40 +173,79 @@ public class PqHybridEnforcementTest {
|
|
final Optional<String> refusal =
|
|
hibrid()
|
|
.refusal(H_HIBRID, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of());
|
|
assertThat(refusal).isPresent();
|
|
assertThat(refusal.get()).contains("carries no").contains(SealSchemes.SLH_DSA_128S.id());
|
|
}
|
|
|
|
@Test
|
|
public void aFullHybridCertificateCounts() {
|
|
assertThat(
|
|
hibrid()
|
|
.refusal(
|
|
H_HIBRID,
|
|
VALIDATOR_0,
|
|
DIGEST,
|
|
Optional.of(sigiliuFalcon(0)),
|
|
List.of(sigiliuSlh(0, DIGEST))))
|
|
.isEmpty();
|
|
}
|
|
|
|
+ // ============================================ intervale per schema (AIP-22 treapta 2)
|
|
+
|
|
+ /**
|
|
+ * With SLH-DSA on the 128 grid (Falcon on the 32 grid), counted from an activation height of 64,
|
|
+ * a commit at the parent of a Falcon-only anchor counts with the Falcon seal alone, and a commit
|
|
+ * at the parent of a hybrid anchor does not. The two heights differ in nothing but the grid; the
|
|
+ * grid origin is the negative control (read against another origin, the two heights swap).
|
|
+ */
|
|
+ @Test
|
|
+ public void withPerSchemeIntervalsTheSlhSealIsDemandedOnlyAtParentsOfAnchorsOnItsGrid() {
|
|
+ final PqSchemeSchedule cuIntervale =
|
|
+ PqSchemeSchedule.parse(
|
|
+ H_ARMARE + ":" + SealSchemes.FALCON_512.id() + "/32+" + SealSchemes.SLH_DSA_128S.id() + "/128");
|
|
+ final long origine = 64L;
|
|
+ long ancoraHibrida = origine;
|
|
+ while (ancoraHibrida <= H_HIBRID) {
|
|
+ ancoraHibrida += 128L;
|
|
+ }
|
|
+ final long ancoraDoarFalcon = ancoraHibrida + 32L;
|
|
+ final PqCommitEnforcement e =
|
|
+ new PqCommitEnforcement(H_ARMARE, registruFalcon(), cuIntervale, registry, h -> true, () -> origine);
|
|
+ assertThat(e.refusal(ancoraDoarFalcon - 1, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of()))
|
|
+ .isEmpty();
|
|
+ final Optional<String> refusal =
|
|
+ e.refusal(ancoraHibrida - 1, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of());
|
|
+ assertThat(refusal).isPresent();
|
|
+ assertThat(refusal.get()).contains("carries no").contains(SealSchemes.SLH_DSA_128S.id());
|
|
+ assertThat(
|
|
+ e.refusal(
|
|
+ ancoraHibrida - 1, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of(sigiliuSlh(0, DIGEST))))
|
|
+ .isEmpty();
|
|
+ final PqCommitEnforcement altaOrigine =
|
|
+ new PqCommitEnforcement(H_ARMARE, registruFalcon(), cuIntervale, registry, h -> true, () -> origine + 32L);
|
|
+ assertThat(altaOrigine.refusal(ancoraHibrida - 1, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of()))
|
|
+ .isEmpty();
|
|
+ assertThat(altaOrigine.refusal(ancoraDoarFalcon - 1, VALIDATOR_0, DIGEST, Optional.of(sigiliuFalcon(0)), List.of()))
|
|
+ .isPresent();
|
|
+ }
|
|
+
|
|
// ============================================================ controalele negative
|
|
|
|
@Test
|
|
public void aHybridSealOverAnotherDigestDoesNotCount() {
|
|
final Hash altul = Hash.hash(Bytes.of(9, 9));
|
|
final Optional<String> refusal =
|
|
hibrid()
|
|
.refusal(
|
|
H_HIBRID,
|
|
VALIDATOR_0,
|
|
DIGEST,
|
|
Optional.of(sigiliuFalcon(0)),
|
|
List.of(sigiliuSlh(0, altul)));
|
|
assertThat(refusal).isPresent();
|
|
assertThat(refusal.get()).contains("does NOT verify");
|
|
}
|
|
|
|
@Test
|
|
public void aHybridSealForAnotherIndexIsRefused() {
|
|
final Optional<String> refusal =
|
|
diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridRotationV3Test.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridRotationV3Test.java
|
|
new file mode 100644
|
|
index 0000000000..3a3e69691a
|
|
--- /dev/null
|
|
+++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/PqHybridRotationV3Test.java
|
|
@@ -0,0 +1,171 @@
|
|
+/* AIP-22 stage 3b: the hybrid (SLH-DSA) seal of a COMMIT is judged, from H_k, with the key of the v3 epoch in force, not with the
|
|
+ * static v2 hybrid registry.
|
|
+ *
|
|
+ * Paid 2026-09-23 on testnet 28001: after the rotation at 3,097,600 the rotated row (index 2) signed its commits with its NEW
|
|
+ * SLH-DSA key, as the v3 epoch says, and PqCommitEnforcement still read the OLD key from the v2 hybrid registry, so every one of its
|
|
+ * commits at an anchor's parent was refused for six hours, invisibly while four other validators sufficed, until the chain stopped at
|
|
+ * 3,135,679 when the Nethermind validator fell behind. The anchor producer and PqAnchorSealsRule were already on v3.
|
|
+ *
|
|
+ * Real cryptography (Falcon-512 and SLH-DSA-SHA2-128s generated on every run, TEST keys); a v3 epoch built from the canonical row
|
|
+ * bytes; the v2 registry built from properties exactly as in production. The negative control plants, at run time, "keys never from
|
|
+ * v3" in PqCommitEnforcement: the two cases from H_k must turn red. */
|
|
+package org.hyperledger.besu.consensus.qbft.core.validation;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.HybridSignerRegistry;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSchemeSchedule;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
+import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+
|
|
+import java.security.SecureRandom;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.Properties;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class PqHybridRotationV3Test {
|
|
+ private static final long CHAIN = 28001L;
|
|
+ private static final long H_ARMARE = 1_000L;
|
|
+ private static final long H_HIBRID = 2_000L;
|
|
+ private static final long H_K = 3_000L;
|
|
+ private static final Hash DIGEST = Hash.hash(Bytes.of(7, 7));
|
|
+ private static final SealScheme FALCON = SealSchemes.FALCON_512;
|
|
+ private static final SealScheme SLH = SealSchemes.SLH_DSA_128S;
|
|
+
|
|
+ private final SecureRandom random = SecureRandomProvider.createSecureRandom();
|
|
+ private SealScheme.GeneratedPair falcon0;
|
|
+ private SealScheme.GeneratedPair slhOld;
|
|
+ private SealScheme.GeneratedPair slhNew;
|
|
+ private Address addr0;
|
|
+ private Address id0;
|
|
+ private PqCommitEnforcement enforcement;
|
|
+
|
|
+ @BeforeEach
|
|
+ public void setup() {
|
|
+ falcon0 = FALCON.generate(random);
|
|
+ slhOld = SLH.generate(random);
|
|
+ slhNew = SLH.generate(random);
|
|
+ final NodeKey nk = NodeKeyUtils.generate();
|
|
+ addr0 = org.hyperledger.besu.ethereum.core.Util.publicKeyToAddress(nk.getPublicKey());
|
|
+
|
|
+ // the v2 hybrid registry: index 0 is addr0, with the OLD SLH-DSA key (what the static registry keeps after a v3 rotation)
|
|
+ final Properties p = new Properties();
|
|
+ p.setProperty("formatVersion", HybridSignerRegistry.FORMAT_VERSION);
|
|
+ p.setProperty("chainId", String.valueOf(CHAIN));
|
|
+ p.setProperty("count", "1");
|
|
+ p.setProperty("0.addr", addr0.toHexString());
|
|
+ p.setProperty("0.key." + FALCON.id(), Bytes.wrap(falcon0.publicRegistryForm()).toHexString());
|
|
+ p.setProperty("0.key." + SLH.id(), Bytes.wrap(slhOld.publicRegistryForm()).toHexString());
|
|
+ final HybridSignerRegistry v2 = HybridSignerRegistry.fromProperties(p, "proba");
|
|
+
|
|
+ // the v3 epoch at H_k: row 0 keeps its Falcon key and carries the NEW SLH-DSA key (a rotation of the hybrid key)
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(falcon0.publicRegistryForm(), 0, std, 1, 896);
|
|
+ final byte[] id = PqRegistryV3.idOf(std);
|
|
+ id0 = Address.wrap(Bytes.wrap(id));
|
|
+ final byte[] slhPub = slhNew.publicRegistryForm();
|
|
+ final byte[] popF = FALCON.sign(falcon0.privateKey(),
|
|
+ PqRegistryV3.popMessage(CHAIN, H_K, 1, 0, id, FALCON.wireId(), std).toArrayUnsafe()).orElseThrow();
|
|
+ final byte[] popS = SLH.sign(slhNew.privateKey(),
|
|
+ PqRegistryV3.popMessage(CHAIN, H_K, 1, 0, id, SLH.wireId(), slhPub).toArrayUnsafe()).orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(FALCON.wireId() & 0xff, new PqRegistryV3.Key(FALCON, std, popF));
|
|
+ keys.put(SLH.wireId() & 0xff, new PqRegistryV3.Key(SLH, slhPub, popS));
|
|
+ final PqRegistryV3.Row bare = new PqRegistryV3.Row(0, id, keys, null, Map.of(), null, null);
|
|
+ final SECPSignature claim = nk.sign(PqRegistryV3.claimDigest(CHAIN, PqRegistryV3.rowHash(CHAIN, H_K, 1, bare)));
|
|
+ final PqRegistryV3.Row row =
|
|
+ new PqRegistryV3.Row(0, id, keys, null, Map.of(), addr0.getBytes().toArrayUnsafe(), claim.encodedBytes().toArrayUnsafe());
|
|
+ final Bytes32 rh = PqRegistryV3.rowHash(CHAIN, H_K, 1, row);
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(List.of(rh));
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(H_K, new PqRegistryV3.Registry(CHAIN, H_K, 1, List.of(row), List.of(rh), root,
|
|
+ PqRegistryV3.registryHash(CHAIN, H_K, 1, root)));
|
|
+ AerePqIdentity.uninstall();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_K, epochs, H_K));
|
|
+
|
|
+ // the Falcon part of the commit check: index 0 is addr0 below H_k and its id from H_k, the Falcon key unchanged
|
|
+ final PqSignerRegistry falconReg =
|
|
+ new PqSignerRegistry() {
|
|
+ @Override
|
|
+ public Address addressForIndexAtHistoric(final long h, final int i) {
|
|
+ return addressForIndexAtOwnHead(h, i);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Address addressForIndexAtOwnHead(final long h, final int i) {
|
|
+ return i != 0 ? null : (h >= H_K ? id0 : addr0);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean verifyAtHistoric(final long h, final int i, final Bytes m, final Bytes s) {
|
|
+ return verifyAtOwnHead(h, i, m, s);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean verifyAtOwnHead(final long h, final int i, final Bytes m, final Bytes s) {
|
|
+ return i == 0 && FALCON.verifyRaw(falcon0.publicRegistryForm(), m.toArray(), s.toArray());
|
|
+ }
|
|
+ };
|
|
+ final PqSchemeSchedule orar =
|
|
+ PqSchemeSchedule.parse(H_ARMARE + ":" + FALCON.id() + "," + H_HIBRID + ":" + FALCON.id() + "+" + SLH.id());
|
|
+ enforcement = new PqCommitEnforcement(H_ARMARE, falconReg, orar, v2, h -> true);
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private Optional<FalconSeal> falconSeal() {
|
|
+ return Optional.of(new FalconSeal(0, Bytes.wrap(FALCON.sign(falcon0.privateKey(), DIGEST.getBytes().toArray()).orElseThrow())));
|
|
+ }
|
|
+
|
|
+ private List<SchemeSeal> slhSeal(final SealScheme.GeneratedPair key) {
|
|
+ return List.of(new SchemeSeal(SLH.wireId(), 0, Bytes.wrap(SLH.sign(key.privateKey(), DIGEST.getBytes().toArray()).orElseThrow())));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHkTheRotatedSlhKeyOfTheV3EpochCounts() {
|
|
+ assertThat(enforcement.refusal(H_K + 5, id0, DIGEST, falconSeal(), slhSeal(slhNew))).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHkTheOldSlhKeyOfTheStaticRegistryNoLongerCounts() {
|
|
+ final Optional<String> r = enforcement.refusal(H_K + 5, id0, DIGEST, falconSeal(), slhSeal(slhOld));
|
|
+ assertThat(r).isPresent();
|
|
+ assertThat(r.get()).contains("does NOT verify").contains(SLH.id());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void belowHkTheStaticRegistryDecidesAsBefore() {
|
|
+ assertThat(enforcement.refusal(H_K - 5, addr0, DIGEST, falconSeal(), slhSeal(slhOld))).isEmpty();
|
|
+ assertThat(enforcement.refusal(H_K - 5, addr0, DIGEST, falconSeal(), slhSeal(slhNew))).isPresent();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHkTheHybridSealCannotVouchForAnotherAuthor() {
|
|
+ final Optional<String> r =
|
|
+ enforcement.refusal(H_K + 5, Address.fromHexString("0x" + "cd".repeat(20)), DIGEST, falconSeal(), slhSeal(slhNew));
|
|
+ assertThat(r).isPresent();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java
|
|
index cfc67a900d..4a2c4f9e0b 100644
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactory.java
|
|
@@ -10,46 +10,47 @@
|
|
* 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/0003-aere-pq-anchor.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft;
|
|
|
|
import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MAX_GAS_LIMIT;
|
|
import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MIN_GAS_LIMIT;
|
|
|
|
import org.hyperledger.besu.consensus.common.bft.BftHelpers;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorConfig;
|
|
import org.hyperledger.besu.consensus.common.bft.headervalidationrules.BftCoinbaseValidationRule;
|
|
-import org.hyperledger.besu.consensus.common.bft.headervalidationrules.BftCommitSealsValidationRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.AereBaseFeeImportRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.FalconSealValidationRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqAnchorDigestAttachedRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqAnchorDigestRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqAnchorSealsRule;
|
|
+import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqCheckpointRule;
|
|
+import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqHeaderSealRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqEmergencyShoutRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.PqRegistryBindingRule;
|
|
import org.hyperledger.besu.consensus.qbft.headervalidationrules.QbftValidatorsValidationRule;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
|
|
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.AncestryValidationRule;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ConstantFieldValidationRule;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasLimitRangeAndDeltaValidationRule;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.GasUsageValidationRule;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter;
|
|
import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent;
|
|
|
|
import java.time.Duration;
|
|
import java.util.Optional;
|
|
|
|
import org.apache.tuweni.units.bigints.UInt256;
|
|
|
|
/** The Qbft block header validation ruleset factory. */
|
|
public class QbftBlockHeaderValidationRulesetFactory {
|
|
@@ -144,61 +145,67 @@ public class QbftBlockHeaderValidationRulesetFactory {
|
|
DEFAULT_MIN_GAS_LIMIT, DEFAULT_MAX_GAS_LIMIT, baseFeeMarket))
|
|
.addRule(new TimestampBoundedByFutureParameter(1))
|
|
// AERE D-AMONTE-02: the base-fee rule every non-BFT factory in this jar wires and the
|
|
// QBFT one upstream forgot. Height-gated (disarmed = today's behaviour, byte for byte):
|
|
// the chain's HISTORY contains blocks this validation would reject (the two floor-less
|
|
// days, the lost-threshold window where the fee was not a function of the parent), so
|
|
// it must never look below its arming height. Delegates to THIS node's fee market, so
|
|
// the AERE 1 Gwei floor is validated too - the check that closes the empty-block
|
|
// one-wei divergence measured on the mixed network (STARE-PRODUCATOR 1bis).
|
|
.addRule(
|
|
new AereBaseFeeImportRule(
|
|
AereBaseFeeImportRule.armedFromSystemConfig(), baseFeeMarket))
|
|
.addRule(
|
|
new ConstantFieldValidationRule<>(
|
|
"MixHash", BlockHeader::getMixHash, BftHelpers.EXPECTED_MIX_HASH))
|
|
.addRule(
|
|
new ConstantFieldValidationRule<>(
|
|
"Difficulty", BlockHeader::getDifficulty, UInt256.ONE))
|
|
.addRule(new QbftValidatorsValidationRule(useValidatorContract))
|
|
.addRule(new BftCoinbaseValidationRule())
|
|
- .addRule(new BftCommitSealsValidationRule())
|
|
+ // AERE AIP-22 stage 5: upstream's committed seals rule below H_hdr, unchanged; from H_hdr the proposer's
|
|
+ // post-quantum seal (element 6) and an EMPTY committed-seal element (PqHeaderSealRule)
|
|
+ .addRule(PqHeaderSealRule.forFleet(pqAnchorConfig.chainId()))
|
|
// AERE ANCORA-V2: the legacy log-only Falcon rule now stands down at H. With an
|
|
// unconfigured anchor this is Long.MAX_VALUE, i.e. it never stands down and behaviour is
|
|
// unchanged.
|
|
.addRule(
|
|
new FalconSealValidationRule(pqAnchorConfig.legacyFalconRuleRetirementBlock()))
|
|
// AERE ANCORA-V2 R1: cheap, detached, IN LIGHT VALIDATION. Ordered before R2 so the one
|
|
// keccak that binds the certificate to the block hash runs before k Falcon
|
|
// verifications are spent on it.
|
|
.addRule(new PqAnchorDigestRule(pqAnchorConfig))
|
|
// AERE SINCRONIZARE R1A (2026-08-02): the SAME digest verdict, on the ATTACHED side.
|
|
// Measured cause it repairs: SKIP_DETACHED, the mode FullImportBlockStep passes to
|
|
// importBlock for every block acquired by sync, keeps exactly the rules that are NOT
|
|
// detached, so R1 does not run at import; and DETACHED_ONLY, the mode under which R1
|
|
// does run, is only applied by DownloadHeaderSequenceTask, i.e. only on ranges with a
|
|
// closed end. The open-ended range at the tip of a recovery, 199 blocks by default, was
|
|
// therefore checked by neither. Ordered immediately before R2 so the one keccak still
|
|
// runs before k Falcon verifications are spent. Delegates to R1, so there is one
|
|
// definition of the digest and the two paths cannot drift.
|
|
.addRule(new PqAnchorDigestAttachedRule(pqAnchorConfig))
|
|
// AERE ANCORA-V2 R2: attached, full validation only.
|
|
.addRule(new PqAnchorSealsRule(pqAnchorConfig))
|
|
// AERE A8 per-block half: the registry this node runs must be the registry
|
|
// config.pqRegistryHash requires AT THIS HEIGHT. The startup guard answers
|
|
// that once, against the head that existed at startup; a rotation entry in
|
|
// the schedule can pass underneath a running node and never be noticed.
|
|
// Inert when no schedule is configured, which is chain 2800 today.
|
|
- .addRule(new PqRegistryBindingRule());
|
|
+ .addRule(new PqRegistryBindingRule())
|
|
+ // AERE AIP-22 stage 4: the checkpoint (aere.pq.checkpoint=<height>:<hash>); a header at a
|
|
+ // checkpoint height with another hash is refused. Attached, so it runs at import. Inert
|
|
+ // when unset, which is every chain today; a malformed value refuses at load.
|
|
+ .addRule(PqCheckpointRule.fromSystemConfiguration());
|
|
|
|
// Currently the minimum acceptable time between blocks is 1 second. The timestamp of an
|
|
// Ethereum header is stored as seconds since Unix epoch so blocks being produced more
|
|
// frequently than once a second cannot pass this validator. For non-production scenarios
|
|
// (e.g. for testing block production much more frequently than once a second) Besu has
|
|
// an experimental 'xblockperiodmilliseconds' option for BFT chains. If this is enabled
|
|
// we cannot apply the TimestampMoreRecentThanParent validation rule so we do not add it
|
|
if (minimumTimeBetweenBlocks.compareTo(Duration.ofSeconds(1)) >= 0) {
|
|
ruleBuilder.addRule(new TimestampMoreRecentThanParent(minimumTimeBetweenBlocks.toSeconds()));
|
|
}
|
|
return ruleBuilder;
|
|
}
|
|
}
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java
|
|
index b3096d3313..d4f6e2d8fc 100644
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftExtraDataCodec.java
|
|
@@ -89,40 +89,53 @@ public class QbftExtraDataCodec extends BftExtraDataCodec {
|
|
/**
|
|
* Create genesis extra data string.
|
|
*
|
|
* @param validators the validators
|
|
* @return the string
|
|
*/
|
|
public static String createGenesisExtraDataString(final List<Address> validators) {
|
|
return encodeFromAddresses(validators).toString();
|
|
}
|
|
|
|
@Override
|
|
public BftExtraData decodeRaw(final Bytes input) {
|
|
if (input.isEmpty()) {
|
|
throw new IllegalArgumentException("Invalid Bytes supplied - Bft Extra Data required.");
|
|
}
|
|
|
|
final RLPInput rlpInput = new BytesValueRLPInput(input, false);
|
|
|
|
rlpInput.enterList(); // This accounts for the "root node" which contains BFT data items.
|
|
final Bytes vanityData = rlpInput.readBytes();
|
|
+ // AERE-D415 (2026-09-25): the vanity field is exactly 32 bytes at EVERY height, not only where
|
|
+ // the anchor rule looks (PqAnchorDigestRule checks it at anchor heights alone). The second
|
|
+ // client's decoder has required 32 from the start, so every header of chains 2800 and 28001,
|
|
+ // both geneses included, satisfies it; the differential fuzzer of the stage-5 header rule found
|
|
+ // the two clients judging a 0-, 31-, 33- or 64-byte vanity between anchors differently (this
|
|
+ // codec admitted it, the second client refused it). One rule, in the codec, for both clients.
|
|
+ if (vanityData.size() != EXTRA_VANITY_LENGTH) {
|
|
+ throw new RLPException(
|
|
+ "AERE-D415: QBFT vanity must be exactly "
|
|
+ + EXTRA_VANITY_LENGTH
|
|
+ + " bytes, the header carries "
|
|
+ + vanityData.size());
|
|
+ }
|
|
final List<Address> validators = rlpInput.readList(Address::readFrom);
|
|
|
|
final Optional<Vote> vote;
|
|
if (rlpInput.nextIsList() && rlpInput.nextSize() == 0) {
|
|
vote = Optional.empty();
|
|
rlpInput.skipNext();
|
|
} else {
|
|
vote = Optional.of(decodeVote(rlpInput));
|
|
}
|
|
|
|
final int round = rlpInput.readIntScalar();
|
|
final List<SECPSignature> seals =
|
|
rlpInput.readList(
|
|
rlp -> SignatureAlgorithmFactory.getInstance().decodeSignature(rlp.readBytes()));
|
|
|
|
// AERE hybrid PQC: an OPTIONAL parallel Falcon-512 seal list may follow the ECDSA seals.
|
|
// Backward-tolerant: older/exclude/no-certificate encodings without this element decode to an
|
|
// empty list.
|
|
final List<FalconSeal> falconSeals;
|
|
final List<SchemeSeal> hybridSeals;
|
|
@@ -147,54 +160,69 @@ public class QbftExtraDataCodec extends BftExtraDataCodec {
|
|
+ e.getMessage());
|
|
}
|
|
} else {
|
|
hybridSeals = Collections.emptyList();
|
|
falconSeals =
|
|
new BytesValueRLPInput(certificateRaw, false)
|
|
.readList(
|
|
rlp -> {
|
|
rlp.enterList();
|
|
final int idx = rlp.readIntScalar();
|
|
final Bytes sig = rlp.readBytes();
|
|
rlp.leaveList();
|
|
return new FalconSeal(idx, sig);
|
|
});
|
|
}
|
|
} else {
|
|
falconSeals = Collections.emptyList();
|
|
hybridSeals = Collections.emptyList();
|
|
}
|
|
|
|
+ // AERE AIP-22 stage 5: an OPTIONAL seventh element, the proposer's seal [index, signature], after
|
|
+ // the certificate slot. When it is present the certificate slot is ALWAYS written (an empty list
|
|
+ // when the header carries no certificate), so the POSITION tells the two apart, never the shape
|
|
+ // (a proposer seal from index 2 would otherwise look like the head of a v2 certificate), and the
|
|
+ // canonical round trip below keeps every value to exactly one encoding.
|
|
+ Optional<FalconSeal> proposerSeal = Optional.empty();
|
|
+ if (!rlpInput.isEndOfCurrentList()) {
|
|
+ rlpInput.enterList();
|
|
+ final int idx = rlpInput.readIntScalar();
|
|
+ final Bytes sig = rlpInput.readBytes();
|
|
+ rlpInput.leaveList();
|
|
+ proposerSeal = Optional.of(new FalconSeal(idx, sig));
|
|
+ }
|
|
+
|
|
// AERE FIX-MALEABILITATE-BLOC (2026-08-01), gate 1 of 2: the leave is STRICT.
|
|
//
|
|
// Upstream ends this decode with leaveListLenient(), which silently discards anything still
|
|
// left in the outer list. That is not survivable here, because the QBFT block hash and the
|
|
// committed-seal pre-image are BOTH computed from a RE-ENCODE of the decoded BftExtraData
|
|
// (BftBlockHashing.calculateHashOfBftBlockOnchain line 84-91, calculateDataHashForCommittedSeal
|
|
// line 53-75). Anything the decoder discards is therefore dropped before hashing, so two
|
|
// different header byte strings carry the same block hash and the same genuine validator
|
|
// seals. leaveList() rejects exactly the inputs that have content left over, and is
|
|
// byte-for-byte identical to the lenient leave on every input that has not.
|
|
rlpInput.leaveList();
|
|
|
|
final BftExtraData decoded =
|
|
- new BftExtraData(vanityData, seals, vote, round, validators, falconSeals, hybridSeals);
|
|
+ new BftExtraData(
|
|
+ vanityData, seals, vote, round, validators, falconSeals, hybridSeals, proposerSeal);
|
|
|
|
// AERE FIX-MALEABILITATE-BLOC (2026-08-01), gate 2 of 2: CANONICAL ROUND TRIP.
|
|
//
|
|
// The strict leave alone does not close the hole. The Falcon element is OPTIONAL on the wire
|
|
// and the encoder omits it when the certificate is empty, so a header carrying an explicit
|
|
// EMPTY Falcon list decodes to exactly the same value as a header carrying no Falcon element
|
|
// at all: the trailing 0xc0 is CONSUMED, not left over, so no leave, strict or lenient, can
|
|
// see it. Requiring the full re-encode to reproduce the received bytes makes the accepted
|
|
// encoding unique by construction, and closes every present and future shape of this defect
|
|
// rather than the one instance of it we happened to look for.
|
|
//
|
|
// Backward compatibility: the re-encode used here is the same EncodingType.ALL the block
|
|
// producer uses, so every header any Aere or stock Besu node has ever produced round trips
|
|
// unchanged. Headers with no Falcon element re-encode with no Falcon element, which is why
|
|
// the whole pre-Falcon history of the chain still decodes.
|
|
final Bytes canonical = encode(decoded, EncodingType.ALL);
|
|
if (!canonical.equals(input)) {
|
|
throw new RLPException(
|
|
"Non-canonical BFT extra data: the header's extraData is "
|
|
+ input.size()
|
|
@@ -226,40 +254,50 @@ public class QbftExtraDataCodec extends BftExtraDataCodec {
|
|
if (encodingType != EncodingType.EXCLUDE_COMMIT_SEALS) {
|
|
encoder.writeList(
|
|
bftExtraData.getSeals(), (committer, rlp) -> rlp.writeBytes(committer.encodedBytes()));
|
|
// AERE hybrid PQC: only the full (stored-header) encoding carries the parallel Falcon
|
|
// quorum certificate, and only when it is non-empty. The exclude encodings omit it so the
|
|
// committed-seal hash and the on-chain block hash are byte-identical to upstream Besu, and a
|
|
// header with no certificate is byte-identical to upstream too, so the Falcon seals are
|
|
// never part of any signed pre-image and never disturb the block hash.
|
|
if (!bftExtraData.getHybridSeals().isEmpty()) {
|
|
// AERE ANCHOR V2: the scheme-tagged certificate, canonical bytes, in the same slot.
|
|
encoder.writeRaw(PqAnchorV2.encode(bftExtraData.getHybridSeals()));
|
|
} else if (!bftExtraData.getFalconSeals().isEmpty()) {
|
|
encoder.writeList(
|
|
bftExtraData.getFalconSeals(),
|
|
(falconSeal, rlp) -> {
|
|
rlp.startList();
|
|
rlp.writeIntScalar(falconSeal.getValidatorIndex());
|
|
rlp.writeBytes(falconSeal.getSignature());
|
|
rlp.endList();
|
|
});
|
|
+ } else if (bftExtraData.getPqProposerSeal().isPresent()) {
|
|
+ // AERE AIP-22 stage 5: the certificate slot stays in place, empty, so the seal is element 6
|
|
+ encoder.writeEmptyList();
|
|
+ }
|
|
+ if (bftExtraData.getPqProposerSeal().isPresent()) {
|
|
+ final FalconSeal ps = bftExtraData.getPqProposerSeal().get();
|
|
+ encoder.startList();
|
|
+ encoder.writeIntScalar(ps.getValidatorIndex());
|
|
+ encoder.writeBytes(ps.getSignature());
|
|
+ encoder.endList();
|
|
}
|
|
} else {
|
|
encoder.writeEmptyList();
|
|
}
|
|
} else {
|
|
encoder.writeIntScalar(0);
|
|
encoder.writeEmptyList();
|
|
}
|
|
encoder.endList();
|
|
|
|
return encoder.encoded();
|
|
}
|
|
|
|
/**
|
|
* Encode vote.
|
|
*
|
|
* @param rlpOutput the rlp output
|
|
* @param vote the vote
|
|
*/
|
|
protected void encodeVote(final RLPOutput rlpOutput, final Vote vote) {
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java
|
|
index dd67707b14..24769c3472 100644
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockCreatorAdaptor.java
|
|
@@ -70,40 +70,72 @@ public class QbftBlockCreatorAdaptor implements QbftBlockCreator {
|
|
this.besuBlockCreator = besuBftBlockCreator;
|
|
this.bftExtraDataCodec = bftExtraDataCodec;
|
|
}
|
|
|
|
@Override
|
|
public BlockCreationResult createBlock(
|
|
final long headerTimeStampSeconds, final QbftBlockHeader parentHeader) {
|
|
var blockResult =
|
|
besuBlockCreator.createBlock(
|
|
headerTimeStampSeconds, AdaptorUtil.toBesuBlockHeader(parentHeader));
|
|
return new BlockCreationResult(
|
|
new QbftBlockAdaptor(blockResult.getBlock()), blockResult.getBlockAccessList());
|
|
}
|
|
|
|
@Override
|
|
public QbftBlock createSealedBlock(
|
|
final QbftBlock block, final int roundNumber, final Collection<SECPSignature> commitSeals) {
|
|
return createSealedBlock(block, roundNumber, commitSeals, Collections.emptyList());
|
|
}
|
|
|
|
+ /**
|
|
+ * AIP-22 stage 5: the stage-5 header, from H_hdr. The proposed header's extraData is carried over
|
|
+ * whole (vanity with the anchor digest, validators, vote, the anchor certificate verbatim) through
|
|
+ * {@link BftExtraData#withSeals}, so nothing the proposer chose can be dropped here; only the round
|
|
+ * is set to the commit round, the ECDSA committed seals are EMPTY and element 6 is the proposal's
|
|
+ * post-quantum seal. Every node seals the same bytes: the header is no longer assembled from what
|
|
+ * each node heard.
|
|
+ */
|
|
+ @Override
|
|
+ public QbftBlock createSealedBlockWithProposerSeal(
|
|
+ final QbftBlock block, final int roundNumber, final FalconSeal proposerSeal) {
|
|
+ final Block besuBlock = AdaptorUtil.toBesuBlock(block);
|
|
+ final BftExtraData initial = bftExtraDataCodec.decode(AdaptorUtil.toBesuBlockHeader(block.getHeader()));
|
|
+ final BftExtraData withRound =
|
|
+ new BftExtraData(
|
|
+ initial.getVanityData(),
|
|
+ Collections.emptyList(),
|
|
+ initial.getVote(),
|
|
+ roundNumber,
|
|
+ initial.getValidators(),
|
|
+ initial.getFalconSeals(),
|
|
+ initial.getHybridSeals(),
|
|
+ initial.getPqProposerSeal());
|
|
+ final BftExtraData sealed = withRound.withSeals(Collections.emptyList(), Optional.of(proposerSeal));
|
|
+ final BlockHeader header =
|
|
+ BlockHeaderBuilder.fromHeader(AdaptorUtil.toBesuBlockHeader(block.getHeader()))
|
|
+ .extraData(bftExtraDataCodec.encode(sealed))
|
|
+ .blockHeaderFunctions(BftBlockHeaderFunctions.forOnchainBlock(bftExtraDataCodec))
|
|
+ .buildBlockHeader();
|
|
+ return new QbftBlockAdaptor(new Block(header, besuBlock.getBody()));
|
|
+ }
|
|
+
|
|
@Override
|
|
public QbftBlock createSealedBlock(
|
|
final QbftBlock block,
|
|
final int roundNumber,
|
|
final Collection<SECPSignature> commitSeals,
|
|
final Collection<FalconSeal> collectedFalconSeals) {
|
|
final Block besuBlock = AdaptorUtil.toBesuBlock(block);
|
|
final QbftBlockHeader initialHeader = block.getHeader();
|
|
final BftExtraData initialExtraData =
|
|
bftExtraDataCodec.decode(AdaptorUtil.toBesuBlockHeader(initialHeader));
|
|
|
|
// AERE ANCHOR V2, THE MEASURED TRAP, CLOSED HERE. Above the activation height element 6 is no
|
|
// longer "the seals I heard for THIS block": it is the quorum certificate over the PARENT,
|
|
// CHOSEN BY THE PROPOSER, and vanityData carries its digest D. Every node that seals this block
|
|
// must therefore carry the proposer's bytes across UNCHANGED. The legacy assembly below would
|
|
// overwrite them with what this node heard for the current block, which would leave a header
|
|
// whose vanity D no longer matches its own element 6, i.e. a header this node's own digest rule
|
|
// rejects. So above the activation height the assembler is skipped outright.
|
|
//
|
|
// Note what is NOT done here: no re-verification, no re-selection, no comparison against what
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftFinalStateImpl.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftFinalStateImpl.java
|
|
index 5a3ff17130..03d2c64c9c 100644
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftFinalStateImpl.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftFinalStateImpl.java
|
|
@@ -1,36 +1,43 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.consensus.qbft.adaptor;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.BftHelpers;
|
|
import org.hyperledger.besu.consensus.common.bft.BlockTimer;
|
|
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
|
|
import org.hyperledger.besu.consensus.common.bft.blockcreation.ProposerSelector;
|
|
import org.hyperledger.besu.consensus.common.bft.network.ValidatorMulticaster;
|
|
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCreatorFactory;
|
|
import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState;
|
|
import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
|
|
import java.time.Clock;
|
|
import java.util.Collection;
|
|
|
|
/** Besu implementation of QbftFinalState for maintaining the state of a QBFT network. */
|
|
public class QbftFinalStateImpl implements QbftFinalState {
|
|
private final ValidatorProvider validatorProvider;
|
|
private final NodeKey nodeKey;
|
|
private final Address localAddress;
|
|
@@ -105,82 +112,83 @@ public class QbftFinalStateImpl implements QbftFinalState {
|
|
return nodeKey;
|
|
}
|
|
|
|
/**
|
|
* Gets local address.
|
|
*
|
|
* @return the local address
|
|
*/
|
|
@Override
|
|
public Address getLocalAddress() {
|
|
return localAddress;
|
|
}
|
|
|
|
/**
|
|
* Is local node validator.
|
|
*
|
|
* @return the boolean
|
|
*/
|
|
@Override
|
|
public boolean isLocalNodeValidator() {
|
|
- return getValidators().contains(localAddress);
|
|
+ return getValidators().stream().anyMatch(a -> AerePqIdentity.isLocal(a, localAddress));
|
|
}
|
|
|
|
/**
|
|
* Gets round timer.
|
|
*
|
|
* @return the round timer
|
|
*/
|
|
@Override
|
|
public RoundTimer getRoundTimer() {
|
|
return roundTimer;
|
|
}
|
|
|
|
/**
|
|
* Gets block creator factory.
|
|
*
|
|
* @return the block creator factory
|
|
*/
|
|
@Override
|
|
public QbftBlockCreatorFactory getBlockCreatorFactory() {
|
|
return blockCreatorFactory;
|
|
}
|
|
|
|
@Override
|
|
public int getQuorum() {
|
|
return BftHelpers.calculateRequiredValidatorQuorum(getValidators().size());
|
|
}
|
|
|
|
@Override
|
|
public BlockTimer getBlockTimer() {
|
|
return blockTimer;
|
|
}
|
|
|
|
/**
|
|
* Is local node proposer for round.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @return the boolean
|
|
*/
|
|
@Override
|
|
public boolean isLocalNodeProposerForRound(final ConsensusRoundIdentifier roundIdentifier) {
|
|
- return getProposerForRound(roundIdentifier).equals(localAddress);
|
|
+ return getProposerForRound(roundIdentifier)
|
|
+ .equals(AerePqIdentity.local(localAddress, roundIdentifier.getSequenceNumber()));
|
|
}
|
|
|
|
/**
|
|
* Gets proposer for round.
|
|
*
|
|
* @param roundIdentifier the round identifier
|
|
* @return the proposer for round
|
|
*/
|
|
public Address getProposerForRound(final ConsensusRoundIdentifier roundIdentifier) {
|
|
return proposerSelector.selectProposerForRound(roundIdentifier);
|
|
}
|
|
|
|
/**
|
|
* Gets clock.
|
|
*
|
|
* @return the clock
|
|
*/
|
|
@Override
|
|
public Clock getClock() {
|
|
return clock;
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDigestRule.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDigestRule.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 3b80c4302c..a9ba7a2ef3
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDigestRule.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDigestRule.java
|
|
@@ -119,79 +119,79 @@ public class PqAnchorDigestRule implements DetachedBlockHeaderValidationRule {
|
|
public boolean validate(final BlockHeader header, final BlockHeader parent) {
|
|
final long number = header.getNumber();
|
|
|
|
// HEIGHT GATE FIRST. Below H nothing at all happens: no decode, no allocation, no log. This is
|
|
// the property that lets a binary built from this code run on a live node before activation and
|
|
// behave bit-for-bit as today. From 2026-08-07 the gate also covers the interval: at a height
|
|
// that carries no certificate there is nothing to bind, so there is nothing to judge.
|
|
//
|
|
// THE SAME METHOD AS R2, and not two questions that merely resemble each other. See the note in
|
|
// PqAnchorSealsRule.
|
|
if (!config.anchorAppliesAt(number)) {
|
|
return true;
|
|
}
|
|
|
|
// SECOND GATE: the named historical windows in which these rules were not in force. Inside one
|
|
// of them vanityData carries the client's version string rather than a digest, so there is no
|
|
// digest to match and no recomputation can produce one; refusing would stop this node forever
|
|
// at a height the whole network holds. See PqAnchorLapse for what happened, how the bounds were
|
|
// measured, and why an exception written anywhere other than validation moves the error instead
|
|
// of ending it.
|
|
- if (PqAnchorLapse.isDisarmed(number)) {
|
|
+ if (PqAnchorLapse.isDisarmed(config.chainId(), number)) {
|
|
return acceptAsWrittenInsideLapse(header, number);
|
|
}
|
|
|
|
try {
|
|
final BftExtraData extraData = extraDataCodec.decodeRaw(header.getExtraData());
|
|
|
|
final Bytes vanity = extraData.getVanityData();
|
|
if (vanity.size() != BftExtraDataCodec.EXTRA_VANITY_LENGTH) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - vanityData is {} bytes, expected {}. From H "
|
|
+ "the whole vanity field is the anchor digest D.",
|
|
number,
|
|
vanity.size(),
|
|
BftExtraDataCodec.EXTRA_VANITY_LENGTH);
|
|
return false;
|
|
}
|
|
|
|
// AERE ANCHOR V2 (2026-09-03): from the v2 height the ONLY accepted form is the scheme-tagged
|
|
// certificate under the v2 digest; below it a v2 certificate is refused. Both directions
|
|
// are checked so the switch is a clean fork and never a header two nodes read differently.
|
|
if (config.anchorV2AppliesAt(number)) {
|
|
return judgeV2(number, header, extraData, vanity);
|
|
}
|
|
if (!extraData.getHybridSeals().isEmpty()) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - carries a v2 (scheme-tagged) certificate below"
|
|
+ " the v2 activation height {}.",
|
|
number,
|
|
config.anchorV2Block());
|
|
return false;
|
|
}
|
|
final List<FalconSeal> certificate = List.copyOf(extraData.getFalconSeals());
|
|
// Height aware since 2026-08-11. Inside the one measured historical window the ordering
|
|
// requirement relaxes from SORTED to DISTINCT, because 36 canonical headers were written
|
|
// unsorted during a production interruption and a node syncing from genesis would otherwise
|
|
// stop at the first of them and never pass it. Distinctness is not relaxed at any height, so a
|
|
// repeated index stays unrepresentable everywhere. See PqAnchor.hasAcceptableIndices.
|
|
- if (!PqAnchor.hasAcceptableIndices(certificate, number)) {
|
|
+ if (!PqAnchor.hasAcceptableIndices(config.chainId(), certificate, number)) {
|
|
// Checked HERE, not only in the seals rule, so reordering and duplicate indices are caught
|
|
// in LIGHT validation too, and so that "the order given" and "sorted" are the same list for
|
|
// every header this rule accepts.
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - the carried certificate's validator indices "
|
|
+ "are not strictly increasing ({} seal(s)). Exactly one order is accepted for a "
|
|
+ "given set, which is also what makes a repeated index unrepresentable.",
|
|
number,
|
|
certificate.size());
|
|
return false;
|
|
}
|
|
|
|
final Bytes32 expected =
|
|
PqAnchor.anchorDigest(
|
|
config.chainId(), number - 1L, header.getParentHash().getBytes(), certificate);
|
|
|
|
if (!expected.equals(Bytes32.wrap(vanity))) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - anchor digest mismatch. vanityData carries "
|
|
+ "{} but the certificate actually carried in this header ({} seal(s), over parent "
|
|
@@ -260,48 +260,48 @@ public class PqAnchorDigestRule implements DetachedBlockHeaderValidationRule {
|
|
* history that exists and nothing weaker.
|
|
*
|
|
* <p>Decoding must still succeed. A header this rule cannot parse has not been shown to be one of
|
|
* the headers the window is about, so it is refused here as everywhere else in this file.
|
|
*
|
|
* @param header the header being judged
|
|
* @param number its height
|
|
* @return true iff the carried certificate decodes and its indices are distinct and non-negative
|
|
*/
|
|
private boolean acceptAsWrittenInsideLapse(final BlockHeader header, final long number) {
|
|
try {
|
|
final BftExtraData extraData = extraDataCodec.decodeRaw(header.getExtraData());
|
|
final List<FalconSeal> certificate = List.copyOf(extraData.getFalconSeals());
|
|
if (!PqAnchor.hasDistinctNonNegativeIndices(certificate)) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - it falls inside the historical range {} in "
|
|
+ "which the anchor rules were not in force, but its certificate repeats a "
|
|
+ "validator index or carries a negative one. That is not a shape any header of "
|
|
+ "that range has, and it is the one property the exception does not relax.",
|
|
number,
|
|
- PqAnchorLapse.windowCovering(number).orElse(null));
|
|
+ PqAnchorLapse.windowCovering(config.chainId(), number).orElse(null));
|
|
return false;
|
|
}
|
|
LOG.debug(
|
|
"AERE PQ ANCHOR (R1): block {} accepted as written; it falls inside the historical range "
|
|
+ "{} in which the anchor rules were not in force, so it carries no digest to bind.",
|
|
number,
|
|
- PqAnchorLapse.windowCovering(number).orElse(null));
|
|
+ PqAnchorLapse.windowCovering(config.chainId(), number).orElse(null));
|
|
return true;
|
|
} catch (final Exception e) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R1): block {} REJECTED - it falls inside a historical unenforced range "
|
|
+ "but its extraData could not be decoded: {}",
|
|
number,
|
|
e.toString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean includeInLightValidation() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "PqAnchorDigest(detached, light, "
|
|
+ (config.everActive() ? "H=" + config.anchorBlock() : "INACTIVE")
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorSealsRule.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorSealsRule.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 78423af47a..3f58217d1f
|
|
--- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorSealsRule.java
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorSealsRule.java
|
|
@@ -1,36 +1,37 @@
|
|
/*
|
|
* Copyright contributors to Besu / 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.consensus.qbft.headervalidationrules;
|
|
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
import org.hyperledger.besu.consensus.common.bft.BftContext;
|
|
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.FalconSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSealSupport;
|
|
import org.hyperledger.besu.consensus.common.bft.HybridSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorConfig;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorLapse;
|
|
import org.hyperledger.besu.consensus.common.bft.PqAnchorV2;
|
|
import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
import org.hyperledger.besu.consensus.common.bft.SchemeSeal;
|
|
import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule;
|
|
|
|
@@ -125,41 +126,41 @@ public class PqAnchorSealsRule implements AttachedBlockHeaderValidationRule {
|
|
public boolean validate(
|
|
final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) {
|
|
final long number = header.getNumber();
|
|
|
|
// HEIGHT GATE FIRST, same contract as R1: below H this rule does nothing at all, and from
|
|
// 2026-08-07 it also does nothing at a height that carries no certificate.
|
|
//
|
|
// BOTH RULES ASK THE SAME QUESTION, THROUGH THE SAME METHOD, and that is deliberate.
|
|
// anchorAppliesAt() = activeAt() AND isAnchorHeight(). If R1 and R2 each asked it their own
|
|
// way, a header accepted by one and refused by the other would be a chain break, appearing at
|
|
// exactly the first height that is not an anchor height, i.e. the day after activation.
|
|
if (!config.anchorAppliesAt(number)) {
|
|
return true;
|
|
}
|
|
|
|
// SECOND GATE, and the SAME method R1 asks, for the same reason both rules share
|
|
// anchorAppliesAt: if the two rules each decided this boundary their own way, a header accepted
|
|
// by one and refused by the other would be a chain break. Inside a named window the threshold
|
|
// was not in force when the header was written and the indices were written in arrival order,
|
|
// so neither can be required of it now.
|
|
- if (PqAnchorLapse.isDisarmed(number)) {
|
|
+ if (PqAnchorLapse.isDisarmed(config.chainId(), number)) {
|
|
return acceptAsWrittenInsideLapse(header, number);
|
|
}
|
|
|
|
try {
|
|
if (parent == null) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - no parent header available, so the "
|
|
+ "certificate cannot be checked against the parent it claims to attest to.",
|
|
number);
|
|
return false;
|
|
}
|
|
// The certificate attests to the parent by NUMBER and HASH, and R1 has already bound the
|
|
// digest to header.getParentHash(). If the parent handed to this rule were a different header,
|
|
// R1 and R2 would be talking about two different objects. Cheap, and it removes any dependence
|
|
// on rule ordering with AncestryValidationRule.
|
|
if (!parent.getHash().equals(header.getParentHash())
|
|
|| parent.getNumber() != number - 1L) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the supplied parent (number {}, hash {}) is "
|
|
+ "not the parent this header names (number {}, hash {}).",
|
|
@@ -187,66 +188,66 @@ public class PqAnchorSealsRule implements AttachedBlockHeaderValidationRule {
|
|
}
|
|
if (!extraData.getHybridSeals().isEmpty()) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - carries a v2 (scheme-tagged) certificate below"
|
|
+ " the v2 activation height {}.",
|
|
number,
|
|
config.anchorV2Block());
|
|
return false;
|
|
}
|
|
final List<FalconSeal> certificate = List.copyOf(extraData.getFalconSeals());
|
|
final int k = certificate.size();
|
|
|
|
// THE THRESHOLD THIS HEIGHT WAS ACTUALLY JUDGED BY. Normally the configured schedule. Inside
|
|
// a named historical range it is the LOWER of the schedule and the emergency ceiling that was
|
|
// in force when these headers were written, which is the same lever the fleet itself used at
|
|
// the time, replayed from a fixed range instead of from a runtime option. Asking a header for
|
|
// more than was asked of the proposer that wrote it refuses history that no node can
|
|
// reproduce; asking for the ceiling rather than for nothing keeps the strongest claim the
|
|
// range supports, and the ceiling is a measured floor, never zero. See PqAnchorLapse.
|
|
int required = config.minSealsAt(number);
|
|
- final OptionalInt inForce = PqAnchorLapse.historicMinSeals(number);
|
|
+ final OptionalInt inForce = PqAnchorLapse.historicMinSeals(config.chainId(), number);
|
|
if (inForce.isPresent() && inForce.getAsInt() < required) {
|
|
LOG.debug(
|
|
"AERE PQ ANCHOR (R2): block {} sits in the historical range {}, so the threshold "
|
|
+ "applied is the {} that was in force then, not the {} the schedule asks for.",
|
|
number,
|
|
- PqAnchorLapse.windowCovering(number).orElse(null),
|
|
+ PqAnchorLapse.windowCovering(config.chainId(), number).orElse(null),
|
|
inForce.getAsInt(),
|
|
required);
|
|
required = inForce.getAsInt();
|
|
}
|
|
|
|
if (k < required) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the carried certificate has {} seal(s), "
|
|
+ "below the threshold K={} in force at this height.",
|
|
number,
|
|
k,
|
|
required);
|
|
return false;
|
|
}
|
|
|
|
// Height aware since 2026-08-11, same measured historical window as rule R1. See
|
|
// PqAnchor.hasAcceptableIndices for why the exception sits at VALIDATION and nowhere else, and
|
|
// for what it deliberately does NOT relax.
|
|
- if (!PqAnchor.hasAcceptableIndices(certificate, number)) {
|
|
+ if (!PqAnchor.hasAcceptableIndices(config.chainId(), certificate, number)) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the certificate's validator indices are not "
|
|
+ "strictly increasing.",
|
|
number);
|
|
return false;
|
|
}
|
|
|
|
if (k == 0) {
|
|
// Legitimate only while K is 0, which is the warm-up stage that starts at H itself, where
|
|
// the parent predates the scheme and no certificate can exist. R1 has already checked that
|
|
// the vanity digest is the digest OF THE EMPTY certificate, so an empty certificate is not
|
|
// an unchecked one.
|
|
LOG.debug(
|
|
"AERE PQ ANCHOR (R2): block {} carries an empty certificate and K={} at this height.",
|
|
number,
|
|
required);
|
|
return true;
|
|
}
|
|
|
|
final BftContext bftContext = protocolContext.getConsensusContext(BftContext.class);
|
|
@@ -406,79 +407,98 @@ public class PqAnchorSealsRule implements AttachedBlockHeaderValidationRule {
|
|
return false;
|
|
}
|
|
final BftContext bftContext = protocolContext.getConsensusContext(BftContext.class);
|
|
final Collection<Address> parentValidators =
|
|
bftContext.getValidatorProvider().getValidatorsForBlock(parent);
|
|
if (parentValidators == null || parentValidators.isEmpty()) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the validator set of the parent block {} could"
|
|
+ " not be resolved, so seal eligibility cannot be decided.",
|
|
number,
|
|
parent.getNumber());
|
|
return false;
|
|
}
|
|
final Set<Address> eligible = new HashSet<>(parentValidators);
|
|
final Bytes32 message =
|
|
PqAnchor.commitMessage(config.chainId(), parent.getNumber(), parent.getHash().getBytes());
|
|
if (!falcon.isEmpty() && !falconSealsVerify(number, parent, eligible, message, falcon)) {
|
|
return false;
|
|
}
|
|
final HybridSealSupport hybrid = HybridSealSupport.instance();
|
|
+ // Two sets, and they differ only with per-scheme intervals (AIP-22 stage 2). NAMED: every scheme
|
|
+ // the step at the parent height names; a seal of any other scheme is refused as today. REQUIRED:
|
|
+ // the named schemes whose grid THIS anchor height sits on, counted from the chain's anchor
|
|
+ // activation height; each must reach K. A seal of a named-but-not-required scheme is a surplus:
|
|
+ // verified and counted like any surplus seal, never ignored, never a reason to refuse.
|
|
+ final Set<String> namedSchemes = new HashSet<>();
|
|
final Set<String> requiredSchemes = new HashSet<>();
|
|
- hybrid.schedule().ifPresent(sch -> requiredSchemes.addAll(sch.schemesAt(parent.getNumber())));
|
|
+ hybrid
|
|
+ .schedule()
|
|
+ .ifPresent(
|
|
+ sch -> {
|
|
+ namedSchemes.addAll(sch.schemesAt(parent.getNumber()));
|
|
+ requiredSchemes.addAll(sch.schemesRequiredForAnchor(number, config.anchorBlock()));
|
|
+ });
|
|
+ namedSchemes.remove(SealSchemes.FALCON_512.id());
|
|
requiredSchemes.remove(SealSchemes.FALCON_512.id());
|
|
final Map<String, Integer> counted = new HashMap<>();
|
|
for (final SchemeSeal s : seals) {
|
|
if (s.getSchemeWireId() == SealSchemes.FALCON_512.wireId()) {
|
|
continue;
|
|
}
|
|
final Optional<SealScheme> scheme = SealSchemes.byWireId(s.getSchemeWireId());
|
|
- if (scheme.isEmpty() || !requiredSchemes.contains(scheme.get().id())) {
|
|
+ if (scheme.isEmpty() || !namedSchemes.contains(scheme.get().id())) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the v2 certificate carries a seal of scheme 0x{},"
|
|
+ " which the scheme schedule does not name at the parent height {} (named: {}).",
|
|
number,
|
|
Integer.toHexString(s.getSchemeWireId() & 0xff),
|
|
parent.getNumber(),
|
|
- requiredSchemes);
|
|
+ namedSchemes);
|
|
return false;
|
|
}
|
|
if (!falconIndices.contains(s.getValidatorIndex())) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - a {} seal from index {} is not bound to a Falcon"
|
|
+ " seal of the same index in this certificate.",
|
|
number,
|
|
scheme.get().id(),
|
|
s.getValidatorIndex());
|
|
return false;
|
|
}
|
|
final Optional<HybridSignerRegistry> registry = hybrid.registry();
|
|
- if (registry.isEmpty()) {
|
|
+ // AERE AIP-22 stage 3b: from H_k the key comes from the v3 epoch in force at the PARENT (the height the
|
|
+ // Falcon key of the same certificate is taken at); the hybrid registry is then not the key set any more
|
|
+ final boolean v3Keys = AerePqIdentity.keysFromV3(parent.getNumber());
|
|
+ if (registry.isEmpty() && !v3Keys) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the certificate carries {} seals and this node"
|
|
+ " has NO hybrid registry loaded, so it cannot verify them. A node that cannot"
|
|
+ " verify has not proved the header good.",
|
|
number,
|
|
scheme.get().id());
|
|
return false;
|
|
}
|
|
- final Optional<byte[]> pk = registry.get().publicKey(s.getValidatorIndex(), scheme.get().id());
|
|
+ final Optional<byte[]> pk =
|
|
+ v3Keys
|
|
+ ? AerePqIdentity.v3KeyAt(parent.getNumber(), s.getValidatorIndex(), scheme.get().id())
|
|
+ : registry.get().publicKey(s.getValidatorIndex(), scheme.get().id());
|
|
if (pk.isEmpty()) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the hybrid registry holds no {} key for index {}.",
|
|
number,
|
|
scheme.get().id(),
|
|
s.getValidatorIndex());
|
|
return false;
|
|
}
|
|
if (!scheme.get().verifyRaw(pk.get(), message.toArray(), s.getSignature().toArray())) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - the {} signature from index {} does not verify"
|
|
+ " over M(parent {}).",
|
|
number,
|
|
scheme.get().id(),
|
|
s.getValidatorIndex(),
|
|
parent.getNumber());
|
|
return false;
|
|
}
|
|
counted.merge(scheme.get().id(), 1, Integer::sum);
|
|
}
|
|
@@ -499,49 +519,49 @@ public class PqAnchorSealsRule implements AttachedBlockHeaderValidationRule {
|
|
"AERE PQ ANCHOR (R2): block {} accepted with a {}-seal scheme-tagged certificate over parent"
|
|
+ " {} (K={} per scheme, schemes={}).",
|
|
number,
|
|
seals.size(),
|
|
parent.getNumber(),
|
|
required,
|
|
requiredSchemes);
|
|
return true;
|
|
}
|
|
|
|
private boolean acceptAsWrittenInsideLapse(final BlockHeader header, final long number) {
|
|
try {
|
|
final BftExtraData extraData = extraDataCodec.decodeRaw(header.getExtraData());
|
|
final List<FalconSeal> certificate = List.copyOf(extraData.getFalconSeals());
|
|
if (!PqAnchor.hasDistinctNonNegativeIndices(certificate)) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - it falls inside the historical range {} in "
|
|
+ "which the anchor rules were not in force, but its certificate repeats a "
|
|
+ "validator index or carries a negative one, which no header of that range does.",
|
|
number,
|
|
- PqAnchorLapse.windowCovering(number).orElse(null));
|
|
+ PqAnchorLapse.windowCovering(config.chainId(), number).orElse(null));
|
|
return false;
|
|
}
|
|
LOG.debug(
|
|
"AERE PQ ANCHOR (R2): block {} accepted as written with {} seal(s); it falls inside the "
|
|
+ "historical range {} in which neither the threshold nor the ordering was in force.",
|
|
number,
|
|
certificate.size(),
|
|
- PqAnchorLapse.windowCovering(number).orElse(null));
|
|
+ PqAnchorLapse.windowCovering(config.chainId(), number).orElse(null));
|
|
return true;
|
|
} catch (final Exception e) {
|
|
LOG.warn(
|
|
"AERE PQ ANCHOR (R2): block {} REJECTED - it falls inside a historical unenforced range "
|
|
+ "but its extraData could not be decoded: {}",
|
|
number,
|
|
e.toString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AERE D-078: hand the parent's validator set to {@link FalconSealSupport} so its registry-
|
|
* coverage report is about the height the chain is actually at. Swallows everything: a rule that
|
|
* rejected a header because a diagnostic threw would be a worse defect than the one this repairs.
|
|
*
|
|
* @param parent the parent header
|
|
* @param protocolContext the protocol context
|
|
*/
|
|
private void observeValidatorsForDiagnostics(
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRule.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRule.java
|
|
new file mode 100644
|
|
index 0000000000..d6b46c5396
|
|
--- /dev/null
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRule.java
|
|
@@ -0,0 +1,133 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.headervalidationrules;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.NavigableMap;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import com.google.common.base.Splitter;
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AERE AIP-22 stage 4 (plan 9.6.7 point iv): the CHECKPOINT, which is how the weak subjectivity of a
|
|
+ * finality gadget is handled, stated publicly rather than hidden. A node that synchronises from
|
|
+ * genesis without other knowledge can be handed, by an eclipsing neighbour, a fork that ends before
|
|
+ * the first certified anchor; it can never reach the honest chain's height with valid certificates,
|
|
+ * but the eclipsed node does not know that height. Given a recent anchor from outside (height and
|
|
+ * block hash, from the published registry epoch or from its operator), it refuses any header at that
|
|
+ * height with another hash, so every chain it accepts runs through the checkpoint, and a rewrite at
|
|
+ * any height below it would have to reproduce every certificate above.
|
|
+ *
|
|
+ * <p>{@code aere.pq.checkpoint=<height>:<block hash>[,<height>:<block hash>...]}. Unset or blank:
|
|
+ * inert (every header passes), which is every chain as it stands. A value it cannot parse refuses at
|
|
+ * load (AERE-PQC-CHECKPOINT-01), never silently degrades to "no checkpoint". ATTACHED, so it runs at
|
|
+ * import under SKIP_DETACHED, the mode full sync imports with (the same reason R1A exists).
|
|
+ */
|
|
+public class PqCheckpointRule implements AttachedBlockHeaderValidationRule {
|
|
+
|
|
+ /** The system property that names the checkpoints. */
|
|
+ public static final String PROPERTY = "aere.pq.checkpoint";
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(PqCheckpointRule.class);
|
|
+
|
|
+ private final NavigableMap<Long, Hash> checkpoints;
|
|
+
|
|
+ /**
|
|
+ * A rule over the given checkpoints (height to block hash).
|
|
+ *
|
|
+ * @param checkpoints the checkpoints; empty means inert
|
|
+ */
|
|
+ public PqCheckpointRule(final NavigableMap<Long, Hash> checkpoints) {
|
|
+ this.checkpoints = Collections.unmodifiableNavigableMap(new TreeMap<>(checkpoints));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The rule configured on this node by {@link #PROPERTY}.
|
|
+ *
|
|
+ * @return the rule
|
|
+ */
|
|
+ public static PqCheckpointRule fromSystemConfiguration() {
|
|
+ return new PqCheckpointRule(parse(System.getProperty(PROPERTY)));
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The checkpoints named by this node's configuration.
|
|
+ *
|
|
+ * @return height to block hash, empty when unset
|
|
+ */
|
|
+ public NavigableMap<Long, Hash> checkpoints() {
|
|
+ return checkpoints;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Parses {@code <height>:<block hash>[,...]}; fail-closed on anything malformed.
|
|
+ *
|
|
+ * @param value the property value, possibly null
|
|
+ * @return height to block hash
|
|
+ */
|
|
+ static NavigableMap<Long, Hash> parse(final String value) {
|
|
+ final TreeMap<Long, Hash> m = new TreeMap<>();
|
|
+ if (value == null || value.isBlank()) {
|
|
+ return m;
|
|
+ }
|
|
+ for (final String part : Splitter.on(',').trimResults().omitEmptyStrings().split(value)) {
|
|
+ final int c = part.indexOf(':');
|
|
+ if (c <= 0) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE-PQC-CHECKPOINT-01: " + PROPERTY + " entry '" + part + "' is not <height>:<block hash>");
|
|
+ }
|
|
+ final long height;
|
|
+ final Hash hash;
|
|
+ try {
|
|
+ height = Long.parseLong(part.substring(0, c).trim());
|
|
+ hash = Hash.fromHexString(part.substring(c + 1).trim());
|
|
+ } catch (final RuntimeException e) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE-PQC-CHECKPOINT-01: " + PROPERTY + " entry '" + part + "' is not <height>:<32-byte block hash>", e);
|
|
+ }
|
|
+ if (height < 1) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE-PQC-CHECKPOINT-01: " + PROPERTY + " height " + height + " must be at least 1");
|
|
+ }
|
|
+ if (m.put(height, hash) != null) {
|
|
+ throw new IllegalArgumentException(
|
|
+ "AERE-PQC-CHECKPOINT-01: " + PROPERTY + " names height " + height + " twice");
|
|
+ }
|
|
+ }
|
|
+ return m;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean validate(
|
|
+ final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) {
|
|
+ final Hash want = checkpoints.get(header.getNumber());
|
|
+ if (want == null || want.equals(header.getHash())) {
|
|
+ return true;
|
|
+ }
|
|
+ LOG.warn(
|
|
+ "AERE-PQC-CHECKPOINT-02: block {} has hash {} but this node's checkpoint at that height is {}; REFUSED (a chain that does not run through the checkpoint is never adopted)",
|
|
+ header.getNumber(),
|
|
+ header.getHash(),
|
|
+ want);
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealRule.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealRule.java
|
|
new file mode 100644
|
|
index 0000000000..e292937e50
|
|
--- /dev/null
|
|
+++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealRule.java
|
|
@@ -0,0 +1,259 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.headervalidationrules;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqHeaderSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
|
|
+import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqSignerRegistry;
|
|
+import org.hyperledger.besu.consensus.common.bft.blockcreation.BftProposerSelector;
|
|
+import org.hyperledger.besu.consensus.common.bft.headervalidationrules.BftCommitSealsValidationRule;
|
|
+import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 5: the seal rule of a header. Below H_hdr it IS the upstream rule (a quorum of ECDSA
|
|
+ * committed seals of the parent's validators), unchanged. From H_hdr a header is admitted iff its ECDSA
|
|
+ * committed-seal element is EMPTY, its seventh element carries the proposer's Falcon-512 seal, the seal's
|
|
+ * index names the header's {@code coinbase} (an id) in the v3 epoch in force at its height, and the seal
|
|
+ * verifies over the PROPOSAL message recomputed from the stored header (chain id, height, the round in
|
|
+ * element 3, the proposal digest, i.e. the committed-seal hash of the header). Finality stays with the
|
|
+ * anchors (AIP-22 section 4); this rule is what admits a header between them.
|
|
+ *
|
|
+ * <p>AERE D-406 (2026-09-25, measured on testnet 28001): a block PREPARED in one round and not
|
|
+ * committed before its timer is RE-PROPOSED unchanged in a later round r by the proposer of round r
|
|
+ * (QBFT's locked value; only element 3 changes, the coinbase stays the builder's), and every node seals
|
|
+ * the header with the accepted proposal's seal, which is the round-r proposer's. Requiring the coinbase
|
|
+ * refused every such header on every node: block 3,314,873 stood 128 s (rounds 1 to 4 refused with
|
|
+ * "a seal cannot vouch for another proposer", round 5 was the builder's own turn again, N = 5); at
|
|
+ * N = 10 the same wait is ten rounds, and with the builder down after the prepare it does not end. So
|
|
+ * the seal's id must be the coinbase OR, at a round above zero, the proposer of the round in element 3
|
|
+ * as upstream's proposer selection computes it from the parent's proposer (its coinbase) and the
|
|
+ * header's own validator list (the set after the parent, which BftValidatorsValidationRule enforces).
|
|
+ * Every header the old rule admitted is admitted unchanged; the new branch only runs where it refused.
|
|
+ */
|
|
+public class PqHeaderSealRule implements AttachedBlockHeaderValidationRule {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(PqHeaderSealRule.class);
|
|
+
|
|
+ private final AttachedBlockHeaderValidationRule belowHdr;
|
|
+ private final BftExtraDataCodec codec;
|
|
+ private final long chainId;
|
|
+ private final AerePqFinality.SealVerifier verifier;
|
|
+
|
|
+ /**
|
|
+ * The rule.
|
|
+ *
|
|
+ * @param belowHdr the rule below H_hdr (upstream's committed seals rule in production)
|
|
+ * @param codec the extraData codec
|
|
+ * @param chainId the chain id every seal message carries
|
|
+ * @param verifier the seal verifier (the anchor rules' historic door in production)
|
|
+ */
|
|
+ public PqHeaderSealRule(
|
|
+ final AttachedBlockHeaderValidationRule belowHdr,
|
|
+ final BftExtraDataCodec codec,
|
|
+ final long chainId,
|
|
+ final AerePqFinality.SealVerifier verifier) {
|
|
+ this.belowHdr = belowHdr;
|
|
+ this.codec = codec;
|
|
+ this.chainId = chainId;
|
|
+ this.verifier = verifier;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The fleet's rule: upstream's committed seals rule below H_hdr, the verifier of the header rules above.
|
|
+ *
|
|
+ * @param chainId the chain id
|
|
+ * @return the rule
|
|
+ */
|
|
+ public static PqHeaderSealRule forFleet(final long chainId) {
|
|
+ final PqSignerRegistry registry = PqSignerRegistry.falconSealSupport();
|
|
+ return new PqHeaderSealRule(
|
|
+ new BftCommitSealsValidationRule(), new QbftExtraDataCodec(), chainId, registry::verifyAtHistoric);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean validate(
|
|
+ final BlockHeader header, final BlockHeader parent, final ProtocolContext protocolContext) {
|
|
+ if (!AerePqHeaderSeal.active(header.getNumber())) {
|
|
+ return belowHdr.validate(header, parent, protocolContext);
|
|
+ }
|
|
+ final Optional<String> r = refusal(header, parent);
|
|
+ r.ifPresent(LOG::info);
|
|
+ return r.isEmpty();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Why a header at or above H_hdr is refused, if it is, judged WITHOUT its parent: only a seal of the
|
|
+ * coinbase's index can be admitted (a re-proposed header needs the parent, {@link #refusal(BlockHeader,
|
|
+ * BlockHeader)}).
|
|
+ *
|
|
+ * @param header the header
|
|
+ * @return the refusal, or empty
|
|
+ */
|
|
+ public Optional<String> refusal(final BlockHeader header) {
|
|
+ return refusal(header, null);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE D-406: the proposer of the round in element 3, as upstream's selection computes it (changeEachBlock,
|
|
+ * as QBFT), from the parent's proposer and the header's validator list. Empty at round 0, without the
|
|
+ * parent, or when the list cannot seed a selection.
|
|
+ *
|
|
+ * @param h the height
|
|
+ * @param round the round in element 3
|
|
+ * @param parent the parent header, or null
|
|
+ * @param validators the header's validator list
|
|
+ * @return the proposer of that round, or empty
|
|
+ */
|
|
+ static Optional<Address> proposerOfRound(
|
|
+ final long h, final int round, final BlockHeader parent, final Collection<Address> validators) {
|
|
+ if (round <= 0 || round > MAX_ROUND || parent == null || validators == null || validators.isEmpty()) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ try {
|
|
+ return Optional.of(
|
|
+ BftProposerSelector.selectProposerForRound(
|
|
+ new ConsensusRoundIdentifier(h, round),
|
|
+ parent.getCoinbase(),
|
|
+ validators,
|
|
+ true));
|
|
+ } catch (final RuntimeException e) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE D-406: the highest round element 3 may carry from H_hdr. No honest round gets near it (the QBFT round timer doubles each
|
|
+ * round), and it keeps the rotation arithmetic, which upstream does in int, in range. The second client applies the same bound.
|
|
+ */
|
|
+ static final int MAX_ROUND = 1024;
|
|
+
|
|
+ /**
|
|
+ * AERE D-406: whether {@code coinbase} is the proposer of some round 0..round at this height, i.e. could have BUILT the block
|
|
+ * (a block is built by the proposer of the round it is first proposed in, and a re-proposal keeps its coinbase). The rotation is
|
|
+ * periodic in n, so rounds 0..min(round, n - 1) cover the set. The second client has required exactly this since D-331.
|
|
+ */
|
|
+ static boolean builtByAProposerUpTo(
|
|
+ final long h, final int round, final BlockHeader parent, final Collection<Address> validators, final Address coinbase) {
|
|
+ final int last = Math.min(round, validators.size() - 1);
|
|
+ for (int r = 0; r <= last; r++) {
|
|
+ try {
|
|
+ if (BftProposerSelector.selectProposerForRound(new ConsensusRoundIdentifier(h, r), parent.getCoinbase(), validators, true)
|
|
+ .equals(coinbase)) {
|
|
+ return true;
|
|
+ }
|
|
+ } catch (final RuntimeException e) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Why a header at or above H_hdr is refused, if it is.
|
|
+ *
|
|
+ * @param header the header
|
|
+ * @param parent its parent, or null (then only the coinbase's seal can be admitted)
|
|
+ * @return the refusal, or empty
|
|
+ */
|
|
+ public Optional<String> refusal(final BlockHeader header, final BlockHeader parent) {
|
|
+ final long h = header.getNumber();
|
|
+ final BftExtraData ed;
|
|
+ try {
|
|
+ ed = codec.decode(header);
|
|
+ } catch (final RuntimeException e) {
|
|
+ return Optional.of("AERE PQ HEADER: block " + h + " extraData does not decode: " + e.getMessage());
|
|
+ }
|
|
+ if (!ed.getSeals().isEmpty()) {
|
|
+ return Optional.of(
|
|
+ "AERE PQ HEADER: block " + h + " carries " + ed.getSeals().size()
|
|
+ + " ECDSA committed seal(s); from H_hdr " + AerePqHeaderSeal.headerBlock() + " the element MUST be empty");
|
|
+ }
|
|
+ if (ed.getPqProposerSeal().isEmpty()) {
|
|
+ return Optional.of("AERE PQ HEADER: block " + h + " carries no proposer seal (element 6) from H_hdr");
|
|
+ }
|
|
+ // AERE D-406: the round bound, and with the parent, the builder: the coinbase is the proposer of some round up to element 3
|
|
+ if (ed.getRound() < 0 || ed.getRound() > MAX_ROUND) {
|
|
+ return Optional.of("AERE PQ HEADER: block " + h + " round " + ed.getRound() + " in element 3 is outside 0.." + MAX_ROUND);
|
|
+ }
|
|
+ if (parent != null
|
|
+ && !ed.getValidators().isEmpty()
|
|
+ && !builtByAProposerUpTo(h, ed.getRound(), parent, ed.getValidators(), header.getCoinbase())) {
|
|
+ return Optional.of(
|
|
+ "AERE PQ HEADER: block " + h + " coinbase " + header.getCoinbase() + " is not the proposer of any round 0.."
|
|
+ + ed.getRound() + " at this height, so it did not build the block");
|
|
+ }
|
|
+ final FalconSeal ps = ed.getPqProposerSeal().get();
|
|
+ final Optional<Address> id = AerePqIdentity.v3IdAt(h, ps.getValidatorIndex());
|
|
+ if (id.isEmpty()) {
|
|
+ return Optional.of(
|
|
+ "AERE PQ HEADER: block " + h + " proposer seal index " + ps.getValidatorIndex() + " names no row of the v3 epoch in force");
|
|
+ }
|
|
+ if (!id.get().equals(header.getCoinbase())) {
|
|
+ // AERE D-406: a re-proposed block carries the seal of the proposer of the round it was committed in
|
|
+ final Optional<Address> roundProposer = proposerOfRound(h, ed.getRound(), parent, ed.getValidators());
|
|
+ if (roundProposer.isEmpty() || !roundProposer.get().equals(id.get())) {
|
|
+ return Optional.of(
|
|
+ "AERE PQ HEADER: block " + h + " proposer seal of index " + ps.getValidatorIndex() + " (id " + id.get()
|
|
+ + ") but coinbase " + header.getCoinbase()
|
|
+ + (ed.getRound() > 0
|
|
+ ? roundProposer
|
|
+ .map(p -> " and the proposer of round " + ed.getRound() + " is " + p)
|
|
+ .orElse(" and the proposer of round " + ed.getRound() + " is not known without the parent")
|
|
+ : "")
|
|
+ + " - a seal cannot vouch for another proposer");
|
|
+ }
|
|
+ }
|
|
+ final Bytes32 message;
|
|
+ try {
|
|
+ message =
|
|
+ PqAnchor.proposalMessage(
|
|
+ chainId, h, ed.getRound(), new BftBlockHashing(codec).calculateDataHashForCommittedSeal(header).getBytes());
|
|
+ } catch (final RuntimeException e) {
|
|
+ return Optional.of("AERE PQ HEADER: block " + h + " proposal message cannot be built: " + e.getMessage());
|
|
+ }
|
|
+ final boolean ok;
|
|
+ try {
|
|
+ ok = verifier.verify(h, ps.getValidatorIndex(), message, ps.getSignature());
|
|
+ } catch (final RuntimeException e) {
|
|
+ return Optional.of("AERE PQ HEADER: block " + h + " proposer seal verification threw: " + e.getMessage());
|
|
+ }
|
|
+ return ok
|
|
+ ? Optional.empty()
|
|
+ : Optional.of("AERE PQ HEADER: block " + h + " proposer seal of index " + ps.getValidatorIndex() + " does not verify");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean includeInLightValidation() {
|
|
+ return belowHdr.includeInLightValidation();
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/AereIdentityHeaderTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/AereIdentityHeaderTest.java
|
|
new file mode 100644
|
|
index 0000000000..e51e617a97
|
|
--- /dev/null
|
|
+++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/AereIdentityHeaderTest.java
|
|
@@ -0,0 +1,144 @@
|
|
+/*
|
|
+ * AERE AIP-22 stage 3: the identity switch on the IMPORT path - the committed seals of a real header.
|
|
+ *
|
|
+ * Four node keys seal a QBFT header (BftExtraDataFixture signs each committed seal over the
|
|
+ * committed-seal hash of that very header, as a live committer does). The committers recovered from
|
|
+ * it, through BOTH places upstream recovers them (BftBlockInterface.getCommitters for the header
|
|
+ * rules, BftBlockHashing.recoverCommitterAddresses for the rest), must be the v3 ids from H_id, and
|
|
+ * the classical addresses one block below H_id or with the switch disarmed. That is exactly what lets
|
|
+ * BftCommitSealsValidationRule accept a header sealed by ids against a validator set of ids.
|
|
+ */
|
|
+package org.hyperledger.besu.consensus.qbft;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftBlockHeaderFunctions;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraDataFixture;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+import java.util.TreeSet;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+public class AereIdentityHeaderTest {
|
|
+
|
|
+ private static final long CHAIN = 28001;
|
|
+ private static final long H_ID = 20;
|
|
+ private final QbftExtraDataCodec codec = new QbftExtraDataCodec();
|
|
+ private final List<NodeKey> keys = new ArrayList<>();
|
|
+ private final List<Address> addr = new ArrayList<>();
|
|
+ private final List<Address> ids = new ArrayList<>();
|
|
+
|
|
+ @BeforeEach
|
|
+ public void registry() {
|
|
+ final long bind = 10;
|
|
+ final List<PqRegistryV3.Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < 4; i++) {
|
|
+ final NodeKey k = NodeKeyUtils.generate();
|
|
+ keys.add(k);
|
|
+ addr.add(Util.publicKeyToAddress(k.getPublicKey()));
|
|
+ final SealScheme f = SealSchemes.FALCON_512;
|
|
+ final SealScheme.GeneratedPair p = f.generate(SecureRandomProvider.createSecureRandom());
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(p.publicRegistryForm(), 0, std, 1, 896);
|
|
+ final byte[] id = PqRegistryV3.idOf(std);
|
|
+ final byte[] pop =
|
|
+ f.sign(
|
|
+ p.privateKey(),
|
|
+ PqRegistryV3.popMessage(CHAIN, bind, 4, i, id, f.wireId(), std).toArrayUnsafe())
|
|
+ .orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> km = new TreeMap<>();
|
|
+ km.put(f.wireId() & 0xff, new PqRegistryV3.Key(f, std, pop));
|
|
+ final Bytes32 rh =
|
|
+ PqRegistryV3.rowHash(
|
|
+ CHAIN, bind, 4, new PqRegistryV3.Row(i, id, km, null, Map.of(), null, null));
|
|
+ final SECPSignature claim = k.sign(PqRegistryV3.claimDigest(CHAIN, rh));
|
|
+ rows.add(
|
|
+ new PqRegistryV3.Row(
|
|
+ i, id, km, null, Map.of(), addr.get(i).getBytes().toArrayUnsafe(),
|
|
+ claim.encodedBytes().toArrayUnsafe()));
|
|
+ ids.add(Address.wrap(Bytes.wrap(id)));
|
|
+ }
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : rows) {
|
|
+ hashes.add(PqRegistryV3.rowHash(CHAIN, bind, 4, r));
|
|
+ }
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(hashes);
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(
|
|
+ bind,
|
|
+ new PqRegistryV3.Registry(
|
|
+ CHAIN, bind, 4, rows, hashes, root, PqRegistryV3.registryHash(CHAIN, bind, 4, root)));
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs));
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ /** A header at this height, listing these validators, sealed by all four keys. */
|
|
+ private BlockHeader sealedHeader(final long number, final List<Address> validators) {
|
|
+ final BlockHeaderTestFixture b = new BlockHeaderTestFixture();
|
|
+ b.number(number);
|
|
+ b.gasLimit(5000);
|
|
+ b.timestamp(6 * number);
|
|
+ b.coinbase(validators.get(0));
|
|
+ b.blockHeaderFunctions(BftBlockHeaderFunctions.forCommittedSeal(codec));
|
|
+ final BftExtraData ed =
|
|
+ BftExtraDataFixture.createExtraData(
|
|
+ b.buildHeader(),
|
|
+ Bytes.wrap(new byte[BftExtraDataCodec.EXTRA_VANITY_LENGTH]),
|
|
+ Optional.empty(),
|
|
+ new ArrayList<>(new TreeSet<>(validators)),
|
|
+ keys,
|
|
+ 0,
|
|
+ codec);
|
|
+ b.extraData(codec.encode(ed));
|
|
+ return b.buildHeader();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHidTheCommittersOfARealHeaderAreTheIds() {
|
|
+ final BlockHeader h = sealedHeader(H_ID, ids);
|
|
+ assertThat(new BftBlockInterface(codec).getCommitters(h)).containsExactlyElementsOf(ids);
|
|
+ assertThat(new BftBlockHashing(codec).recoverCommitterAddresses(h, codec.decode(h)))
|
|
+ .containsExactlyElementsOf(ids);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void belowHidAndDisarmedTheyAreTheAddresses() {
|
|
+ final BlockHeader below = sealedHeader(H_ID - 1, addr);
|
|
+ assertThat(new BftBlockInterface(codec).getCommitters(below)).containsExactlyElementsOf(addr);
|
|
+ final BlockHeader at = sealedHeader(H_ID, ids);
|
|
+ AerePqIdentity.uninstall();
|
|
+ assertThat(new BftBlockInterface(codec).getCommitters(at)).containsExactlyElementsOf(addr);
|
|
+ assertThat(new BftBlockHashing(codec).recoverCommitterAddresses(at, codec.decode(at)))
|
|
+ .containsExactlyElementsOf(addr);
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDisarmedWindowTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDisarmedWindowTest.java
|
|
old mode 100755
|
|
new mode 100644
|
|
index 9451ec7b7f..e7604a4fca
|
|
--- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDisarmedWindowTest.java
|
|
+++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorDisarmedWindowTest.java
|
|
@@ -122,46 +122,46 @@ public class PqAnchorDisarmedWindowTest {
|
|
|
|
private final LocalRegistry registry = new LocalRegistry();
|
|
private final PqAnchorDigestRule r1 = new PqAnchorDigestRule(live);
|
|
private final PqAnchorSealsRule r2 = new PqAnchorSealsRule(live, registry);
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// The heights under test really are anchor heights. Without this the file measures nothing.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void everyHeightUnderTestIsAnAnchorHeightOfTheLiveConfiguration() {
|
|
for (final long height :
|
|
List.of(BEFORE, OFF_FIRST, OFF_MIDDLE, OFF_LAST, LOW_FIRST, LOW_MIDDLE, LOW_LAST, AFTER)) {
|
|
assertThat(live.anchorAppliesAt(height))
|
|
.describedAs("height %d must be one the rules judge, or this file proves nothing", height)
|
|
.isTrue();
|
|
assertThat(live.minSealsAt(height))
|
|
.describedAs("the schedule asks for three seals at height %d", height)
|
|
.isEqualTo(3);
|
|
}
|
|
- assertThat(PqAnchorLapse.isDisarmed(OFF_FIRST)).isTrue();
|
|
- assertThat(PqAnchorLapse.isDisarmed(OFF_LAST)).isTrue();
|
|
- assertThat(PqAnchorLapse.isDisarmed(BEFORE)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(LOW_FIRST)).isFalse();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOW_FIRST)).hasValue(1);
|
|
- assertThat(PqAnchorLapse.historicMinSeals(AFTER)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, OFF_FIRST)).isTrue();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, OFF_LAST)).isTrue();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, BEFORE)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, LOW_FIRST)).isFalse();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOW_FIRST)).hasValue(1);
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, AFTER)).isEmpty();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// RANGE 1, nothing in force: a header of the shape the chain holds is accepted by both rules.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void r1AcceptsAHeaderOfTheFirstRangeAsWritten() {
|
|
for (final long height : List.of(OFF_FIRST, OFF_MIDDLE, OFF_LAST)) {
|
|
final BlockHeader parent = parentHeader(height - 1L);
|
|
final BlockHeader block = unenforcedHeader(height, parent, ARRIVAL_ORDER);
|
|
assertThat(r1.validate(block, parent))
|
|
.describedAs(
|
|
"height %d carries the client version string in vanityData and a certificate in "
|
|
+ "arrival order; that is what the chain holds, and a node syncing from genesis "
|
|
+ "must be able to pass it",
|
|
height)
|
|
.isTrue();
|
|
}
|
|
}
|
|
@@ -366,43 +366,43 @@ public class PqAnchorDisarmedWindowTest {
|
|
assertThat(r1.validate(unenforcedHeader(LOW_FIRST, lowParent, ARRIVAL_ORDER), lowParent))
|
|
.isFalse();
|
|
|
|
// And the far end of the lowered range, to one anchor step, on the threshold.
|
|
final BlockHeader lowLastParent = parentHeader(LOW_LAST - 1L);
|
|
final ProtocolContext context = contextWith(VALIDATORS);
|
|
assertThat(r2.validate(honestBlock(LOW_LAST, lowLastParent, List.of(0)), lowLastParent, context))
|
|
.isTrue();
|
|
final BlockHeader afterParent = parentHeader(AFTER - 1L);
|
|
assertThat(r2.validate(honestBlock(AFTER, afterParent, List.of(0)), afterParent, context))
|
|
.isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void theBoundsAreExactToOneBlockOnBothRules() {
|
|
// The heights either side of the bounds are not anchor heights, so both rules stand down there
|
|
// for the ordinary reason. Asserted so that "accepted" at OFF_FIRST - 1 is not mistaken for the
|
|
// exception having leaked one block down.
|
|
assertThat(live.anchorAppliesAt(OFF_FIRST - 1L)).isFalse();
|
|
assertThat(live.anchorAppliesAt(OFF_LAST + 1L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(OFF_FIRST - 1L)).isFalse();
|
|
- assertThat(PqAnchorLapse.isDisarmed(OFF_LAST + 1L)).isFalse();
|
|
- assertThat(PqAnchorLapse.historicMinSeals(LOW_LAST + 1L)).isEmpty();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, OFF_FIRST - 1L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.isDisarmed(PqAnchorLapse.CHAIN_ID, OFF_LAST + 1L)).isFalse();
|
|
+ assertThat(PqAnchorLapse.historicMinSeals(PqAnchorLapse.CHAIN_ID, LOW_LAST + 1L)).isEmpty();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// What the exception deliberately does NOT relax, at any height.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
@Test
|
|
public void insideTheFirstRangeARepeatedIndexIsStillRefusedByBothRules() {
|
|
// Sortedness fixes one accepted order for a given set; distinctness is what makes "repeat one
|
|
// seal to inflate the count" unrepresentable. Measured on every header of the range: distinct
|
|
// in all of them. So this refusal costs nothing and keeps the attack unrepresentable.
|
|
final BlockHeader parent = parentHeader(OFF_FIRST - 1L);
|
|
final BlockHeader repeated = unenforcedHeader(OFF_FIRST, parent, List.of(2, 6, 2));
|
|
assertThat(r1.validate(repeated, parent)).isFalse();
|
|
assertThat(r2.validate(repeated, parent, contextWith(VALIDATORS))).isFalse();
|
|
|
|
// Positive control: the same rule at the same height accepts the distinct version.
|
|
final BlockHeader distinct = unenforcedHeader(OFF_FIRST, parent, ARRIVAL_ORDER);
|
|
assertThat(r1.validate(distinct, parent)).isTrue();
|
|
assertThat(r2.validate(distinct, parent, contextWith(VALIDATORS))).isTrue();
|
|
@@ -411,72 +411,146 @@ public class PqAnchorDisarmedWindowTest {
|
|
@Test
|
|
public void insideTheFirstRangeAnUndecodableHeaderIsStillRefused() {
|
|
final BlockHeader parent = parentHeader(OFF_FIRST - 1L);
|
|
final BlockHeader garbage =
|
|
header(OFF_FIRST, parent.getHash(), Bytes.fromHexString("0xdeadbeef"));
|
|
assertThat(r1.validate(garbage, parent)).isFalse();
|
|
assertThat(r2.validate(garbage, parent, contextWith(VALIDATORS))).isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void belowTheActivationHeightNothingIsJudgedAtAll() {
|
|
// The ranges sit far above H, so this only restates the height gate; it is here because a
|
|
// future edit that moved the range gates ABOVE the height gate would make the rules decode
|
|
// headers on the whole existing chain, which is the property that lets this binary be warmed.
|
|
final BlockHeader parent = parentHeader(H_LIVE - 2L);
|
|
final BlockHeader block = unenforcedHeader(H_LIVE - 1L, parent, ARRIVAL_ORDER);
|
|
assertThat(r1.validate(block, parent)).isTrue();
|
|
assertThat(r2.validate(block, parent, contextWith(VALIDATORS))).isTrue();
|
|
}
|
|
|
|
+ // -----------------------------------------------------------------------------------------------
|
|
+ // D-428 (2026-09-28): the ranges are facts about chain 2800. The same heights on ANY other chain are
|
|
+ // judged by the plain rules, as the second client does. Each case carries its positive control, so a
|
|
+ // refusal here cannot come from a signature made for the wrong chain.
|
|
+ // -----------------------------------------------------------------------------------------------
|
|
+
|
|
+ private static final long OTHER_CHAIN = 28001L;
|
|
+
|
|
+ private final PqAnchorConfig otherChain =
|
|
+ new PqAnchorConfig(
|
|
+ OTHER_CHAIN,
|
|
+ H_LIVE,
|
|
+ Map.of(H_LIVE, 0, 13_034_000L, 3),
|
|
+ OptionalInt.empty(),
|
|
+ false,
|
|
+ OptionalInt.empty(),
|
|
+ OptionalInt.of(INTERVAL));
|
|
+
|
|
+ private final PqAnchorDigestRule r1Other = new PqAnchorDigestRule(otherChain);
|
|
+ private final PqAnchorSealsRule r2Other = new PqAnchorSealsRule(otherChain, registry);
|
|
+
|
|
+ @Test
|
|
+ public void onAnotherChainTheFirstRangeIsJudgedByThePlainRules() {
|
|
+ for (final long height : List.of(OFF_FIRST, OFF_MIDDLE, OFF_LAST)) {
|
|
+ final BlockHeader parent = parentHeader(height - 1L);
|
|
+ final ProtocolContext context = contextWith(VALIDATORS);
|
|
+ final BlockHeader unenforced = unenforcedHeader(height, parent, ARRIVAL_ORDER);
|
|
+ assertThat(r1.validate(unenforced, parent))
|
|
+ .describedAs("positive control: on chain 2800 height %d is inside the first range", height)
|
|
+ .isTrue();
|
|
+ assertThat(r1Other.validate(unenforced, parent))
|
|
+ .describedAs("on chain %d there was no lapse: no digest must be refused at %d", OTHER_CHAIN, height)
|
|
+ .isFalse();
|
|
+ assertThat(r2Other.validate(unenforced, parent, context))
|
|
+ .describedAs("on chain %d the arrival order and the missing digest are refused at %d", OTHER_CHAIN, height)
|
|
+ .isFalse();
|
|
+ final BlockHeader honest = honestBlockOn(OTHER_CHAIN, height, parent, List.of(0, 1, 2));
|
|
+ assertThat(r1Other.validate(honest, parent))
|
|
+ .describedAs("positive control: an honest header OF chain %d is accepted at %d", OTHER_CHAIN, height)
|
|
+ .isTrue();
|
|
+ assertThat(r2Other.validate(honest, parent, context)).isTrue();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void onAnotherChainTheSecondRangeKeepsTheScheduledThreshold() {
|
|
+ for (final long height : List.of(LOW_FIRST, LOW_MIDDLE, LOW_LAST)) {
|
|
+ final BlockHeader parent = parentHeader(height - 1L);
|
|
+ final ProtocolContext context = contextWith(VALIDATORS);
|
|
+ assertThat(r2.validate(honestBlock(height, parent, List.of(5)), parent, context))
|
|
+ .describedAs("positive control: on chain 2800 one seal passes at %d, the threshold in force then", height)
|
|
+ .isTrue();
|
|
+ assertThat(r2Other.validate(honestBlockOn(OTHER_CHAIN, height, parent, List.of(5)), parent, context))
|
|
+ .describedAs("on chain %d the threshold at %d is the scheduled three, not the 2800 lapse", OTHER_CHAIN, height)
|
|
+ .isFalse();
|
|
+ assertThat(r2Other.validate(honestBlockOn(OTHER_CHAIN, height, parent, List.of(0, 1, 5)), parent, context))
|
|
+ .describedAs("positive control: three seals OF chain %d pass at %d", OTHER_CHAIN, height)
|
|
+ .isTrue();
|
|
+ }
|
|
+ }
|
|
+
|
|
// -----------------------------------------------------------------------------------------------
|
|
// Helpers.
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A header of the shape the first range holds: the client version string in vanityData instead of
|
|
* a digest, and the certificate written in the order the commits arrived.
|
|
*/
|
|
private BlockHeader unenforcedHeader(
|
|
final long number, final BlockHeader parent, final List<Integer> indicesInArrivalOrder) {
|
|
return header(
|
|
number, parent.getHash(), extraData(CLIENT_VANITY, sealsFor(parent, indicesInArrivalOrder)));
|
|
}
|
|
|
|
/** A header whose digest is correctly bound but whose indices are left in arrival order. */
|
|
private BlockHeader digestBoundButUnsorted(
|
|
final long number, final BlockHeader parent, final List<Integer> indicesInArrivalOrder) {
|
|
final List<FalconSeal> seals = sealsFor(parent, indicesInArrivalOrder);
|
|
final Bytes32 digest =
|
|
PqAnchor.anchorDigest(CHAIN_ID, parent.getNumber(), parent.getHash().getBytes(), seals);
|
|
return header(number, parent.getHash(), extraData(digest, seals));
|
|
}
|
|
|
|
/** A header an honest proposer under the armed rules writes: digest bound, indices sorted. */
|
|
private BlockHeader honestBlock(
|
|
final long number, final BlockHeader parent, final List<Integer> indices) {
|
|
final List<FalconSeal> sorted = PqAnchor.sortedByIndex(sealsFor(parent, indices));
|
|
final Bytes32 digest =
|
|
PqAnchor.anchorDigest(CHAIN_ID, parent.getNumber(), parent.getHash().getBytes(), sorted);
|
|
return header(number, parent.getHash(), extraData(digest, sorted));
|
|
}
|
|
|
|
+ /** An honest header for ANY chain: the digest and the seals are computed for that chain (D-428). */
|
|
+ private BlockHeader honestBlockOn(
|
|
+ final long chain, final long number, final BlockHeader parent, final List<Integer> indices) {
|
|
+ final Bytes32 message = PqAnchor.commitMessage(chain, parent.getNumber(), parent.getHash().getBytes());
|
|
+ final List<FalconSeal> seals = new ArrayList<>();
|
|
+ for (final int index : indices) {
|
|
+ seals.add(new FalconSeal(index, LocalRegistry.sign(index, message)));
|
|
+ }
|
|
+ final List<FalconSeal> sorted = PqAnchor.sortedByIndex(seals);
|
|
+ final Bytes32 digest = PqAnchor.anchorDigest(chain, parent.getNumber(), parent.getHash().getBytes(), sorted);
|
|
+ return header(number, parent.getHash(), extraData(digest, sorted));
|
|
+ }
|
|
+
|
|
private List<FalconSeal> sealsFor(final BlockHeader parent, final List<Integer> indices) {
|
|
// One return, one mutability. An early return of an immutable empty list here is what
|
|
// errorprone's MixedMutabilityReturnType refuses, and it is refusing something real: the empty
|
|
// case is not special, it is the case where the loop runs zero times.
|
|
final Bytes32 message =
|
|
PqAnchor.commitMessage(CHAIN_ID, parent.getNumber(), parent.getHash().getBytes());
|
|
final List<FalconSeal> seals = new ArrayList<>();
|
|
for (final int index : indices) {
|
|
seals.add(new FalconSeal(index, LocalRegistry.sign(index, message)));
|
|
}
|
|
return seals;
|
|
}
|
|
|
|
private ProtocolContext contextWith(final Collection<Address> parentValidators) {
|
|
final ValidatorProvider validatorProvider =
|
|
mock(ValidatorProvider.class, withSettings().strictness(Strictness.LENIENT));
|
|
when(validatorProvider.getValidatorsForBlock(any())).thenReturn(parentValidators);
|
|
final BftContext bftContext =
|
|
mock(BftContext.class, withSettings().strictness(Strictness.LENIENT));
|
|
when(bftContext.getValidatorProvider()).thenReturn(validatorProvider);
|
|
diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorV2RulesTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorV2RulesTest.java
|
|
index 4c542fe876..867b46b6f6 100755
|
|
--- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorV2RulesTest.java
|
|
+++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqAnchorV2RulesTest.java
|
|
@@ -180,40 +180,74 @@ public class PqAnchorV2RulesTest {
|
|
@Test
|
|
public void r1RefusesAV2CertificateBelowTheV2HeightAndAV1CertificateAtIt() {
|
|
// v2 below V2: the anchor height V2-1 (interval absent => every height from H is an anchor height)
|
|
final BlockHeader parentBelow = parentHeader(V2 - 2L);
|
|
final BlockHeader v2Early = honestV2(V2 - 1L, parentBelow, certificate(parentBelow, 5, 5));
|
|
assertThat(r1.validate(v2Early, parentBelow)).isFalse();
|
|
// v1 at V2: an honest v1 header (correct v1 digest) is still refused, the form is wrong
|
|
final BlockHeader parent = parentHeader(V2 + 4L);
|
|
final BlockHeader v1Late = PqAnchorTestSupport.honestHeader(V2 + 5L, parent.getHash(),
|
|
List.of(PqAnchorTestSupport.seal(0), PqAnchorTestSupport.seal(1), PqAnchorTestSupport.seal(2)));
|
|
assertThat(r1.validate(v1Late, parent)).isFalse();
|
|
// control: the same v1 header is accepted by a rule whose V2 lies in the future
|
|
final PqAnchorConfig v1World = new PqAnchorConfig(
|
|
CHAIN_ID, H, Map.of(H, 0, V2, K), OptionalInt.empty(), false, OptionalInt.empty(),
|
|
OptionalInt.empty(), V2 + 1_000L);
|
|
assertThat(new PqAnchorDigestRule(v1World).validate(v1Late, parent)).isTrue();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------- R2
|
|
|
|
+ /**
|
|
+ * AIP-22 stage 2, per-scheme intervals: Falcon on the 32 grid and SLH-DSA on the 128 grid, both
|
|
+ * counted from H. At an anchor on the 128 grid the certificate must reach K SLH-DSA seals; at an
|
|
+ * anchor on the 32 grid only, K Falcon seals suffice, and SLH-DSA seals carried there anyway are a
|
|
+ * surplus that is VERIFIED (a tampered one still refuses), not ignored and not refused.
|
|
+ */
|
|
+ @Test
|
|
+ public void r2WithPerSchemeIntervalsDemandsSlhDsaOnlyOnItsGridAndVerifiesSurplus() throws Exception {
|
|
+ armHybrid("0:falcon-512/32+" + SLH + "/128");
|
|
+ long hybridAnchor = H;
|
|
+ while (hybridAnchor <= V2) {
|
|
+ hybridAnchor += 128L;
|
|
+ }
|
|
+ final long falconOnlyAnchor = hybridAnchor + 32L;
|
|
+ final BlockHeader p1 = parentHeader(hybridAnchor - 1L);
|
|
+ assertThat(r2.validate(honestV2(hybridAnchor, p1, certificate(p1, K, 0)), p1, context())).isFalse();
|
|
+ assertThat(r2.validate(honestV2(hybridAnchor, p1, certificate(p1, K, K)), p1, context())).isTrue();
|
|
+ final BlockHeader p2 = parentHeader(falconOnlyAnchor - 1L);
|
|
+ assertThat(r2.validate(honestV2(falconOnlyAnchor, p2, certificate(p2, K, 0)), p2, context())).isTrue();
|
|
+ assertThat(r2.validate(honestV2(falconOnlyAnchor, p2, certificate(p2, K, K)), p2, context())).isTrue();
|
|
+ final List<SchemeSeal> surplus = new ArrayList<>(certificate(p2, K, K));
|
|
+ for (int i = 0; i < surplus.size(); i++) {
|
|
+ final SchemeSeal s = surplus.get(i);
|
|
+ if (s.getSchemeWireId() == SealSchemes.SLH_DSA_128S.wireId()) {
|
|
+ final byte[] b = s.getSignature().toArray();
|
|
+ b[b.length / 2] ^= 1;
|
|
+ surplus.set(i, new SchemeSeal(s.getSchemeWireId(), s.getValidatorIndex(), Bytes.wrap(b)));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ surplus.sort(PqAnchorV2.CANONICAL);
|
|
+ assertThat(r2.validate(honestV2(falconOnlyAnchor, p2, surplus), p2, context())).isFalse();
|
|
+ }
|
|
+
|
|
@Test
|
|
public void r2AcceptsTheHonestV2HeaderWithKSealsPerScheme() {
|
|
final BlockHeader parent = parentHeader(V2 + 4L);
|
|
assertThat(r2.validate(honestV2(V2 + 5L, parent, certificate(parent, K, K)), parent, context())).isTrue();
|
|
// more than K of each is fine too: K is a floor
|
|
assertThat(r2.validate(honestV2(V2 + 5L, parent, certificate(parent, 5, 5)), parent, context())).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void r2RefusesAnSlhDsaSealFromAnIndexWithoutAFalconSeal() {
|
|
final BlockHeader parent = parentHeader(V2 + 4L);
|
|
final List<SchemeSeal> tagged = certificate(parent, K, K + 1); // SLH-DSA from index K has no Falcon
|
|
assertThat(r2.validate(honestV2(V2 + 5L, parent, tagged), parent, context())).isFalse();
|
|
}
|
|
|
|
@Test
|
|
public void r2RefusesACertificateShortOfOneScheme() {
|
|
final BlockHeader parent = parentHeader(V2 + 4L);
|
|
assertThat(r2.validate(honestV2(V2 + 5L, parent, certificate(parent, 5, K - 1)), parent, context()))
|
|
.describedAs("K Falcon seals and only K-1 SLH-DSA: the schedule demands K of EVERY scheme")
|
|
diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRuleTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRuleTest.java
|
|
new file mode 100644
|
|
index 0000000000..dfdc78622c
|
|
--- /dev/null
|
|
+++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqCheckpointRuleTest.java
|
|
@@ -0,0 +1,75 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.headervalidationrules;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 4: the checkpoint rule. At the checkpoint height only the checkpoint's hash passes;
|
|
+ * every other height passes; unset is inert; a malformed value refuses at load with its reason. The
|
|
+ * negative control of the runner plants "never refuse" at run time and turns the refusal probe red.
|
|
+ */
|
|
+class PqCheckpointRuleTest {
|
|
+
|
|
+ private static BlockHeader header(final long number, final long timestamp) {
|
|
+ return new BlockHeaderTestFixture().number(number).timestamp(timestamp).buildHeader();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void atTheCheckpointHeightOnlyTheCheckpointHashPassesAndAnotherHashIsRefused() {
|
|
+ final BlockHeader honest = header(2048, 1000);
|
|
+ final BlockHeader fork = header(2048, 1001);
|
|
+ assertThat(fork.getHash()).isNotEqualTo(honest.getHash());
|
|
+ final TreeMap<Long, Hash> cp = new TreeMap<>();
|
|
+ cp.put(2048L, honest.getHash());
|
|
+ final PqCheckpointRule rule = new PqCheckpointRule(cp);
|
|
+ assertThat(rule.validate(honest, null, null)).isTrue();
|
|
+ assertThat(rule.validate(fork, null, null)).isFalse();
|
|
+ // other heights are not judged by the checkpoint
|
|
+ assertThat(rule.validate(header(2047, 999), null, null)).isTrue();
|
|
+ assertThat(rule.validate(header(2049, 1002), null, null)).isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void unsetIsInertAndTheParserReadsSeveralCheckpoints() {
|
|
+ final PqCheckpointRule inert = new PqCheckpointRule(PqCheckpointRule.parse(null));
|
|
+ assertThat(inert.checkpoints()).isEmpty();
|
|
+ assertThat(inert.validate(header(2048, 1001), null, null)).isTrue();
|
|
+ assertThat(PqCheckpointRule.parse(" ")).isEmpty();
|
|
+ final String h1 = header(10, 1).getHash().toHexString();
|
|
+ final String h2 = header(20, 2).getHash().toHexString();
|
|
+ assertThat(PqCheckpointRule.parse("10:" + h1 + ", 20:" + h2)).hasSize(2).containsKeys(10L, 20L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aMalformedValueRefusesAtLoadWithItsReason() {
|
|
+ final String h = header(10, 1).getHash().toHexString();
|
|
+ for (final String bad : new String[] {"10", "x:" + h, "10:0x1234", "0:" + h, "10:" + h + ",10:" + h}) {
|
|
+ assertThatThrownBy(() -> PqCheckpointRule.parse(bad))
|
|
+ .as(bad)
|
|
+ .isInstanceOf(IllegalArgumentException.class)
|
|
+ .hasMessageStartingWith("AERE-PQC-CHECKPOINT-01");
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealStage5Test.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealStage5Test.java
|
|
new file mode 100644
|
|
index 0000000000..2a928bda7c
|
|
--- /dev/null
|
|
+++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/PqHeaderSealStage5Test.java
|
|
@@ -0,0 +1,478 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.consensus.qbft.headervalidationrules;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqFinality;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqHeaderSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.AerePqIdentity;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
|
|
+import org.hyperledger.besu.consensus.common.bft.BftExtraData;
|
|
+import org.hyperledger.besu.consensus.common.bft.FalconSeal;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqAnchor;
|
|
+import org.hyperledger.besu.consensus.common.bft.PqRegistryV3;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealScheme;
|
|
+import org.hyperledger.besu.consensus.common.bft.SealSchemes;
|
|
+import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
|
|
+import org.hyperledger.besu.crypto.SECPSignature;
|
|
+import org.hyperledger.besu.crypto.SecureRandomProvider;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKey;
|
|
+import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AttachedBlockHeaderValidationRule;
|
|
+import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
|
+import org.hyperledger.besu.ethereum.rlp.RLPException;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.TreeMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.bytes.Bytes32;
|
|
+import org.junit.jupiter.api.AfterEach;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AIP-22 stage 5 in the Besu-derived client, with real Falcon-512 keys generated for the run: the
|
|
+ * seventh extraData element (the proposer's seal) round-trips canonically, stays outside BOTH hashes,
|
|
+ * and the header rule admits a header from H_hdr iff its ECDSA committed seals are empty and the seal
|
|
+ * of its coinbase's index verifies over the proposal message recomputed from the stored header. Each
|
|
+ * refusal is asserted BY ITS REASON. Below H_hdr the upstream rule decides. The runner's negative
|
|
+ * control plants "never refuse" in the rule at run time and these probes turn red.
|
|
+ */
|
|
+public class PqHeaderSealStage5Test {
|
|
+
|
|
+ private static final long CHAIN = 28001;
|
|
+ private static final long BIND = 10;
|
|
+ private static final long H_ID = 10;
|
|
+ private static final long H_FIN = 20;
|
|
+ private static final long H_HDR = 30;
|
|
+ private static final int N = 4;
|
|
+ private static final SealScheme FALCON = SealSchemes.FALCON_512;
|
|
+ private static final QbftExtraDataCodec CODEC = new QbftExtraDataCodec();
|
|
+
|
|
+ private final List<SealScheme.PrivateHandle> falcon = new ArrayList<>();
|
|
+ private final List<Address> ids = new ArrayList<>();
|
|
+ private PqHeaderSealRule rule;
|
|
+
|
|
+ @BeforeEach
|
|
+ public void arm() {
|
|
+ final List<PqRegistryV3.Row> rows = new ArrayList<>();
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ final NodeKey nk = NodeKeyUtils.generate();
|
|
+ final SealScheme.GeneratedPair p = FALCON.generate(SecureRandomProvider.createSecureRandom());
|
|
+ falcon.add(p.privateKey());
|
|
+ final byte[] std = new byte[897];
|
|
+ std[0] = 0x09;
|
|
+ System.arraycopy(p.publicRegistryForm(), 0, std, 1, 896);
|
|
+ final byte[] id = PqRegistryV3.idOf(std);
|
|
+ final Bytes32 popMsg = PqRegistryV3.popMessage(CHAIN, BIND, N, i, id, FALCON.wireId(), std);
|
|
+ final byte[] pop = FALCON.sign(p.privateKey(), popMsg.toArrayUnsafe()).orElseThrow();
|
|
+ final TreeMap<Integer, PqRegistryV3.Key> keys = new TreeMap<>();
|
|
+ keys.put(FALCON.wireId() & 0xff, new PqRegistryV3.Key(FALCON, std, pop));
|
|
+ final PqRegistryV3.Row bare = new PqRegistryV3.Row(i, id, keys, null, Map.of(), null, null);
|
|
+ final SECPSignature claim = nk.sign(PqRegistryV3.claimDigest(CHAIN, PqRegistryV3.rowHash(CHAIN, BIND, N, bare)));
|
|
+ rows.add(
|
|
+ new PqRegistryV3.Row(
|
|
+ i, id, keys, null, Map.of(),
|
|
+ Util.publicKeyToAddress(nk.getPublicKey()).getBytes().toArrayUnsafe(),
|
|
+ claim.encodedBytes().toArrayUnsafe()));
|
|
+ ids.add(Address.wrap(Bytes.wrap(id)));
|
|
+ }
|
|
+ final List<Bytes32> hashes = new ArrayList<>();
|
|
+ for (final PqRegistryV3.Row r : rows) {
|
|
+ hashes.add(PqRegistryV3.rowHash(CHAIN, BIND, N, r));
|
|
+ }
|
|
+ final Bytes32 root = PqRegistryV3.merkleRoot(hashes);
|
|
+ final TreeMap<Long, PqRegistryV3.Registry> epochs = new TreeMap<>();
|
|
+ epochs.put(
|
|
+ BIND,
|
|
+ new PqRegistryV3.Registry(CHAIN, BIND, N, rows, hashes, root, PqRegistryV3.registryHash(CHAIN, BIND, N, root)));
|
|
+ AerePqHeaderSeal.uninstall();
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ AerePqIdentity.install(new AerePqIdentity.Config(H_ID, epochs, H_ID));
|
|
+ final AerePqFinality.SealVerifier v =
|
|
+ (h, i, m, s) ->
|
|
+ AerePqIdentity.v3KeyAt(h, i, "falcon-512")
|
|
+ .map(k -> FALCON.verifyRaw(k, m.toArrayUnsafe(), s.toArrayUnsafe()))
|
|
+ .orElse(false);
|
|
+ AerePqFinality.install(H_FIN, CHAIN, v);
|
|
+ AerePqHeaderSeal.install(H_HDR);
|
|
+ rule = new PqHeaderSealRule(sentinel(false), CODEC, CHAIN, v);
|
|
+ }
|
|
+
|
|
+ @AfterEach
|
|
+ public void disarm() {
|
|
+ AerePqHeaderSeal.uninstall();
|
|
+ AerePqFinality.uninstall();
|
|
+ AerePqIdentity.uninstall();
|
|
+ }
|
|
+
|
|
+ private static AttachedBlockHeaderValidationRule sentinel(final boolean answer) {
|
|
+ return (header, parent, ctx) -> answer;
|
|
+ }
|
|
+
|
|
+ private BftExtraData extra(final int round, final List<SECPSignature> seals, final Optional<FalconSeal> ps) {
|
|
+ return new BftExtraData(
|
|
+ Bytes.wrap(new byte[32]), seals, Optional.empty(), round, ids, Collections.emptyList(), Collections.emptyList(), ps);
|
|
+ }
|
|
+
|
|
+ private static BlockHeader header(final long h, final Address coinbase, final BftExtraData ed) {
|
|
+ return new BlockHeaderTestFixture().number(h).coinbase(coinbase).extraData(CODEC.encode(ed)).buildHeader();
|
|
+ }
|
|
+
|
|
+ /** The proposer seal of {@code signer} over the header's own proposal message (for the index {@code index}). */
|
|
+ private Optional<FalconSeal> sealOver(final BlockHeader unsealed, final int round, final int index, final int signer) {
|
|
+ final Bytes32 m =
|
|
+ PqAnchor.proposalMessage(
|
|
+ CHAIN, unsealed.getNumber(), round, new BftBlockHashing(CODEC).calculateDataHashForCommittedSeal(unsealed).getBytes());
|
|
+ return Optional.of(new FalconSeal(index, Bytes.wrap(FALCON.sign(falcon.get(signer), m.toArrayUnsafe()).orElseThrow())));
|
|
+ }
|
|
+
|
|
+ private BlockHeader sealedHeader(final long h, final int round, final int coinbase, final int index, final int signer) {
|
|
+ final BlockHeader unsealed = header(h, ids.get(coinbase), extra(round, List.of(), Optional.empty()));
|
|
+ return header(h, ids.get(coinbase), extra(round, List.of(), sealOver(unsealed, round, index, signer)));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theProposerSealIsTheSeventhElementCanonicalAndOutsideBothHashes() {
|
|
+ final BlockHeader unsealed = header(H_HDR, ids.get(1), extra(2, List.of(), Optional.empty()));
|
|
+ final BlockHeader sealed = sealedHeader(H_HDR, 2, 1, 1, 1);
|
|
+ final BftExtraData back = CODEC.decode(sealed);
|
|
+ assertThat(back.getPqProposerSeal()).isPresent();
|
|
+ assertThat(back.getPqProposerSeal().get().getValidatorIndex()).isEqualTo(1);
|
|
+ assertThat(back.getSeals()).isEmpty();
|
|
+ assertThat(back.getRound()).isEqualTo(2);
|
|
+ final BftBlockHashing hashing = new BftBlockHashing(CODEC);
|
|
+ assertThat(hashing.calculateHashOfBftBlockOnchain(sealed)).isEqualTo(hashing.calculateHashOfBftBlockOnchain(unsealed));
|
|
+ assertThat(hashing.calculateDataHashForCommittedSeal(sealed)).isEqualTo(hashing.calculateDataHashForCommittedSeal(unsealed));
|
|
+ assertThat(sealed.getExtraData().size()).isGreaterThan(unsealed.getExtraData().size() + 600);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void anEmptyCertificateSlotWithoutTheProposerSealIsNonCanonicalAndRefused() {
|
|
+ // six elements whose sixth is an explicit empty list: two encodings of one value, refused as before
|
|
+ final BytesValueRLPOutput o = new BytesValueRLPOutput();
|
|
+ o.startList();
|
|
+ o.writeBytes(Bytes.wrap(new byte[32]));
|
|
+ o.writeList(ids, (a, rlp) -> rlp.writeBytes(a.getBytes()));
|
|
+ o.writeEmptyList();
|
|
+ o.writeIntScalar(0);
|
|
+ o.writeEmptyList();
|
|
+ o.writeEmptyList();
|
|
+ o.endList();
|
|
+ assertThatThrownBy(() -> CODEC.decodeRaw(o.encoded())).hasMessageContaining("Non-canonical");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHhdrAHeaderWithAVerifiedProposerSealOfItsCoinbaseAndNoEcdsaSealIsAdmitted() {
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ assertThat(rule.refusal(sealedHeader(H_HDR, 0, i, i, i))).as("proposer %s", i).isEmpty();
|
|
+ }
|
|
+ assertThat(rule.validate(sealedHeader(H_HDR + 7, 3, 2, 2, 2), null, null)).isTrue();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void fromHhdrEachWayOfBeingWrongIsRefusedByItsReason() {
|
|
+ // an ECDSA committed seal present
|
|
+ final SECPSignature ecdsa = NodeKeyUtils.generate().sign(Bytes32.ZERO);
|
|
+ final BlockHeader unsealed = header(H_HDR, ids.get(0), extra(0, List.of(), Optional.empty()));
|
|
+ final BlockHeader withEcdsa = header(H_HDR, ids.get(0), extra(0, List.of(ecdsa), sealOver(unsealed, 0, 0, 0)));
|
|
+ assertThat(rule.refusal(withEcdsa)).get().asString().contains("MUST be empty");
|
|
+ // no proposer seal
|
|
+ assertThat(rule.refusal(unsealed)).get().asString().contains("no proposer seal");
|
|
+ // index 0 sealed by key 1
|
|
+ assertThat(rule.refusal(sealedHeader(H_HDR, 0, 0, 0, 1))).get().asString().contains("does not verify");
|
|
+ // a valid seal of index 1 on a header whose coinbase is id 0
|
|
+ assertThat(rule.refusal(sealedHeader(H_HDR, 0, 0, 1, 1))).get().asString().contains("cannot vouch");
|
|
+ // an index with no row
|
|
+ assertThat(rule.refusal(sealedHeader(H_HDR, 0, 0, N, 0))).get().asString().contains("names no row");
|
|
+ // a seal over another round than the header's
|
|
+ final BlockHeader r1 = header(H_HDR, ids.get(0), extra(1, List.of(), Optional.empty()));
|
|
+ final BlockHeader sealedAtRound0 = header(H_HDR, ids.get(0), extra(1, List.of(), sealOver(unsealed, 0, 0, 0)));
|
|
+ assertThat(rule.refusal(sealedAtRound0)).get().asString().contains("does not verify");
|
|
+ assertThat(rule.refusal(header(H_HDR, ids.get(0), extra(1, List.of(), sealOver(r1, 1, 0, 0))))).isEmpty();
|
|
+ }
|
|
+
|
|
+ // ---- AERE D-406 (2026-09-25): a block re-proposed at round r carries the seal of round r's proposer ----
|
|
+
|
|
+ /** The validator list as a real header stores it: ascending. */
|
|
+ private List<Address> sortedIds() {
|
|
+ final List<Address> s = new ArrayList<>(ids);
|
|
+ Collections.sort(s);
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The proposer of round r written HERE, independently of the rule (which calls upstream's selector): the
|
|
+ * existing-proposer case is list[(indexOf(prev) + 1 + r) mod n], the missing-proposer case seeds from the first
|
|
+ * validator strictly above prev (the first if none) with no +1.
|
|
+ */
|
|
+ private static Address expectedProposer(final List<Address> sorted, final Address prev, final int r) {
|
|
+ final int n = sorted.size();
|
|
+ final int i = sorted.indexOf(prev);
|
|
+ if (i >= 0) {
|
|
+ return sorted.get((i + 1 + r) % n);
|
|
+ }
|
|
+ int seed = 0;
|
|
+ for (int k = 0; k < n; k++) {
|
|
+ if (sorted.get(k).compareTo(prev) > 0) {
|
|
+ seed = k;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return sorted.get((seed + r) % n);
|
|
+ }
|
|
+
|
|
+ private BlockHeader parentWithCoinbase(final long h, final Address coinbase) {
|
|
+ return new BlockHeaderTestFixture().number(h - 1).coinbase(coinbase).buildHeader();
|
|
+ }
|
|
+
|
|
+ /** A header at h, round r, built by {@code coinbase}, sealed as index {@code index} by key {@code signer}. */
|
|
+ private BlockHeader reproposed(final long h, final int round, final Address coinbase, final int index, final int signer) {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final BftExtraData bare =
|
|
+ new BftExtraData(
|
|
+ Bytes.wrap(new byte[32]), List.of(), Optional.empty(), round, sorted, Collections.emptyList(),
|
|
+ Collections.emptyList(), Optional.empty());
|
|
+ final BlockHeader unsealed = header(h, coinbase, bare);
|
|
+ final BftExtraData sealed =
|
|
+ new BftExtraData(
|
|
+ Bytes.wrap(new byte[32]), List.of(), Optional.empty(), round, sorted, Collections.emptyList(),
|
|
+ Collections.emptyList(), sealOver(unsealed, round, index, signer));
|
|
+ return header(h, coinbase, sealed);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aReProposedHeaderSealedByTheProposerOfItsRoundIsAdmittedOnlyWithItsParent() {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 5;
|
|
+ int judged = 0;
|
|
+ for (int p = 0; p < N; p++) {
|
|
+ final Address prev = sorted.get(p);
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ for (int r = 1; r < 2 * N; r++) {
|
|
+ final Address roundProposer = expectedProposer(sorted, prev, r);
|
|
+ if (roundProposer.equals(builder)) {
|
|
+ continue;
|
|
+ }
|
|
+ final int idx = ids.indexOf(roundProposer);
|
|
+ final BlockHeader hd = reproposed(h, r, builder, idx, idx);
|
|
+ final BlockHeader parent = parentWithCoinbase(h, prev);
|
|
+ assertThat(rule.refusal(hd, parent)).as("prev %s round %s", p, r).isEmpty();
|
|
+ assertThat(rule.validate(hd, parent, null)).as("prev %s round %s", p, r).isTrue();
|
|
+ // without the parent the round's proposer is not known: refused, and the reason says why
|
|
+ assertThat(rule.refusal(hd)).get().asString()
|
|
+ .contains("cannot vouch").contains("not known without the parent");
|
|
+ judged++;
|
|
+ }
|
|
+ }
|
|
+ // every (prev, round) pair whose round proposer differs from the builder was judged: 4 x (7 - 1) at N = 4
|
|
+ assertThat(judged).isEqualTo(N * (2 * N - 1 - 1));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void aReProposedHeaderSealedByAThirdValidatorIsRefusedAndTheReasonNamesTheRoundsProposer() {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 6;
|
|
+ final Address prev = sorted.get(0);
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ final int r = 1;
|
|
+ final Address roundProposer = expectedProposer(sorted, prev, r);
|
|
+ Address third = null;
|
|
+ for (final Address a : sorted) {
|
|
+ if (!a.equals(builder) && !a.equals(roundProposer)) {
|
|
+ third = a;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ final int idx = ids.indexOf(third);
|
|
+ final Optional<String> why = rule.refusal(reproposed(h, r, builder, idx, idx), parentWithCoinbase(h, prev));
|
|
+ assertThat(why).get().asString()
|
|
+ .contains("cannot vouch")
|
|
+ .contains("the proposer of round " + r + " is " + roundProposer);
|
|
+ // the round proposer's key over ANOTHER round than element 3: the id passes, the signature does not
|
|
+ final int rp = ids.indexOf(roundProposer);
|
|
+ final List<Address> s2 = sortedIds();
|
|
+ final BlockHeader atRound0 =
|
|
+ header(h, builder, new BftExtraData(Bytes.wrap(new byte[32]), List.of(), Optional.empty(), 0, s2,
|
|
+ Collections.emptyList(), Collections.emptyList(), Optional.empty()));
|
|
+ final BlockHeader wrongRound =
|
|
+ header(h, builder, new BftExtraData(Bytes.wrap(new byte[32]), List.of(), Optional.empty(), r, s2,
|
|
+ Collections.emptyList(), Collections.emptyList(), sealOver(atRound0, 0, rp, rp)));
|
|
+ assertThat(rule.refusal(wrongRound, parentWithCoinbase(h, prev))).get().asString().contains("does not verify");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theSealMustBeExactlyTheProposerOfRoundRNotOfAnEarlierRound() {
|
|
+ // found by the adversarial review of 2026-09-25: an implementation admitting ANY P(r') with r' <= r passed every probe above
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 9;
|
|
+ final Address prev = sorted.get(0);
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ final Address p1 = expectedProposer(sorted, prev, 1);
|
|
+ final Address p2 = expectedProposer(sorted, prev, 2);
|
|
+ assertThat(p1).isNotEqualTo(p2);
|
|
+ final int i1 = ids.indexOf(p1);
|
|
+ assertThat(rule.refusal(reproposed(h, 2, builder, i1, i1), parentWithCoinbase(h, prev))).get().asString()
|
|
+ .contains("cannot vouch").contains("the proposer of round 2 is " + p2);
|
|
+ final int i2 = ids.indexOf(p2);
|
|
+ assertThat(rule.refusal(reproposed(h, 2, builder, i2, i2), parentWithCoinbase(h, prev))).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void withTheParentTheCoinbaseMustBeTheProposerOfSomeRoundUpToElement3() {
|
|
+ // the second client has refused this since D-331; the Besu-derived rule did not, so the two judged such a header differently
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 10;
|
|
+ final Address prev = sorted.get(0);
|
|
+ final Address p1 = expectedProposer(sorted, prev, 1);
|
|
+ final Address p3 = expectedProposer(sorted, prev, 3);
|
|
+ final int i1 = ids.indexOf(p1);
|
|
+ // round 1, built by P(3) (a proposer of a LATER round), sealed by P(1): the seal is the round's, the builder is impossible
|
|
+ assertThat(rule.refusal(reproposed(h, 1, p3, i1, i1), parentWithCoinbase(h, prev))).get().asString()
|
|
+ .contains("is not the proposer of any round 0..1");
|
|
+ // and a coinbase-sealed header at round 0 whose coinbase is not P(0)
|
|
+ final int i3 = ids.indexOf(p3);
|
|
+ assertThat(rule.refusal(reproposed(h, 0, p3, i3, i3), parentWithCoinbase(h, prev))).get().asString()
|
|
+ .contains("is not the proposer of any round 0..0");
|
|
+ // without the parent the builder cannot be judged, and the coinbase's own seal is admitted as before
|
|
+ assertThat(rule.refusal(reproposed(h, 0, p3, i3, i3))).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theRoundInElement3IsBoundedAndTheBoundIsInclusive() {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 11;
|
|
+ final Address prev = sorted.get(2);
|
|
+ final int max = PqHeaderSealRule.MAX_ROUND;
|
|
+ // at the bound: a re-proposal sealed by P(max) is admitted (upstream's int arithmetic stays in range)
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ final Address pm = expectedProposer(sorted, prev, max);
|
|
+ final int im = ids.indexOf(pm);
|
|
+ final int ib = ids.indexOf(builder);
|
|
+ final Address sealer = pm.equals(builder) ? builder : pm;
|
|
+ final int is = sealer.equals(builder) ? ib : im;
|
|
+ assertThat(rule.refusal(reproposed(h, max, builder, is, is), parentWithCoinbase(h, prev))).isEmpty();
|
|
+ // above it: refused by the bound, with or without the parent, whoever sealed
|
|
+ assertThat(rule.refusal(reproposed(h, max + 1, builder, ib, ib), parentWithCoinbase(h, prev))).get().asString()
|
|
+ .contains("is outside 0.." + max);
|
|
+ assertThat(rule.refusal(reproposed(h, max + 1, builder, ib, ib))).get().asString().contains("is outside 0.." + max);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void atRoundZeroOnlyTheCoinbaseSealIsAdmittedEvenWithTheParent() {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 7;
|
|
+ final Address prev = sorted.get(1);
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ for (final Address other : sorted) {
|
|
+ if (other.equals(builder)) {
|
|
+ continue;
|
|
+ }
|
|
+ final int idx = ids.indexOf(other);
|
|
+ final Optional<String> why = rule.refusal(reproposed(h, 0, builder, idx, idx), parentWithCoinbase(h, prev));
|
|
+ assertThat(why).get().asString().contains("cannot vouch").doesNotContain("proposer of round");
|
|
+ }
|
|
+ final int b = ids.indexOf(builder);
|
|
+ assertThat(rule.refusal(reproposed(h, 0, builder, b, b), parentWithCoinbase(h, prev))).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void whenTheParentsProposerLeftTheSetTheRoundsProposerFollowsUpstreamsMissingProposerSeed() {
|
|
+ final List<Address> sorted = sortedIds();
|
|
+ final long h = H_HDR + 8;
|
|
+ // a parent proposer below every id (the seed is the first validator) and one above every id (it wraps to the first)
|
|
+ final Address below = Address.fromHexString("0x0000000000000000000000000000000000000001");
|
|
+ final Address above = Address.fromHexString("0xffffffffffffffffffffffffffffffffffffffff");
|
|
+ // and one strictly between the second and the third id, so the seed is the third (index 2), not the first
|
|
+ final byte[] mid = sorted.get(1).getBytes().toArrayUnsafe().clone();
|
|
+ int k = mid.length - 1;
|
|
+ while (k >= 0 && mid[k] == (byte) 0xff) {
|
|
+ mid[k--] = 0;
|
|
+ }
|
|
+ mid[k]++;
|
|
+ final Address middle = Address.wrap(Bytes.wrap(mid));
|
|
+ assertThat(middle.compareTo(sorted.get(1)) > 0 && middle.compareTo(sorted.get(2)) < 0).isTrue();
|
|
+ assertThat(expectedProposer(sorted, middle, 0)).isEqualTo(sorted.get(2));
|
|
+ int judged = 0;
|
|
+ for (final Address prev : List.of(below, above, middle)) {
|
|
+ final Address builder = expectedProposer(sorted, prev, 0);
|
|
+ for (int r = 1; r < N; r++) {
|
|
+ final Address rp = expectedProposer(sorted, prev, r);
|
|
+ final int idx = ids.indexOf(rp);
|
|
+ assertThat(rule.refusal(reproposed(h, r, builder, idx, idx), parentWithCoinbase(h, prev)))
|
|
+ .as("prev %s round %s", prev, r).isEmpty();
|
|
+ judged++;
|
|
+ }
|
|
+ }
|
|
+ assertThat(judged).isEqualTo(3 * (N - 1));
|
|
+ }
|
|
+
|
|
+ // ---- AERE D-415 (2026-09-25): the vanity field is exactly 32 bytes at EVERY height, in the codec, as in the second client ----
|
|
+
|
|
+ /** The genesis extraData of chains 2800 and 28001 (both a 32-zero vanity), as published. */
|
|
+ private static final String GENESIS_2800_EXTRA =
|
|
+ "0xf865a00000000000000000000000000000000000000000000000000000000000000000f83f94b5e768cb3117ea25175f51aa956b48691025c2a894f73bbbd26a82dbc769066550d8d4585eab2fc00d944bf6f91d84b37454544279cba152581ed6820044c080c0";
|
|
+ private static final String GENESIS_28001_EXTRA =
|
|
+ "0xf87aa00000000000000000000000000000000000000000000000000000000000000000f8549404211fd71c1eae94f560e7e173399c91c15fd9b394070d5e1534a367430307a6e56bef29ddff79c0e394b84ec13c5811264f60a8bc392634709558223ea694fb6be1504acf8262cf98669f7833b9cf1cbfabb9c080c0";
|
|
+ /** A real 32-byte vanity between anchors on 28001 today: the client version string, not a digest. */
|
|
+ private static final String VANITY_VERSIUNE = "0x626573752032362e342e302d616572652e312d643230333230312d7774396239";
|
|
+
|
|
+ private BlockHeader cuVanity(final long h, final Bytes vanity) {
|
|
+ final BftExtraData ed =
|
|
+ new BftExtraData(vanity, List.of(), Optional.empty(), 0, ids, Collections.emptyList(), Collections.emptyList(), Optional.empty());
|
|
+ return new BlockHeaderTestFixture().number(h).coinbase(ids.get(0)).extraData(CODEC.encode(ed)).buildHeader();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void theVanityFieldIsExactly32BytesAtEveryHeightAndBothGenesesStillDecode() {
|
|
+ // the two real geneses and a real between-anchors vanity decode as before (the check cannot touch the chain)
|
|
+ for (final String g : List.of(GENESIS_2800_EXTRA, GENESIS_28001_EXTRA)) {
|
|
+ assertThat(CODEC.decodeRaw(Bytes.fromHexString(g)).getVanityData().size()).as("genesis").isEqualTo(32);
|
|
+ }
|
|
+ assertThat(CODEC.decode(cuVanity(H_HDR - 5, Bytes.fromHexString(VANITY_VERSIUNE))).getVanityData().size()).isEqualTo(32);
|
|
+ // found by the differential fuzzer: a 0-, 31-, 33- or 64-byte vanity between anchors was admitted here and refused by the
|
|
+ // second client; now the codec refuses it at any height, above and below H_hdr, and the header rule reports the reason
|
|
+ for (final int n : new int[] {0, 31, 33, 64}) {
|
|
+ final Bytes v = Bytes.wrap(new byte[n]);
|
|
+ assertThatThrownBy(() -> CODEC.decode(cuVanity(H_HDR + 12, v))).as("vanity %s above H_hdr", n)
|
|
+ .isInstanceOf(RLPException.class).hasMessageContaining("AERE-D415");
|
|
+ assertThatThrownBy(() -> CODEC.decode(cuVanity(H_HDR - 5, v))).as("vanity %s below H_hdr", n)
|
|
+ .isInstanceOf(RLPException.class).hasMessageContaining("AERE-D415");
|
|
+ assertThat(rule.refusal(cuVanity(H_HDR + 12, v))).get().asString().contains("does not decode").contains("AERE-D415");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void belowHhdrTheUpstreamRuleDecidesAndHhdrNeedsHfin() {
|
|
+ final BlockHeader below = sealedHeader(H_HDR - 1, 0, 0, 0, 0);
|
|
+ assertThat(new PqHeaderSealRule(sentinel(false), CODEC, CHAIN, (h, i, m, s) -> true).validate(below, null, null)).isFalse();
|
|
+ assertThat(new PqHeaderSealRule(sentinel(true), CODEC, CHAIN, (h, i, m, s) -> false).validate(below, null, null)).isTrue();
|
|
+ assertThatThrownBy(() -> AerePqHeaderSeal.install(H_FIN - 1)).hasMessageStartingWith("AERE-PQC-HDR-01");
|
|
+ AerePqFinality.uninstall();
|
|
+ assertThatThrownBy(() -> AerePqHeaderSeal.install(H_HDR)).hasMessageStartingWith("AERE-PQC-HDR-01");
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java
|
|
index cb1d879a05..5c74d44292 100644
|
|
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java
|
|
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBalance.java
|
|
@@ -1,70 +1,86 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
|
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
public class EthGetBalance extends AbstractBlockParameterOrBlockHashMethod {
|
|
public EthGetBalance(final BlockchainQueries blockchainQueries) {
|
|
super(blockchainQueries);
|
|
}
|
|
|
|
public EthGetBalance(final Supplier<BlockchainQueries> blockchainQueries) {
|
|
super(blockchainQueries);
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return RpcMethod.ETH_GET_BALANCE.getMethodName();
|
|
}
|
|
|
|
@Override
|
|
protected BlockParameterOrBlockHash blockParameterOrBlockHash(
|
|
final JsonRpcRequestContext request) {
|
|
try {
|
|
return request.getRequiredParameter(1, BlockParameterOrBlockHash.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid block or block hash parameter (index 1)", RpcErrorType.INVALID_BLOCK_PARAMS, e);
|
|
}
|
|
}
|
|
|
|
+ // AERE D-FAZA2-04 (2026-09-10): an EMPTY answer from the state query means the world state for that
|
|
+ // block is not available (outside the node's state window, or not yet persisted); it never means
|
|
+ // "no such account" - fromAccount() fills a default for that. Upstream serialised the empty answer as
|
|
+ // a bare JSON null, which every client reads as a value. Here it is the same honest error that
|
|
+ // eth_getProof already returns: WORLD_STATE_UNAVAILABLE.
|
|
@Override
|
|
- protected String resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
+ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
final Address address;
|
|
try {
|
|
address = request.getRequiredParameter(0, Address.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid address parameter (index 0)", RpcErrorType.INVALID_ADDRESS_PARAMS, e);
|
|
}
|
|
return blockchainQueries
|
|
.get()
|
|
.accountBalance(address, blockHash)
|
|
.map(Quantity::create)
|
|
- .orElse(null);
|
|
+ .<Object>map(s -> s)
|
|
+ .orElseGet(
|
|
+ () ->
|
|
+ new JsonRpcErrorResponse(
|
|
+ request.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE));
|
|
}
|
|
}
|
|
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java
|
|
index 0c9194b0b3..52bc65eece 100644
|
|
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java
|
|
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetCode.java
|
|
@@ -1,68 +1,87 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
|
|
public class EthGetCode extends AbstractBlockParameterOrBlockHashMethod {
|
|
|
|
public EthGetCode(final BlockchainQueries blockchainQueries) {
|
|
super(blockchainQueries);
|
|
}
|
|
|
|
public EthGetCode(final Supplier<BlockchainQueries> blockchainQueries) {
|
|
super(blockchainQueries);
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return RpcMethod.ETH_GET_CODE.getMethodName();
|
|
}
|
|
|
|
@Override
|
|
protected BlockParameterOrBlockHash blockParameterOrBlockHash(
|
|
final JsonRpcRequestContext request) {
|
|
try {
|
|
return request.getRequiredParameter(1, BlockParameterOrBlockHash.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid block or block hash parameter (index 1)", RpcErrorType.INVALID_BLOCK_PARAMS, e);
|
|
}
|
|
}
|
|
|
|
+ // AERE D-FAZA2-04 (2026-09-10): an EMPTY answer from the state query means the world state for that
|
|
+ // block is not available (outside the node's state window, or not yet persisted); it never means
|
|
+ // "no such account" - fromAccount() fills a default for that. Upstream serialised the empty answer as
|
|
+ // a bare JSON null, which every client reads as a value. Here it is the same honest error that
|
|
+ // eth_getProof already returns: WORLD_STATE_UNAVAILABLE.
|
|
@Override
|
|
- protected String resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
+ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
final Address address;
|
|
try {
|
|
address = request.getRequiredParameter(0, Address.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid address parameter (index 0)", RpcErrorType.INVALID_ADDRESS_PARAMS, e);
|
|
}
|
|
- return getBlockchainQueries().getCode(address, blockHash).map(Bytes::toString).orElse(null);
|
|
+ return getBlockchainQueries()
|
|
+ .getCode(address, blockHash)
|
|
+ .map(Bytes::toString)
|
|
+ .<Object>map(s -> s)
|
|
+ .orElseGet(
|
|
+ () ->
|
|
+ new JsonRpcErrorResponse(
|
|
+ request.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE));
|
|
}
|
|
}
|
|
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java
|
|
index 22de0da444..b6a3e95eec 100644
|
|
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java
|
|
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetStorageAt.java
|
|
@@ -1,73 +1,89 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.datatypes.parameters.UInt256Parameter;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|
|
|
import org.apache.tuweni.units.bigints.UInt256;
|
|
|
|
public class EthGetStorageAt extends AbstractBlockParameterOrBlockHashMethod {
|
|
public EthGetStorageAt(final BlockchainQueries blockchainQueries) {
|
|
super(blockchainQueries);
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return RpcMethod.ETH_GET_STORAGE_AT.getMethodName();
|
|
}
|
|
|
|
@Override
|
|
protected BlockParameterOrBlockHash blockParameterOrBlockHash(
|
|
final JsonRpcRequestContext request) {
|
|
try {
|
|
return request.getRequiredParameter(2, BlockParameterOrBlockHash.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid block or block hash parameter (index 2)", RpcErrorType.INVALID_BLOCK_PARAMS, e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
- protected String resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
+ // AERE D-FAZA2-04 (2026-09-10): an EMPTY answer from the state query means the world state for that
|
|
+ // block is not available (outside the node's state window, or not yet persisted); it never means
|
|
+ // "no such account" - fromAccount() fills a default for that. Upstream serialised the empty answer as
|
|
+ // a bare JSON null, which every client reads as a value. Here it is the same honest error that
|
|
+ // eth_getProof already returns: WORLD_STATE_UNAVAILABLE.
|
|
+ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
final Address address;
|
|
try {
|
|
address = request.getRequiredParameter(0, Address.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid address parameter (index 0)", RpcErrorType.INVALID_ADDRESS_PARAMS, e);
|
|
}
|
|
final UInt256 position;
|
|
try {
|
|
position = request.getRequiredParameter(1, UInt256Parameter.class).getValue();
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid position parameter (index 1)", RpcErrorType.INVALID_POSITION_PARAMS, e);
|
|
}
|
|
return blockchainQueries
|
|
.get()
|
|
.storageAt(address, position, blockHash)
|
|
.map(UInt256::toHexString)
|
|
- .orElse(null);
|
|
+ .<Object>map(s -> s)
|
|
+ .orElseGet(
|
|
+ () ->
|
|
+ new JsonRpcErrorResponse(
|
|
+ request.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE));
|
|
}
|
|
}
|
|
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java
|
|
index 4e26f8ee98..291056a7af 100644
|
|
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java
|
|
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionCount.java
|
|
@@ -1,43 +1,50 @@
|
|
/*
|
|
* 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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
|
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
import com.google.common.base.Suppliers;
|
|
|
|
public class EthGetTransactionCount extends AbstractBlockParameterOrBlockHashMethod {
|
|
private final Supplier<TransactionPool> transactionPoolSupplier;
|
|
|
|
public EthGetTransactionCount(
|
|
final BlockchainQueries blockchain, final TransactionPool transactionPoolSupplier) {
|
|
this(Suppliers.ofInstance(blockchain), Suppliers.ofInstance(transactionPoolSupplier));
|
|
}
|
|
|
|
public EthGetTransactionCount(
|
|
final Supplier<BlockchainQueries> blockchain,
|
|
final Supplier<TransactionPool> transactionPoolSupplier) {
|
|
@@ -67,34 +74,46 @@ public class EthGetTransactionCount extends AbstractBlockParameterOrBlockHashMet
|
|
try {
|
|
address = request.getRequiredParameter(0, Address.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid address parameter (index 0)", RpcErrorType.INVALID_ADDRESS_PARAMS, e);
|
|
}
|
|
final long pendingNonce =
|
|
transactionPoolSupplier.get().getNextNonceForSender(address).orElse(0);
|
|
final long latestNonce =
|
|
getBlockchainQueries()
|
|
.getTransactionCount(
|
|
address, getBlockchainQueries().getBlockchain().getChainHead().getHash());
|
|
|
|
if (Long.compareUnsigned(pendingNonce, latestNonce) > 0) {
|
|
return Quantity.create(pendingNonce);
|
|
}
|
|
|
|
return Quantity.create(latestNonce);
|
|
}
|
|
|
|
+ // AERE D-FAZA2-04 (2026-09-10): an EMPTY answer from the state query means the world state for that
|
|
+ // block is not available (outside the node's state window, or not yet persisted); it never means
|
|
+ // "no such account" - fromAccount() fills a default for that. Upstream serialised the empty answer as
|
|
+ // a bare JSON null, which every client reads as a value. Here it is the same honest error that
|
|
+ // eth_getProof already returns: WORLD_STATE_UNAVAILABLE.
|
|
+ // Upstream folded the missing state into a nonce of 0 (`.orElse(0L)`), a FALSE 0x0 that a wallet
|
|
+ // signs with. Here the nonce is asked for as an Optional and the missing state is an error.
|
|
@Override
|
|
- protected String resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
+ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) {
|
|
final Address address;
|
|
try {
|
|
address = request.getRequiredParameter(0, Address.class);
|
|
} catch (JsonRpcParameterException e) {
|
|
throw new InvalidJsonRpcParameters(
|
|
"Invalid address parameter (index 0)", RpcErrorType.INVALID_ADDRESS_PARAMS, e);
|
|
}
|
|
- final long transactionCount = getBlockchainQueries().getTransactionCount(address, blockHash);
|
|
-
|
|
- return Quantity.create(transactionCount);
|
|
+ return getBlockchainQueries()
|
|
+ .getTransactionCountIfStateAvailable(address, blockHash)
|
|
+ .map(Quantity::create)
|
|
+ .<Object>map(s -> s)
|
|
+ .orElseGet(
|
|
+ () ->
|
|
+ new JsonRpcErrorResponse(
|
|
+ request.getRequest().getId(), RpcErrorType.WORLD_STATE_UNAVAILABLE));
|
|
}
|
|
}
|
|
diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java
|
|
index caa03d9ce8..b7e4c4524e 100644
|
|
--- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java
|
|
+++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.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/aere-drop-per-request-console-writes.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.api.query;
|
|
|
|
import static com.google.common.base.Preconditions.checkArgument;
|
|
import static org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher.BLOCKS_PER_BLOOM_CACHE;
|
|
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
|
|
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.LogsBloomFilter;
|
|
import org.hyperledger.besu.datatypes.Wei;
|
|
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
|
|
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
|
|
import org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.chain.TransactionLocation;
|
|
import org.hyperledger.besu.ethereum.core.Block;
|
|
import org.hyperledger.besu.ethereum.core.BlockBody;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
@@ -320,40 +326,53 @@ public class BlockchainQueries {
|
|
final Hash blockHash =
|
|
getBlockHeaderByNumber(blockNumber).map(BlockHeader::getHash).orElse(Hash.EMPTY);
|
|
|
|
return getTransactionCount(address, blockHash);
|
|
}
|
|
|
|
/**
|
|
* Returns the number of transactions sent from the given address in the block at the given hash.
|
|
*
|
|
* @param address The address whose sent transactions we want to count.
|
|
* @param blockHash The hash of the block being queried.
|
|
* @return The number of transactions sent from the given address.
|
|
*/
|
|
public long getTransactionCount(final Address address, final Hash blockHash) {
|
|
return getAndMapWorldState(
|
|
blockHash, worldState -> Optional.ofNullable(worldState.get(address)))
|
|
.map(Account::getNonce)
|
|
.orElse(0L);
|
|
}
|
|
|
|
+ /**
|
|
+ * AERE D-FAZA2-04: the nonce as an Optional that is EMPTY when the world state for the block is not
|
|
+ * available, so a caller can tell "state missing" from "nonce zero". {@link #getTransactionCount(Address,
|
|
+ * Hash)} keeps upstream's behaviour (0 when missing) for the callers that rely on it.
|
|
+ */
|
|
+ public Optional<Long> getTransactionCountIfStateAvailable(final Address address, final Hash blockHash) {
|
|
+ return getAndMapWorldState(
|
|
+ blockHash,
|
|
+ worldState ->
|
|
+ Optional.of(
|
|
+ Optional.ofNullable(worldState.get(address)).map(Account::getNonce).orElse(0L)));
|
|
+ }
|
|
+
|
|
/**
|
|
* Returns the number of transactions sent from the given address in the latest block.
|
|
*
|
|
* @param address The address whose sent transactions we want to count.
|
|
* @return The number of transactions sent from the given address.
|
|
*/
|
|
public long getTransactionCount(final Address address) {
|
|
return getTransactionCount(address, headBlockNumber());
|
|
}
|
|
|
|
/**
|
|
* Returns the number of ommers in the block at the given height.
|
|
*
|
|
* @param blockNumber The height of the block being queried.
|
|
* @return The number of ommers in the referenced block.
|
|
*/
|
|
public Optional<Integer> getOmmerCount(final long blockNumber) {
|
|
return blockchain.getBlockHashByNumber(blockNumber).flatMap(this::getOmmerCount);
|
|
}
|
|
|
|
@@ -905,41 +924,41 @@ public class BlockchainQueries {
|
|
for (long pos = offset; pos <= endOffset; pos++) {
|
|
BackendQuery.stopIfExpired(isQueryAlive);
|
|
try {
|
|
raf.readFully(bloomBuff);
|
|
} catch (final EOFException e) {
|
|
results.addAll(
|
|
matchingLogsUncached(
|
|
segmentStart + pos, segmentStart + endOffset, query, isQueryAlive));
|
|
break;
|
|
}
|
|
final LogsBloomFilter logsBloom = new LogsBloomFilter(bytesValue);
|
|
if (query.couldMatch(logsBloom)) {
|
|
results.addAll(
|
|
matchingLogs(
|
|
blockchain.getBlockHashByNumber(segmentStart + pos).orElseThrow(),
|
|
query,
|
|
isQueryAlive));
|
|
}
|
|
}
|
|
} catch (final IOException e) {
|
|
- e.printStackTrace(System.out);
|
|
+ // AERE D-434 (fbfb5f9ecd): removed printStackTrace(System.out) on the cached-log-blooms error path; a cheap malformed log query could otherwise spam the process console, bypassing log4j. LOG.error below records the exception.
|
|
LOG.error("Error reading cached log blooms", e);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
public List<LogWithMetadata> matchingLogs(
|
|
final Hash blockHash, final LogsQuery query, final Supplier<Boolean> isQueryAlive) {
|
|
try {
|
|
final Optional<BlockHeader> blockHeader = getBlockHeader(blockHash, isQueryAlive);
|
|
if (blockHeader.isEmpty()) {
|
|
return Collections.emptyList();
|
|
}
|
|
// receipts and transactions should exist if the header exists, so throwing is ok.
|
|
final List<TransactionReceipt> receipts = getReceipts(blockHash, isQueryAlive);
|
|
final List<Transaction> transactions = getTransactions(blockHash, isQueryAlive);
|
|
final long number = blockHeader.get().getNumber();
|
|
final long blockTimestamp = blockHeader.get().getTimestamp();
|
|
final boolean removed = getRemoved(blockHash, isQueryAlive);
|
|
|
|
final AtomicInteger logIndexOffset = new AtomicInteger();
|
|
@@ -998,76 +1017,119 @@ public class BlockchainQueries {
|
|
final int transactionIndex = transactionWithMetaData.getTransactionIndex().get();
|
|
final int logIndexOffset =
|
|
logIndexOffset(
|
|
transactionWithMetaData.getTransaction().getHash(), receipts, transactions);
|
|
|
|
return LogWithMetadata.generate(
|
|
logIndexOffset,
|
|
receipts.get(transactionIndex),
|
|
number,
|
|
blockHash,
|
|
blockTimestamp,
|
|
transactions.get(transactionIndex).getHash(),
|
|
transactionIndex,
|
|
removed);
|
|
|
|
} catch (final Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
+ // AERE D-109 (2026-09-10): the world state of a block that has JUST become the chain head is not
|
|
+ // available for a few milliseconds (measured on the live readers: 2-96 ms, occasionally >300 ms)
|
|
+ // after its header is; a query resolved against 'latest' in that window used to return
|
|
+ // Optional.empty, which JSON-RPC serialises as a bare null - a value Besu never returns otherwise
|
|
+ // for eth_getCode/getBalance/getStorageAt/getTransactionCount. Measured directly on a reader:
|
|
+ // ~1 in 5,000 'latest' queries, always within a few ms of an import, never for older blocks. So
|
|
+ // when the lookup fails for a header at (or within HEAD_WINDOW blocks of) the chain head, we look
|
|
+ // again a bounded number of times, with short pauses, before giving up. Older blocks are not
|
|
+ // retried: for them an empty result is the state window closing, and a retry would only add latency.
|
|
+ private static final long AERE_HEAD_WINDOW_BLOCKS = 2;
|
|
+ private static final long[] AERE_HEAD_STATE_RETRY_PAUSES_MS = {50, 100, 150, 300};
|
|
+
|
|
+
|
|
/**
|
|
* Wraps an operation on MutableWorldState with try-with-resources the corresponding block hash.
|
|
* This method provides access to the worldstate via a mapper function in order to ensure all uses
|
|
* of the MutableWorldState are subsequently closed, via the try-with-resources block.
|
|
*
|
|
* @param <U> return type of the operation on the MutableWorldState
|
|
* @param blockHash the block hash
|
|
* @param mapper Function which performs an operation on a MutableWorldState
|
|
* @return the world state at the block number
|
|
*/
|
|
public <U> Optional<U> getAndMapWorldState(
|
|
final Hash blockHash, final Function<MutableWorldState, ? extends Optional<U>> mapper) {
|
|
|
|
return blockchain
|
|
.getBlockHeader(blockHash)
|
|
.flatMap(
|
|
blockHeader -> {
|
|
- try (var ws =
|
|
- worldStateArchive
|
|
- .getWorldState(withBlockHeaderAndNoUpdateNodeHead(blockHeader))
|
|
- .orElse(null)) {
|
|
- if (ws != null) {
|
|
- return mapper.apply(ws);
|
|
+ int attempts = 0;
|
|
+ while (true) {
|
|
+ try (var ws =
|
|
+ worldStateArchive
|
|
+ .getWorldState(withBlockHeaderAndNoUpdateNodeHead(blockHeader))
|
|
+ .orElse(null)) {
|
|
+ if (ws != null) {
|
|
+ if (attempts > 0) {
|
|
+ LOG.info(
|
|
+ "AERE-D109: world state for {} became available after {} retr{}",
|
|
+ blockHeader.toLogString(),
|
|
+ attempts,
|
|
+ attempts == 1 ? "y" : "ies");
|
|
+ }
|
|
+ return mapper.apply(ws);
|
|
+ }
|
|
+ } catch (Exception ex) {
|
|
+ LOG.error(
|
|
+ "failed worldstate query for " + blockHash.getBytes().toShortHexString(), ex);
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ if (!aereShouldRetryHeadState(blockHeader, attempts)) {
|
|
+ break;
|
|
+ }
|
|
+ try {
|
|
+ Thread.sleep(AERE_HEAD_STATE_RETRY_PAUSES_MS[attempts]);
|
|
+ } catch (InterruptedException ie) {
|
|
+ Thread.currentThread().interrupt();
|
|
+ break;
|
|
}
|
|
- } catch (Exception ex) {
|
|
- LOG.error(
|
|
- "failed worldstate query for " + blockHash.getBytes().toShortHexString(), ex);
|
|
+ attempts++;
|
|
}
|
|
LOG.atDebug()
|
|
.setMessage("Failed to find worldstate for {}")
|
|
.addArgument(blockHeader.toLogString())
|
|
.log();
|
|
return Optional.empty();
|
|
});
|
|
}
|
|
|
|
+ // AERE D-109: retry only near the head, and only a bounded number of times.
|
|
+ boolean aereShouldRetryHeadState(final BlockHeader blockHeader, final int attempts) {
|
|
+ if (attempts >= AERE_HEAD_STATE_RETRY_PAUSES_MS.length) {
|
|
+ return false;
|
|
+ }
|
|
+ final long head = blockchain.getChainHeadBlockNumber();
|
|
+ return head - blockHeader.getNumber() <= AERE_HEAD_WINDOW_BLOCKS;
|
|
+ }
|
|
+
|
|
/**
|
|
* Wraps an operation on MutableWorldState with try-with-resources the corresponding block number
|
|
*
|
|
* @param <U> return type of the operation on the MutableWorldState
|
|
* @param blockNumber the block number
|
|
* @param mapper Function which performs an operation on a MutableWorldState returning type U
|
|
* @return the world state at the block number
|
|
*/
|
|
public <U> Optional<U> getAndMapWorldState(
|
|
final long blockNumber, final Function<MutableWorldState, ? extends Optional<U>> mapper) {
|
|
final Hash blockHash =
|
|
getBlockHeaderByNumber(blockNumber).map(BlockHeader::getHash).orElse(Hash.EMPTY);
|
|
return getAndMapWorldState(blockHash, mapper);
|
|
}
|
|
|
|
public Wei gasPrice() {
|
|
final Block chainHeadBlock = blockchain.getChainHeadBlock();
|
|
final var chainHeadHeader = chainHeadBlock.getHeader();
|
|
final long blockHeight = chainHeadHeader.getNumber();
|
|
|
|
diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AereStateUnavailableIsAnErrorTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AereStateUnavailableIsAnErrorTest.java
|
|
new file mode 100755
|
|
index 0000000000..d2caccd124
|
|
--- /dev/null
|
|
+++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AereStateUnavailableIsAnErrorTest.java
|
|
@@ -0,0 +1,138 @@
|
|
+/*
|
|
+ * 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
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.Mockito.mock;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
|
+import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
|
+import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-FAZA2-04: when the world state for the requested block is not available, the four state
|
|
+ * methods answer with the WORLD_STATE_UNAVAILABLE error, never with a bare null (or a nonce of 0).
|
|
+ * When the state IS available they answer as before.
|
|
+ */
|
|
+public class AereStateUnavailableIsAnErrorTest {
|
|
+
|
|
+ private static final Address ADDR = Address.fromHexString("0x1111111111111111111111111111111111111111");
|
|
+ private static final Hash BLOCK_HASH = Hash.fromHexStringLenient("0xabcd");
|
|
+ private static final long HEAD = 1000L;
|
|
+
|
|
+ private BlockchainQueries queries;
|
|
+
|
|
+ @BeforeEach
|
|
+ public void setUp() {
|
|
+ queries = mock(BlockchainQueries.class);
|
|
+ // the numeric block parameter path: number -> hash
|
|
+ when(queries.headBlockNumber()).thenReturn(HEAD);
|
|
+ when(queries.getBlockHashByNumber(HEAD)).thenReturn(Optional.of(BLOCK_HASH));
|
|
+ final BlockHeader header = mock(BlockHeader.class);
|
|
+ when(header.getBlockHash()).thenReturn(BLOCK_HASH);
|
|
+ when(queries.getBlockHeaderByNumber(HEAD)).thenReturn(Optional.of(header));
|
|
+ when(queries.getBlockHeaderByHash(BLOCK_HASH)).thenReturn(Optional.of(header));
|
|
+ }
|
|
+
|
|
+ private static JsonRpcRequestContext request(final String method, final Object... params) {
|
|
+ return new JsonRpcRequestContext(new JsonRpcRequest("2.0", method, params));
|
|
+ }
|
|
+
|
|
+ private static void assertWorldStateUnavailable(final JsonRpcResponse response) {
|
|
+ assertThat(response).isInstanceOf(JsonRpcErrorResponse.class);
|
|
+ assertThat(((JsonRpcErrorResponse) response).getErrorType())
|
|
+ .isEqualTo(RpcErrorType.WORLD_STATE_UNAVAILABLE);
|
|
+ }
|
|
+
|
|
+ private static Object result(final JsonRpcResponse response) {
|
|
+ assertThat(response).isInstanceOf(JsonRpcSuccessResponse.class);
|
|
+ return ((JsonRpcSuccessResponse) response).getResult();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getCodeWithoutStateIsAnError() {
|
|
+ when(queries.getCode(any(Address.class), any(Hash.class))).thenReturn(Optional.empty());
|
|
+ final EthGetCode method = new EthGetCode(queries);
|
|
+ assertWorldStateUnavailable(method.response(request("eth_getCode", ADDR.toHexString(), "0x3e8")));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getCodeWithStateAnswersAsBefore() {
|
|
+ when(queries.getCode(any(Address.class), any(Hash.class))).thenReturn(Optional.of(Bytes.fromHexString("0x6001")));
|
|
+ final EthGetCode method = new EthGetCode(queries);
|
|
+ assertThat(result(method.response(request("eth_getCode", ADDR.toHexString(), "0x3e8")))).isEqualTo("0x6001");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getBalanceWithoutStateIsAnError() {
|
|
+ when(queries.accountBalance(any(Address.class), any(Hash.class))).thenReturn(Optional.empty());
|
|
+ final EthGetBalance method = new EthGetBalance(queries);
|
|
+ assertWorldStateUnavailable(method.response(request("eth_getBalance", ADDR.toHexString(), "0x3e8")));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getBalanceWithStateAnswersAsBefore() {
|
|
+ when(queries.accountBalance(any(Address.class), any(Hash.class))).thenReturn(Optional.of(Wei.of(7)));
|
|
+ final EthGetBalance method = new EthGetBalance(queries);
|
|
+ assertThat(result(method.response(request("eth_getBalance", ADDR.toHexString(), "0x3e8")))).isEqualTo("0x7");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getStorageAtWithoutStateIsAnError() {
|
|
+ when(queries.storageAt(any(Address.class), any(UInt256.class), any(Hash.class))).thenReturn(Optional.empty());
|
|
+ final EthGetStorageAt method = new EthGetStorageAt(queries);
|
|
+ assertWorldStateUnavailable(method.response(request("eth_getStorageAt", ADDR.toHexString(), "0x0", "0x3e8")));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getStorageAtWithStateAnswersAsBefore() {
|
|
+ when(queries.storageAt(any(Address.class), any(UInt256.class), any(Hash.class))).thenReturn(Optional.of(UInt256.valueOf(5)));
|
|
+ final EthGetStorageAt method = new EthGetStorageAt(queries);
|
|
+ assertThat(result(method.response(request("eth_getStorageAt", ADDR.toHexString(), "0x0", "0x3e8"))))
|
|
+ .isEqualTo(UInt256.valueOf(5).toHexString());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getTransactionCountWithoutStateIsAnErrorNotZero() {
|
|
+ when(queries.getTransactionCountIfStateAvailable(any(Address.class), any(Hash.class))).thenReturn(Optional.empty());
|
|
+ final EthGetTransactionCount method = new EthGetTransactionCount(queries, mock(TransactionPool.class));
|
|
+ assertWorldStateUnavailable(method.response(request("eth_getTransactionCount", ADDR.toHexString(), "0x3e8")));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void getTransactionCountWithStateAnswersAsBefore() {
|
|
+ when(queries.getTransactionCountIfStateAvailable(any(Address.class), any(Hash.class))).thenReturn(Optional.of(3L));
|
|
+ final EthGetTransactionCount method = new EthGetTransactionCount(queries, mock(TransactionPool.class));
|
|
+ assertThat(result(method.response(request("eth_getTransactionCount", ADDR.toHexString(), "0x3e8")))).isEqualTo("0x3");
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/AereHeadStateRetryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/AereHeadStateRetryTest.java
|
|
new file mode 100755
|
|
index 0000000000..33be192f65
|
|
--- /dev/null
|
|
+++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/AereHeadStateRetryTest.java
|
|
@@ -0,0 +1,140 @@
|
|
+/*
|
|
+ * 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
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.api.query;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.Mockito.mock;
|
|
+import static org.mockito.Mockito.times;
|
|
+import static org.mockito.Mockito.verify;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
|
+import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
|
+import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
|
+import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.common.provider.WorldStateQueryParams;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-109: a query against a block that has just become the chain head can find no world state
|
|
+ * for a few milliseconds. {@link BlockchainQueries#getAndMapWorldState(Hash, java.util.function.Function)}
|
|
+ * must look again (a bounded number of times) near the head, and must NOT retry for old blocks,
|
|
+ * where an empty result is the state window closing.
|
|
+ */
|
|
+public class AereHeadStateRetryTest {
|
|
+
|
|
+ private static final Hash HASH = Hash.fromHexStringLenient("0x1234");
|
|
+
|
|
+ private static BlockHeader headerAt(final long number) {
|
|
+ final BlockHeader header = mock(BlockHeader.class);
|
|
+ when(header.getNumber()).thenReturn(number);
|
|
+ when(header.getHash()).thenReturn(HASH);
|
|
+ when(header.getBlockHash()).thenReturn(HASH);
|
|
+ when(header.getStateRoot()).thenReturn(Hash.EMPTY_TRIE_HASH);
|
|
+ when(header.getParentHash()).thenReturn(Hash.ZERO);
|
|
+ when(header.toLogString()).thenReturn("#" + number);
|
|
+ return header;
|
|
+ }
|
|
+
|
|
+ private static BlockchainQueries queries(
|
|
+ final Blockchain blockchain, final WorldStateArchive archive) {
|
|
+ return new BlockchainQueries(
|
|
+ mock(ProtocolSchedule.class), blockchain, archive, MiningConfiguration.newDefault());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void headBlockStateThatAppearsOnSecondLookIsReturned() {
|
|
+ final Blockchain blockchain = mock(Blockchain.class);
|
|
+ final WorldStateArchive archive = mock(WorldStateArchive.class);
|
|
+ final BlockHeader head = headerAt(1000);
|
|
+ when(blockchain.getBlockHeader(HASH)).thenReturn(Optional.of(head));
|
|
+ when(blockchain.getChainHeadBlockNumber()).thenReturn(1000L);
|
|
+ final MutableWorldState ws = mock(MutableWorldState.class);
|
|
+ when(archive.getWorldState(any(WorldStateQueryParams.class)))
|
|
+ .thenReturn(Optional.empty())
|
|
+ .thenReturn(Optional.of(ws));
|
|
+
|
|
+ final Optional<String> result =
|
|
+ queries(blockchain, archive).getAndMapWorldState(HASH, w -> Optional.of("ok"));
|
|
+
|
|
+ assertThat(result).contains("ok");
|
|
+ verify(archive, times(2)).getWorldState(any(WorldStateQueryParams.class));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void oldBlockWithoutStateIsNotRetried() {
|
|
+ // negative control: an old block gets exactly ONE look, and an empty answer stays empty
|
|
+ final Blockchain blockchain = mock(Blockchain.class);
|
|
+ final WorldStateArchive archive = mock(WorldStateArchive.class);
|
|
+ final BlockHeader old = headerAt(1000);
|
|
+ when(blockchain.getBlockHeader(HASH)).thenReturn(Optional.of(old));
|
|
+ when(blockchain.getChainHeadBlockNumber()).thenReturn(5000L);
|
|
+ when(archive.getWorldState(any(WorldStateQueryParams.class))).thenReturn(Optional.empty());
|
|
+
|
|
+ final Optional<String> result =
|
|
+ queries(blockchain, archive).getAndMapWorldState(HASH, w -> Optional.of("ok"));
|
|
+
|
|
+ assertThat(result).isEmpty();
|
|
+ verify(archive, times(1)).getWorldState(any(WorldStateQueryParams.class));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void headBlockThatNeverGetsStateStopsAfterBoundedRetries() {
|
|
+ // the retry is bounded: a head block that never gets its state is asked 1 + 4 times, then empty
|
|
+ final Blockchain blockchain = mock(Blockchain.class);
|
|
+ final WorldStateArchive archive = mock(WorldStateArchive.class);
|
|
+ final BlockHeader head = headerAt(1000);
|
|
+ when(blockchain.getBlockHeader(HASH)).thenReturn(Optional.of(head));
|
|
+ when(blockchain.getChainHeadBlockNumber()).thenReturn(1001L);
|
|
+ when(archive.getWorldState(any(WorldStateQueryParams.class))).thenReturn(Optional.empty());
|
|
+
|
|
+ final long t0 = System.nanoTime();
|
|
+ final Optional<String> result =
|
|
+ queries(blockchain, archive).getAndMapWorldState(HASH, w -> Optional.of("ok"));
|
|
+ final long elapsedMs = (System.nanoTime() - t0) / 1_000_000;
|
|
+
|
|
+ assertThat(result).isEmpty();
|
|
+ verify(archive, times(5)).getWorldState(any(WorldStateQueryParams.class));
|
|
+ // 50 + 100 + 150 + 300 ms of pauses, and nothing unbounded
|
|
+ assertThat(elapsedMs).isBetween(550L, 5000L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ public void stateFoundOnFirstLookIsReturnedWithoutWaiting() {
|
|
+ final Blockchain blockchain = mock(Blockchain.class);
|
|
+ final WorldStateArchive archive = mock(WorldStateArchive.class);
|
|
+ final BlockHeader head = headerAt(1000);
|
|
+ when(blockchain.getBlockHeader(HASH)).thenReturn(Optional.of(head));
|
|
+ when(blockchain.getChainHeadBlockNumber()).thenReturn(1000L);
|
|
+ when(archive.getWorldState(any(WorldStateQueryParams.class)))
|
|
+ .thenReturn(Optional.of(mock(MutableWorldState.class)));
|
|
+
|
|
+ final long t0 = System.nanoTime();
|
|
+ final Optional<String> result =
|
|
+ queries(blockchain, archive).getAndMapWorldState(HASH, w -> Optional.of("ok"));
|
|
+ final long elapsedMs = (System.nanoTime() - t0) / 1_000_000;
|
|
+
|
|
+ assertThat(result).contains("ok");
|
|
+ verify(archive, times(1)).getWorldState(any(WorldStateQueryParams.class));
|
|
+ assertThat(elapsedMs).isLessThan(50L);
|
|
+ }
|
|
+}
|
|
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 e765d882f2..3acaea6ba6 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
|
|
@@ -1,47 +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 2026 Aere Network.
|
|
*
|
|
- * This file was changed by Aere Network: the futureEips milestone is based on
|
|
- * osakaDefinition instead of amsterdamDefinition, so that the AERE activation at
|
|
- * block 9,189,161 keeps the Osaka block format, and EIP-2935 (historical block
|
|
- * hashes in the system contract) is enabled in that same milestone. Nothing
|
|
- * upstream was removed; the unmodified original is Hyperledger Besu commit
|
|
- * d2032017bb3b8cb215a97303980a1e4a643f7180, and the upstream copyright header
|
|
- * above is left exactly as it was found.
|
|
+ * Modifications Copyright contributors to the Aere Network.
|
|
*
|
|
- * This notice is required by Apache License 2.0 section 4(b).
|
|
+ * 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/0005-aere-eip2935-futureeips.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.mainnet;
|
|
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.AMSTERDAM;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.ARROW_GLACIER;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BERLIN;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BPO1;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BPO2;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BPO3;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BPO4;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BPO5;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.BYZANTIUM;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.CANCUN;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.CONSTANTINOPLE;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.DAO_RECOVERY_INIT;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.DAO_RECOVERY_TRANSITION;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.EXPERIMENTAL_EIPS;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.FRONTIER;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.FUTURE_EIPS;
|
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.GRAY_GLACIER;
|
|
@@ -1347,40 +1339,52 @@ public abstract class MainnetProtocolSpecs {
|
|
// the post-activation block format IDENTICAL to Osaka and adds ONLY the two
|
|
// AERE features below: (a) the 5 PQC precompiles and (b) EIP-2935.
|
|
return osakaDefinition(
|
|
chainId,
|
|
enableRevertReason,
|
|
genesisConfigOptions,
|
|
evmConfiguration,
|
|
miningConfiguration,
|
|
isParallelTxProcessingEnabled,
|
|
balConfiguration,
|
|
metricsSystem)
|
|
// AERE EIP-2935: historical block hashes (ring buffer in the system
|
|
// contract at 0x0000f9...2935), wired into the SAME futureEips (AerePQC)
|
|
// hard fork as the PQC precompiles so a single futureEipsTime activation
|
|
// delivers both. Forced on unconditionally here: the inherited Prague
|
|
// definition falls back to FrontierPreExecutionProcessor for QBFT/PoA
|
|
// chains without system-contract addresses, which would silently skip
|
|
// EIP-2935 history storage. This override restores it, protocol-native.
|
|
.preExecutionProcessor(new PraguePreExecutionProcessor())
|
|
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::futureEips)
|
|
+ // AERE AerePQC fork also activates Block-STM optimistic parallel execution when
|
|
+ // AERE_BLOCKSTM=1, so one hard fork delivers PQC + EIP-2935 + parallel exec together.
|
|
+ // When unset this reproduces the inherited default builder exactly (live-safe).
|
|
+ .blockProcessorBuilder(
|
|
+ "1".equals(System.getenv("AERE_BLOCKSTM"))
|
|
+ ? new org.hyperledger.besu.ethereum.mainnet.blockstm.AereBlockStmProcessor
|
|
+ .AereBlockStmProcessorBuilder(metricsSystem)
|
|
+ : (isParallelTxProcessingEnabled
|
|
+ ? new org.hyperledger.besu.ethereum.mainnet.parallelization
|
|
+ .MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem)
|
|
+ : new org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor
|
|
+ .MainnetBlockProcessorBuilder(metricsSystem)))
|
|
.hardforkId(FUTURE_EIPS);
|
|
}
|
|
|
|
static ProtocolSpecBuilder experimentalEipsDefinition(
|
|
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) {
|
|
|
|
return futureEipsDefinition(
|
|
chainId,
|
|
enableRevertReason,
|
|
genesisConfigOptions,
|
|
evmConfiguration,
|
|
miningConfiguration,
|
|
isParallelTxProcessingEnabled,
|
|
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
|
|
old mode 100644
|
|
new mode 100755
|
|
index 4c1d265a80..804f4bed0a
|
|
--- 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,39 +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.
|
|
+ * found, as section 4(c) requires. The change itself is in patches/aere-tx-gas-cap-unsigned.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;
|
|
@@ -99,41 +99,43 @@ public class MainnetTransactionValidator implements TransactionValidator {
|
|
validateTransactionSignature(transaction);
|
|
if (!signatureResult.isValid()) {
|
|
return signatureResult;
|
|
}
|
|
|
|
final TransactionType transactionType = transaction.getType();
|
|
if (!acceptedTransactionTypes.contains(transactionType)) {
|
|
return ValidationResult.invalid(
|
|
TransactionInvalidReason.INVALID_TRANSACTION_FORMAT,
|
|
String.format(
|
|
"Transaction type %s is invalid, accepted transaction types are %s",
|
|
transactionType, acceptedTransactionTypes));
|
|
}
|
|
|
|
if (!transactionValidationParams.isAllowFutureNonce() && transaction.getNonce() == MAX_NONCE) {
|
|
return ValidationResult.invalid(
|
|
TransactionInvalidReason.NONCE_OVERFLOW, "Nonce must be less than 2^64-1");
|
|
}
|
|
|
|
if (!transactionValidationParams.isAllowExceedingGasLimit()
|
|
- && transaction.getGasLimit() > gasLimitCalculator.transactionGasLimitCap()) {
|
|
+ // AERE D-432: unsigned, like the intrinsic-gas check below. The decoder reads gasLimit with readLongScalar, so a limit of 2^63
|
|
+ // or more arrives as a negative long, and a signed compare let it through the EIP-7825 cap.
|
|
+ && Long.compareUnsigned(transaction.getGasLimit(), gasLimitCalculator.transactionGasLimitCap()) > 0) {
|
|
return ValidationResult.invalid(
|
|
TransactionInvalidReason.EXCEEDS_TRANSACTION_GAS_LIMIT,
|
|
"Transaction gas limit must be at most " + gasLimitCalculator.transactionGasLimitCap());
|
|
}
|
|
|
|
if (transactionType.supportsBlob()) {
|
|
final ValidationResult<TransactionInvalidReason> blobTransactionResult =
|
|
blobsValidator.validate(transaction);
|
|
if (!blobTransactionResult.isValid()) {
|
|
LOG.debug(
|
|
"Blob transaction {} validation failed: {}",
|
|
transaction.getHash().getBytes().toHexString(),
|
|
blobTransactionResult.getErrorMessage());
|
|
return blobTransactionResult;
|
|
}
|
|
}
|
|
|
|
if (transaction.isContractCreation() && transaction.getPayload().size() > maxInitcodeSize) {
|
|
return ValidationResult.invalid(
|
|
TransactionInvalidReason.INITCODE_TOO_LARGE,
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsValidator.java
|
|
old mode 100644
|
|
new mode 100755
|
|
index 2adda62054..fc04a7c55b
|
|
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsValidator.java
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/WithdrawalsValidator.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/aere-bft-withdrawals-not-applicable.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.mainnet;
|
|
|
|
import static com.google.common.base.Preconditions.checkArgument;
|
|
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.core.Block;
|
|
import org.hyperledger.besu.ethereum.core.Withdrawal;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
public interface WithdrawalsValidator {
|
|
|
|
boolean validateWithdrawals(Optional<List<Withdrawal>> withdrawals);
|
|
|
|
boolean validateWithdrawalsRoot(Block block);
|
|
@@ -82,31 +88,62 @@ public interface WithdrawalsValidator {
|
|
LOG.warn("withdrawalsRoot must not be null when Withdrawals are activated");
|
|
return false;
|
|
}
|
|
|
|
final List<Withdrawal> withdrawals = block.getBody().getWithdrawals().get();
|
|
final Hash expectedWithdrawalsRoot = BodyValidation.withdrawalsRoot(withdrawals);
|
|
if (!expectedWithdrawalsRoot.equals(withdrawalsRoot.get())) {
|
|
LOG.info(
|
|
"Invalid block: transaction root mismatch (expected={}, actual={})",
|
|
expectedWithdrawalsRoot,
|
|
withdrawalsRoot.get());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class NotApplicableWithdrawals implements WithdrawalsValidator {
|
|
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(NotApplicableWithdrawals.class);
|
|
+
|
|
+ // AERE D-433: ported from upstream hyperledger/besu ffe8104ee2 (GHSA-p4h2-gvh4-pv6j) and b7f1387cb4. On a BFT chain a non-empty list is a
|
|
+ // Byzantine proposer's injection that WithdrawalsProcessor would credit as native balance on every honest node.
|
|
@Override
|
|
public boolean validateWithdrawals(final Optional<List<Withdrawal>> withdrawals) {
|
|
+ // Pre-Shanghai blocks have no withdrawals field (Optional.empty()) - valid.
|
|
+ // Shanghai+ blocks must carry an empty list; a non-empty list means a Byzantine
|
|
+ // proposer injected unauthorized withdrawals that would be executed as balance credits.
|
|
+ if (withdrawals.isPresent() && !withdrawals.get().isEmpty()) {
|
|
+ LOG.warn(
|
|
+ "Withdrawals not applicable but block contained {} withdrawal(s)",
|
|
+ withdrawals.get().size());
|
|
+ return false;
|
|
+ }
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean validateWithdrawalsRoot(final Block block) {
|
|
+ final Optional<Hash> withdrawalsRoot = block.getHeader().getWithdrawalsRoot();
|
|
+ if (withdrawalsRoot.isEmpty()) {
|
|
+ return true; // pre-Shanghai block, no withdrawals root field
|
|
+ }
|
|
+ // A block with a withdrawalsRoot in the header but no withdrawals field in the body is
|
|
+ // malformed.
|
|
+ if (block.getBody().getWithdrawals().isEmpty()) {
|
|
+ LOG.warn(
|
|
+ "Invalid block: withdrawalsRoot present in header but withdrawals absent from body");
|
|
+ return false;
|
|
+ }
|
|
+ if (!Hash.EMPTY_TRIE_HASH.equals(withdrawalsRoot.get())) {
|
|
+ LOG.warn(
|
|
+ "Invalid block: withdrawals root mismatch (expected={}, actual={})",
|
|
+ Hash.EMPTY_TRIE_HASH,
|
|
+ withdrawalsRoot.get());
|
|
+ return false;
|
|
+ }
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmEngine.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmEngine.java
|
|
new file mode 100644
|
|
index 0000000000..1ef6489405
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmEngine.java
|
|
@@ -0,0 +1,528 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
|
+import org.hyperledger.besu.ethereum.core.Transaction;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
|
|
+import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList.BlockAccessListBuilder;
|
|
+import org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.worldview.BonsaiWorldState;
|
|
+import org.hyperledger.besu.evm.account.Account;
|
|
+import org.hyperledger.besu.evm.account.MutableAccount;
|
|
+import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
|
+import org.hyperledger.besu.evm.tracing.OperationTracer;
|
|
+import org.hyperledger.besu.evm.worldstate.WorldUpdater;
|
|
+import org.hyperledger.besu.plugin.services.metrics.Counter;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.Set;
|
|
+import java.util.concurrent.ExecutorService;
|
|
+import java.util.concurrent.Executors;
|
|
+import java.util.concurrent.TimeUnit;
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AERE Block-STM optimistic parallel execution engine, wired into Besu's block-processing
|
|
+ * preprocessing hook. Faithful realisation of the AERE Rust Block-STM (Gelashvili et al. 2022):
|
|
+ * {@link Scheduler} + {@link MvMemory} drive a worker pool that runs the block's transactions
|
|
+ * concurrently against a multi-version world view ({@link MvBaseLayer}/{@link MvAccount}), captures
|
|
+ * read/write sets, re-executes conflicting transactions, and yields per-transaction outcomes that
|
|
+ * the block processor commits IN BLOCK ORDER — producing a state root bit-identical to sequential
|
|
+ * execution.
|
|
+ *
|
|
+ * <p>Safety: any transaction whose parallel outcome is missing, unsuccessful, or produced by a run
|
|
+ * that did not reach {@code scheduler.done()} falls back to Besu's sequential execution in the block
|
|
+ * loop (see {@link #getProcessingResult}). The engine can never commit an unverified result.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class AereBlockStmEngine extends ParallelBlockTransactionProcessor {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(AereBlockStmEngine.class);
|
|
+ private static final long PARALLEL_TIMEOUT_SECONDS = 60;
|
|
+
|
|
+ private final MainnetTransactionProcessor transactionProcessor;
|
|
+ private final int numThreads;
|
|
+
|
|
+ // Populated by runAsyncBlock, consumed in block order by getProcessingResult.
|
|
+ private volatile MvOutcome[] outcomes;
|
|
+ private volatile boolean success = false;
|
|
+ private final AtomicInteger totalExecutions = new AtomicInteger();
|
|
+ private final AtomicInteger totalValidations = new AtomicInteger();
|
|
+ private final AtomicInteger totalAborts = new AtomicInteger();
|
|
+ private final AtomicInteger committedParallel = new AtomicInteger();
|
|
+
|
|
+ // Execution-phase instrumentation (see BlockStmStats): snapshotNanos = time to mint the single
|
|
+ // parent Bonsai view + flat pre-snapshot wrapper; execPhaseNanos = the PARALLEL EXECUTION PHASE
|
|
+ // (worker pool start -> termination) in isolation. Neither includes the downstream serial Bonsai
|
|
+ // trie commit, which happens in the block processor after this preprocessing returns.
|
|
+ private volatile long snapshotNanos = 0L;
|
|
+ private volatile long execPhaseNanos = 0L;
|
|
+
|
|
+ /**
|
|
+ * @param transactionProcessor the mainnet transaction processor (EVM)
|
|
+ * @param numThreads worker-pool size (typically NCPU)
|
|
+ */
|
|
+ public AereBlockStmEngine(
|
|
+ final MainnetTransactionProcessor transactionProcessor, final int numThreads) {
|
|
+ this.transactionProcessor = transactionProcessor;
|
|
+ this.numThreads = Math.max(1, numThreads);
|
|
+ }
|
|
+
|
|
+ /** Per-transaction net outcome captured by the parallel phase. */
|
|
+ private static final class MvOutcome {
|
|
+ final Map<MvKey, Object> writes;
|
|
+ final Set<MvKey> writeKeys;
|
|
+ final List<Map.Entry<Address, Map<UInt256, UInt256>>> storageByAddr;
|
|
+ final Map<Address, long[]> nonceByAddr; // addr -> [nonce] if written
|
|
+ final Map<Address, Wei> balanceByAddr; // addr -> balance if written
|
|
+ final Map<Address, Bytes> codeByAddr; // addr -> code if written
|
|
+ final Set<Address> deleted;
|
|
+ Wei beneficiaryDelta = Wei.ZERO;
|
|
+ TransactionProcessingResult result;
|
|
+
|
|
+ MvOutcome() {
|
|
+ this.writes = new HashMap<>();
|
|
+ this.writeKeys = new HashSet<>();
|
|
+ this.storageByAddr = new ArrayList<>();
|
|
+ this.nonceByAddr = new HashMap<>();
|
|
+ this.balanceByAddr = new HashMap<>();
|
|
+ this.codeByAddr = new HashMap<>();
|
|
+ this.deleted = new HashSet<>();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // ---- shared per-block execution state ----
|
|
+ private MvMemory mv;
|
|
+ private Scheduler scheduler;
|
|
+ private List<Transaction> txns;
|
|
+ private BlockHeader blockHeader;
|
|
+ private Address beneficiary;
|
|
+ private BlockHashLookup blockHashLookup;
|
|
+ private Wei blobGasPrice;
|
|
+ private Object[] slotLocks;
|
|
+ private Map<MvKey, MvMemory.ReadDescriptor>[] lastReads;
|
|
+ private Set<MvKey>[] lastWriteKeys;
|
|
+ private final AtomicBoolean hardFail = new AtomicBoolean(false);
|
|
+
|
|
+ @Override
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
+ public void runAsyncBlock(
|
|
+ final ProtocolContext protocolContext,
|
|
+ final BlockHeader header,
|
|
+ final List<Transaction> transactions,
|
|
+ final Address miningBeneficiary,
|
|
+ final BlockHashLookup blockHashLookupParam,
|
|
+ final Wei blobGasPriceParam,
|
|
+ final java.util.concurrent.Executor executorUnused,
|
|
+ final Optional<BlockAccessListBuilder> blockAccessListBuilder,
|
|
+ final Optional<BlockHeader> maybeParentHeader) {
|
|
+
|
|
+ final int n = transactions.size();
|
|
+ outcomes = new MvOutcome[n];
|
|
+ success = false;
|
|
+ if (n == 0 || maybeParentHeader.isEmpty()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // AERE Block-STM Track B: FLAT immutable base pre-snapshot shared lock-free by all workers.
|
|
+ // Iteration 1 gave each worker its OWN frozen BonsaiWorldState and re-walked the parent trie on
|
|
+ // every base read (task bottleneck #2: per-worker Bonsai-view minting + layered-trie traversal
|
|
+ // per read). Here we mint the parent Bonsai view exactly ONCE, wrap it in a FlatBaseSnapshot
|
|
+ // that materialises each base value ONCE into an in-memory ConcurrentHashMap, and hand the SAME
|
|
+ // snapshot to every worker. Hot-path base reads become lock-free O(1) hashmap lookups with no
|
|
+ // trie traversal and no per-worker view. The base state is immutable for the round, so all
|
|
+ // workers observe identical parent values and serial equivalence holds (parallelRoot ==
|
|
+ // sequentialRoot). snapshotNanos captures this one-time mint separately from execPhaseNanos.
|
|
+ final long snapT0 = System.nanoTime();
|
|
+ final List<BonsaiWorldState> openStates = new ArrayList<>(1);
|
|
+ try {
|
|
+ final BonsaiWorldState ws =
|
|
+ getWorldState(protocolContext, maybeParentHeader.get()).orElse(null);
|
|
+ if (ws == null) {
|
|
+ return; // success stays false -> sequential fallback
|
|
+ }
|
|
+ ws.disableCacheMerkleTrieLoader();
|
|
+ openStates.add(ws);
|
|
+ final BaseReader sharedBase = new FlatBaseSnapshot(ws);
|
|
+ this.snapshotNanos = System.nanoTime() - snapT0;
|
|
+
|
|
+ this.mv = new MvMemory();
|
|
+ this.scheduler = new Scheduler(n);
|
|
+ this.txns = transactions;
|
|
+ this.blockHeader = header;
|
|
+ this.beneficiary = miningBeneficiary;
|
|
+ this.blockHashLookup = blockHashLookupParam;
|
|
+ this.blobGasPrice = blobGasPriceParam;
|
|
+ this.slotLocks = new Object[n];
|
|
+ this.lastReads = new Map[n];
|
|
+ this.lastWriteKeys = new Set[n];
|
|
+ for (int i = 0; i < n; i++) {
|
|
+ slotLocks[i] = new Object();
|
|
+ lastWriteKeys[i] = new HashSet<>();
|
|
+ }
|
|
+ hardFail.set(false);
|
|
+
|
|
+ // EXECUTION PHASE (timed in isolation from the snapshot mint above and from the downstream
|
|
+ // serial Bonsai trie commit that runs after this method returns). All workers share the one
|
|
+ // FlatBaseSnapshot; its hot-path reads are lock-free, so distinct-key base reads never contend.
|
|
+ final long execT0 = System.nanoTime();
|
|
+ final ExecutorService pool = Executors.newFixedThreadPool(numThreads);
|
|
+ try {
|
|
+ for (int t = 0; t < numThreads; t++) {
|
|
+ pool.execute(() -> worker(sharedBase));
|
|
+ }
|
|
+ pool.shutdown();
|
|
+ final boolean finished = pool.awaitTermination(PARALLEL_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
|
+ if (!finished) {
|
|
+ pool.shutdownNow();
|
|
+ }
|
|
+ this.execPhaseNanos = System.nanoTime() - execT0;
|
|
+ success = finished && scheduler.done() && !hardFail.get();
|
|
+ } catch (final InterruptedException ie) {
|
|
+ Thread.currentThread().interrupt();
|
|
+ pool.shutdownNow();
|
|
+ this.execPhaseNanos = System.nanoTime() - execT0;
|
|
+ success = false;
|
|
+ }
|
|
+ if (!success) {
|
|
+ LOG.info(
|
|
+ "AERE Block-STM: parallel phase did not verify (done={}, hardFail={}); block falls back"
|
|
+ + " to sequential per-transaction execution",
|
|
+ scheduler.done(),
|
|
+ hardFail.get());
|
|
+ }
|
|
+ } catch (final RuntimeException ex) {
|
|
+ LOG.info("AERE Block-STM: parallel preprocessing error; sequential fallback", ex);
|
|
+ success = false;
|
|
+ } finally {
|
|
+ for (final BonsaiWorldState ws : openStates) {
|
|
+ try {
|
|
+ ws.close();
|
|
+ } catch (final Exception ignored) {
|
|
+ // best-effort close
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void worker(final BaseReader base) {
|
|
+ try {
|
|
+ Scheduler.Task task = scheduler.nextTask();
|
|
+ while (!hardFail.get()) {
|
|
+ switch (task.kind()) {
|
|
+ case DONE:
|
|
+ return;
|
|
+ case NO_TASK:
|
|
+ task = scheduler.nextTask();
|
|
+ break;
|
|
+ case EXECUTION:
|
|
+ task = tryExecute(base, task.idx(), task.inc());
|
|
+ break;
|
|
+ case VALIDATION:
|
|
+ task = tryValidate(task.idx(), task.inc());
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ } catch (final Throwable th) {
|
|
+ hardFail.set(true);
|
|
+ LOG.debug("AERE Block-STM worker aborted", th);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Scheduler.Task tryExecute(final BaseReader base, final int idx, final int inc) {
|
|
+ while (true) {
|
|
+ if (hardFail.get()) {
|
|
+ return Scheduler.Task.NO_TASK;
|
|
+ }
|
|
+ final MvContext ctx = new MvContext(idx, mv, base, beneficiary);
|
|
+ final MvBaseLayer baseLayer = new MvBaseLayer(ctx);
|
|
+ final WorldUpdater txUpdater = baseLayer.updater();
|
|
+ totalExecutions.incrementAndGet();
|
|
+
|
|
+ TransactionProcessingResult res = null;
|
|
+ try {
|
|
+ res =
|
|
+ transactionProcessor.processTransaction(
|
|
+ txUpdater,
|
|
+ blockHeader,
|
|
+ txns.get(idx).detachedCopy(),
|
|
+ beneficiary,
|
|
+ OperationTracer.NO_TRACING,
|
|
+ blockHashLookup,
|
|
+ TransactionValidationParams.processingBlock(),
|
|
+ blobGasPrice,
|
|
+ Optional.empty());
|
|
+ } catch (final RuntimeException ex) {
|
|
+ if (ctx.blockedOn < 0) {
|
|
+ throw ex; // genuine failure -> worker aborts -> sequential fallback
|
|
+ }
|
|
+ // else: a routed read parked; fall through to dependency handling
|
|
+ }
|
|
+
|
|
+ if (ctx.blockedOn >= 0) {
|
|
+ final int blocking = ctx.blockedOn;
|
|
+ if (scheduler.addDependency(idx, blocking)) {
|
|
+ return Scheduler.Task.NO_TASK; // parked
|
|
+ }
|
|
+ continue; // dependency already resolved; re-run same incarnation
|
|
+ }
|
|
+
|
|
+ final MvOutcome outcome = harvest(ctx, baseLayer, txUpdater, res);
|
|
+ final Set<MvKey> prevKeys;
|
|
+ synchronized (slotLocks[idx]) {
|
|
+ prevKeys = lastWriteKeys[idx];
|
|
+ }
|
|
+ final boolean wroteNewPath = mv.applyWriteSet(idx, inc, outcome.writes, prevKeys);
|
|
+ synchronized (slotLocks[idx]) {
|
|
+ lastReads[idx] = ctx.reads;
|
|
+ lastWriteKeys[idx] = outcome.writeKeys;
|
|
+ outcomes[idx] = outcome;
|
|
+ }
|
|
+ return scheduler.finishExecution(idx, inc, wroteNewPath);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Scheduler.Task tryValidate(final int idx, final int inc) {
|
|
+ totalValidations.incrementAndGet();
|
|
+ final Map<MvKey, MvMemory.ReadDescriptor> reads;
|
|
+ synchronized (slotLocks[idx]) {
|
|
+ reads = lastReads[idx];
|
|
+ }
|
|
+ boolean valid = true;
|
|
+ if (reads != null) {
|
|
+ for (final Map.Entry<MvKey, MvMemory.ReadDescriptor> e : reads.entrySet()) {
|
|
+ final MvMemory.ReadResult now = mv.read(e.getKey(), idx);
|
|
+ final boolean matches = !now.isBlocked() && e.getValue().sameProvenance(now.descriptor());
|
|
+ if (!matches) {
|
|
+ valid = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ final boolean aborted = !valid && scheduler.tryValidationAbort(idx, inc);
|
|
+ if (aborted) {
|
|
+ totalAborts.incrementAndGet();
|
|
+ final Set<MvKey> keys;
|
|
+ synchronized (slotLocks[idx]) {
|
|
+ keys = lastWriteKeys[idx];
|
|
+ }
|
|
+ if (keys != null) {
|
|
+ mv.markEstimates(idx, keys);
|
|
+ }
|
|
+ }
|
|
+ return scheduler.finishValidation(idx, aborted);
|
|
+ }
|
|
+
|
|
+ private MvOutcome harvest(
|
|
+ final MvContext ctx,
|
|
+ final MvBaseLayer baseLayer,
|
|
+ final WorldUpdater txUpdater,
|
|
+ final TransactionProcessingResult res) {
|
|
+ final MvOutcome o = new MvOutcome();
|
|
+ o.result = res;
|
|
+
|
|
+ for (final Account acct : txUpdater.getTouchedAccounts()) {
|
|
+ final Address a = acct.getAddress();
|
|
+ final MvAccount seed = baseLayer.materializedAccount(a);
|
|
+ final long seedNonce = seed == null ? 0L : seed.seededNonce();
|
|
+ final Wei seedBalance = seed == null ? Wei.ZERO : seed.seededBalance();
|
|
+ final Hash seedCodeHash = seed == null ? Hash.EMPTY : seed.seededCodeHash();
|
|
+
|
|
+ final long nonce = acct.getNonce();
|
|
+ if (nonce != seedNonce) {
|
|
+ o.nonceByAddr.put(a, new long[] {nonce});
|
|
+ final MvKey k = MvKey.nonce(a);
|
|
+ o.writes.put(k, Long.valueOf(nonce));
|
|
+ o.writeKeys.add(k);
|
|
+ }
|
|
+
|
|
+ if (ctx.isBeneficiary(a)) {
|
|
+ final Wei bal = acct.getBalance();
|
|
+ o.beneficiaryDelta = bal.subtract(seedBalance);
|
|
+ } else {
|
|
+ final Wei bal = acct.getBalance();
|
|
+ if (!bal.equals(seedBalance)) {
|
|
+ o.balanceByAddr.put(a, bal);
|
|
+ final MvKey k = MvKey.balance(a);
|
|
+ o.writes.put(k, bal);
|
|
+ o.writeKeys.add(k);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ final Hash codeHash = acct.getCodeHash();
|
|
+ if (!codeHash.equals(seedCodeHash)) {
|
|
+ final Bytes code = acct.getCode();
|
|
+ o.codeByAddr.put(a, code);
|
|
+ final MvKey k = MvKey.code(a);
|
|
+ o.writes.put(k, code);
|
|
+ o.writeKeys.add(k);
|
|
+ }
|
|
+
|
|
+ final Map<UInt256, UInt256> updated =
|
|
+ (acct instanceof MutableAccount) ? ((MutableAccount) acct).getUpdatedStorage() : null;
|
|
+ if (updated != null && !updated.isEmpty()) {
|
|
+ final Map<UInt256, UInt256> copy = new HashMap<>(updated);
|
|
+ o.storageByAddr.add(Map.entry(a, copy));
|
|
+ for (final Map.Entry<UInt256, UInt256> se : copy.entrySet()) {
|
|
+ final MvKey k = MvKey.storage(a, se.getKey());
|
|
+ o.writes.put(k, se.getValue());
|
|
+ o.writeKeys.add(k);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (final Address d : txUpdater.getDeletedAccountAddresses()) {
|
|
+ o.deleted.add(d);
|
|
+ // reflect clearing in MVMemory so higher transactions read cleared state
|
|
+ final MvKey bk = MvKey.balance(d);
|
|
+ final MvKey nk = MvKey.nonce(d);
|
|
+ final MvKey ck = MvKey.code(d);
|
|
+ o.writes.put(bk, Wei.ZERO);
|
|
+ o.writes.put(nk, Long.valueOf(0L));
|
|
+ o.writes.put(ck, Bytes.EMPTY);
|
|
+ o.writeKeys.add(bk);
|
|
+ o.writeKeys.add(nk);
|
|
+ o.writeKeys.add(ck);
|
|
+ }
|
|
+ return o;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Commit phase: called by the block processor in strict block order (location 0..n-1) on the real
|
|
+ * world state. Applies transaction {@code location}'s parallel outcome and returns its result, or
|
|
+ * empty to request sequential re-execution for this transaction.
|
|
+ */
|
|
+ @Override
|
|
+ public Optional<TransactionProcessingResult> getProcessingResult(
|
|
+ final MutableWorldState worldState,
|
|
+ final Address miningBeneficiary,
|
|
+ final Transaction transaction,
|
|
+ final int location,
|
|
+ final Optional<Counter> confirmedParallelizedTransactionCounter,
|
|
+ final Optional<Counter> conflictingButCachedTransactionCounter) {
|
|
+
|
|
+ if (!success || outcomes == null || location >= outcomes.length) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ final MvOutcome o = outcomes[location];
|
|
+ if (o == null || o.result == null || !o.result.isSuccessful()) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ try {
|
|
+ final WorldUpdater updater = worldState.updater();
|
|
+ // deletions win over writes for the same address
|
|
+ for (final Map.Entry<Address, Wei> e : o.balanceByAddr.entrySet()) {
|
|
+ if (!o.deleted.contains(e.getKey())) {
|
|
+ updater.getOrCreate(e.getKey()).setBalance(e.getValue());
|
|
+ }
|
|
+ }
|
|
+ for (final Map.Entry<Address, long[]> e : o.nonceByAddr.entrySet()) {
|
|
+ if (!o.deleted.contains(e.getKey())) {
|
|
+ updater.getOrCreate(e.getKey()).setNonce(e.getValue()[0]);
|
|
+ }
|
|
+ }
|
|
+ for (final Map.Entry<Address, Bytes> e : o.codeByAddr.entrySet()) {
|
|
+ if (!o.deleted.contains(e.getKey())) {
|
|
+ updater.getOrCreate(e.getKey()).setCode(e.getValue());
|
|
+ }
|
|
+ }
|
|
+ for (final Map.Entry<Address, Map<UInt256, UInt256>> e : o.storageByAddr) {
|
|
+ if (o.deleted.contains(e.getKey())) {
|
|
+ continue;
|
|
+ }
|
|
+ final MutableAccount ra = updater.getOrCreate(e.getKey());
|
|
+ for (final Map.Entry<UInt256, UInt256> se : e.getValue().entrySet()) {
|
|
+ ra.setStorageValue(se.getKey(), se.getValue());
|
|
+ }
|
|
+ }
|
|
+ if (!o.beneficiaryDelta.isZero()) {
|
|
+ updater.getOrCreate(miningBeneficiary).incrementBalance(o.beneficiaryDelta);
|
|
+ }
|
|
+ for (final Address d : o.deleted) {
|
|
+ updater.deleteAccount(d);
|
|
+ }
|
|
+ updater.commit();
|
|
+ committedParallel.incrementAndGet();
|
|
+ confirmedParallelizedTransactionCounter.ifPresent(Counter::inc);
|
|
+ o.result.setIsProcessedInParallel(Optional.of(Boolean.TRUE));
|
|
+ return Optional.of(o.result);
|
|
+ } catch (final RuntimeException ex) {
|
|
+ LOG.info("AERE Block-STM: commit of tx {} failed; sequential fallback", location, ex);
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelizedTransactionContext
|
|
+ runTransaction(
|
|
+ final ProtocolContext protocolContext,
|
|
+ final BlockHeader header,
|
|
+ final int transactionLocation,
|
|
+ final Transaction transaction,
|
|
+ final Address miningBeneficiary,
|
|
+ final BlockHashLookup blockHashLookupParam,
|
|
+ final Wei blobGasPriceParam,
|
|
+ final Optional<BlockAccessListBuilder> blockAccessListBuilder,
|
|
+ final Optional<BlockHeader> maybeParentHeader) {
|
|
+ // Unused: AERE Block-STM overrides runAsyncBlock wholesale.
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ /** @return whether the last parallel run verified (reached done with no hard failure). */
|
|
+ public boolean lastRunSucceeded() {
|
|
+ return success;
|
|
+ }
|
|
+
|
|
+ /** @return Block-STM statistics for the last run. */
|
|
+ public BlockStmStats stats() {
|
|
+ return new BlockStmStats(
|
|
+ outcomes == null ? 0 : outcomes.length,
|
|
+ numThreads,
|
|
+ totalExecutions.get(),
|
|
+ totalValidations.get(),
|
|
+ totalAborts.get(),
|
|
+ committedParallel.get(),
|
|
+ success,
|
|
+ snapshotNanos,
|
|
+ execPhaseNanos);
|
|
+ }
|
|
+
|
|
+ /** @return wall-clock nanos of the last parallel EXECUTION PHASE (worker pool only). */
|
|
+ public long execPhaseNanos() {
|
|
+ return execPhaseNanos;
|
|
+ }
|
|
+
|
|
+ /** @return wall-clock nanos spent building the last flat base pre-snapshot. */
|
|
+ public long snapshotNanos() {
|
|
+ return snapshotNanos;
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmPreprocessing.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmPreprocessing.java
|
|
new file mode 100644
|
|
index 0000000000..db6562e254
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmPreprocessing.java
|
|
@@ -0,0 +1,119 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.Transaction;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor.PreprocessingFunction;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList;
|
|
+import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList.BlockAccessListBuilder;
|
|
+import org.hyperledger.besu.ethereum.mainnet.parallelization.PreprocessingContext;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.common.provider.PathBasedWorldStateProvider;
|
|
+import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * Preprocessing hook that runs AERE Block-STM optimistic parallel execution over the block's
|
|
+ * transactions before the sequential commit loop. Occupies the same {@code PreprocessingFunction}
|
|
+ * slot Besu uses for its built-in single-round parallelizer, but drives the AERE multi-version
|
|
+ * Block-STM engine instead. A fresh {@link AereBlockStmEngine} is created per block, so no state
|
|
+ * leaks between blocks.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class AereBlockStmPreprocessing implements PreprocessingFunction {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(AereBlockStmPreprocessing.class);
|
|
+
|
|
+ private final MainnetTransactionProcessor transactionProcessor;
|
|
+ private final int numThreads;
|
|
+
|
|
+ /**
|
|
+ * @param transactionProcessor the EVM transaction processor
|
|
+ * @param numThreads worker-pool size (typically NCPU)
|
|
+ */
|
|
+ public AereBlockStmPreprocessing(
|
|
+ final MainnetTransactionProcessor transactionProcessor, final int numThreads) {
|
|
+ this.transactionProcessor = transactionProcessor;
|
|
+ this.numThreads = numThreads;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Optional<PreprocessingContext> run(
|
|
+ final ProtocolContext protocolContext,
|
|
+ final BlockHeader blockHeader,
|
|
+ final List<Transaction> transactions,
|
|
+ final Address miningBeneficiary,
|
|
+ final BlockHashLookup blockHashLookup,
|
|
+ final Wei blobGasPrice,
|
|
+ final Optional<BlockAccessListBuilder> blockAccessListBuilder,
|
|
+ final Optional<BlockAccessList> maybeBlockBal,
|
|
+ final Optional<BlockHeader> maybeParentHeader) {
|
|
+
|
|
+ if (!(protocolContext.getWorldStateArchive() instanceof PathBasedWorldStateProvider)) {
|
|
+ // Block-STM multi-version view requires a Bonsai/path-based world state.
|
|
+ return Optional.empty();
|
|
+ }
|
|
+
|
|
+ final AereBlockStmEngine engine = new AereBlockStmEngine(transactionProcessor, numThreads);
|
|
+ engine.runAsyncBlock(
|
|
+ protocolContext,
|
|
+ blockHeader,
|
|
+ transactions,
|
|
+ miningBeneficiary,
|
|
+ blockHashLookup,
|
|
+ blobGasPrice,
|
|
+ Runnable::run,
|
|
+ blockAccessListBuilder,
|
|
+ maybeParentHeader);
|
|
+
|
|
+ final BlockStmStats stats = engine.stats();
|
|
+ LOG.debug(
|
|
+ "AERE Block-STM block #{}: txns={} threads={} exec={} valid={} aborts={} committedParallel={}"
|
|
+ + " verified={}",
|
|
+ blockHeader.getNumber(),
|
|
+ stats.numTxns(),
|
|
+ stats.numThreads(),
|
|
+ stats.totalExecutions(),
|
|
+ stats.totalValidations(),
|
|
+ stats.totalAborts(),
|
|
+ stats.committedParallel(),
|
|
+ stats.verified());
|
|
+ // Parseable single-line marker for the benchmark harness: the isolated EXECUTION-PHASE nanos
|
|
+ // (worker pool only, excludes the flat-snapshot mint AND the downstream serial Bonsai trie
|
|
+ // commit) plus the snapshot-mint nanos, per block. Gated on AERE_BLOCKSTM_STATS=1 so it is
|
|
+ // silent in normal operation and only emitted during benchmarking.
|
|
+ if ("1".equals(System.getenv("AERE_BLOCKSTM_STATS")) && stats.numTxns() > 0) {
|
|
+ LOG.info(
|
|
+ "AERE-BLOCKSTM-STATS blk={} n={} thr={} execNs={} snapNs={} exec={} aborts={}"
|
|
+ + " committedParallel={} verified={}",
|
|
+ blockHeader.getNumber(),
|
|
+ stats.numTxns(),
|
|
+ stats.numThreads(),
|
|
+ stats.execPhaseNanos(),
|
|
+ stats.snapshotNanos(),
|
|
+ stats.totalExecutions(),
|
|
+ stats.totalAborts(),
|
|
+ stats.committedParallel(),
|
|
+ stats.verified());
|
|
+ }
|
|
+
|
|
+ return Optional.of(new PreprocessingContext(engine));
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmProcessor.java
|
|
new file mode 100644
|
|
index 0000000000..db2065a4a6
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/AereBlockStmProcessor.java
|
|
@@ -0,0 +1,160 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.BlockProcessingResult;
|
|
+import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
+import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
+import org.hyperledger.besu.ethereum.core.Block;
|
|
+import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor.PreprocessingFunction.NoPreprocessing;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor.TransactionReceiptFactory;
|
|
+import org.hyperledger.besu.ethereum.mainnet.BalConfiguration;
|
|
+import org.hyperledger.besu.ethereum.mainnet.BlockProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator;
|
|
+import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
|
+import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
|
|
+import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList;
|
|
+import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.worldview.BonsaiWorldState;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
|
|
+import org.hyperledger.besu.plugin.services.MetricsSystem;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * L1 block processor that executes a block's transactions with AERE Block-STM optimistic parallel
|
|
+ * execution, committing in block order to produce a state root bit-identical to sequential
|
|
+ * execution. It reuses Besu's parallel consume path ({@link MainnetParallelBlockProcessor}: the
|
|
+ * overridden {@code getTransactionProcessingResult} pulls per-transaction results from the
|
|
+ * preprocessing context) but swaps Besu's single-round parallelizer for the AERE multi-version
|
|
+ * Block-STM engine via {@link AereBlockStmPreprocessing}.
|
|
+ *
|
|
+ * <p>Fork gate: this processor is selected only for the AERE {@code AerePQC} (FUTURE_EIPS) hard fork
|
|
+ * and only when {@code AERE_BLOCKSTM=1}, so a single activation delivers PQC precompiles + EIP-2935
|
|
+ * + parallel execution together. On any parallel-phase failure the whole block falls back to
|
|
+ * sequential execution, so the processor can never persist an unverified state root.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class AereBlockStmProcessor extends MainnetParallelBlockProcessor {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(AereBlockStmProcessor.class);
|
|
+ private static final int NCPU = Runtime.getRuntime().availableProcessors();
|
|
+
|
|
+ /**
|
|
+ * @param transactionProcessor the EVM transaction processor
|
|
+ * @param transactionReceiptFactory receipt factory
|
|
+ * @param blockReward block reward
|
|
+ * @param miningBeneficiaryCalculator beneficiary calculator
|
|
+ * @param skipZeroBlockRewards whether to skip zero rewards
|
|
+ * @param protocolSchedule the protocol schedule
|
|
+ * @param balConfiguration BAL configuration
|
|
+ * @param metricsSystem metrics
|
|
+ */
|
|
+ public AereBlockStmProcessor(
|
|
+ final MainnetTransactionProcessor transactionProcessor,
|
|
+ final TransactionReceiptFactory transactionReceiptFactory,
|
|
+ final Wei blockReward,
|
|
+ final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
|
|
+ final boolean skipZeroBlockRewards,
|
|
+ final ProtocolSchedule protocolSchedule,
|
|
+ final BalConfiguration balConfiguration,
|
|
+ final MetricsSystem metricsSystem) {
|
|
+ super(
|
|
+ transactionProcessor,
|
|
+ transactionReceiptFactory,
|
|
+ blockReward,
|
|
+ miningBeneficiaryCalculator,
|
|
+ skipZeroBlockRewards,
|
|
+ protocolSchedule,
|
|
+ balConfiguration,
|
|
+ metricsSystem);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockProcessingResult processBlock(
|
|
+ final ProtocolContext protocolContext,
|
|
+ final Blockchain blockchain,
|
|
+ final MutableWorldState worldState,
|
|
+ final Block block) {
|
|
+ return processBlock(protocolContext, blockchain, worldState, block, Optional.empty());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockProcessingResult processBlock(
|
|
+ final ProtocolContext protocolContext,
|
|
+ final Blockchain blockchain,
|
|
+ final MutableWorldState worldState,
|
|
+ final Block block,
|
|
+ final Optional<BlockAccessList> blockAccessList) {
|
|
+
|
|
+ final BlockProcessingResult result =
|
|
+ super.processBlock(
|
|
+ protocolContext,
|
|
+ blockchain,
|
|
+ worldState,
|
|
+ block,
|
|
+ blockAccessList,
|
|
+ new AereBlockStmPreprocessing(transactionProcessor, NCPU));
|
|
+
|
|
+ if (result.isFailed()) {
|
|
+ LOG.info(
|
|
+ "AERE Block-STM processing failure for block #{} ({}); falling back to sequential",
|
|
+ block.getHeader().getNumber(),
|
|
+ block.getHash());
|
|
+ if (worldState instanceof BonsaiWorldState) {
|
|
+ ((BonsaiWorldStateUpdateAccumulator) worldState.updater()).reset();
|
|
+ }
|
|
+ return super.processBlock(
|
|
+ protocolContext, blockchain, worldState, block, blockAccessList, new NoPreprocessing());
|
|
+ }
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ /** Builds {@link AereBlockStmProcessor}, mirroring Besu's parallel builder. */
|
|
+ public static class AereBlockStmProcessorBuilder
|
|
+ implements ProtocolSpecBuilder.BlockProcessorBuilder {
|
|
+
|
|
+ private final MetricsSystem metricsSystem;
|
|
+
|
|
+ /**
|
|
+ * @param metricsSystem metrics
|
|
+ */
|
|
+ public AereBlockStmProcessorBuilder(final MetricsSystem metricsSystem) {
|
|
+ this.metricsSystem = metricsSystem;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockProcessor apply(
|
|
+ final MainnetTransactionProcessor transactionProcessor,
|
|
+ final TransactionReceiptFactory transactionReceiptFactory,
|
|
+ final Wei blockReward,
|
|
+ final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
|
|
+ final boolean skipZeroBlockRewards,
|
|
+ final ProtocolSchedule protocolSchedule,
|
|
+ final BalConfiguration balConfiguration) {
|
|
+ return new AereBlockStmProcessor(
|
|
+ transactionProcessor,
|
|
+ transactionReceiptFactory,
|
|
+ blockReward,
|
|
+ miningBeneficiaryCalculator,
|
|
+ skipZeroBlockRewards,
|
|
+ protocolSchedule,
|
|
+ balConfiguration,
|
|
+ metricsSystem);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BaseReader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BaseReader.java
|
|
new file mode 100644
|
|
index 0000000000..2020655ef9
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BaseReader.java
|
|
@@ -0,0 +1,67 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+
|
|
+/**
|
|
+ * Read-only access to the immutable base (parent-block) world state. A {@code Base} read in
|
|
+ * MVMemory falls through to here. Implementations must be safe for concurrent reads (the base state
|
|
+ * does not change during block execution).
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public interface BaseReader {
|
|
+
|
|
+ /**
|
|
+ * Whether the account exists in base state.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return true if present
|
|
+ */
|
|
+ boolean accountExists(Address address);
|
|
+
|
|
+ /**
|
|
+ * Base nonce (0 if absent).
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return nonce
|
|
+ */
|
|
+ long getNonce(Address address);
|
|
+
|
|
+ /**
|
|
+ * Base balance (ZERO if absent).
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return balance
|
|
+ */
|
|
+ Wei getBalance(Address address);
|
|
+
|
|
+ /**
|
|
+ * Base code (EMPTY if absent).
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return code
|
|
+ */
|
|
+ Bytes getCode(Address address);
|
|
+
|
|
+ /**
|
|
+ * Base storage slot value (ZERO if absent).
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @param slot the slot
|
|
+ * @return value
|
|
+ */
|
|
+ UInt256 getStorageValue(Address address, UInt256 slot);
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BlockStmStats.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BlockStmStats.java
|
|
new file mode 100644
|
|
index 0000000000..a6a05f00ca
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/BlockStmStats.java
|
|
@@ -0,0 +1,38 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+/**
|
|
+ * Aggregate statistics for one Block-STM run.
|
|
+ *
|
|
+ * @param numTxns transactions in the block
|
|
+ * @param numThreads worker-pool size
|
|
+ * @param totalExecutions total incarnations executed (excess over numTxns = re-executions)
|
|
+ * @param totalValidations total validation tasks run
|
|
+ * @param totalAborts validation failures that triggered re-execution
|
|
+ * @param committedParallel transactions committed from a parallel outcome (not sequential fallback)
|
|
+ * @param verified whether the run reached scheduler.done() with no hard failure
|
|
+ * @param snapshotNanos wall-clock nanos spent building the flat base pre-snapshot (single Bonsai
|
|
+ * view mint + wrapper), excluded from the parallel execution phase
|
|
+ * @param execPhaseNanos wall-clock nanos of the PARALLEL EXECUTION PHASE only (worker pool start to
|
|
+ * termination); excludes both the snapshot build and the downstream serial Bonsai trie commit
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public record BlockStmStats(
|
|
+ int numTxns,
|
|
+ int numThreads,
|
|
+ int totalExecutions,
|
|
+ int totalValidations,
|
|
+ int totalAborts,
|
|
+ int committedParallel,
|
|
+ boolean verified,
|
|
+ long snapshotNanos,
|
|
+ long execPhaseNanos) {}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/FlatBaseSnapshot.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/FlatBaseSnapshot.java
|
|
new file mode 100644
|
|
index 0000000000..20c3441fca
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/FlatBaseSnapshot.java
|
|
@@ -0,0 +1,165 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.worldview.BonsaiWorldState;
|
|
+import org.hyperledger.besu.evm.account.Account;
|
|
+
|
|
+import java.util.Objects;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+
|
|
+/**
|
|
+ * A FLAT, immutable, in-memory pre-snapshot of the parent-block base world state, shared lock-free
|
|
+ * by every Block-STM worker.
|
|
+ *
|
|
+ * <p>Iteration-1 gave each worker its OWN frozen {@link BonsaiWorldState} view and routed every base
|
|
+ * read through a layered-trie traversal. Two costs dominated cheap-tx blocks and capped scaling on
|
|
+ * execution-bound blocks (task bottleneck #2): (1) minting {@code numThreads} BonsaiWorldState
|
|
+ * snapshots per block, and (2) re-walking the parent trie on every read, on every worker, on every
|
|
+ * re-execution incarnation, even for keys already seen.
|
|
+ *
|
|
+ * <p>This snapshot mints the parent Bonsai view exactly ONCE. Each distinct base value (account
|
|
+ * facet triple, or one storage slot) is materialised the first time any worker touches it and cached
|
|
+ * in a {@link ConcurrentHashMap}; every subsequent read by any worker/incarnation is a lock-free
|
|
+ * O(1) hashmap lookup with no trie traversal. Cold loads (cache misses) route through the single
|
|
+ * shared BonsaiWorldState and are serialised on {@link #loadLock} because a BonsaiWorldState is not
|
|
+ * safe for concurrent {@code get}; this cold path is one-time-per-key and negligible for
|
|
+ * execution-bound workloads, and the hot path is fully lock-free.
|
|
+ *
|
|
+ * <p>Serial-equivalence is preserved: the base state is immutable for the whole parallel round, so
|
|
+ * every worker observes identical parent values regardless of load order (parallelRoot ==
|
|
+ * sequentialRoot). An account is materialised as a whole {@link Shell} (existence + nonce + balance
|
|
+ * + code) in one trie hit, so the common pattern of reading several facets of the same account costs
|
|
+ * a single traversal.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+final class FlatBaseSnapshot implements BaseReader {
|
|
+
|
|
+ /** Immutable materialised account facet triple. */
|
|
+ private static final class Shell {
|
|
+ final boolean exists;
|
|
+ final long nonce;
|
|
+ final Wei balance;
|
|
+ final Bytes code;
|
|
+
|
|
+ Shell(final boolean exists, final long nonce, final Wei balance, final Bytes code) {
|
|
+ this.exists = exists;
|
|
+ this.nonce = nonce;
|
|
+ this.balance = balance;
|
|
+ this.code = code;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static final Shell ABSENT = new Shell(false, 0L, Wei.ZERO, Bytes.EMPTY);
|
|
+
|
|
+ /** Composite key for a materialised storage slot. */
|
|
+ private static final class SlotKey {
|
|
+ private final Address address;
|
|
+ private final UInt256 slot;
|
|
+ private final int hash;
|
|
+
|
|
+ SlotKey(final Address address, final UInt256 slot) {
|
|
+ this.address = address;
|
|
+ this.slot = slot;
|
|
+ this.hash = Objects.hash(address, slot);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(final Object o) {
|
|
+ if (this == o) {
|
|
+ return true;
|
|
+ }
|
|
+ if (!(o instanceof SlotKey)) {
|
|
+ return false;
|
|
+ }
|
|
+ final SlotKey k = (SlotKey) o;
|
|
+ return address.equals(k.address) && slot.equals(k.slot);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return hash;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final BonsaiWorldState bws;
|
|
+ private final Object loadLock = new Object();
|
|
+ private final ConcurrentHashMap<Address, Shell> accounts = new ConcurrentHashMap<>();
|
|
+ private final ConcurrentHashMap<SlotKey, UInt256> storage = new ConcurrentHashMap<>();
|
|
+
|
|
+ FlatBaseSnapshot(final BonsaiWorldState bws) {
|
|
+ this.bws = bws;
|
|
+ }
|
|
+
|
|
+ private Shell shell(final Address a) {
|
|
+ final Shell hit = accounts.get(a); // lock-free hot path
|
|
+ if (hit != null) {
|
|
+ return hit;
|
|
+ }
|
|
+ synchronized (loadLock) {
|
|
+ final Shell again = accounts.get(a);
|
|
+ if (again != null) {
|
|
+ return again;
|
|
+ }
|
|
+ final Account acct = bws.get(a);
|
|
+ final Shell shell =
|
|
+ acct == null
|
|
+ ? ABSENT
|
|
+ : new Shell(true, acct.getNonce(), acct.getBalance(), acct.getCode());
|
|
+ accounts.put(a, shell);
|
|
+ return shell;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean accountExists(final Address address) {
|
|
+ return shell(address).exists;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getNonce(final Address address) {
|
|
+ return shell(address).nonce;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Wei getBalance(final Address address) {
|
|
+ return shell(address).balance;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Bytes getCode(final Address address) {
|
|
+ return shell(address).code;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public UInt256 getStorageValue(final Address address, final UInt256 slot) {
|
|
+ final SlotKey key = new SlotKey(address, slot);
|
|
+ final UInt256 hit = storage.get(key); // lock-free hot path
|
|
+ if (hit != null) {
|
|
+ return hit;
|
|
+ }
|
|
+ synchronized (loadLock) {
|
|
+ final UInt256 again = storage.get(key);
|
|
+ if (again != null) {
|
|
+ return again;
|
|
+ }
|
|
+ final Account acct = bws.get(address);
|
|
+ final UInt256 value = acct == null ? UInt256.ZERO : acct.getStorageValue(slot);
|
|
+ storage.put(key, value);
|
|
+ return value;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvAccount.java
|
|
new file mode 100644
|
|
index 0000000000..97feae1227
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvAccount.java
|
|
@@ -0,0 +1,82 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.evm.fluent.SimpleAccount;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+
|
|
+/**
|
|
+ * An account facade over multi-version memory for a single Block-STM incarnation. Reads of a storage
|
|
+ * slot are routed through MVMemory (highest lower-index write, else base), recording the observed
|
|
+ * provenance into the execution's read set. Writes buffer in the inherited {@link SimpleAccount}
|
|
+ * overlay and are extracted as the write set after execution.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class MvAccount extends SimpleAccount {
|
|
+
|
|
+ private final MvContext ctx;
|
|
+ private final Address addr;
|
|
+
|
|
+ // Values this incarnation started from (for write-set diffing).
|
|
+ private final long seededNonce;
|
|
+ private final Wei seededBalance;
|
|
+ private final Hash seededCodeHash;
|
|
+
|
|
+ MvAccount(
|
|
+ final MvContext ctx,
|
|
+ final Address address,
|
|
+ final long nonce,
|
|
+ final Wei balance,
|
|
+ final Bytes code) {
|
|
+ super(null, address, nonce, balance, code);
|
|
+ this.ctx = ctx;
|
|
+ this.addr = address;
|
|
+ this.seededNonce = nonce;
|
|
+ this.seededBalance = balance;
|
|
+ this.seededCodeHash = code == null || code.isEmpty() ? Hash.EMPTY : Hash.hash(code);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public UInt256 getOriginalStorageValue(final UInt256 key) {
|
|
+ final MvKey k = MvKey.storage(addr, key);
|
|
+ final MvMemory.ReadResult rr = ctx.mv.read(k, ctx.txnIdx);
|
|
+ if (rr.isBlocked()) {
|
|
+ if (ctx.blockedOn < 0) {
|
|
+ ctx.blockedOn = rr.blockingTxn();
|
|
+ }
|
|
+ return UInt256.ZERO;
|
|
+ }
|
|
+ if (!rr.descriptor().isBase()) {
|
|
+ ctx.record(k, rr.descriptor());
|
|
+ final Object v = rr.value();
|
|
+ return v == null ? UInt256.ZERO : (UInt256) v;
|
|
+ }
|
|
+ ctx.record(k, MvMemory.ReadDescriptor.BASE);
|
|
+ return ctx.base.getStorageValue(addr, key);
|
|
+ }
|
|
+
|
|
+ long seededNonce() {
|
|
+ return seededNonce;
|
|
+ }
|
|
+
|
|
+ Wei seededBalance() {
|
|
+ return seededBalance;
|
|
+ }
|
|
+
|
|
+ Hash seededCodeHash() {
|
|
+ return seededCodeHash;
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvBaseLayer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvBaseLayer.java
|
|
new file mode 100644
|
|
index 0000000000..bbb54d60c2
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvBaseLayer.java
|
|
@@ -0,0 +1,149 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.evm.account.Account;
|
|
+import org.hyperledger.besu.evm.account.MutableAccount;
|
|
+import org.hyperledger.besu.evm.fluent.SimpleWorld;
|
|
+
|
|
+import java.util.HashMap;
|
|
+import java.util.HashSet;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+
|
|
+/**
|
|
+ * The base (bottom) world layer for one Block-STM incarnation. It never holds writes: every EVM
|
|
+ * write lands in a child {@link SimpleWorld} layer obtained via {@link #updater()}. On a miss, this
|
|
+ * layer materialises an {@link MvAccount} by routing balance/nonce/code reads through MVMemory
|
|
+ * (highest lower-index write, else the immutable base state), recording provenance into the read
|
|
+ * set. Storage reads route lazily inside {@link MvAccount}.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class MvBaseLayer extends SimpleWorld {
|
|
+
|
|
+ private final MvContext ctx;
|
|
+ private final Map<Address, MvAccount> materialized = new HashMap<>();
|
|
+ private final Set<Address> absent = new HashSet<>();
|
|
+
|
|
+ MvBaseLayer(final MvContext ctx) {
|
|
+ super();
|
|
+ this.ctx = ctx;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Account get(final Address address) {
|
|
+ return getAccount(address);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public MutableAccount getAccount(final Address address) {
|
|
+ final MvAccount m = materialized.get(address);
|
|
+ if (m != null) {
|
|
+ return m;
|
|
+ }
|
|
+ if (absent.contains(address)) {
|
|
+ return null;
|
|
+ }
|
|
+ final MvAccount created = materialize(address);
|
|
+ if (created == null) {
|
|
+ absent.add(address);
|
|
+ return null;
|
|
+ }
|
|
+ materialized.put(address, created);
|
|
+ return created;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The seeded (pre-execution) account, for write-set diffing.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return the materialised account, or null if it was absent / freshly created in a child layer
|
|
+ */
|
|
+ MvAccount materializedAccount(final Address address) {
|
|
+ return materialized.get(address);
|
|
+ }
|
|
+
|
|
+ private MvAccount materialize(final Address a) {
|
|
+ boolean exists = ctx.base.accountExists(a);
|
|
+
|
|
+ // balance (beneficiary balance is excluded from conflict tracking)
|
|
+ final Wei balance;
|
|
+ if (ctx.isBeneficiary(a)) {
|
|
+ balance = ctx.base.getBalance(a);
|
|
+ } else {
|
|
+ final MvKey k = MvKey.balance(a);
|
|
+ final MvMemory.ReadResult rr = ctx.mv.read(k, ctx.txnIdx);
|
|
+ if (rr.isBlocked()) {
|
|
+ block(rr);
|
|
+ balance = Wei.ZERO;
|
|
+ } else if (!rr.descriptor().isBase()) {
|
|
+ ctx.record(k, rr.descriptor());
|
|
+ balance = (Wei) rr.value();
|
|
+ exists = true;
|
|
+ } else {
|
|
+ ctx.record(k, MvMemory.ReadDescriptor.BASE);
|
|
+ balance = ctx.base.getBalance(a);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // nonce
|
|
+ final long nonce;
|
|
+ {
|
|
+ final MvKey k = MvKey.nonce(a);
|
|
+ final MvMemory.ReadResult rr = ctx.mv.read(k, ctx.txnIdx);
|
|
+ if (rr.isBlocked()) {
|
|
+ block(rr);
|
|
+ nonce = 0L;
|
|
+ } else if (!rr.descriptor().isBase()) {
|
|
+ ctx.record(k, rr.descriptor());
|
|
+ nonce = (Long) rr.value();
|
|
+ exists = true;
|
|
+ } else {
|
|
+ ctx.record(k, MvMemory.ReadDescriptor.BASE);
|
|
+ nonce = ctx.base.getNonce(a);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // code
|
|
+ final Bytes code;
|
|
+ {
|
|
+ final MvKey k = MvKey.code(a);
|
|
+ final MvMemory.ReadResult rr = ctx.mv.read(k, ctx.txnIdx);
|
|
+ if (rr.isBlocked()) {
|
|
+ block(rr);
|
|
+ code = Bytes.EMPTY;
|
|
+ } else if (!rr.descriptor().isBase()) {
|
|
+ ctx.record(k, rr.descriptor());
|
|
+ code = (Bytes) rr.value();
|
|
+ exists = true;
|
|
+ } else {
|
|
+ ctx.record(k, MvMemory.ReadDescriptor.BASE);
|
|
+ code = ctx.base.getCode(a);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!exists) {
|
|
+ // Absent account: reads recorded so a later creating write is caught by validation.
|
|
+ return null;
|
|
+ }
|
|
+ return new MvAccount(ctx, a, nonce, balance, code);
|
|
+ }
|
|
+
|
|
+ private void block(final MvMemory.ReadResult rr) {
|
|
+ if (ctx.blockedOn < 0) {
|
|
+ ctx.blockedOn = rr.blockingTxn();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvContext.java
|
|
new file mode 100644
|
|
index 0000000000..6f1902b421
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvContext.java
|
|
@@ -0,0 +1,55 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.util.LinkedHashMap;
|
|
+import java.util.Map;
|
|
+
|
|
+/**
|
|
+ * Per-execution capture state for one incarnation of one transaction. Confined to the single worker
|
|
+ * thread executing that incarnation, so it needs no synchronization internally.
|
|
+ *
|
|
+ * <p>Records the read set (key -> observed provenance) for later validation, and the address of the
|
|
+ * mining beneficiary, whose balance is excluded from conflict detection (its reward is applied
|
|
+ * additively during in-order commit, mirroring Besu's {@code traceBeforeRewardTransaction} trick).
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public final class MvContext {
|
|
+
|
|
+ final int txnIdx;
|
|
+ final MvMemory mv;
|
|
+ final BaseReader base;
|
|
+ final Address beneficiary;
|
|
+
|
|
+ /** key -> first observed provenance (dedup on key, preserve encounter order). */
|
|
+ final Map<MvKey, MvMemory.ReadDescriptor> reads = new LinkedHashMap<>();
|
|
+
|
|
+ /** set to the blocking txn index (>=0) the first time a read hit an ESTIMATE. */
|
|
+ int blockedOn = -1;
|
|
+
|
|
+ MvContext(
|
|
+ final int txnIdx, final MvMemory mv, final BaseReader base, final Address beneficiary) {
|
|
+ this.txnIdx = txnIdx;
|
|
+ this.mv = mv;
|
|
+ this.base = base;
|
|
+ this.beneficiary = beneficiary;
|
|
+ }
|
|
+
|
|
+ void record(final MvKey key, final MvMemory.ReadDescriptor desc) {
|
|
+ reads.putIfAbsent(key, desc);
|
|
+ }
|
|
+
|
|
+ boolean isBeneficiary(final Address a) {
|
|
+ return beneficiary != null && beneficiary.equals(a);
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvKey.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvKey.java
|
|
new file mode 100644
|
|
index 0000000000..b06eecf35c
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvKey.java
|
|
@@ -0,0 +1,156 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+
|
|
+import java.util.Objects;
|
|
+
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+
|
|
+/**
|
|
+ * A location in world state that Block-STM tracks for read/write-set conflict detection. Mirrors the
|
|
+ * Rust {@code Key} enum (Balance / Storage) generalised to the four EVM account facets that a
|
|
+ * transaction can read or write: BALANCE, NONCE, CODE and a STORAGE slot.
|
|
+ *
|
|
+ * <p>This is the unit over which MVMemory shards and over which read-set validation compares
|
|
+ * provenance. Two {@code MvKey}s are equal iff they refer to the same facet of the same account (and
|
|
+ * same slot for STORAGE).
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public final class MvKey {
|
|
+
|
|
+ /** The account facet this key addresses. */
|
|
+ public enum Kind {
|
|
+ /** Account balance. */
|
|
+ BALANCE,
|
|
+ /** Account nonce. */
|
|
+ NONCE,
|
|
+ /** Account code. */
|
|
+ CODE,
|
|
+ /** A single storage slot. */
|
|
+ STORAGE
|
|
+ }
|
|
+
|
|
+ private final Kind kind;
|
|
+ private final Address address;
|
|
+ private final UInt256 slot; // null unless STORAGE
|
|
+ private final int hash;
|
|
+
|
|
+ private MvKey(final Kind kind, final Address address, final UInt256 slot) {
|
|
+ this.kind = kind;
|
|
+ this.address = address;
|
|
+ this.slot = slot;
|
|
+ this.hash = Objects.hash(kind, address, slot);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Balance key.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return the key
|
|
+ */
|
|
+ public static MvKey balance(final Address address) {
|
|
+ return new MvKey(Kind.BALANCE, address, null);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Nonce key.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return the key
|
|
+ */
|
|
+ public static MvKey nonce(final Address address) {
|
|
+ return new MvKey(Kind.NONCE, address, null);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Code key.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @return the key
|
|
+ */
|
|
+ public static MvKey code(final Address address) {
|
|
+ return new MvKey(Kind.CODE, address, null);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Storage-slot key.
|
|
+ *
|
|
+ * @param address the account
|
|
+ * @param slot the slot
|
|
+ * @return the key
|
|
+ */
|
|
+ public static MvKey storage(final Address address, final UInt256 slot) {
|
|
+ return new MvKey(Kind.STORAGE, address, slot);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The facet kind.
|
|
+ *
|
|
+ * @return kind
|
|
+ */
|
|
+ public Kind kind() {
|
|
+ return kind;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * The account address.
|
|
+ *
|
|
+ * @return address
|
|
+ */
|
|
+ public Address address() {
|
|
+ return address;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Deterministic shard index, mirroring the Rust FNV-1a spread.
|
|
+ *
|
|
+ * @param shards number of shards
|
|
+ * @return shard index in [0, shards)
|
|
+ */
|
|
+ public int shard(final int shards) {
|
|
+ long h = 0xcbf29ce484222325L;
|
|
+ h = fnv(h, kind.ordinal() + 1L);
|
|
+ h = fnv(h, address.hashCode() & 0xffffffffL);
|
|
+ h = fnv(h, slot == null ? 0L : slot.hashCode() & 0xffffffffL);
|
|
+ int s = (int) Long.remainderUnsigned(h, shards);
|
|
+ return s;
|
|
+ }
|
|
+
|
|
+ private static long fnv(final long acc, final long b) {
|
|
+ long h = acc ^ b;
|
|
+ h *= 0x100000001b3L;
|
|
+ return h;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(final Object o) {
|
|
+ if (this == o) {
|
|
+ return true;
|
|
+ }
|
|
+ if (!(o instanceof MvKey)) {
|
|
+ return false;
|
|
+ }
|
|
+ final MvKey k = (MvKey) o;
|
|
+ return kind == k.kind && address.equals(k.address) && Objects.equals(slot, k.slot);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return hash;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String toString() {
|
|
+ return kind + "(" + address + (slot == null ? "" : "," + slot.toShortHexString()) + ")";
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvMemory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvMemory.java
|
|
new file mode 100644
|
|
index 0000000000..914df3a3ad
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/MvMemory.java
|
|
@@ -0,0 +1,266 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import java.util.HashMap;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.TreeMap;
|
|
+import java.util.concurrent.locks.ReentrantLock;
|
|
+
|
|
+/**
|
|
+ * Multi-version shared memory (MVMemory). Faithful Java port of the AERE Rust {@code mvmemory.rs}
|
|
+ * (Gelashvili et al. 2022).
|
|
+ *
|
|
+ * <p>For every {@link MvKey}, MVMemory keeps an ordered map {@code txnIndex -> Cell}, where a cell
|
|
+ * is either a concrete value written by that transaction's latest incarnation, or an ESTIMATE
|
|
+ * placeholder (a marker that a lower transaction previously wrote here but is currently being
|
|
+ * re-executed, so its value is not trustworthy).
|
|
+ *
|
|
+ * <p>A read by transaction {@code i} for key {@code k} returns the entry of the HIGHEST transaction
|
|
+ * {@code j < i} that wrote {@code k}. That is what makes speculative parallel execution
|
|
+ * serial-equivalent: transaction {@code i} always observes the writes of all lower-indexed
|
|
+ * transactions that have run, and nothing from higher ones.
|
|
+ *
|
|
+ * <p>Storage is sharded across many independent locks keyed by a hash of the key, so
|
|
+ * non-conflicting transactions touch disjoint locks and run without contention.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class MvMemory {
|
|
+
|
|
+ private static final int SHARDS = 256;
|
|
+
|
|
+ /** What a read observed, recorded into the reader's read set for later validation. */
|
|
+ public enum DescKind {
|
|
+ /** Nothing below the reader wrote this key: it came from base state. */
|
|
+ BASE,
|
|
+ /** It was written by some (txnIndex, incarnation). */
|
|
+ VERSION
|
|
+ }
|
|
+
|
|
+ /** A read-set descriptor: BASE, or VERSION(txnIndex, incarnation). */
|
|
+ public static final class ReadDescriptor {
|
|
+ /** Shared BASE singleton. */
|
|
+ public static final ReadDescriptor BASE = new ReadDescriptor(DescKind.BASE, -1, -1);
|
|
+
|
|
+ private final DescKind kind;
|
|
+ private final int txnIndex;
|
|
+ private final int incarnation;
|
|
+
|
|
+ private ReadDescriptor(final DescKind kind, final int txnIndex, final int incarnation) {
|
|
+ this.kind = kind;
|
|
+ this.txnIndex = txnIndex;
|
|
+ this.incarnation = incarnation;
|
|
+ }
|
|
+
|
|
+ static ReadDescriptor version(final int txnIndex, final int incarnation) {
|
|
+ return new ReadDescriptor(DescKind.VERSION, txnIndex, incarnation);
|
|
+ }
|
|
+
|
|
+ /** @return true if this descriptor is a BASE read. */
|
|
+ public boolean isBase() {
|
|
+ return kind == DescKind.BASE;
|
|
+ }
|
|
+
|
|
+ boolean sameProvenance(final ReadDescriptor other) {
|
|
+ if (kind != other.kind) {
|
|
+ return false;
|
|
+ }
|
|
+ if (kind == DescKind.BASE) {
|
|
+ return true;
|
|
+ }
|
|
+ return txnIndex == other.txnIndex && incarnation == other.incarnation;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** Live read outcome: OK(descriptor,value) or BLOCKED(blockingTxn). */
|
|
+ public static final class ReadResult {
|
|
+ final boolean blocked;
|
|
+ final int blockingTxn;
|
|
+ final ReadDescriptor descriptor;
|
|
+ final Object value;
|
|
+
|
|
+ private ReadResult(
|
|
+ final boolean blocked,
|
|
+ final int blockingTxn,
|
|
+ final ReadDescriptor descriptor,
|
|
+ final Object value) {
|
|
+ this.blocked = blocked;
|
|
+ this.blockingTxn = blockingTxn;
|
|
+ this.descriptor = descriptor;
|
|
+ this.value = value;
|
|
+ }
|
|
+
|
|
+ static ReadResult ok(final ReadDescriptor d, final Object v) {
|
|
+ return new ReadResult(false, -1, d, v);
|
|
+ }
|
|
+
|
|
+ static ReadResult blocked(final int blockingTxn) {
|
|
+ return new ReadResult(true, blockingTxn, null, null);
|
|
+ }
|
|
+
|
|
+ /** @return true if this read hit an ESTIMATE and the reader must park. */
|
|
+ public boolean isBlocked() {
|
|
+ return blocked;
|
|
+ }
|
|
+
|
|
+ /** @return the blocking txn index (valid iff {@link #isBlocked()}). */
|
|
+ public int blockingTxn() {
|
|
+ return blockingTxn;
|
|
+ }
|
|
+
|
|
+ /** @return the observed provenance descriptor (valid iff not blocked). */
|
|
+ public ReadDescriptor descriptor() {
|
|
+ return descriptor;
|
|
+ }
|
|
+
|
|
+ /** @return the observed value, or null for a BASE read (caller falls back to base state). */
|
|
+ public Object value() {
|
|
+ return value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static final class Cell {
|
|
+ final boolean estimate;
|
|
+ final int incarnation;
|
|
+ final Object value;
|
|
+
|
|
+ private Cell(final boolean estimate, final int incarnation, final Object value) {
|
|
+ this.estimate = estimate;
|
|
+ this.incarnation = incarnation;
|
|
+ this.value = value;
|
|
+ }
|
|
+
|
|
+ static Cell value(final int inc, final Object v) {
|
|
+ return new Cell(false, inc, v);
|
|
+ }
|
|
+
|
|
+ static final Cell ESTIMATE = new Cell(true, -1, null);
|
|
+ }
|
|
+
|
|
+ private final ReentrantLock[] locks = new ReentrantLock[SHARDS];
|
|
+ // shard -> (key -> (txnIndex -> Cell))
|
|
+ private final Map<MvKey, TreeMap<Integer, Cell>>[] shards;
|
|
+
|
|
+ /** New empty MVMemory. */
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
+ public MvMemory() {
|
|
+ shards = new Map[SHARDS];
|
|
+ for (int i = 0; i < SHARDS; i++) {
|
|
+ locks[i] = new ReentrantLock();
|
|
+ shards[i] = new HashMap<>();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Read the value visible to {@code txnIdx}: the highest entry strictly below it.
|
|
+ *
|
|
+ * @param key the key
|
|
+ * @param txnIdx the reading transaction index
|
|
+ * @return the read result
|
|
+ */
|
|
+ public ReadResult read(final MvKey key, final int txnIdx) {
|
|
+ final int s = key.shard(SHARDS);
|
|
+ locks[s].lock();
|
|
+ try {
|
|
+ final TreeMap<Integer, Cell> versions = shards[s].get(key);
|
|
+ if (versions != null) {
|
|
+ final Map.Entry<Integer, Cell> e = versions.lowerEntry(txnIdx);
|
|
+ if (e != null) {
|
|
+ final Cell cell = e.getValue();
|
|
+ if (cell.estimate) {
|
|
+ return ReadResult.blocked(e.getKey());
|
|
+ }
|
|
+ return ReadResult.ok(ReadDescriptor.version(e.getKey(), cell.incarnation), cell.value);
|
|
+ }
|
|
+ }
|
|
+ return ReadResult.ok(ReadDescriptor.BASE, null);
|
|
+ } finally {
|
|
+ locks[s].unlock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Install {@code txnIdx}'s new write set (incarnation {@code inc}); remove stale entries the
|
|
+ * previous incarnation wrote but this one no longer does. Returns true if the written key-SET
|
|
+ * changed (a key added or removed) — Block-STM's "wrote a new path", which triggers revalidation
|
|
+ * of the suffix.
|
|
+ *
|
|
+ * @param txnIdx the writing transaction
|
|
+ * @param inc the incarnation
|
|
+ * @param writes the new write set
|
|
+ * @param prevKeys the keys written by the previous incarnation
|
|
+ * @return whether the written key-set changed
|
|
+ */
|
|
+ public boolean applyWriteSet(
|
|
+ final int txnIdx,
|
|
+ final int inc,
|
|
+ final Map<MvKey, Object> writes,
|
|
+ final Set<MvKey> prevKeys) {
|
|
+ for (final Map.Entry<MvKey, Object> w : writes.entrySet()) {
|
|
+ final MvKey k = w.getKey();
|
|
+ final int s = k.shard(SHARDS);
|
|
+ locks[s].lock();
|
|
+ try {
|
|
+ shards[s].computeIfAbsent(k, kk -> new TreeMap<>()).put(txnIdx, Cell.value(inc, w.getValue()));
|
|
+ } finally {
|
|
+ locks[s].unlock();
|
|
+ }
|
|
+ }
|
|
+ boolean removedAny = false;
|
|
+ for (final MvKey k : prevKeys) {
|
|
+ if (!writes.containsKey(k)) {
|
|
+ final int s = k.shard(SHARDS);
|
|
+ locks[s].lock();
|
|
+ try {
|
|
+ final TreeMap<Integer, Cell> versions = shards[s].get(k);
|
|
+ if (versions != null) {
|
|
+ versions.remove(txnIdx);
|
|
+ }
|
|
+ } finally {
|
|
+ locks[s].unlock();
|
|
+ }
|
|
+ removedAny = true;
|
|
+ }
|
|
+ }
|
|
+ boolean addedAny = false;
|
|
+ for (final MvKey k : writes.keySet()) {
|
|
+ if (!prevKeys.contains(k)) {
|
|
+ addedAny = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return addedAny || removedAny;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Convert all of {@code txnIdx}'s current writes (over {@code keys}) into ESTIMATE placeholders,
|
|
+ * so any concurrent higher transaction that reads one of these keys blocks on {@code txnIdx}
|
|
+ * instead of consuming a soon-to-be-wrong value.
|
|
+ *
|
|
+ * @param txnIdx the aborted transaction
|
|
+ * @param keys its written keys
|
|
+ */
|
|
+ public void markEstimates(final int txnIdx, final Set<MvKey> keys) {
|
|
+ for (final MvKey k : keys) {
|
|
+ final int s = k.shard(SHARDS);
|
|
+ locks[s].lock();
|
|
+ try {
|
|
+ final TreeMap<Integer, Cell> versions = shards[s].get(k);
|
|
+ if (versions != null && versions.containsKey(txnIdx)) {
|
|
+ versions.put(txnIdx, Cell.ESTIMATE);
|
|
+ }
|
|
+ } finally {
|
|
+ locks[s].unlock();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/Scheduler.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/Scheduler.java
|
|
new file mode 100644
|
|
index 0000000000..a967bbd6f3
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/blockstm/Scheduler.java
|
|
@@ -0,0 +1,390 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.blockstm;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import java.util.concurrent.locks.ReentrantLock;
|
|
+
|
|
+/**
|
|
+ * The Block-STM collaborative scheduler (Gelashvili et al. 2022, Algorithm 3). Faithful Java port of
|
|
+ * the AERE Rust {@code scheduler.rs}.
|
|
+ *
|
|
+ * <p>Hands out EXECUTION and VALIDATION tasks to a worker pool. Two cursors ({@code executionIdx},
|
|
+ * {@code validationIdx}) drive it; validation of a lower index always takes priority over execution
|
|
+ * of a higher one. When a transaction aborts or writes a new path, the relevant cursor is decreased
|
|
+ * so the affected range is revisited. The block is done when both cursors have passed the end AND no
|
|
+ * task is in flight AND no decrease happened during the check. Dependencies are handled without
|
|
+ * condvars via parking on the blocker's dependency list.
|
|
+ */
|
|
+@SuppressWarnings("MissingSummary")
|
|
+public class Scheduler {
|
|
+
|
|
+ /** Task type handed to a worker. */
|
|
+ public enum TaskKind {
|
|
+ /** Run incarnation {@code inc} of transaction {@code idx}. */
|
|
+ EXECUTION,
|
|
+ /** Re-check {@code idx}'s read set. */
|
|
+ VALIDATION,
|
|
+ /** No task available right now; retry. */
|
|
+ NO_TASK,
|
|
+ /** Block fully executed & validated. */
|
|
+ DONE
|
|
+ }
|
|
+
|
|
+ /** A unit of work, or a control signal. */
|
|
+ public static final class Task {
|
|
+ /** Shared NO_TASK singleton. */
|
|
+ public static final Task NO_TASK = new Task(TaskKind.NO_TASK, -1, -1);
|
|
+ /** Shared DONE singleton. */
|
|
+ public static final Task DONE = new Task(TaskKind.DONE, -1, -1);
|
|
+
|
|
+ final TaskKind kind;
|
|
+ final int idx;
|
|
+ final int inc;
|
|
+
|
|
+ Task(final TaskKind kind, final int idx, final int inc) {
|
|
+ this.kind = kind;
|
|
+ this.idx = idx;
|
|
+ this.inc = inc;
|
|
+ }
|
|
+
|
|
+ /** @return the task kind */
|
|
+ public TaskKind kind() {
|
|
+ return kind;
|
|
+ }
|
|
+
|
|
+ /** @return the transaction index */
|
|
+ public int idx() {
|
|
+ return idx;
|
|
+ }
|
|
+
|
|
+ /** @return the incarnation */
|
|
+ public int inc() {
|
|
+ return inc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private enum StatusKind {
|
|
+ READY_TO_EXECUTE,
|
|
+ EXECUTING,
|
|
+ SUSPENDED,
|
|
+ EXECUTED,
|
|
+ ABORTING
|
|
+ }
|
|
+
|
|
+ private static final class Status {
|
|
+ StatusKind kind;
|
|
+ int inc;
|
|
+
|
|
+ Status(final StatusKind kind, final int inc) {
|
|
+ this.kind = kind;
|
|
+ this.inc = inc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final int numTxns;
|
|
+ private final AtomicInteger executionIdx = new AtomicInteger(0);
|
|
+ private final AtomicInteger validationIdx = new AtomicInteger(0);
|
|
+ private final AtomicInteger decreaseCnt = new AtomicInteger(0);
|
|
+ private final AtomicInteger numActiveTasks = new AtomicInteger(0);
|
|
+ private final AtomicBoolean done = new AtomicBoolean(false);
|
|
+ private final Status[] status;
|
|
+ private final ReentrantLock[] statusLocks;
|
|
+ private final List<Integer>[] dependencies;
|
|
+ private final ReentrantLock[] depLocks;
|
|
+
|
|
+ /**
|
|
+ * New scheduler over {@code numTxns} transactions.
|
|
+ *
|
|
+ * @param numTxns transaction count
|
|
+ */
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
+ public Scheduler(final int numTxns) {
|
|
+ this.numTxns = numTxns;
|
|
+ this.status = new Status[numTxns];
|
|
+ this.statusLocks = new ReentrantLock[numTxns];
|
|
+ this.dependencies = new List[numTxns];
|
|
+ this.depLocks = new ReentrantLock[numTxns];
|
|
+ for (int i = 0; i < numTxns; i++) {
|
|
+ status[i] = new Status(StatusKind.READY_TO_EXECUTE, 0);
|
|
+ statusLocks[i] = new ReentrantLock();
|
|
+ dependencies[i] = new ArrayList<>();
|
|
+ depLocks[i] = new ReentrantLock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /** @return true once the block is fully executed & validated. */
|
|
+ public boolean done() {
|
|
+ return done.get();
|
|
+ }
|
|
+
|
|
+ private void decreaseExecutionIdx(final int target) {
|
|
+ executionIdx.getAndUpdate(cur -> Math.min(cur, target));
|
|
+ decreaseCnt.incrementAndGet();
|
|
+ }
|
|
+
|
|
+ private void decreaseValidationIdx(final int target) {
|
|
+ validationIdx.getAndUpdate(cur -> Math.min(cur, target));
|
|
+ decreaseCnt.incrementAndGet();
|
|
+ }
|
|
+
|
|
+ private void checkDone() {
|
|
+ final int observed = decreaseCnt.get();
|
|
+ if (executionIdx.get() >= numTxns
|
|
+ && validationIdx.get() >= numTxns
|
|
+ && numActiveTasks.get() == 0
|
|
+ && decreaseCnt.get() == observed) {
|
|
+ done.set(true);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Task tryIncarnate(final int idx) {
|
|
+ if (idx < numTxns) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.READY_TO_EXECUTE) {
|
|
+ final int inc = status[idx].inc;
|
|
+ status[idx].kind = StatusKind.EXECUTING;
|
|
+ return new Task(TaskKind.EXECUTION, idx, inc);
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ private Task nextVersionToExecute() {
|
|
+ if (executionIdx.get() >= numTxns) {
|
|
+ checkDone();
|
|
+ return null;
|
|
+ }
|
|
+ numActiveTasks.incrementAndGet();
|
|
+ final int idx = executionIdx.getAndIncrement();
|
|
+ return tryIncarnate(idx);
|
|
+ }
|
|
+
|
|
+ private Task nextVersionToValidate() {
|
|
+ if (validationIdx.get() >= numTxns) {
|
|
+ checkDone();
|
|
+ return null;
|
|
+ }
|
|
+ numActiveTasks.incrementAndGet();
|
|
+ final int idx = validationIdx.getAndIncrement();
|
|
+ if (idx < numTxns) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.EXECUTED) {
|
|
+ return new Task(TaskKind.VALIDATION, idx, status[idx].inc);
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Main entry point workers spin on.
|
|
+ *
|
|
+ * @return a task, NO_TASK (retry), or DONE
|
|
+ */
|
|
+ public Task nextTask() {
|
|
+ int idle = 0;
|
|
+ while (true) {
|
|
+ if (done.get()) {
|
|
+ return Task.DONE;
|
|
+ }
|
|
+ final int v = validationIdx.get();
|
|
+ final int e = executionIdx.get();
|
|
+ Task task = (v < e) ? nextVersionToValidate() : nextVersionToExecute();
|
|
+ if (task == null && v < e) {
|
|
+ // The preferred lower-index validation had nothing runnable (its target is still
|
|
+ // EXECUTING on another worker). Rather than busy-draining validationIdx while pending
|
|
+ // independent EXECUTION tasks sit ungrabbed (which starved real parallel work and made
|
|
+ // the execution phase anti-scale with worker count), try to grab a pending execution.
|
|
+ // This is scheduling-order only: executing any READY incarnation in any order is already
|
|
+ // permitted by Block-STM, and read-set validation still re-checks and re-executes on any
|
|
+ // conflict, so the committed result stays bit-identical to sequential.
|
|
+ task = nextVersionToExecute();
|
|
+ }
|
|
+ if (task != null) {
|
|
+ return task;
|
|
+ }
|
|
+ if (done.get()) {
|
|
+ return Task.DONE;
|
|
+ }
|
|
+ // Nothing runnable right now: back off so idle workers stop ping-ponging the shared
|
|
+ // cursors/locks across cores (that cache-line contention slows the workers doing real
|
|
+ // execution). Pure CPU hint / brief park; does not alter task selection or ordering.
|
|
+ if (++idle < 128) {
|
|
+ Thread.onSpinWait();
|
|
+ } else {
|
|
+ java.util.concurrent.locks.LockSupport.parkNanos(Math.min((idle - 127) * 512L, 50_000L));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Register that {@code idx} depends on {@code blocking} (it read {@code blocking}'s ESTIMATE).
|
|
+ *
|
|
+ * @param idx the reader
|
|
+ * @param blocking the blocker
|
|
+ * @return true if {@code idx} was parked (caller drops the task); false if {@code blocking}
|
|
+ * already finished (caller re-executes {@code idx})
|
|
+ */
|
|
+ public boolean addDependency(final int idx, final int blocking) {
|
|
+ statusLocks[blocking].lock();
|
|
+ try {
|
|
+ if (status[blocking].kind == StatusKind.EXECUTED) {
|
|
+ return false;
|
|
+ }
|
|
+ depLocks[blocking].lock();
|
|
+ try {
|
|
+ dependencies[blocking].add(idx);
|
|
+ } finally {
|
|
+ depLocks[blocking].unlock();
|
|
+ }
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.EXECUTING) {
|
|
+ status[idx].kind = StatusKind.SUSPENDED;
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[blocking].unlock();
|
|
+ }
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private void resume(final int idx) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.SUSPENDED) {
|
|
+ status[idx].kind = StatusKind.READY_TO_EXECUTE;
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void setReadyAfterAbort(final int idx) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.ABORTING) {
|
|
+ status[idx].kind = StatusKind.READY_TO_EXECUTE;
|
|
+ status[idx].inc = status[idx].inc + 1;
|
|
+ }
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void setExecuted(final int idx, final int inc) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ status[idx].kind = StatusKind.EXECUTED;
|
|
+ status[idx].inc = inc;
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Called after an execution task completes.
|
|
+ *
|
|
+ * @param idx transaction
|
|
+ * @param inc incarnation
|
|
+ * @param wroteNewPath whether the written key-set changed vs the previous incarnation
|
|
+ * @return a follow-up task (inheriting the active-task unit) or NO_TASK (releasing it)
|
|
+ */
|
|
+ public Task finishExecution(final int idx, final int inc, final boolean wroteNewPath) {
|
|
+ setExecuted(idx, inc);
|
|
+
|
|
+ final List<Integer> deps;
|
|
+ depLocks[idx].lock();
|
|
+ try {
|
|
+ deps = new ArrayList<>(dependencies[idx]);
|
|
+ dependencies[idx].clear();
|
|
+ } finally {
|
|
+ depLocks[idx].unlock();
|
|
+ }
|
|
+ if (!deps.isEmpty()) {
|
|
+ final int minDep = Collections.min(deps);
|
|
+ for (final int d : deps) {
|
|
+ resume(d);
|
|
+ }
|
|
+ decreaseExecutionIdx(minDep);
|
|
+ }
|
|
+
|
|
+ if (validationIdx.get() > idx) {
|
|
+ if (wroteNewPath) {
|
|
+ decreaseValidationIdx(idx);
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return Task.NO_TASK;
|
|
+ } else {
|
|
+ return new Task(TaskKind.VALIDATION, idx, inc);
|
|
+ }
|
|
+ } else {
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return Task.NO_TASK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Attempt to win the right to abort {@code idx} at {@code inc}.
|
|
+ *
|
|
+ * @param idx transaction
|
|
+ * @param inc incarnation
|
|
+ * @return true iff this caller flipped EXECUTED(inc) -> ABORTING(inc)
|
|
+ */
|
|
+ public boolean tryValidationAbort(final int idx, final int inc) {
|
|
+ statusLocks[idx].lock();
|
|
+ try {
|
|
+ if (status[idx].kind == StatusKind.EXECUTED && status[idx].inc == inc) {
|
|
+ status[idx].kind = StatusKind.ABORTING;
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ } finally {
|
|
+ statusLocks[idx].unlock();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Called after a validation task.
|
|
+ *
|
|
+ * @param idx transaction
|
|
+ * @param aborted whether validation failed AND this caller won {@link #tryValidationAbort}
|
|
+ * @return a follow-up execution task (inheriting the active-task unit) or NO_TASK (releasing it)
|
|
+ */
|
|
+ public Task finishValidation(final int idx, final boolean aborted) {
|
|
+ if (aborted) {
|
|
+ setReadyAfterAbort(idx);
|
|
+ decreaseValidationIdx(idx + 1);
|
|
+ if (executionIdx.get() > idx) {
|
|
+ final Task t = tryIncarnate(idx);
|
|
+ return t == null ? Task.NO_TASK : t;
|
|
+ }
|
|
+ }
|
|
+ numActiveTasks.decrementAndGet();
|
|
+ return Task.NO_TASK;
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD432GasCapUnsignedTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD432GasCapUnsignedTest.java
|
|
new file mode 100644
|
|
index 0000000000..7dcf917525
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD432GasCapUnsignedTest.java
|
|
@@ -0,0 +1,103 @@
|
|
+/*
|
|
+ * 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
|
|
+ *
|
|
+ * Aere Network notice (Apache-2.0 section 4(b)): this file was added by Aere Network, 2026-09-28 (D-432).
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.crypto.KeyPair;
|
|
+import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.BlobType;
|
|
+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.gascalculator.OsakaGasCalculator;
|
|
+
|
|
+import java.math.BigInteger;
|
|
+import java.util.Optional;
|
|
+import java.util.Set;
|
|
+
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-432: the EIP-7825 transaction gas cap is compared UNSIGNED. The decoder reads gasLimit with readLongScalar, so a limit
|
|
+ * of 2^63 or more is a negative long here; a signed compare let it through the cap, while the second client refuses it at
|
|
+ * decoding. Found by the AIP-20 differential fuzzer (aips/aip20-conformitate/fuzz-pqtx).
|
|
+ */
|
|
+class AereD432GasCapUnsignedTest {
|
|
+
|
|
+ private static final long CAP = 1L << 24;
|
|
+ private static final BigInteger CHAIN = BigInteger.valueOf(28001);
|
|
+ private static final KeyPair KEYS = SignatureAlgorithmFactory.getInstance().generateKeyPair();
|
|
+
|
|
+ private static MainnetTransactionValidator validator() {
|
|
+ final GasLimitCalculator glc =
|
|
+ new GasLimitCalculator() {
|
|
+ @Override
|
|
+ public long nextGasLimit(final long currentGasLimit, final long targetGasLimit, final long newBlockNumber) {
|
|
+ return currentGasLimit;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long transactionGasLimitCap() {
|
|
+ return CAP;
|
|
+ }
|
|
+ };
|
|
+ return new MainnetTransactionValidator(
|
|
+ new OsakaGasCalculator(), glc, FeeMarket.london(0L), true, Optional.of(CHAIN), Set.of(TransactionType.EIP1559),
|
|
+ Set.of(BlobType.KZG_CELL_PROOFS), 2 * 24576);
|
|
+ }
|
|
+
|
|
+ private static ValidationResult<TransactionInvalidReason> judge(final long gasLimit) {
|
|
+ final Transaction tx =
|
|
+ Transaction.builder()
|
|
+ .type(TransactionType.EIP1559)
|
|
+ .chainId(CHAIN)
|
|
+ .nonce(0)
|
|
+ .maxPriorityFeePerGas(Wei.ONE)
|
|
+ .maxFeePerGas(Wei.of(2_000_000_000L))
|
|
+ .gasLimit(gasLimit)
|
|
+ .to(Address.ZERO)
|
|
+ .value(Wei.ZERO)
|
|
+ .payload(Bytes.EMPTY)
|
|
+ .signAndBuild(KEYS);
|
|
+ return validator().validate(tx, Optional.of(Wei.of(1_000_000_000L)), Optional.empty(), TransactionValidationParams.processingBlock());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void aGasLimitOf2To63OrMoreIsRefusedByTheCapNotLetThroughAsANegativeLong() {
|
|
+ // 2^63, 2^63 + 5 and 2^64 - 1, as readLongScalar hands them over
|
|
+ for (final long g : new long[] {Long.MIN_VALUE, Long.MIN_VALUE + 5, -1L}) {
|
|
+ final ValidationResult<TransactionInvalidReason> r = judge(g);
|
|
+ assertThat(r.isValid()).withFailMessage("gasLimit %s admitted", Long.toUnsignedString(g)).isFalse();
|
|
+ assertThat(r.getInvalidReason())
|
|
+ .withFailMessage("gasLimit %s refused for %s, not the cap", Long.toUnsignedString(g), r.getInvalidReason())
|
|
+ .isEqualTo(TransactionInvalidReason.EXCEEDS_TRANSACTION_GAS_LIMIT);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theCapItselfIsAdmittedAndOneAboveIsRefused() {
|
|
+ // positive control: the rule is armed at exactly 2^24 and the fixture is otherwise valid
|
|
+ assertThat(judge(CAP).isValid()).withFailMessage(() -> "gasLimit = cap refused: " + judge(CAP).getErrorMessage()).isTrue();
|
|
+ assertThat(judge(CAP + 1).getInvalidReason()).isEqualTo(TransactionInvalidReason.EXCEEDS_TRANSACTION_GAS_LIMIT);
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD433BftWithdrawalsTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD433BftWithdrawalsTest.java
|
|
new file mode 100644
|
|
index 0000000000..6c935b7394
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/AereD433BftWithdrawalsTest.java
|
|
@@ -0,0 +1,75 @@
|
|
+/*
|
|
+ * 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
|
|
+ *
|
|
+ * Aere Network notice (Apache-2.0 section 4(b)): this file was added by Aere Network, 2026-09-28 (D-433), as the regression
|
|
+ * test of the ported upstream fixes hyperledger/besu ffe8104ee2 (GHSA-p4h2-gvh4-pv6j) and b7f1387cb4.
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Address;
|
|
+import org.hyperledger.besu.datatypes.GWei;
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.ethereum.core.Block;
|
|
+import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
|
|
+import org.hyperledger.besu.ethereum.core.Withdrawal;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.apache.tuweni.units.bigints.UInt64;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE D-433: on a BFT chain (QBFT on 2800 and 28001, Shanghai active from genesis) withdrawals are not applicable, and the
|
|
+ * BFT schedule installs NotApplicableWithdrawals while keeping Shanghai's WithdrawalsProcessor. Before the port the validator
|
|
+ * returned true for anything, so a single Byzantine proposer could put withdrawals in a block and every honest Besu node would
|
|
+ * credit them as native balance. The port (upstream ffe8104ee2) refuses a non-empty list and a withdrawals root other than the
|
|
+ * empty trie root.
|
|
+ */
|
|
+class AereD433BftWithdrawalsTest {
|
|
+
|
|
+ private static final WithdrawalsValidator V = new WithdrawalsValidator.NotApplicableWithdrawals();
|
|
+
|
|
+ @Test
|
|
+ void aByzantineWithdrawalListAndItsRootAreRefused() {
|
|
+ final List<Withdrawal> injected =
|
|
+ List.of(new Withdrawal(UInt64.valueOf(1), UInt64.valueOf(2), Address.fromHexString("0x000000000000000000000000000000000000c0de"), GWei.of(11)));
|
|
+ assertThat(V.validateWithdrawals(Optional.of(injected))).withFailMessage("a non-empty withdrawal list was accepted").isFalse();
|
|
+ final BlockDataGenerator gen = new BlockDataGenerator();
|
|
+ final Block withRoot =
|
|
+ gen.block(BlockDataGenerator.BlockOptions.create().setWithdrawals(Optional.of(injected)).setWithdrawalsRoot(Hash.ZERO));
|
|
+ assertThat(V.validateWithdrawalsRoot(withRoot)).withFailMessage("a withdrawals root other than the empty trie was accepted").isFalse();
|
|
+ // upstream b7f1387cb4: a root in the header with NO withdrawals field in the body is malformed, even when the root is the empty one
|
|
+ final Block noBody = gen.block(BlockDataGenerator.BlockOptions.create().setWithdrawals(Optional.empty()).setWithdrawalsRoot(Hash.EMPTY_TRIE_HASH));
|
|
+ assertThat(V.validateWithdrawalsRoot(noBody)).withFailMessage("a header root without body withdrawals was accepted").isFalse();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ void theEmptyFormsAreStillAccepted() {
|
|
+ // positive control: the blocks the chain actually carries (empty list, empty-trie root) and pre-Shanghai (absent)
|
|
+ assertThat(V.validateWithdrawals(Optional.of(Collections.emptyList()))).isTrue();
|
|
+ assertThat(V.validateWithdrawals(Optional.empty())).isTrue();
|
|
+ final BlockDataGenerator gen = new BlockDataGenerator();
|
|
+ assertThat(
|
|
+ V.validateWithdrawalsRoot(
|
|
+ gen.block(
|
|
+ BlockDataGenerator.BlockOptions.create()
|
|
+ .setWithdrawals(Optional.of(Collections.emptyList()))
|
|
+ .setWithdrawalsRoot(Hash.EMPTY_TRIE_HASH))))
|
|
+ .isTrue();
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketAereFloorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketAereFloorTest.java
|
|
new file mode 100644
|
|
index 0000000000..b36bfd7811
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarketAereFloorTest.java
|
|
@@ -0,0 +1,129 @@
|
|
+/*
|
|
+ * 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
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.feemarket;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * Tests for the AERE fork-gated base-fee floor in {@link LondonFeeMarket}.
|
|
+ *
|
|
+ * <p>Proves: (a) fork UNSET is byte-behaviour-identical to upstream London (empty blocks decay to /
|
|
+ * stay at the legacy 7-wei floor, no 1-Gwei clamp); (b) once the fork block N is set with a 1-Gwei
|
|
+ * floor, empty blocks at/after N floor at EXACTLY 1 Gwei and never below; (c) the jump to >= 1 Gwei
|
|
+ * happens exactly at block N (block N-1 is still legacy); (d) an over-target block still rises above
|
|
+ * 1 Gwei via the normal EIP-1559 formula.
|
|
+ */
|
|
+public class LondonFeeMarketAereFloorTest {
|
|
+
|
|
+ private static final long ONE_GWEI = 1_000_000_000L;
|
|
+ private static final long GAS_TARGET = 15_000_000L;
|
|
+ private static final long FORK_BLOCK = 100L;
|
|
+
|
|
+ /** London fee market with an explicit AERE floor-fork configuration (bypasses global JVM config). */
|
|
+ private static LondonFeeMarket market(final long aereForkBlock, final long aereFloorValueWei) {
|
|
+ return new LondonFeeMarket(
|
|
+ TransactionPriceCalculator.eip1559(),
|
|
+ 0L, // londonForkBlockNumber (kept off the tested block range)
|
|
+ Optional.empty(),
|
|
+ aereForkBlock,
|
|
+ aereFloorValueWei);
|
|
+ }
|
|
+
|
|
+ // (a) UNSET fork => byte-identical to upstream: empty blocks decay to and stay at 7 wei, and no
|
|
+ // value is ever clamped up to 1 Gwei.
|
|
+ @Test
|
|
+ public void forkUnset_emptyBlocksDecayToSevenWei_noClampToOneGwei() {
|
|
+ final LondonFeeMarket unset = market(Long.MAX_VALUE, ONE_GWEI);
|
|
+
|
|
+ // Decay many empty blocks from well above the floor: must settle at EXACTLY 7 wei.
|
|
+ Wei baseFee = Wei.of(10_000L);
|
|
+ for (int i = 0; i < 400; i++) {
|
|
+ baseFee = unset.computeBaseFee(500L + i, baseFee, 0L, GAS_TARGET);
|
|
+ }
|
|
+ assertThat(baseFee).isEqualTo(Wei.of(7L));
|
|
+
|
|
+ // Once at 7 wei it stays at 7 wei (never below), never jumps to 1 Gwei.
|
|
+ assertThat(unset.computeBaseFee(9_000L, Wei.of(7L), 0L, GAS_TARGET)).isEqualTo(Wei.of(7L));
|
|
+
|
|
+ // A mid-range empty-block value is NOT clamped up (proves the fork is a genuine no-op):
|
|
+ // 1000 - 1000/8 = 1000 - 125 = 875 wei.
|
|
+ assertThat(unset.computeBaseFee(9_000L, Wei.of(1_000L), 0L, GAS_TARGET))
|
|
+ .isEqualTo(Wei.of(875L));
|
|
+ }
|
|
+
|
|
+ // (b) Fork ACTIVE => empty blocks at/after N floor at EXACTLY 1 Gwei and never drop below.
|
|
+ @Test
|
|
+ public void forkActive_emptyBlocksFloorAtExactlyOneGwei_neverBelow() {
|
|
+ final LondonFeeMarket forked = market(FORK_BLOCK, ONE_GWEI);
|
|
+
|
|
+ // Sanity: raw EIP-1559 decrease from 1 Gwei on an empty block would be 875M; clamp pins it.
|
|
+ assertThat(forked.computeBaseFee(FORK_BLOCK + 1, Wei.of(ONE_GWEI), 0L, GAS_TARGET))
|
|
+ .isEqualTo(Wei.of(ONE_GWEI));
|
|
+
|
|
+ // Many consecutive empty blocks after the fork: stays EXACTLY at 1 Gwei each block.
|
|
+ Wei baseFee = Wei.of(ONE_GWEI);
|
|
+ for (int i = 0; i < 50; i++) {
|
|
+ baseFee = forked.computeBaseFee(FORK_BLOCK + 1 + i, baseFee, 0L, GAS_TARGET);
|
|
+ assertThat(baseFee).isEqualTo(Wei.of(ONE_GWEI));
|
|
+ }
|
|
+
|
|
+ // Even a pathologically low parent baseFee (7 wei) is clamped up to exactly 1 Gwei post-fork.
|
|
+ assertThat(forked.computeBaseFee(FORK_BLOCK + 500, Wei.of(7L), 0L, GAS_TARGET))
|
|
+ .isEqualTo(Wei.of(ONE_GWEI));
|
|
+ }
|
|
+
|
|
+ // (c) The jump to >= 1 Gwei happens exactly at the fork block N (N-1 is still legacy).
|
|
+ @Test
|
|
+ public void forkActivation_jumpHappensExactlyAtForkBlock() {
|
|
+ final LondonFeeMarket forked = market(FORK_BLOCK, ONE_GWEI);
|
|
+
|
|
+ // Block N-1 is pre-fork: legacy behaviour, a 7-wei empty-block parent stays at 7 wei.
|
|
+ assertThat(forked.computeBaseFee(FORK_BLOCK - 1, Wei.of(7L), 0L, GAS_TARGET))
|
|
+ .isEqualTo(Wei.of(7L));
|
|
+
|
|
+ // Block N itself jumps to >= 1 Gwei even though the parent baseFee was only 7 wei.
|
|
+ final Wei atForkBlock = forked.computeBaseFee(FORK_BLOCK, Wei.of(7L), 0L, GAS_TARGET);
|
|
+ assertThat(atForkBlock).isEqualTo(Wei.of(ONE_GWEI));
|
|
+ assertThat(atForkBlock.greaterOrEqualThan(Wei.of(ONE_GWEI))).isTrue();
|
|
+ }
|
|
+
|
|
+ // (d) An over-target (active) block still rises above 1 Gwei via the normal EIP-1559 formula,
|
|
+ // and the clamp does not distort above-floor values (identical to the unset market's raw result).
|
|
+ @Test
|
|
+ public void forkActive_overTargetBlockRisesAboveOneGweiNormally() {
|
|
+ final LondonFeeMarket forked = market(FORK_BLOCK, ONE_GWEI);
|
|
+ final LondonFeeMarket unset = market(Long.MAX_VALUE, ONE_GWEI);
|
|
+
|
|
+ final long parentGasUsed = 2 * GAS_TARGET; // over target => baseFee increases
|
|
+ final Wei parent = Wei.of(ONE_GWEI);
|
|
+
|
|
+ // EIP-1559 rise: 1Gwei + 1Gwei * (2T - T)/T / 8 = 1Gwei + 1Gwei/8 = 1_125_000_000 wei.
|
|
+ final Wei rose = forked.computeBaseFee(FORK_BLOCK + 5, parent, parentGasUsed, GAS_TARGET);
|
|
+ assertThat(rose).isEqualTo(Wei.of(1_125_000_000L));
|
|
+ assertThat(rose.greaterOrEqualThan(Wei.of(ONE_GWEI))).isTrue();
|
|
+ assertThat(rose).isNotEqualTo(Wei.of(ONE_GWEI)); // strictly above the floor
|
|
+
|
|
+ // Above-floor values are unaffected by the clamp: identical to the unset (no-op) market.
|
|
+ assertThat(rose)
|
|
+ .isEqualTo(unset.computeBaseFee(FORK_BLOCK + 5, parent, parentGasUsed, GAS_TARGET));
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmBenchmarkTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmBenchmarkTest.java
|
|
new file mode 100644
|
|
index 0000000000..aac192aeba
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmBenchmarkTest.java
|
|
@@ -0,0 +1,620 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.parallelization;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.MINING_BENEFICIARY;
|
|
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
+
|
|
+import org.hyperledger.besu.config.GenesisConfig;
|
|
+import org.hyperledger.besu.config.JsonUtil;
|
|
+import org.hyperledger.besu.crypto.KeyPair;
|
|
+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.BlockProcessingResult;
|
|
+import org.hyperledger.besu.ethereum.core.Block;
|
|
+import org.hyperledger.besu.ethereum.core.BlockBody;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
|
+import org.hyperledger.besu.ethereum.core.Transaction;
|
|
+import org.hyperledger.besu.ethereum.core.Util;
|
|
+import org.hyperledger.besu.ethereum.mainnet.BlockProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
|
+import org.hyperledger.besu.ethereum.mainnet.blockstm.AereBlockStmEngine;
|
|
+import org.hyperledger.besu.ethereum.mainnet.blockstm.AereBlockStmPreprocessing;
|
|
+import org.hyperledger.besu.ethereum.mainnet.blockstm.BlockStmStats;
|
|
+import org.hyperledger.besu.ethereum.trie.pathbased.common.provider.WorldStateQueryParams;
|
|
+import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
|
+import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
|
|
+import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
|
|
+
|
|
+import java.io.InputStream;
|
|
+import java.lang.management.ManagementFactory;
|
|
+import java.math.BigInteger;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.nio.file.StandardOpenOption;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+
|
|
+import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
+import org.apache.tuweni.bytes.Bytes;
|
|
+import org.apache.tuweni.units.bigints.UInt256;
|
|
+import org.junit.jupiter.api.BeforeAll;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * AERE Block-STM benchmark + verification harness (chain-independent, block-processor grain).
|
|
+ *
|
|
+ * <p>Proves serial-equivalence (parallel state root == sequential state root) for an independent
|
|
+ * workload AND a genuine read/write-conflict workload (all transfers to one shared recipient, which
|
|
+ * forces the multi-version scheduler to abort and re-execute), and measures parallel-vs-sequential
|
|
+ * block execution time / TPS across worker counts. All numbers are written to {@code REPORT}.
|
|
+ */
|
|
+public class AereBlockStmBenchmarkTest extends AbstractParallelBlockProcessorIntegrationTest {
|
|
+
|
|
+ private static final String BASE_GENESIS =
|
|
+ "/org/hyperledger/besu/ethereum/mainnet/parallelization/genesis-it.json";
|
|
+ private static final Path REPORT =
|
|
+ Path.of(System.getProperty("java.io.tmpdir"), "blockstm_bench_results.txt");
|
|
+
|
|
+ // Compute-heavy runtime: PUSH1 0 CALLDATALOAD (iters); loop { KECCAK256 32 bytes of mem; MSTORE };
|
|
+ // then SSTORE slot0=1; STOP. Iteration count is supplied per-tx via 32-byte calldata.
|
|
+ private static final String COMPUTE_CODE =
|
|
+ "0x6000355b60206000206000526001900380600357600160005500";
|
|
+
|
|
+ private static final int MAX_SENDERS = 1024;
|
|
+ private static final Wei BASE_FEE = Wei.of(5);
|
|
+
|
|
+ private static GenesisConfig customGenesis;
|
|
+ private static KeyPair[] senders;
|
|
+ private static Address[] senderAddr;
|
|
+ private final List<String> lines = new ArrayList<>();
|
|
+
|
|
+ private static Address recipient(final int i) {
|
|
+ return Address.fromHexString(String.format("0x%040x", 0x10000000L + i));
|
|
+ }
|
|
+
|
|
+ private static final Address SHARED_RECIPIENT =
|
|
+ Address.fromHexString(String.format("0x%040x", 0x0DEAD001L));
|
|
+
|
|
+ private static Address computeContract(final int i) {
|
|
+ return Address.fromHexString(String.format("0x%040x", 0x20000000L + i));
|
|
+ }
|
|
+
|
|
+ @BeforeAll
|
|
+ static void buildGenesis() throws Exception {
|
|
+ final String baseText;
|
|
+ try (InputStream is = AereBlockStmBenchmarkTest.class.getResourceAsStream(BASE_GENESIS)) {
|
|
+ baseText = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
|
+ }
|
|
+ final ObjectNode root = JsonUtil.objectNodeFromString(baseText);
|
|
+ final ObjectNode alloc = (ObjectNode) root.get("alloc");
|
|
+
|
|
+ senders = new KeyPair[MAX_SENDERS];
|
|
+ senderAddr = new Address[MAX_SENDERS];
|
|
+ final String richBalance = "0x" + new BigInteger("1000000000000000000000000").toString(16);
|
|
+ for (int i = 0; i < MAX_SENDERS; i++) {
|
|
+ final String pkHex = String.format("%064x", i + 1);
|
|
+ final KeyPair kp = ParallelBlockProcessorTestSupport.generateKeyPair(pkHex);
|
|
+ senders[i] = kp;
|
|
+ senderAddr[i] = Util.publicKeyToAddress(kp.getPublicKey());
|
|
+ final ObjectNode acct = JsonUtil.createEmptyObjectNode();
|
|
+ acct.put("balance", richBalance);
|
|
+ alloc.set(senderAddr[i].getBytes().toUnprefixedHexString(), acct);
|
|
+
|
|
+ final ObjectNode contract = JsonUtil.createEmptyObjectNode();
|
|
+ contract.put("balance", "0");
|
|
+ contract.put("code", COMPUTE_CODE);
|
|
+ alloc.set(computeContract(i).getBytes().toUnprefixedHexString(), contract);
|
|
+ }
|
|
+ customGenesis = GenesisConfig.fromConfig(root);
|
|
+ Files.write(
|
|
+ REPORT,
|
|
+ ("AERE BLOCK-STM BENCHMARK / VERIFICATION REPORT\n"
|
|
+ + "generated on a scratch host (chain-independent block-processor grain)\n"
|
|
+ + "cpus(reported)=" + Runtime.getRuntime().availableProcessors()
|
|
+ + " loadAvg(start)="
|
|
+ + String.format("%.2f", ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage())
|
|
+ + "\n===============================================================\n")
|
|
+ .getBytes(StandardCharsets.UTF_8),
|
|
+ StandardOpenOption.CREATE,
|
|
+ StandardOpenOption.TRUNCATE_EXISTING);
|
|
+ }
|
|
+
|
|
+ private void log(final String s) {
|
|
+ lines.add(s);
|
|
+ System.out.println("[BLOCKSTM-BENCH] " + s);
|
|
+ }
|
|
+
|
|
+ private void flush() throws Exception {
|
|
+ Files.write(
|
|
+ REPORT,
|
|
+ (String.join("\n", lines) + "\n").getBytes(StandardCharsets.UTF_8),
|
|
+ StandardOpenOption.APPEND);
|
|
+ lines.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected ExecutionContextTestFixture createFreshContext() {
|
|
+ return ExecutionContextTestFixture.builder(customGenesis)
|
|
+ .dataStorageFormat(DataStorageFormat.BONSAI)
|
|
+ .build();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected String getVariantName() {
|
|
+ return "AERE Block-STM Benchmark";
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected ParallelTransactionPreprocessing createParallelPreprocessing(
|
|
+ final MainnetTransactionProcessor transactionProcessor) {
|
|
+ return new ParallelTransactionPreprocessing(
|
|
+ transactionProcessor, Runnable::run, getBalConfiguration());
|
|
+ }
|
|
+
|
|
+ // ---- workloads ----------------------------------------------------------
|
|
+
|
|
+ private Transaction[] independentTransfers(final int n) {
|
|
+ final Transaction[] txs = new Transaction[n];
|
|
+ for (int i = 0; i < n; i++) {
|
|
+ txs[i] =
|
|
+ createTransferTransaction(
|
|
+ 0, 1L, 100_000L, 0L, 5L, recipient(i).toHexString(), senders[i]);
|
|
+ }
|
|
+ return txs;
|
|
+ }
|
|
+
|
|
+ private Transaction[] lowConflictTransfers(final int n, final int pool) {
|
|
+ // Distinct senders credit recipients drawn from a small pool -> occasional write-conflict on a
|
|
+ // shared recipient balance (ERC20-style low contention). pool<n means ~ (n-pool)/n of txs share.
|
|
+ final int p = Math.max(1, pool);
|
|
+ final Transaction[] txs = new Transaction[n];
|
|
+ for (int i = 0; i < n; i++) {
|
|
+ txs[i] =
|
|
+ createTransferTransaction(
|
|
+ 0, 1L, 100_000L, 0L, 5L, recipient(i % p).toHexString(), senders[i]);
|
|
+ }
|
|
+ return txs;
|
|
+ }
|
|
+
|
|
+ private Transaction[] conflictingTransfers(final int n) {
|
|
+ // Every distinct sender credits ONE shared recipient -> read/write conflict on that balance.
|
|
+ final Transaction[] txs = new Transaction[n];
|
|
+ for (int i = 0; i < n; i++) {
|
|
+ txs[i] =
|
|
+ createTransferTransaction(
|
|
+ 0, 1L, 100_000L, 0L, 5L, SHARED_RECIPIENT.toHexString(), senders[i]);
|
|
+ }
|
|
+ return txs;
|
|
+ }
|
|
+
|
|
+ private Transaction[] independentCompute(final int n, final long iters) {
|
|
+ final Bytes payload = UInt256.valueOf(iters).toBytes();
|
|
+ final Transaction[] txs = new Transaction[n];
|
|
+ for (int i = 0; i < n; i++) {
|
|
+ txs[i] =
|
|
+ Transaction.builder()
|
|
+ .type(TransactionType.EIP1559)
|
|
+ .nonce(0)
|
|
+ .maxPriorityFeePerGas(Wei.ZERO)
|
|
+ .maxFeePerGas(Wei.of(5))
|
|
+ .gasLimit(30_000_000L)
|
|
+ .to(computeContract(i))
|
|
+ .value(Wei.ZERO)
|
|
+ .payload(payload)
|
|
+ .chainId(BigInteger.valueOf(42))
|
|
+ .signAndBuild(senders[i]);
|
|
+ }
|
|
+ return txs;
|
|
+ }
|
|
+
|
|
+ // ---- block plumbing (configurable gas limit) ----------------------------
|
|
+
|
|
+ private Block buildBlock(
|
|
+ final BlockHeader parent,
|
|
+ final Hash stateRoot,
|
|
+ final long gasLimit,
|
|
+ final Transaction[] txs) {
|
|
+ final BlockHeader header =
|
|
+ new BlockHeaderTestFixture()
|
|
+ .number(parent.getNumber() + 1L)
|
|
+ .parentHash(parent.getHash())
|
|
+ .coinbase(MINING_BENEFICIARY)
|
|
+ .stateRoot(stateRoot)
|
|
+ .gasLimit(gasLimit)
|
|
+ .baseFeePerGas(BASE_FEE)
|
|
+ .buildHeader();
|
|
+ final BlockBody body =
|
|
+ new BlockBody(Arrays.asList(txs), Collections.emptyList(), Optional.empty());
|
|
+ return new Block(header, body);
|
|
+ }
|
|
+
|
|
+ private Hash discover(final long gasLimit, final Transaction[] txs) {
|
|
+ final ExecutionContextTestFixture ctx = createFreshContext();
|
|
+ final BlockHeader parent = ctx.getBlockchain().getChainHeadHeader();
|
|
+ final MutableWorldState ws =
|
|
+ ctx.getStateArchive()
|
|
+ .getWorldState(WorldStateQueryParams.withBlockHeaderAndUpdateNodeHead(parent))
|
|
+ .orElseThrow();
|
|
+ final Block block = buildBlock(parent, Hash.ZERO, gasLimit, txs);
|
|
+ final BlockProcessor seq = createSequentialProcessor(ctx);
|
|
+ final BlockProcessingResult r =
|
|
+ seq.processBlock(ctx.getProtocolContext(), ctx.getBlockchain(), ws, block);
|
|
+ if (r.isSuccessful()) {
|
|
+ return ws.rootHash();
|
|
+ }
|
|
+ // Header stateRoot was ZERO, so processing "failed" on the root-mismatch check; recover the
|
|
+ // real (calculated) root from the error message: the first non-zero 32-byte hex it contains.
|
|
+ final String msg = r.errorMessage.orElseThrow();
|
|
+ final java.util.regex.Matcher m =
|
|
+ java.util.regex.Pattern.compile("0x[0-9a-fA-F]{64}").matcher(msg);
|
|
+ while (m.find()) {
|
|
+ final Hash h = Hash.fromHexString(m.group());
|
|
+ if (!h.equals(Hash.ZERO)) {
|
|
+ return h;
|
|
+ }
|
|
+ }
|
|
+ throw new AssertionError("could not recover state root from: " + msg);
|
|
+ }
|
|
+
|
|
+ private BlockProcessor stockParallel(final ExecutionContextTestFixture ctx) {
|
|
+ final ProtocolSpec spec =
|
|
+ ctx.getProtocolSchedule()
|
|
+ .getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader());
|
|
+ return new MainnetParallelBlockProcessor(
|
|
+ spec.getTransactionProcessor(),
|
|
+ spec.getTransactionReceiptFactory(),
|
|
+ Wei.ZERO,
|
|
+ BlockHeader::getCoinbase,
|
|
+ true,
|
|
+ ctx.getProtocolSchedule(),
|
|
+ getBalConfiguration(),
|
|
+ new NoOpMetricsSystem());
|
|
+ }
|
|
+
|
|
+ /** One timed sequential run. Returns [rootHex, nanos]. */
|
|
+ private Object[] runSeq(final long gasLimit, final Hash stateRoot, final Transaction[] txs) {
|
|
+ final ExecutionContextTestFixture ctx = createFreshContext();
|
|
+ final BlockHeader parent = ctx.getBlockchain().getChainHeadHeader();
|
|
+ final MutableWorldState ws =
|
|
+ ctx.getStateArchive()
|
|
+ .getWorldState(WorldStateQueryParams.withBlockHeaderAndUpdateNodeHead(parent))
|
|
+ .orElseThrow();
|
|
+ final Block block = buildBlock(parent, stateRoot, gasLimit, txs);
|
|
+ final BlockProcessor seq = createSequentialProcessor(ctx);
|
|
+ final long t0 = System.nanoTime();
|
|
+ final BlockProcessingResult r =
|
|
+ seq.processBlock(ctx.getProtocolContext(), ctx.getBlockchain(), ws, block);
|
|
+ final long dt = System.nanoTime() - t0;
|
|
+ assertTrue(r.isSuccessful(), "seq failed: " + r.errorMessage.orElse("?"));
|
|
+ return new Object[] {ws.rootHash(), dt, r};
|
|
+ }
|
|
+
|
|
+ /** One timed AERE Block-STM parallel run at {@code workers}. Returns [rootHex, nanos, nbParallel]. */
|
|
+ private Object[] runPar(
|
|
+ final long gasLimit, final Hash stateRoot, final int workers, final Transaction[] txs) {
|
|
+ final ExecutionContextTestFixture ctx = createFreshContext();
|
|
+ final BlockHeader parent = ctx.getBlockchain().getChainHeadHeader();
|
|
+ final MutableWorldState ws =
|
|
+ ctx.getStateArchive()
|
|
+ .getWorldState(WorldStateQueryParams.withBlockHeaderAndUpdateNodeHead(parent))
|
|
+ .orElseThrow();
|
|
+ final Block block = buildBlock(parent, stateRoot, gasLimit, txs);
|
|
+ final ProtocolSpec spec =
|
|
+ ctx.getProtocolSchedule()
|
|
+ .getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader());
|
|
+ final BlockProcessor par = stockParallel(ctx);
|
|
+ final AereBlockStmPreprocessing pf =
|
|
+ new AereBlockStmPreprocessing(spec.getTransactionProcessor(), workers);
|
|
+ final long t0 = System.nanoTime();
|
|
+ final BlockProcessingResult r =
|
|
+ par.processBlock(ctx.getProtocolContext(), ctx.getBlockchain(), ws, block, pf);
|
|
+ final long dt = System.nanoTime() - t0;
|
|
+ assertTrue(r.isSuccessful(), "par failed: " + r.errorMessage.orElse("?"));
|
|
+ return new Object[] {ws.rootHash(), dt, r.getNbParallelizedTransactions().orElse(0)};
|
|
+ }
|
|
+
|
|
+ /** Drive the engine directly to read scheduler statistics (executions / aborts / verified). */
|
|
+ private BlockStmStats engineStats(final long gasLimit, final int workers, final Transaction[] txs) {
|
|
+ final ExecutionContextTestFixture ctx = createFreshContext();
|
|
+ final BlockHeader parent = ctx.getBlockchain().getChainHeadHeader();
|
|
+ final Block block = buildBlock(parent, Hash.ZERO, gasLimit, txs);
|
|
+ final AereBlockStmEngine engine =
|
|
+ new AereBlockStmEngine(
|
|
+ ctx.getProtocolSchedule()
|
|
+ .getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader())
|
|
+ .getTransactionProcessor(),
|
|
+ workers);
|
|
+ final BlockHashLookup zero = (frame, number) -> Hash.ZERO;
|
|
+ engine.runAsyncBlock(
|
|
+ ctx.getProtocolContext(),
|
|
+ block.getHeader(),
|
|
+ Arrays.asList(txs),
|
|
+ MINING_BENEFICIARY,
|
|
+ zero,
|
|
+ Wei.ZERO,
|
|
+ Runnable::run,
|
|
+ Optional.empty(),
|
|
+ Optional.of(parent));
|
|
+ return engine.stats();
|
|
+ }
|
|
+
|
|
+ private static long median(final long[] a) {
|
|
+ final long[] c = a.clone();
|
|
+ Arrays.sort(c);
|
|
+ return c[c.length / 2];
|
|
+ }
|
|
+
|
|
+ // ---- the suite ----------------------------------------------------------
|
|
+
|
|
+ @Test
|
|
+ void blockStmVerifyAndBenchmark() throws Exception {
|
|
+ final int cpus = Runtime.getRuntime().availableProcessors();
|
|
+ final int[] workerCounts = {1, 2, 4, 8, 16};
|
|
+
|
|
+ // ===================== CORRECTNESS =====================
|
|
+ log("");
|
|
+ log("## PART 1 - CORRECTNESS (parallel root == sequential root)");
|
|
+
|
|
+ // 1a. Independent transfers: expect zero aborts, executions == n.
|
|
+ {
|
|
+ final int n = 300;
|
|
+ final Transaction[] txs = independentTransfers(n);
|
|
+ final Hash root = discover(30_000_000L, txs);
|
|
+ final Object[] seq = runSeq(30_000_000L, root, txs);
|
|
+ final Object[] par = runPar(30_000_000L, root, cpus, txs);
|
|
+ final Hash seqRoot = (Hash) seq[0];
|
|
+ final Hash parRoot = (Hash) par[0];
|
|
+ final int nbPar = (Integer) par[2];
|
|
+ final BlockStmStats st = engineStats(30_000_000L, cpus, txs);
|
|
+ assertThat(parRoot).as("independent parallel root == sequential").isEqualTo(seqRoot);
|
|
+ log(String.format(
|
|
+ " [independent n=%d w=%d] parRoot==seqRoot: %s root=%s", n, cpus,
|
|
+ parRoot.equals(seqRoot), seqRoot.toHexString()));
|
|
+ log(String.format(
|
|
+ " nbParallelized=%d verified=%s execs=%d (n=%d) aborts=%d committedParallel=%d",
|
|
+ nbPar, st.verified(), st.totalExecutions(), st.numTxns(), st.totalAborts(),
|
|
+ st.committedParallel()));
|
|
+ assertThat(st.verified()).as("independent must verify").isTrue();
|
|
+ assertThat(st.totalAborts()).as("independent must have zero aborts").isZero();
|
|
+ assertThat(st.totalExecutions()).as("independent: one execution per tx").isEqualTo(n);
|
|
+ assertThat(nbPar).as("parallel path exercised").isGreaterThan(0);
|
|
+ }
|
|
+
|
|
+ // 1b. Conflicting transfers (shared recipient): expect aborts>0, executions>n, root still equal.
|
|
+ {
|
|
+ final int n = 300;
|
|
+ final Transaction[] txs = conflictingTransfers(n);
|
|
+ final Hash root = discover(30_000_000L, txs);
|
|
+ final Object[] seq = runSeq(30_000_000L, root, txs);
|
|
+ final Object[] par = runPar(30_000_000L, root, cpus, txs);
|
|
+ final Hash seqRoot = (Hash) seq[0];
|
|
+ final Hash parRoot = (Hash) par[0];
|
|
+ final int nbPar = (Integer) par[2];
|
|
+ final BlockStmStats st = engineStats(30_000_000L, cpus, txs);
|
|
+ assertThat(parRoot).as("CONFLICT parallel root == sequential").isEqualTo(seqRoot);
|
|
+ log(String.format(
|
|
+ " [conflict n=%d w=%d] parRoot==seqRoot: %s root=%s", n, cpus,
|
|
+ parRoot.equals(seqRoot), seqRoot.toHexString()));
|
|
+ log(String.format(
|
|
+ " nbParallelized=%d verified=%s execs=%d (n=%d, re-exec=%d) aborts=%d committedParallel=%d",
|
|
+ nbPar, st.verified(), st.totalExecutions(), st.numTxns(),
|
|
+ st.totalExecutions() - st.numTxns(), st.totalAborts(), st.committedParallel()));
|
|
+ assertThat(st.verified()).as("conflict must verify").isTrue();
|
|
+ assertThat(st.totalAborts()).as("conflict must trigger re-execution (aborts>0)").isGreaterThan(0);
|
|
+ assertThat(st.totalExecutions()).as("conflict re-executes (execs>n)").isGreaterThan(n);
|
|
+ }
|
|
+
|
|
+ // 1c. Independent compute contract calls: root equal, zero aborts.
|
|
+ {
|
|
+ final int n = 128;
|
|
+ final long iters = 400;
|
|
+ final Transaction[] txs = independentCompute(n, iters);
|
|
+ final Hash root = discover(3_000_000_000L, txs);
|
|
+ final Object[] seq = runSeq(3_000_000_000L, root, txs);
|
|
+ final Object[] par = runPar(3_000_000_000L, root, cpus, txs);
|
|
+ final Hash seqRoot = (Hash) seq[0];
|
|
+ final Hash parRoot = (Hash) par[0];
|
|
+ final BlockStmStats st = engineStats(3_000_000_000L, cpus, txs);
|
|
+ assertThat(parRoot).as("compute parallel root == sequential").isEqualTo(seqRoot);
|
|
+ log(String.format(
|
|
+ " [compute n=%d w=%d iters=%d] parRoot==seqRoot: %s root=%s", n, cpus, iters,
|
|
+ parRoot.equals(seqRoot), seqRoot.toHexString()));
|
|
+ log(String.format(
|
|
+ " verified=%s execs=%d (n=%d) aborts=%d committedParallel=%d",
|
|
+ st.verified(), st.totalExecutions(), st.numTxns(), st.totalAborts(),
|
|
+ st.committedParallel()));
|
|
+ assertThat(st.verified()).isTrue();
|
|
+ assertThat(st.totalAborts()).isZero();
|
|
+ }
|
|
+
|
|
+ // 1d. Low-conflict transfers (recipient pool): root equal, verified (aborts allowed but rare).
|
|
+ {
|
|
+ final int n = 300;
|
|
+ final Transaction[] txs = lowConflictTransfers(n, 270);
|
|
+ final Hash root = discover(30_000_000L, txs);
|
|
+ final Object[] seq = runSeq(30_000_000L, root, txs);
|
|
+ final Object[] par = runPar(30_000_000L, root, cpus, txs);
|
|
+ final Hash seqRoot = (Hash) seq[0];
|
|
+ final Hash parRoot = (Hash) par[0];
|
|
+ final int nbPar = (Integer) par[2];
|
|
+ final BlockStmStats st = engineStats(30_000_000L, cpus, txs);
|
|
+ assertThat(parRoot).as("low-conflict parallel root == sequential").isEqualTo(seqRoot);
|
|
+ log(String.format(
|
|
+ " [low-conflict n=%d w=%d pool=270] parRoot==seqRoot: %s root=%s", n, cpus,
|
|
+ parRoot.equals(seqRoot), seqRoot.toHexString()));
|
|
+ log(String.format(
|
|
+ " nbParallelized=%d verified=%s execs=%d (n=%d, re-exec=%d) aborts=%d committedParallel=%d",
|
|
+ nbPar, st.verified(), st.totalExecutions(), st.numTxns(),
|
|
+ st.totalExecutions() - st.numTxns(), st.totalAborts(), st.committedParallel()));
|
|
+ assertThat(st.verified()).as("low-conflict must verify").isTrue();
|
|
+ }
|
|
+ flush();
|
|
+
|
|
+ // ===================== THROUGHPUT =====================
|
|
+ final int warmup = 3;
|
|
+ final int measure = 5;
|
|
+
|
|
+ // Workload A: independent transfers.
|
|
+ runThroughput(
|
|
+ "PART 2A - THROUGHPUT: independent transfers", 1000, 30_000_000L,
|
|
+ independentTransfers(1000), workerCounts, warmup, measure);
|
|
+
|
|
+ // Workload A': independent compute-heavy calls (execution-bound; best case for parallelism).
|
|
+ runThroughput(
|
|
+ "PART 2B - THROUGHPUT: independent compute calls (iters=800)", 256, 3_000_000_000L,
|
|
+ independentCompute(256, 800), workerCounts, warmup, measure);
|
|
+
|
|
+ // Workload C: high-conflict transfers (all to one recipient) - expect no speedup.
|
|
+ runThroughput(
|
|
+ "PART 2C - THROUGHPUT: high-conflict transfers (shared recipient)", 500, 30_000_000L,
|
|
+ conflictingTransfers(500), workerCounts, warmup, measure);
|
|
+
|
|
+ // Workload D: low-conflict transfers (recipient pool=900 of 1000) - ERC20-style ~10% contention.
|
|
+ runThroughput(
|
|
+ "PART 2D - THROUGHPUT: low-conflict transfers (recipient pool=900)", 1000, 30_000_000L,
|
|
+ lowConflictTransfers(1000, 900), workerCounts, warmup, measure);
|
|
+
|
|
+ // ===================== ISOLATED EXECUTION PHASE =====================
|
|
+ // The real Block-STM test: time ONLY the parallel execution phase (engine.runAsyncBlock, i.e.
|
|
+ // the flat-snapshot base reads + concurrent EVM execution + MV bookkeeping), measured INSIDE the
|
|
+ // engine (execPhaseNanos), with the serial Bonsai trie commit excluded entirely. Execution-bound
|
|
+ // independent compute calls so there is real work to parallelize; scaling vs w=1 is the proof.
|
|
+ runExecPhase(
|
|
+ "PART 3A - EXECUTION PHASE (isolated): independent compute calls (iters=800)",
|
|
+ 256, 3_000_000_000L, independentCompute(256, 800), workerCounts, warmup, measure);
|
|
+ runExecPhase(
|
|
+ "PART 3B - EXECUTION PHASE (isolated): independent compute calls (iters=3000, heavy)",
|
|
+ 256, 3_000_000_000L, independentCompute(256, 3000), workerCounts, warmup, measure);
|
|
+
|
|
+ log("");
|
|
+ log("loadAvg(end)="
|
|
+ + String.format("%.2f", ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage()));
|
|
+ log("=============================== END ===============================");
|
|
+ flush();
|
|
+ }
|
|
+
|
|
+ private void runThroughput(
|
|
+ final String title,
|
|
+ final int n,
|
|
+ final long gasLimit,
|
|
+ final Transaction[] txs,
|
|
+ final int[] workerCounts,
|
|
+ final int warmup,
|
|
+ final int measure)
|
|
+ throws Exception {
|
|
+ log("");
|
|
+ log("## " + title + " (n=" + n + " txs)");
|
|
+ final Hash root = discover(gasLimit, txs);
|
|
+
|
|
+ // Sequential baseline.
|
|
+ for (int i = 0; i < warmup; i++) {
|
|
+ runSeq(gasLimit, root, txs);
|
|
+ }
|
|
+ final long[] seqT = new long[measure];
|
|
+ for (int i = 0; i < measure; i++) {
|
|
+ seqT[i] = (Long) runSeq(gasLimit, root, txs)[1];
|
|
+ }
|
|
+ final long seqMed = median(seqT);
|
|
+ final double seqMs = seqMed / 1e6;
|
|
+ final double seqTps = n / (seqMed / 1e9);
|
|
+ log(String.format(
|
|
+ " SEQUENTIAL (MainnetBlockProcessor): %8.3f ms %10.0f tx/s", seqMs, seqTps));
|
|
+ log(" worker | median ms | tx/s | speedup vs seq | scaling vs w=1");
|
|
+ log(" -------+------------+----------+----------------+---------------");
|
|
+
|
|
+ double par1Ms = Double.NaN;
|
|
+ for (final int w : workerCounts) {
|
|
+ for (int i = 0; i < warmup; i++) {
|
|
+ runPar(gasLimit, root, w, txs);
|
|
+ }
|
|
+ final long[] pt = new long[measure];
|
|
+ int nbPar = 0;
|
|
+ for (int i = 0; i < measure; i++) {
|
|
+ final Object[] r = runPar(gasLimit, root, w, txs);
|
|
+ pt[i] = (Long) r[1];
|
|
+ nbPar = (Integer) r[2];
|
|
+ }
|
|
+ final long med = median(pt);
|
|
+ final double ms = med / 1e6;
|
|
+ final double tps = n / (med / 1e9);
|
|
+ if (w == 1) {
|
|
+ par1Ms = ms;
|
|
+ }
|
|
+ log(String.format(
|
|
+ " %6d | %10.3f | %8.0f | %13.2fx | %12.2fx (nbParallel=%d)",
|
|
+ w, ms, tps, seqMs / ms, par1Ms / ms, nbPar));
|
|
+ }
|
|
+ flush();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Measures the ISOLATED parallel execution phase across worker counts. Drives the engine directly
|
|
+ * (runAsyncBlock) and reads {@code execPhaseNanos} recorded INSIDE the engine (worker pool start ->
|
|
+ * termination), so the flat-snapshot mint and the downstream serial Bonsai trie commit are both
|
|
+ * excluded. Scaling vs w=1 of this number is the direct test of whether Block-STM execution
|
|
+ * parallelism works once the per-worker snapshot overhead is removed.
|
|
+ */
|
|
+ private void runExecPhase(
|
|
+ final String title,
|
|
+ final int n,
|
|
+ final long gasLimit,
|
|
+ final Transaction[] txs,
|
|
+ final int[] workerCounts,
|
|
+ final int warmup,
|
|
+ final int measure)
|
|
+ throws Exception {
|
|
+ log("");
|
|
+ log("## " + title + " (n=" + n + " txs)");
|
|
+ log(" worker | exec-phase ms | snapshot ms | exec tx/s | scaling vs w=1 | verified");
|
|
+ log(" -------+----------------+-------------+--------------+----------------+---------");
|
|
+
|
|
+ double w1Ms = Double.NaN;
|
|
+ for (final int w : workerCounts) {
|
|
+ for (int i = 0; i < warmup; i++) {
|
|
+ engineStats(gasLimit, w, txs);
|
|
+ }
|
|
+ final long[] execT = new long[measure];
|
|
+ final long[] snapT = new long[measure];
|
|
+ boolean verified = true;
|
|
+ for (int i = 0; i < measure; i++) {
|
|
+ final BlockStmStats st = engineStats(gasLimit, w, txs);
|
|
+ execT[i] = st.execPhaseNanos();
|
|
+ snapT[i] = st.snapshotNanos();
|
|
+ verified = verified && st.verified();
|
|
+ }
|
|
+ final long execMed = median(execT);
|
|
+ final long snapMed = median(snapT);
|
|
+ final double execMs = execMed / 1e6;
|
|
+ final double snapMs = snapMed / 1e6;
|
|
+ final double tps = n / (execMed / 1e9);
|
|
+ if (w == 1) {
|
|
+ w1Ms = execMs;
|
|
+ }
|
|
+ assertThat(verified).as("exec-phase run must verify at w=" + w).isTrue();
|
|
+ log(String.format(
|
|
+ " %6d | %14.3f | %11.3f | %12.0f | %13.2fx | %s",
|
|
+ w, execMs, snapMs, tps, w1Ms / execMs, verified));
|
|
+ }
|
|
+ flush();
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmSmokeTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmSmokeTest.java
|
|
new file mode 100644
|
|
index 0000000000..a8e3db99de
|
|
--- /dev/null
|
|
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/AereBlockStmSmokeTest.java
|
|
@@ -0,0 +1,130 @@
|
|
+/*
|
|
+ * Copyright contributors to 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
|
|
+ *
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
+ */
|
|
+package org.hyperledger.besu.ethereum.mainnet.parallelization;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.ACCOUNT_2;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.ACCOUNT_3;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.ACCOUNT_4;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.ACCOUNT_GENESIS_1_KEYPAIR;
|
|
+import static org.hyperledger.besu.ethereum.mainnet.parallelization.ParallelBlockProcessorTestSupport.ACCOUNT_GENESIS_2_KEYPAIR;
|
|
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
+
|
|
+import org.hyperledger.besu.datatypes.Hash;
|
|
+import org.hyperledger.besu.datatypes.Wei;
|
|
+import org.hyperledger.besu.ethereum.BlockProcessingResult;
|
|
+import org.hyperledger.besu.ethereum.core.Block;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
|
|
+import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
|
+import org.hyperledger.besu.ethereum.core.Transaction;
|
|
+import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor.PreprocessingFunction;
|
|
+import org.hyperledger.besu.ethereum.mainnet.BlockProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
|
+import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
|
+import org.hyperledger.besu.ethereum.mainnet.blockstm.AereBlockStmPreprocessing;
|
|
+import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
|
|
+
|
|
+import org.junit.jupiter.api.DisplayName;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+/**
|
|
+ * Smoke test proving AERE Block-STM parallel execution is serial-equivalent: a block processed
|
|
+ * through the AERE Block-STM engine (a stock {@link MainnetParallelBlockProcessor} driven by {@link
|
|
+ * AereBlockStmPreprocessing}) yields a state root bit-identical to sequential {@code
|
|
+ * MainnetBlockProcessor} execution of the same block, and the parallel path is actually exercised.
|
|
+ */
|
|
+public class AereBlockStmSmokeTest extends AbstractParallelBlockProcessorIntegrationTest {
|
|
+
|
|
+ @Override
|
|
+ protected String getVariantName() {
|
|
+ return "AERE Block-STM";
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected ParallelTransactionPreprocessing createParallelPreprocessing(
|
|
+ final MainnetTransactionProcessor transactionProcessor) {
|
|
+ // Not used by this test; provided to satisfy the abstract base.
|
|
+ return new ParallelTransactionPreprocessing(
|
|
+ transactionProcessor, Runnable::run, getBalConfiguration());
|
|
+ }
|
|
+
|
|
+ private BlockProcessor stockParallelProcessor(final ExecutionContextTestFixture ctx) {
|
|
+ final ProtocolSpec spec =
|
|
+ ctx.getProtocolSchedule()
|
|
+ .getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader());
|
|
+ return new MainnetParallelBlockProcessor(
|
|
+ spec.getTransactionProcessor(),
|
|
+ spec.getTransactionReceiptFactory(),
|
|
+ Wei.ZERO,
|
|
+ BlockHeader::getCoinbase,
|
|
+ true,
|
|
+ ctx.getProtocolSchedule(),
|
|
+ getBalConfiguration(),
|
|
+ new NoOpMetricsSystem());
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("AERE Block-STM parallel root equals sequential root for independent transfers")
|
|
+ void blockStmRootMatchesSequential() {
|
|
+ final Transaction tx1 =
|
|
+ createTransferTransaction(
|
|
+ 0, 1_000_000_000_000_000_000L, 300_000L, 0L, 5L, ACCOUNT_2, ACCOUNT_GENESIS_1_KEYPAIR);
|
|
+ final Transaction tx2 =
|
|
+ createTransferTransaction(
|
|
+ 0, 2_000_000_000_000_000_000L, 300_000L, 0L, 5L, ACCOUNT_3, ACCOUNT_GENESIS_2_KEYPAIR);
|
|
+ final Transaction tx3 =
|
|
+ createTransferTransaction(
|
|
+ 1, 3_000_000_000_000_000_000L, 300_000L, 0L, 5L, ACCOUNT_4, ACCOUNT_GENESIS_1_KEYPAIR);
|
|
+
|
|
+ final Wei baseFee = Wei.of(5);
|
|
+ final Transaction[] txs = {tx1, tx2, tx3};
|
|
+ final Hash stateRoot = discoverStateRoot(baseFee, txs);
|
|
+
|
|
+ // Sequential
|
|
+ final ExecutionContextTestFixture seqCtx = createFreshContext();
|
|
+ final MutableWorldState seqWs = seqCtx.getStateArchive().getWorldState();
|
|
+ final Block seqBlock = createBlock(seqCtx, stateRoot, baseFee, txs);
|
|
+ final BlockProcessor seqProcessor = createSequentialProcessor(seqCtx);
|
|
+ final BlockProcessingResult seqResult =
|
|
+ seqProcessor.processBlock(
|
|
+ seqCtx.getProtocolContext(), seqCtx.getBlockchain(), seqWs, seqBlock);
|
|
+ assertTrue(seqResult.isSuccessful(), "sequential processing failed");
|
|
+
|
|
+ // Parallel via AERE Block-STM
|
|
+ final ExecutionContextTestFixture parCtx = createFreshContext();
|
|
+ final MutableWorldState parWs = parCtx.getStateArchive().getWorldState();
|
|
+ final Block parBlock = createBlock(parCtx, stateRoot, baseFee, txs);
|
|
+ final ProtocolSpec spec =
|
|
+ parCtx
|
|
+ .getProtocolSchedule()
|
|
+ .getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader());
|
|
+ final BlockProcessor parProcessor = stockParallelProcessor(parCtx);
|
|
+ final PreprocessingFunction blockStm =
|
|
+ new AereBlockStmPreprocessing(
|
|
+ spec.getTransactionProcessor(), Runtime.getRuntime().availableProcessors());
|
|
+ final BlockProcessingResult parResult =
|
|
+ parProcessor.processBlock(
|
|
+ parCtx.getProtocolContext(), parCtx.getBlockchain(), parWs, parBlock, blockStm);
|
|
+ assertTrue(
|
|
+ parResult.isSuccessful(),
|
|
+ "AERE Block-STM processing failed: " + parResult.errorMessage.orElse("(no message)"));
|
|
+
|
|
+ // Serial-equivalence: bit-identical 32-byte state root.
|
|
+ assertThat(parWs.rootHash())
|
|
+ .as("AERE Block-STM parallel state root must equal sequential")
|
|
+ .isEqualTo(seqWs.rootHash());
|
|
+
|
|
+ // The parallel path was actually exercised (outcomes consumed, not per-tx sequential fallback).
|
|
+ assertParallelizationRecordedInResults(seqResult, parResult, txs.length);
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java
|
|
index ee4e941111..92ec415271 100644
|
|
--- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java
|
|
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.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/aere-cap-prestatus-rlpx-connections.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.eth.manager;
|
|
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.eth.EthProtocol;
|
|
import org.hyperledger.besu.ethereum.eth.SnapProtocol;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthPeer.DisconnectCallback;
|
|
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerSelector;
|
|
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator;
|
|
import org.hyperledger.besu.ethereum.eth.sync.ChainHeadTracker;
|
|
import org.hyperledger.besu.ethereum.eth.sync.SnapServerChecker;
|
|
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
|
|
import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements;
|
|
import org.hyperledger.besu.ethereum.forkid.ForkId;
|
|
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
|
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
|
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
|
|
import org.hyperledger.besu.ethereum.p2p.peers.PeerId;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.RlpxAgent;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
|
|
@@ -74,46 +80,55 @@ public class EthPeers implements PeerSelector {
|
|
Comparator.comparing((final EthPeerImmutableAttributes p) -> p.estimatedTotalDifficulty());
|
|
|
|
public static final Comparator<EthPeerImmutableAttributes> CHAIN_HEIGHT =
|
|
Comparator.comparing((final EthPeerImmutableAttributes p) -> p.estimatedChainHeight());
|
|
|
|
public static final Comparator<EthPeerImmutableAttributes> MOST_USEFUL_PEER =
|
|
Comparator.comparing((final EthPeerImmutableAttributes p) -> p.reputationScore())
|
|
.thenComparing(CHAIN_HEIGHT);
|
|
|
|
public static final Comparator<EthPeerImmutableAttributes> TOTAL_DIFFICULTY_THEN_HEIGHT =
|
|
TOTAL_DIFFICULTY.thenComparing(CHAIN_HEIGHT);
|
|
|
|
public static final Comparator<EthPeerImmutableAttributes> LEAST_TO_MOST_BUSY =
|
|
Comparator.comparing(EthPeerImmutableAttributes::outstandingRequests)
|
|
.thenComparing(EthPeerImmutableAttributes::lastRequestTimestamp);
|
|
public static final int NODE_ID_LENGTH = 64;
|
|
public static final int USEFULL_PEER_SCORE_THRESHOLD = 102;
|
|
|
|
private final Map<Bytes, EthPeer> activeConnections = new ConcurrentHashMap<>();
|
|
|
|
- private final Cache<PeerConnection, EthPeer> incompleteConnections =
|
|
- CacheBuilder.newBuilder()
|
|
- .expireAfterWrite(Duration.ofSeconds(20L))
|
|
- .concurrencyLevel(1)
|
|
- .removalListener(this::onCacheRemoval)
|
|
- .build();
|
|
+ /**
|
|
+ * Lower bound for the pre-STATUS (incomplete) connection cap, so that even very small {@code
|
|
+ * --max-peers} values still tolerate a reasonable number of concurrent inbound handshakes. AERE
|
|
+ * D-434: ported from upstream hyperledger/besu e540ae2394 (GHSA-6r9q-wjp4-34gh).
|
|
+ */
|
|
+ private static final int INCOMPLETE_CONNECTIONS_CAP_FLOOR = 10;
|
|
+
|
|
+ /**
|
|
+ * Maximum number of connections that have completed the devp2p HELLO but not yet the eth STATUS
|
|
+ * handshake that we retain. Bounds file-descriptor and heap growth from peers that connect and
|
|
+ * never send STATUS, which are otherwise invisible to {@code --max-peers} accounting.
|
|
+ */
|
|
+ private final int maxIncompleteConnections;
|
|
+
|
|
+ private final Cache<PeerConnection, EthPeer> incompleteConnections;
|
|
private final Clock clock;
|
|
private final List<NodeMessagePermissioningProvider> permissioningProviders;
|
|
private final int maxMessageSize;
|
|
private final Subscribers<ConnectCallback> connectCallbacks = Subscribers.create();
|
|
private final Subscribers<DisconnectCallback> disconnectCallbacks = Subscribers.create();
|
|
private final Collection<PendingPeerRequest> pendingRequests = new CopyOnWriteArrayList<>();
|
|
private final int peerUpperBound;
|
|
private final int maxRemotelyInitiatedConnections;
|
|
private final Boolean randomPeerPriority;
|
|
private final Bytes nodeIdMask = Bytes.random(NODE_ID_LENGTH);
|
|
private final Supplier<ProtocolSpec> currentProtocolSpecSupplier;
|
|
private final SyncMode syncMode;
|
|
private final ForkIdManager forkIdManager;
|
|
private final int snapServerTargetNumber;
|
|
private final boolean shouldLimitRemoteConnections;
|
|
|
|
private Comparator<EthPeerImmutableAttributes> bestPeerComparator;
|
|
private final Bytes localNodeId;
|
|
private RlpxAgent rlpxAgent;
|
|
|
|
@@ -134,62 +149,75 @@ public class EthPeers implements PeerSelector {
|
|
final int peerUpperBound,
|
|
final int maxRemotelyInitiatedConnections,
|
|
final Boolean randomPeerPriority,
|
|
final SyncMode syncMode,
|
|
final ForkIdManager forkIdManager) {
|
|
this.currentProtocolSpecSupplier = currentProtocolSpecSupplier;
|
|
this.clock = clock;
|
|
this.permissioningProviders = permissioningProviders;
|
|
this.maxMessageSize = maxMessageSize;
|
|
this.bestPeerComparator = TOTAL_DIFFICULTY_THEN_HEIGHT;
|
|
this.localNodeId = localNodeId;
|
|
this.peerUpperBound = peerUpperBound;
|
|
this.maxRemotelyInitiatedConnections = maxRemotelyInitiatedConnections;
|
|
this.randomPeerPriority = randomPeerPriority;
|
|
LOG.trace("MaxPeers: {}, Max Remote: {}", peerUpperBound, maxRemotelyInitiatedConnections);
|
|
this.syncMode = syncMode;
|
|
this.forkIdManager = forkIdManager;
|
|
this.snapServerTargetNumber =
|
|
peerUpperBound / 2; // 50% of peers should be snap servers while snap syncing
|
|
this.shouldLimitRemoteConnections = maxRemotelyInitiatedConnections < peerUpperBound;
|
|
+ this.maxIncompleteConnections = Math.max(peerUpperBound * 2, INCOMPLETE_CONNECTIONS_CAP_FLOOR);
|
|
+ this.incompleteConnections =
|
|
+ CacheBuilder.newBuilder()
|
|
+ .maximumSize(maxIncompleteConnections)
|
|
+ .expireAfterWrite(Duration.ofSeconds(20L))
|
|
+ .concurrencyLevel(1)
|
|
+ .removalListener(this::onCacheRemoval)
|
|
+ .build();
|
|
|
|
metricsSystem.createIntegerGauge(
|
|
BesuMetricCategory.ETHEREUM,
|
|
"peer_count",
|
|
"The current number of peers connected",
|
|
activeConnections::size);
|
|
metricsSystem.createIntegerGauge(
|
|
BesuMetricCategory.ETHEREUM,
|
|
"peer_count_snap_server",
|
|
"The current number of peers connected that serve snap data",
|
|
() ->
|
|
(int) streamAvailablePeers().filter(EthPeerImmutableAttributes::isServingSnap).count());
|
|
metricsSystem.createIntegerGauge(
|
|
BesuMetricCategory.PEERS,
|
|
"pending_peer_requests_current",
|
|
"Number of peer requests currently pending because peers are busy",
|
|
pendingRequests::size);
|
|
metricsSystem.createIntegerGauge(
|
|
BesuMetricCategory.ETHEREUM,
|
|
"peer_limit",
|
|
"The maximum number of peers this node allows to connect",
|
|
() -> peerUpperBound);
|
|
+ metricsSystem.createIntegerGauge(
|
|
+ BesuMetricCategory.ETHEREUM,
|
|
+ "peer_count_incomplete",
|
|
+ "The current number of connections that have not yet completed the eth STATUS handshake",
|
|
+ () -> (int) incompleteConnections.size());
|
|
|
|
connectedPeersCounter =
|
|
metricsSystem.createCounter(
|
|
BesuMetricCategory.PEERS, "connected_total", "Total number of peers connected");
|
|
|
|
final LabelledSuppliedMetric peerClientLabelledGauge =
|
|
metricsSystem.createLabelledSuppliedGauge(
|
|
BesuMetricCategory.PEERS,
|
|
"peer_count_by_client",
|
|
"The number of clients connected by client",
|
|
"client");
|
|
|
|
for (final var clientName : PeerClientName.values()) {
|
|
peerClientLabelledGauge.labels(
|
|
() -> countConnectedPeersByClientName(clientName), clientName.getDisplayName());
|
|
}
|
|
}
|
|
|
|
private double countConnectedPeersByClientName(final PeerClientName clientName) {
|
|
return streamAllActiveConnections()
|
|
@@ -737,56 +765,86 @@ public class EthPeers implements PeerSelector {
|
|
conn,
|
|
peerUpperBound);
|
|
conn.disconnect(DisconnectMessage.DisconnectReason.TOO_MANY_PEERS);
|
|
});
|
|
}
|
|
|
|
private boolean inboundInitiatedConnectionLimitExceeded() {
|
|
return shouldLimitRemoteConnections
|
|
&& countUntrustedRemotelyInitiatedConnections() > maxRemotelyInitiatedConnections;
|
|
}
|
|
|
|
private long countUntrustedRemotelyInitiatedConnections() {
|
|
return activeConnections.values().stream()
|
|
.map(EthPeer::getConnection)
|
|
.filter(PeerConnection::inboundInitiated)
|
|
.filter(c -> !c.isDisconnected())
|
|
.filter(conn -> !canExceedPeerLimits(conn.getPeer().getId()))
|
|
.count();
|
|
}
|
|
|
|
- private void onCacheRemoval(
|
|
- final RemovalNotification<PeerConnection, EthPeer> removalNotification) {
|
|
- if (removalNotification.wasEvicted()) {
|
|
- final PeerConnection peerConnectionRemoved = removalNotification.getKey();
|
|
- final EthPeer peer = removalNotification.getValue();
|
|
- if (peer == null) {
|
|
- return;
|
|
- }
|
|
- final PeerConnection peerConnectionOfEthPeer = peer.getConnection();
|
|
- if (peerConnectionRemoved != null) {
|
|
- if (!peerConnectionRemoved.equals(peerConnectionOfEthPeer)) {
|
|
- // If this connection is not the connection of the EthPeer by now we can disconnect
|
|
- peerConnectionRemoved.disconnect(DisconnectMessage.DisconnectReason.ALREADY_CONNECTED);
|
|
- }
|
|
- }
|
|
+ // AERE D-434 (e540ae2394, GHSA-6r9q-wjp4-34gh): close pre-STATUS connections evicted from the
|
|
+ // bounded incomplete-connection cache so they cannot leak file descriptors or heap.
|
|
+ @VisibleForTesting
|
|
+ void onCacheRemoval(final RemovalNotification<PeerConnection, EthPeer> removalNotification) {
|
|
+ // Only react to evictions (size cap or expiry). Explicit invalidations (e.g. on a normal
|
|
+ // disconnect) already close the connection through their own path.
|
|
+ if (!removalNotification.wasEvicted()) {
|
|
+ return;
|
|
+ }
|
|
+ final PeerConnection evictedConnection = removalNotification.getKey();
|
|
+ final EthPeer peer = removalNotification.getValue();
|
|
+ if (evictedConnection == null || evictedConnection.isDisconnected()) {
|
|
+ return;
|
|
}
|
|
+
|
|
+ final boolean isCurrentConnectionOfPeer =
|
|
+ peer != null && evictedConnection.equals(peer.getConnection());
|
|
+ if (isCurrentConnectionOfPeer && peer.statusHasBeenReceived()) {
|
|
+ // The peer completed (or is completing) the eth STATUS handshake and is being promoted to an
|
|
+ // active connection; its incomplete-cache entry is expiring naturally. Leave the live
|
|
+ // connection alone - it is (or will be) tracked in activeConnections.
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Either a superseded connection (the peer reconnected with a different connection), or a
|
|
+ // connection that completed the devp2p HELLO but never sent eth STATUS and has now been evicted
|
|
+ // (20s expiry, or pushed out of the bounded cache). Close the socket so evicted pre-STATUS
|
|
+ // connections cannot leak file descriptors or heap while remaining invisible to --max-peers.
|
|
+ DisconnectReason reason =
|
|
+ isCurrentConnectionOfPeer
|
|
+ ? DisconnectMessage.DisconnectReason.TIMEOUT
|
|
+ : DisconnectMessage.DisconnectReason.ALREADY_CONNECTED;
|
|
+
|
|
+ LOG.atTrace()
|
|
+ .setMessage(
|
|
+ "Closing pre-STATUS connection {} evicted from incomplete-connection cache, reason {}")
|
|
+ .addArgument(evictedConnection::getPeerInfo)
|
|
+ .addArgument(reason)
|
|
+ .log();
|
|
+
|
|
+ evictedConnection.disconnect(reason);
|
|
+ }
|
|
+
|
|
+ @VisibleForTesting
|
|
+ int incompleteConnectionCount() {
|
|
+ return (int) incompleteConnections.size();
|
|
}
|
|
|
|
boolean addPeerToEthPeers(final EthPeer peer) {
|
|
// We have a connection to a peer that is on the right chain and is willing to connect to us.
|
|
// Figure out whether we want to add it to the active connections.
|
|
final PeerConnection connection = peer.getConnection();
|
|
if (activeConnections.containsValue(peer)) {
|
|
return false;
|
|
}
|
|
|
|
final Bytes id = peer.getId();
|
|
if (!randomPeerPriority) {
|
|
|
|
if (peerCount() >= peerUpperBound) {
|
|
final long numSnapServers = numberOfSnapServers();
|
|
final boolean inboundLimitExceeded = inboundInitiatedConnectionLimitExceeded();
|
|
// three reasons why we would disconnect an existing peer to accommodate the new peer
|
|
if (canExceedPeerLimits(id)
|
|
|| (snapServerPeersNeeded
|
|
&& numSnapServers < snapServerTargetNumber
|
|
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java
|
|
index 7fde3a17c7..dbcc8fbacc 100644
|
|
--- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.java
|
|
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/BlockPropagationManager.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/0008-aere-pq-aip22.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.eth.sync;
|
|
|
|
import static org.hyperledger.besu.util.FutureUtils.exceptionallyCompose;
|
|
|
|
import org.hyperledger.besu.consensus.merge.ForkchoiceEvent;
|
|
import org.hyperledger.besu.consensus.merge.UnverifiedForkchoiceListener;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.ProtocolContext;
|
|
import org.hyperledger.besu.ethereum.chain.BadBlockCause;
|
|
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
|
|
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
|
|
import org.hyperledger.besu.ethereum.core.Block;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.Difficulty;
|
|
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthMessage;
|
|
@@ -704,40 +710,53 @@ public class BlockPropagationManager implements UnverifiedForkchoiceListener {
|
|
if (!protocolContext
|
|
.getBlockchain()
|
|
.contains(lowestPendingBlock.getHeader().getParentHash())) {
|
|
requestParentBlock(lowestPendingBlock);
|
|
} else {
|
|
LOG.trace("Parent block is already in the chain");
|
|
// if the parent is already imported, process its children
|
|
maybeProcessPendingChildrenBlocks(lowestPendingBlock.getHeader());
|
|
}
|
|
}
|
|
}
|
|
|
|
private CompletableFuture<Block> validateAndProcessPendingBlock(
|
|
final BlockHeaderValidator blockHeaderValidator,
|
|
final Block block,
|
|
final BlockHeader parent,
|
|
final BadBlockManager badBlockManager) {
|
|
final HeaderValidationMode validationMode = HeaderValidationMode.FULL;
|
|
if (blockHeaderValidator.validateHeader(
|
|
block.getHeader(), parent, protocolContext, validationMode)) {
|
|
+ // AERE D-412 (2026-09-26), Rule C: a valid header is not, from AIP-22 stage 5, a proof that a
|
|
+ // quorum agreed the block (it carries only the proposer's single Falcon seal). A validator does
|
|
+ // not ADOPT a propagated block at the tip of its own consensus height without a post-quantum
|
|
+ // commit quorum for it; the gate is inert below H_hdr and for non-validators, and the sync
|
|
+ // downloader (a different path) is untouched, so this is fork choice, not validation.
|
|
+ if (!PropagatedBlockAdoptionGate.mayAdopt(block.getHeader(), parent)) {
|
|
+ processingBlocksManager.registerBlockImportDone(block.getHash());
|
|
+ LOG.info(
|
|
+ "AERE D-412: not adopting propagated block {} at the tip without a post-quantum commit "
|
|
+ + "quorum; this node's own consensus decides this height",
|
|
+ block.toLogString());
|
|
+ return CompletableFuture.completedFuture(block);
|
|
+ }
|
|
ethContext.getScheduler().scheduleSyncWorkerTask(() -> broadcastBlock(block, parent));
|
|
return runImportTask(block);
|
|
} else {
|
|
processingBlocksManager.registerBlockImportDone(block.getHash());
|
|
final String description = String.format("Failed header validation (%s)", validationMode);
|
|
badBlockManager.addBadBlock(block, BadBlockCause.fromValidationFailure(description));
|
|
LOG.warn(
|
|
"Added to bad block manager for invalid header, failed to import announced block {}",
|
|
block.toLogString());
|
|
return CompletableFuture.completedFuture(block);
|
|
}
|
|
}
|
|
|
|
private CompletableFuture<Block> runImportTask(final Block block) {
|
|
final PersistBlockTask importTask =
|
|
PersistBlockTask.create(
|
|
protocolSchedule,
|
|
protocolContext,
|
|
ethContext,
|
|
block,
|
|
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PropagatedBlockAdoptionGate.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PropagatedBlockAdoptionGate.java
|
|
new file mode 100644
|
|
index 0000000000..7e11ed3686
|
|
--- /dev/null
|
|
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PropagatedBlockAdoptionGate.java
|
|
@@ -0,0 +1,103 @@
|
|
+/*
|
|
+ * Copyright contributors to Besu / 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.eth.sync;
|
|
+
|
|
+import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
+
|
|
+import org.slf4j.Logger;
|
|
+import org.slf4j.LoggerFactory;
|
|
+
|
|
+/**
|
|
+ * AERE D-412 (2026-09-26), Rule C. A process-wide gate the block PROPAGATION path asks before it adopts
|
|
+ * a block arriving from the network as the new canonical head.
|
|
+ *
|
|
+ * <p>WHY IT EXISTS. From AIP-22 stage 5 (H_hdr) a header carries only the proposer's single Falcon-512
|
|
+ * seal, so a valid header no longer proves a quorum agreed the block: an honest committed block and a
|
|
+ * block a single key forged are indistinguishable to header validation. The quorum agreement lives OFF
|
|
+ * the header, in the commit seals a validator heard (AIP-21, {@code PqSealCache}). Measured on rep28098,
|
|
+ * a single validator forged its own between-anchor block, gossiped it, and honest validators imported it
|
|
+ * as head and built on top. This gate lets a validator refuse to ADOPT such a propagated block at the tip
|
|
+ * of its own consensus height unless it holds a post-quantum commit quorum for it. Block VALIDITY is
|
|
+ * unchanged (this is fork choice, not validation), so the sync downloader - a different code path that
|
|
+ * does not consult this gate - still imports the same chain and catch-up is unaffected.
|
|
+ *
|
|
+ * <p>WHY A STATIC REGISTRY. This module ({@code ethereum/eth}) sits below the consensus modules and
|
|
+ * cannot depend on them, so the smart part of the decision (the seal cache, the registry, the validator
|
|
+ * set) lives in a consensus-aware implementation that registers itself here at startup, exactly as
|
|
+ * {@code PqSealCache.instance()} and the other AERE consensus singletons are process-wide. The interface
|
|
+ * takes only {@code ethereum/core} types, so there is no backward dependency. Unset, the gate is
|
|
+ * {@link #ALLOW_ALL} and behaviour is byte-for-byte as before.
|
|
+ *
|
|
+ * <p>FAIL OPEN. {@link #mayAdopt} never throws: a bug in the installed gate reverts to the current
|
|
+ * behaviour (adopt), never to refusing every block, because a repair that could stop the chain is worse
|
|
+ * than the exposure it closes.
|
|
+ */
|
|
+public final class PropagatedBlockAdoptionGate {
|
|
+
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(PropagatedBlockAdoptionGate.class);
|
|
+
|
|
+ /** The decision a consensus-aware implementation supplies. */
|
|
+ @FunctionalInterface
|
|
+ public interface Gate {
|
|
+ /**
|
|
+ * Whether this node may adopt a block that arrived by propagation as the new canonical head.
|
|
+ *
|
|
+ * @param header the propagated block's header, already header-validated
|
|
+ * @param parent the parent header, already on this node's chain
|
|
+ * @return true to adopt (import as head), false to leave this height to this node's own consensus
|
|
+ */
|
|
+ boolean mayAdopt(BlockHeader header, BlockHeader parent);
|
|
+ }
|
|
+
|
|
+ /** The default: adopt everything, i.e. exactly the behaviour before this gate existed. */
|
|
+ public static final Gate ALLOW_ALL = (header, parent) -> true;
|
|
+
|
|
+ private static volatile Gate gate = ALLOW_ALL;
|
|
+
|
|
+ private PropagatedBlockAdoptionGate() {}
|
|
+
|
|
+ /**
|
|
+ * Install the gate for this process. A consensus builder calls this at startup.
|
|
+ *
|
|
+ * @param g the gate, or null to reset to {@link #ALLOW_ALL}
|
|
+ */
|
|
+ public static void install(final Gate g) {
|
|
+ gate = (g == null) ? ALLOW_ALL : g;
|
|
+ }
|
|
+
|
|
+ /** Reset to {@link #ALLOW_ALL}. For tests and a deliberate operator reset. */
|
|
+ public static void reset() {
|
|
+ gate = ALLOW_ALL;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Whether the installed gate allows adopting this propagated block. Never throws: on any error it
|
|
+ * allows (fail open), so a gate bug can never stop the chain.
|
|
+ *
|
|
+ * @param header the propagated block's header
|
|
+ * @param parent the parent header
|
|
+ * @return true to adopt
|
|
+ */
|
|
+ public static boolean mayAdopt(final BlockHeader header, final BlockHeader parent) {
|
|
+ try {
|
|
+ return gate.mayAdopt(header, parent);
|
|
+ } catch (final RuntimeException e) {
|
|
+ LOG.warn(
|
|
+ "AERE D-412: propagation adoption gate threw ({}); allowing the block, as before the gate.",
|
|
+ e.toString());
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java
|
|
old mode 100644
|
|
new mode 100755
|
|
index ab09fafaa0..9d5cdadf39
|
|
--- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java
|
|
+++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncState.java
|
|
@@ -1,65 +1,77 @@
|
|
/*
|
|
* 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/aere-syncstate-in-sync-lock.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.eth.sync.state;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|
import org.hyperledger.besu.ethereum.chain.ChainHead;
|
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
|
import org.hyperledger.besu.ethereum.core.DefaultSyncStatus;
|
|
import org.hyperledger.besu.ethereum.core.Synchronizer;
|
|
import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener;
|
|
import org.hyperledger.besu.ethereum.eth.manager.ChainHeadEstimate;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
|
|
import org.hyperledger.besu.ethereum.eth.sync.common.checkpoint.Checkpoint;
|
|
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadStatus;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason;
|
|
import org.hyperledger.besu.plugin.data.SyncStatus;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.InitialSyncCompletionListener;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.TTDReachedListener;
|
|
import org.hyperledger.besu.util.Subscribers;
|
|
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
public class SyncState {
|
|
|
|
private final Blockchain blockchain;
|
|
private final EthPeers ethPeers;
|
|
|
|
+ // Ensures checkInSync() re-evaluation gives a consistent view of sync status. A
|
|
+ // standalone lock is used instead of the object monitor to prevent checkInSync()
|
|
+ // causing a deadlock while synchronized on the object monitor.
|
|
+ // (AERE D-426: upstream hyperledger/besu#11041, ported)
|
|
+ private final Object inSyncLock = new Object();
|
|
+
|
|
private final AtomicLong inSyncSubscriberId = new AtomicLong();
|
|
private final Map<Long, InSyncTracker> inSyncTrackers = new ConcurrentHashMap<>();
|
|
private final Subscribers<SyncStatusListener> syncStatusListeners = Subscribers.create();
|
|
private final Subscribers<TTDReachedListener> ttdReachedListeners = Subscribers.create();
|
|
|
|
private final Subscribers<InitialSyncCompletionListener> completionListenerSubscribers =
|
|
Subscribers.create();
|
|
|
|
private volatile long chainHeightListenerId;
|
|
private volatile Optional<SyncTarget> syncTarget = Optional.empty();
|
|
private Optional<WorldStateDownloadStatus> worldStateDownloadStatus = Optional.empty();
|
|
private Optional<Long> newPeerListenerId;
|
|
private Optional<Boolean> reachedTerminalDifficulty = Optional.empty();
|
|
private final Optional<Checkpoint> checkpoint;
|
|
private volatile boolean isInitialSyncPhaseDone;
|
|
|
|
private volatile boolean isResyncNeeded;
|
|
|
|
private Optional<Address> maybeAccountToRepair = Optional.empty();
|
|
|
|
@@ -285,56 +297,59 @@ public class SyncState {
|
|
}
|
|
|
|
public long getLocalChainHeight() {
|
|
return blockchain.getChainHeadBlockNumber();
|
|
}
|
|
|
|
public long bestChainHeight() {
|
|
final long localChainHeight = blockchain.getChainHeadBlockNumber();
|
|
return bestChainHeight(localChainHeight);
|
|
}
|
|
|
|
public long bestChainHeight(final long localChainHeight) {
|
|
return Math.max(
|
|
localChainHeight,
|
|
ethPeers
|
|
.bestPeerWithHeightEstimate()
|
|
.map(p -> p.chainState().getEstimatedHeight())
|
|
.orElse(localChainHeight));
|
|
}
|
|
|
|
- private synchronized void checkInSync() {
|
|
- final ChainHead localChain = getLocalChainHead();
|
|
- final Optional<ChainHeadEstimate> syncTargetChain = getSyncTargetChainHead();
|
|
- final Optional<ChainHeadEstimate> bestPeerChain = getBestPeerChainHead();
|
|
-
|
|
- // Remove listener when we've found a peer.
|
|
- newPeerListenerId.ifPresent(
|
|
- listenerId -> {
|
|
- ethPeers.unsubscribeConnect(listenerId);
|
|
- newPeerListenerId = Optional.empty();
|
|
- });
|
|
-
|
|
- inSyncTrackers
|
|
- .values()
|
|
- .forEach(
|
|
- (syncTracker) -> syncTracker.checkState(localChain, syncTargetChain, bestPeerChain));
|
|
+ /** Evaluates whether this node is in sync and notifies any tracker whose verdict changed. */
|
|
+ private void checkInSync() {
|
|
+ synchronized (inSyncLock) {
|
|
+ final ChainHead localChain = getLocalChainHead();
|
|
+ final Optional<ChainHeadEstimate> syncTargetChain = getSyncTargetChainHead();
|
|
+ final Optional<ChainHeadEstimate> bestPeerChain = getBestPeerChainHead();
|
|
+
|
|
+ // Remove listener when we've found a peer.
|
|
+ newPeerListenerId.ifPresent(
|
|
+ listenerId -> {
|
|
+ ethPeers.unsubscribeConnect(listenerId);
|
|
+ newPeerListenerId = Optional.empty();
|
|
+ });
|
|
+
|
|
+ inSyncTrackers
|
|
+ .values()
|
|
+ .forEach(
|
|
+ (syncTracker) -> syncTracker.checkState(localChain, syncTargetChain, bestPeerChain));
|
|
+ }
|
|
}
|
|
|
|
public Optional<Checkpoint> getCheckpoint() {
|
|
return checkpoint;
|
|
}
|
|
|
|
public boolean isInitialSyncPhaseDone() {
|
|
return isInitialSyncPhaseDone;
|
|
}
|
|
|
|
public void markInitialSyncPhaseAsDone() {
|
|
isInitialSyncPhaseDone = true;
|
|
isResyncNeeded = false;
|
|
completionListenerSubscribers.forEach(InitialSyncCompletionListener::onInitialSyncCompleted);
|
|
}
|
|
|
|
public boolean isResyncNeeded() {
|
|
return isResyncNeeded;
|
|
}
|
|
|
|
diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java
|
|
index ba6fd7b3dd..5b58648df1 100644
|
|
--- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.java
|
|
+++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/state/SyncStateTest.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/aere-syncstate-in-sync-lock.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.eth.sync.state;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
import static org.mockito.Mockito.doReturn;
|
|
import static org.mockito.Mockito.lenient;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.never;
|
|
import static org.mockito.Mockito.spy;
|
|
import static org.mockito.Mockito.times;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Hash;
|
|
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
|
|
import org.hyperledger.besu.ethereum.core.Block;
|
|
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
|
|
@@ -39,42 +45,47 @@ import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
|
|
import org.hyperledger.besu.ethereum.core.Synchronizer;
|
|
import org.hyperledger.besu.ethereum.core.Synchronizer.InSyncListener;
|
|
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
|
|
import org.hyperledger.besu.ethereum.eth.manager.ChainHeadEstimate;
|
|
import org.hyperledger.besu.ethereum.eth.manager.ChainState;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
|
|
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
|
|
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
|
|
import org.hyperledger.besu.ethereum.eth.sync.common.checkpoint.Checkpoint;
|
|
import org.hyperledger.besu.ethereum.eth.sync.common.checkpoint.ImmutableCheckpoint;
|
|
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason;
|
|
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
|
|
import org.hyperledger.besu.plugin.data.SyncStatus;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.InitialSyncCompletionListener;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener;
|
|
import org.hyperledger.besu.plugin.services.BesuEvents.TTDReachedListener;
|
|
|
|
+import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
+import java.util.concurrent.CountDownLatch;
|
|
+import java.util.concurrent.TimeUnit;
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
import org.mockito.ArgumentCaptor;
|
|
import org.mockito.Captor;
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
public class SyncStateTest {
|
|
|
|
private static final Difficulty standardDifficultyPerBlock = Difficulty.ONE;
|
|
private static final long OUR_CHAIN_HEAD_NUMBER = 3;
|
|
private static final Difficulty OUR_CHAIN_DIFFICULTY =
|
|
standardDifficultyPerBlock.multiply(OUR_CHAIN_HEAD_NUMBER);
|
|
private static final long TARGET_CHAIN_DELTA = 20;
|
|
private static final long TARGET_CHAIN_HEIGHT = OUR_CHAIN_HEAD_NUMBER + TARGET_CHAIN_DELTA;
|
|
private static final Difficulty TARGET_DIFFICULTY =
|
|
standardDifficultyPerBlock.multiply(TARGET_CHAIN_HEIGHT);
|
|
|
|
@@ -527,40 +538,117 @@ public class SyncStateTest {
|
|
}
|
|
|
|
private EthPeer mockChainIsBetterThan(final EthPeer peer, final boolean isBetter) {
|
|
final ChainState chainState = spy(peer.chainState());
|
|
final ChainHeadEstimate chainStateSnapshot = spy(peer.chainStateSnapshot());
|
|
lenient().doReturn(isBetter).when(chainState).chainIsBetterThan(any());
|
|
lenient().doReturn(isBetter).when(chainStateSnapshot).chainIsBetterThan(any());
|
|
final EthPeer mockedPeer = spy(peer);
|
|
lenient().doReturn(chainStateSnapshot).when(chainState).getSnapshot();
|
|
lenient().doReturn(chainStateSnapshot).when(mockedPeer).chainStateSnapshot();
|
|
lenient().doReturn(chainState).when(mockedPeer).chainState();
|
|
return mockedPeer;
|
|
}
|
|
|
|
private void setupOutOfSyncState() {
|
|
syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getGenesisBlock().getHeader());
|
|
verify(inSyncListener).onInSyncStatusChange(false);
|
|
verify(inSyncListenerExact).onInSyncStatusChange(false);
|
|
}
|
|
|
|
+ @Test
|
|
+ public void inSyncCheckDrivenByABlockImportDoesNotTakeTheSyncStateMonitor() {
|
|
+ // AERE D-426: upstream hyperledger/besu#11041, ported (unnamed lambda parameter spelled out for Java 21)
|
|
+ final List<Boolean> heldMonitorDuringCallback = new ArrayList<>();
|
|
+ syncState.subscribeInSync(
|
|
+ ignored -> heldMonitorDuringCallback.add(Thread.holdsLock(syncState)),
|
|
+ Synchronizer.DEFAULT_IN_SYNC_TOLERANCE);
|
|
+
|
|
+ // Fires the block-added observer and therefore calls checkInSync() on this thread.
|
|
+ advanceLocalChain(blockchain.getChainHeadBlockNumber() + 1);
|
|
+
|
|
+ assertThat(heldMonitorDuringCallback)
|
|
+ .withFailMessage("a block import called checkInSync() while holding the sync state monitor")
|
|
+ .isNotEmpty()
|
|
+ .containsOnly(false);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * AERE D-426: the chain that froze validator 2 of testnet 28001 for 3 h 18 min on 2026-09-28. The chain downloader
|
|
+ * sets a sync target (replaceSyncTarget holds this monitor) and publishes the sync status; the BFT mining
|
|
+ * coordinator's listener stops the coordinator and waits for the BFT thread, which is importing a block, and the
|
|
+ * block-added observer calls checkInSync(). With checkInSync() on the monitor the import cannot finish while the
|
|
+ * listener waits, so each side waits for the other.
|
|
+ */
|
|
+ @Test
|
|
+ public void syncStatusListenerWaitingOnABlockImportDoesNotDeadlockTheImport() throws Exception {
|
|
+ final CountDownLatch inCallback = new CountDownLatch(1);
|
|
+ final CountDownLatch blockAppended = new CountDownLatch(1);
|
|
+ final AtomicBoolean importFinishedWhileListenerWaited = new AtomicBoolean();
|
|
+ final AtomicReference<Throwable> importFailure = new AtomicReference<>();
|
|
+ syncState.subscribeSyncStatus(
|
|
+ ignored -> {
|
|
+ if (inCallback.getCount() == 0) {
|
|
+ return;
|
|
+ }
|
|
+ inCallback.countDown();
|
|
+ try {
|
|
+ // stands for BftMiningCoordinator.stop() -> BftProcessor.awaitStop()
|
|
+ importFinishedWhileListenerWaited.set(blockAppended.await(5, TimeUnit.SECONDS));
|
|
+ } catch (final InterruptedException e) {
|
|
+ Thread.currentThread().interrupt();
|
|
+ }
|
|
+ });
|
|
+
|
|
+ final long headBefore = blockchain.getChainHeadBlockNumber();
|
|
+ final Thread importer =
|
|
+ new Thread(
|
|
+ () -> {
|
|
+ try {
|
|
+ if (!inCallback.await(5, TimeUnit.SECONDS)) {
|
|
+ return;
|
|
+ }
|
|
+ // stands for QbftRound.importSealedBlock on the BFT thread
|
|
+ advanceLocalChain(headBefore + 1);
|
|
+ blockAppended.countDown();
|
|
+ } catch (final Throwable t) {
|
|
+ importFailure.set(t);
|
|
+ }
|
|
+ },
|
|
+ "aere-d426-importer");
|
|
+ importer.start();
|
|
+
|
|
+ // publishes on this thread, as PipelineChainDownloader.startDownloadForSyncTarget does
|
|
+ syncState.setSyncTarget(syncTargetPeer.getEthPeer(), blockchain.getGenesisBlock().getHeader());
|
|
+ importer.join(TimeUnit.SECONDS.toMillis(30));
|
|
+
|
|
+ assertThat(importer.isAlive()).withFailMessage("the importer thread never finished").isFalse();
|
|
+ assertThat(importFailure.get()).withFailMessage("the import itself failed: %s", importFailure.get()).isNull();
|
|
+ assertThat(inCallback.getCount()).withFailMessage("the sync status was never published").isZero();
|
|
+ assertThat(blockchain.getChainHeadBlockNumber()).isEqualTo(headBefore + 1);
|
|
+ assertThat(importFinishedWhileListenerWaited)
|
|
+ .withFailMessage(
|
|
+ "a block import could not finish while a sync-status listener waited for it: "
|
|
+ + "checkInSync() is taking the monitor that replaceSyncTarget() holds (D-426)")
|
|
+ .isTrue();
|
|
+ }
|
|
+
|
|
private void advanceLocalChain(final long newChainHeight) {
|
|
while (blockchain.getChainHeadBlockNumber() < newChainHeight) {
|
|
final BlockHeader parent = blockchain.getChainHeadHeader();
|
|
final Block block =
|
|
gen.block(
|
|
BlockOptions.create()
|
|
.setDifficulty(standardDifficultyPerBlock)
|
|
.setParentHash(parent.getHash())
|
|
.setBlockNumber(parent.getNumber() + 1L)
|
|
.transactionCount(0));
|
|
final List<TransactionReceipt> receipts = gen.receipts(block);
|
|
blockchain.appendBlock(block, receipts);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the chain state, such that the peer will end up with an estimated height of {@code
|
|
* blockHeight} and an estimated total difficulty of {@code totalDifficulty}
|
|
*
|
|
* @param peer The peer whose chain should be updated
|
|
diff --git a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java
|
|
old mode 100644
|
|
new mode 100755
|
|
index 15fc61698b..695f088181
|
|
--- a/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java
|
|
+++ b/ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.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/aere-bft-bounded-message-lists.patch.
|
|
*/
|
|
package org.hyperledger.besu.ethereum.rlp;
|
|
|
|
import java.math.BigInteger;
|
|
import java.net.InetAddress;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.function.Function;
|
|
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
import org.apache.tuweni.bytes.Bytes32;
|
|
import org.apache.tuweni.bytes.Bytes48;
|
|
import org.apache.tuweni.units.bigints.UInt256;
|
|
import org.apache.tuweni.units.bigints.UInt64;
|
|
|
|
/**
|
|
* An input used to decode data in RLP encoding.
|
|
*
|
|
* <p>An RLP "value" is fundamentally an {@code Item} defined the following way:
|
|
*
|
|
@@ -369,41 +375,61 @@ public interface RLPInput {
|
|
/** Resets this RLP input to the start. */
|
|
void reset();
|
|
|
|
/**
|
|
* Returns a raw {@link Bytes} representation of this RLP list.
|
|
*
|
|
* @return The raw RLP list.
|
|
*/
|
|
Bytes currentListAsBytes();
|
|
|
|
/**
|
|
* Reads a full list from the input given a method that knows how to read its elements.
|
|
*
|
|
* @param valueReader A method that can decode a single list element.
|
|
* @param <T> The type of the elements of the decoded list.
|
|
* @return The next list of this input, where elements are decoded using {@code valueReader}.
|
|
* @throws RLPException is the next item to read is not a list, of if any error happens when
|
|
* applying {@code valueReader} to read elements of the list.
|
|
*/
|
|
default <T> List<T> readList(final Function<RLPInput, T> valueReader) {
|
|
+ return readList(valueReader, Integer.MAX_VALUE);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Reads a full list from the input, rejecting inputs whose element count exceeds {@code
|
|
+ * maxElements}. AERE D-434: ported from upstream hyperledger/besu dd4101c9ec.
|
|
+ *
|
|
+ * @param valueReader A method that can decode a single list element.
|
|
+ * @param maxElements The maximum number of elements the list may contain.
|
|
+ * @param <T> The type of the elements of the decoded list.
|
|
+ * @return The next list of this input, where elements are decoded using {@code valueReader}.
|
|
+ * @throws RLPException if the next item is not a list, if it holds more than {@code maxElements}
|
|
+ * elements, or if any error happens when applying {@code valueReader} to read elements.
|
|
+ */
|
|
+ default <T> List<T> readList(final Function<RLPInput, T> valueReader, final int maxElements) {
|
|
final int size = enterList();
|
|
+ if (size > maxElements) {
|
|
+ throw new RLPException(
|
|
+ String.format(
|
|
+ "List of %d elements exceeds the maximum permitted size of %d", size, maxElements));
|
|
+ }
|
|
final List<T> res = size == 0 ? List.of() : new ArrayList<>(size);
|
|
for (int i = 0; i < size; i++) {
|
|
try {
|
|
res.add(valueReader.apply(this));
|
|
} catch (final RLPException e) {
|
|
throw e;
|
|
} catch (final Exception e) {
|
|
throw new RLPException(
|
|
String.format("Error applying element decoding function on element %d of the list", i),
|
|
e);
|
|
}
|
|
}
|
|
leaveList();
|
|
return res;
|
|
}
|
|
|
|
default Bytes currentListAsBytesNoCopy(final boolean moveToNextItem) {
|
|
throw new UnsupportedOperationException("Not supported by this input");
|
|
}
|
|
}
|
|
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java
|
|
index 954f4e1e95..eadf4b3c49 100644
|
|
--- a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java
|
|
+++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java
|
|
@@ -1,57 +1,63 @@
|
|
/*
|
|
* 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/aere-warm-access-hashdos-treeset.patch.
|
|
*/
|
|
package org.hyperledger.besu.evm.frame;
|
|
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
import static java.util.Collections.emptySet;
|
|
|
|
import org.hyperledger.besu.collections.undo.UndoSet;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.Log;
|
|
import org.hyperledger.besu.datatypes.VersionedHash;
|
|
import org.hyperledger.besu.datatypes.Wei;
|
|
import org.hyperledger.besu.evm.Code;
|
|
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
|
import org.hyperledger.besu.evm.internal.MemoryEntry;
|
|
import org.hyperledger.besu.evm.internal.OperandStack;
|
|
import org.hyperledger.besu.evm.internal.StorageEntry;
|
|
import org.hyperledger.besu.evm.internal.UnderflowException;
|
|
import org.hyperledger.besu.evm.operation.Operation;
|
|
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Deque;
|
|
import java.util.HashMap;
|
|
-import java.util.HashSet;
|
|
+import java.util.TreeSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.function.Consumer;
|
|
|
|
import com.google.common.collect.HashMultimap;
|
|
import com.google.common.collect.Multimap;
|
|
import com.google.common.collect.Table;
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
import org.apache.tuweni.bytes.Bytes32;
|
|
import org.apache.tuweni.bytes.MutableBytes;
|
|
import org.apache.tuweni.units.bigints.UInt256;
|
|
|
|
/**
|
|
* A container object for all the states associated with a message.
|
|
*
|
|
* <p>A message corresponds to an interaction between two accounts. A Transaction spawns at least
|
|
* one message when it's processed. Messages can also spawn messages depending on the code executed
|
|
* within a message.
|
|
@@ -1842,41 +1848,41 @@ public class MessageFrame {
|
|
checkState(sender != null, "Missing message frame sender");
|
|
checkState(value != null, "Missing message frame value");
|
|
checkState(apparentValue != null, "Missing message frame apparent value");
|
|
checkState(code != null, "Missing message frame code");
|
|
checkState(completer != null, "Missing message frame completer");
|
|
}
|
|
|
|
/**
|
|
* Build MessageFrame.
|
|
*
|
|
* @return instance of MessageFrame
|
|
*/
|
|
public MessageFrame build() {
|
|
validate();
|
|
|
|
WorldUpdater updater;
|
|
boolean newStatic;
|
|
TxValues newTxValues;
|
|
|
|
if (parentMessageFrame == null) {
|
|
- HashSet<Address> warmedUpAddresses = new HashSet<>();
|
|
+ TreeSet<Address> warmedUpAddresses = new TreeSet<>(); // AERE D-434 (adfa98d013): TreeSet defeats the grindable base-31 HashDoS
|
|
warmedUpAddresses.add(contract);
|
|
newTxValues =
|
|
TxValues.forTransaction(
|
|
blockHashLookup,
|
|
maxStackSize,
|
|
UndoSet.of(warmedUpAddresses),
|
|
originator,
|
|
gasPrice,
|
|
blobGasPrice,
|
|
blockValues,
|
|
miningBeneficiary,
|
|
versionedHashes);
|
|
updater = worldUpdater;
|
|
newStatic = isStatic;
|
|
} else {
|
|
newTxValues = parentMessageFrame.txValues;
|
|
updater = parentMessageFrame.getWorldUpdater().updater();
|
|
newStatic = isStatic || parentMessageFrame.isStatic;
|
|
parentMessageFrame.warmUpAddress(contract);
|
|
}
|
|
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java
|
|
index d4c9edad39..b13a96f5bb 100644
|
|
--- a/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java
|
|
+++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/TxValues.java
|
|
@@ -1,51 +1,57 @@
|
|
/*
|
|
* 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/aere-warm-access-hashdos-treeset.patch.
|
|
*/
|
|
package org.hyperledger.besu.evm.frame;
|
|
|
|
import org.hyperledger.besu.collections.undo.UndoScalar;
|
|
import org.hyperledger.besu.collections.undo.UndoSet;
|
|
import org.hyperledger.besu.collections.undo.UndoTable;
|
|
import org.hyperledger.besu.datatypes.Address;
|
|
import org.hyperledger.besu.datatypes.VersionedHash;
|
|
import org.hyperledger.besu.datatypes.Wei;
|
|
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
|
|
|
import java.util.ArrayDeque;
|
|
import java.util.Deque;
|
|
-import java.util.HashSet;
|
|
+import java.util.TreeSet;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
|
|
-import com.google.common.collect.HashBasedTable;
|
|
+import com.google.common.collect.TreeBasedTable;
|
|
import org.apache.tuweni.bytes.Bytes32;
|
|
|
|
/**
|
|
* Transaction Values used by various EVM Opcodes. These are the values that either do not change or
|
|
* the backing stores whose changes transcend message frames and are not part of state, such as
|
|
* transient storage and address warming.
|
|
*
|
|
* @param blockHashLookup The block hash lookup function
|
|
* @param maxStackSize The maximum stack size
|
|
* @param warmedUpAddresses The warmed-up addresses
|
|
* @param warmedUpStorage The warmed-up storage
|
|
* @param originator The originator address
|
|
* @param gasPrice The gas price
|
|
* @param blobGasPrice The blob gas price
|
|
* @param blockValues The block values
|
|
* @param messageFrameStack The message frame stack
|
|
* @param miningBeneficiary The mining beneficiary address
|
|
* @param versionedHashes The optional list of versioned hashes
|
|
* @param transientStorage The transient storage
|
|
* @param creates The set of addresses that creates
|
|
@@ -93,51 +99,51 @@ public record TxValues(
|
|
* @param blobGasPrice the blob gas price
|
|
* @param blockValues the block values
|
|
* @param miningBeneficiary the mining beneficiary
|
|
* @param versionedHashes optional versioned hashes
|
|
* @return a new TxValues instance
|
|
*/
|
|
public static TxValues forTransaction(
|
|
final BlockHashLookup blockHashLookup,
|
|
final int maxStackSize,
|
|
final UndoSet<Address> warmedUpAddresses,
|
|
final Address originator,
|
|
final Wei gasPrice,
|
|
final Wei blobGasPrice,
|
|
final BlockValues blockValues,
|
|
final Address miningBeneficiary,
|
|
final Optional<List<VersionedHash>> versionedHashes) {
|
|
return new TxValues(
|
|
blockHashLookup,
|
|
maxStackSize,
|
|
warmedUpAddresses,
|
|
- UndoTable.of(HashBasedTable.create()),
|
|
+ UndoTable.of(TreeBasedTable.create()),
|
|
originator,
|
|
gasPrice,
|
|
blobGasPrice,
|
|
blockValues,
|
|
new ArrayDeque<>(),
|
|
miningBeneficiary,
|
|
versionedHashes,
|
|
- UndoTable.of(HashBasedTable.create()),
|
|
- UndoSet.of(new HashSet<>()),
|
|
- UndoSet.of(new HashSet<>()),
|
|
+ UndoTable.of(TreeBasedTable.create()),
|
|
+ UndoSet.of(new TreeSet<>()),
|
|
+ UndoSet.of(new TreeSet<>()),
|
|
new UndoScalar<>(0L),
|
|
new UndoScalar<>(0L),
|
|
new UndoScalar<>(0L),
|
|
new long[] {0L},
|
|
new long[] {0L});
|
|
}
|
|
|
|
/**
|
|
* For all data stored in this record, undo the changes since the mark.
|
|
*
|
|
* @param mark the mark to which it should be rolled back to
|
|
*/
|
|
public void undoChanges(final long mark) {
|
|
warmedUpAddresses.undo(mark);
|
|
warmedUpStorage.undo(mark);
|
|
transientStorage.undo(mark);
|
|
creates.undo(mark);
|
|
selfDestructs.undo(mark);
|
|
gasRefunds.undo(mark);
|
|
stateGasUsed.undo(mark);
|
|
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/P256VerifyPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/P256VerifyPrecompiledContract.java
|
|
index 47b7145d17..220194b6ab 100644
|
|
--- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/P256VerifyPrecompiledContract.java
|
|
+++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/P256VerifyPrecompiledContract.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/aere-drop-per-request-console-writes.patch.
|
|
*/
|
|
package org.hyperledger.besu.evm.precompile;
|
|
|
|
import org.hyperledger.besu.crypto.SECP256R1;
|
|
import org.hyperledger.besu.crypto.SECPPublicKey;
|
|
import org.hyperledger.besu.crypto.SECPSignature;
|
|
import org.hyperledger.besu.crypto.SignatureAlgorithm;
|
|
import org.hyperledger.besu.evm.frame.MessageFrame;
|
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
|
|
import org.hyperledger.besu.nativelib.boringssl.BoringSSLPrecompiles;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
import com.github.benmanes.caffeine.cache.Cache;
|
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
import jakarta.validation.constraints.NotNull;
|
|
import org.apache.tuweni.bytes.Bytes;
|
|
import org.apache.tuweni.bytes.Bytes32;
|
|
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
|
@@ -152,41 +158,41 @@ public class P256VerifyPrecompiledContract extends AbstractPrecompiledContract {
|
|
}
|
|
} else {
|
|
cacheEventConsumer.accept(new CacheEvent(PRECOMPILE_NAME, CacheMetric.MISS));
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (useNativeBoringSSL) {
|
|
res = computeNative(input);
|
|
} else {
|
|
res = computeDefault(input);
|
|
}
|
|
|
|
if (enableResultCaching) {
|
|
p256VerifyCache.put(cacheKey, res);
|
|
}
|
|
return res.cachedResult();
|
|
|
|
} catch (Exception e) {
|
|
LOG.warn("P256VERIFY verification failed: {}", e.getMessage());
|
|
- System.err.println("P256VERIFY verification failed: " + e.getMessage());
|
|
+ // AERE D-434 (fbfb5f9ecd): removed System.err print on the P256VERIFY failure path; a cheap invalid signature could otherwise spam the process console, bypassing log4j. LOG.warn above records it.
|
|
return PrecompileContractResult.success(INVALID);
|
|
}
|
|
}
|
|
|
|
@NotNull
|
|
private static PrecompileInputResultTuple computeNative(final Bytes input) {
|
|
PrecompileInputResultTuple res;
|
|
BoringSSLPrecompiles.P256VerifyResult result =
|
|
BoringSSLPrecompiles.p256Verify(input.toArrayUnsafe(), input.size());
|
|
|
|
if (result.status != 0) {
|
|
LOG.atTrace().setMessage("Verify failed: {}").addArgument(result.error).log();
|
|
}
|
|
res =
|
|
new PrecompileInputResultTuple(
|
|
enableResultCaching ? input.copy() : input,
|
|
PrecompileContractResult.success(result.status == 0 ? VALID : INVALID));
|
|
return res;
|
|
}
|
|
|