From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aere Network Date: Thu, 10 Sep 2026 21:47:55 +0300 Subject: [PATCH] Aere Network: post-quantum signature verification precompiles Regenerated 2026-09-10 from the production tree (overlay applied) over the same file set. diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java index 950cd59e3..0f486dfcf 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java @@ -91,6 +91,21 @@ public class Address extends BytesHolder { /** Precompile address for P256_VERIFY. */ public static final Address P256_VERIFY = Address.precompiled(0x0100); + /** AERE PQC precompile: Falcon-512 verify. */ + public static final Address AERE_FALCON512 = Address.fromHexString("0x0000000000000000000000000000000000000ae1"); + + /** AERE PQC precompile: Falcon-1024 verify. */ + public static final Address AERE_FALCON1024 = Address.fromHexString("0x0000000000000000000000000000000000000ae2"); + + /** AERE PQC precompile: ML-DSA-44 (FIPS 204) verify. */ + public static final Address AERE_MLDSA44 = Address.fromHexString("0x0000000000000000000000000000000000000ae3"); + + /** AERE PQC precompile: SLH-DSA-SHA2-128s (FIPS 205) verify. */ + public static final Address AERE_SLHDSA128S = Address.fromHexString("0x0000000000000000000000000000000000000ae4"); + + /** AERE PQC precompile: SHAKE256 XOF (FIPS 202). */ + public static final Address AERE_SHAKE256 = Address.fromHexString("0x0000000000000000000000000000000000000ae5"); + /** The constant ZERO. */ public static final Address ZERO = Address.fromHexString("0x0"); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AereFalconSupport.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AereFalconSupport.java new file mode 100644 index 000000000..1dbb2b85c --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AereFalconSupport.java @@ -0,0 +1,94 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import java.util.Arrays; + +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.FalconPublicKeyParameters; +import org.bouncycastle.pqc.crypto.falcon.FalconSigner; + +/** + * Shared logic for the AERE Falcon-512 / Falcon-1024 verification precompiles. + * + *

Transcodes the NIST round-3 reference "signed message" (sm) blob into the encoding Bouncy + * Castle's {@link FalconSigner#verifySignature(byte[], byte[])} expects and drives the audited + * verifier. No cryptography is reimplemented here. + * + *

NIST sm layout: {@code sigLen(2, big-endian) || nonce(40) || message || esig} where + * {@code esig = (0x20+logn) || compressedSig} and {@code sigLen == esig.length}. The Falcon public + * key is {@code (0x00+logn) || packed_h}; Bouncy Castle wants only {@code packed_h} (header + * stripped), and the signature it wants is {@code (0x30+logn) || nonce(40) || compressedSig}. + */ +final class AereFalconSupport { + + static final int NONCE_LEN = 40; + + private AereFalconSupport() {} + + static Bytes resultWord(final boolean valid) { + return valid ? Bytes32.leftPad(Bytes.of((byte) 1)) : Bytes32.ZERO; + } + + /** + * Verify a NIST signed-message blob against a Falcon public key. + * + * @param params Bouncy Castle Falcon parameter set (falcon_512 / falcon_1024) + * @param logn 9 for Falcon-512, 10 for Falcon-1024 + * @param pkFull the 897- (512) or 1793-byte (1024) public key including the leading header byte + * @param sm the NIST signed-message blob + * @return true iff the signature is valid for the embedded message under pkFull + */ + static boolean verify( + final FalconParameters params, final int logn, final byte[] pkFull, final byte[] sm) { + try { + if (pkFull.length < 2 || sm.length < 2 + NONCE_LEN + 2) { + return false; + } + if ((pkFull[0] & 0xff) != logn) { + return false; + } + final int sigLen = ((sm[0] & 0xff) << 8) | (sm[1] & 0xff); + if (sigLen < 2 || 2 + NONCE_LEN + sigLen > sm.length) { + return false; + } + final int msgLen = sm.length - 2 - NONCE_LEN - sigLen; + if (msgLen < 0) { + return false; + } + final byte[] esig = Arrays.copyOfRange(sm, sm.length - sigLen, sm.length); + if ((esig[0] & 0xff) != (0x20 + logn)) { + return false; + } + final byte[] H = Arrays.copyOfRange(pkFull, 1, pkFull.length); + final byte[] nonce = Arrays.copyOfRange(sm, 2, 2 + NONCE_LEN); + final byte[] message = Arrays.copyOfRange(sm, 2 + NONCE_LEN, 2 + NONCE_LEN + msgLen); + + final byte[] bcSig = new byte[1 + NONCE_LEN + (esig.length - 1)]; + bcSig[0] = (byte) (0x30 + logn); + System.arraycopy(nonce, 0, bcSig, 1, NONCE_LEN); + System.arraycopy(esig, 1, bcSig, 1 + NONCE_LEN, esig.length - 1); + + final FalconPublicKeyParameters pub = new FalconPublicKeyParameters(params, H); + final FalconSigner signer = new FalconSigner(); + signer.init(false, pub); + return signer.verifySignature(message, bcSig); + } catch (final Throwable t) { + return false; + } + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon1024PrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon1024PrecompiledContract.java new file mode 100644 index 000000000..80aca574d --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon1024PrecompiledContract.java @@ -0,0 +1,62 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import jakarta.validation.constraints.NotNull; +import org.apache.tuweni.bytes.Bytes; +import org.bouncycastle.pqc.crypto.falcon.FalconParameters; + +/** + * AERE PQC precompile: Falcon-1024 signature verification (NIST round-3 reference encoding). + * + *

Input: {@code pk(1793) || sm(rest)} where pk is the reference public key (header 0x0A) and sm + * is the reference signed-message blob. Output: 32-byte word, {@code ...01} valid else {@code ...00}. + */ +public class Falcon1024PrecompiledContract extends AbstractPrecompiledContract { + + static final int PK_LEN = 1793; + private static final int LOGN = 10; + private static final long GAS = 75_000L; + + /** + * Instantiates a new Falcon-1024 precompiled contract. + * + * @param gasCalculator the gas calculator + */ + Falcon1024PrecompiledContract(final GasCalculator gasCalculator) { + super("AereFalcon1024", gasCalculator); + } + + @Override + public long gasRequirement(final Bytes input) { + return GAS; + } + + @NotNull + @Override + public PrecompileContractResult computePrecompile( + final Bytes input, @NotNull final MessageFrame messageFrame) { + boolean valid = false; + if (input.size() > PK_LEN) { + final byte[] pk = input.slice(0, PK_LEN).toArrayUnsafe(); + final byte[] sm = input.slice(PK_LEN).toArrayUnsafe(); + valid = AereFalconSupport.verify(FalconParameters.falcon_1024, LOGN, pk, sm); + } + return PrecompileContractResult.success(AereFalconSupport.resultWord(valid)); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon512PrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon512PrecompiledContract.java new file mode 100644 index 000000000..5df074ceb --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/Falcon512PrecompiledContract.java @@ -0,0 +1,62 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import jakarta.validation.constraints.NotNull; +import org.apache.tuweni.bytes.Bytes; +import org.bouncycastle.pqc.crypto.falcon.FalconParameters; + +/** + * AERE PQC precompile: Falcon-512 signature verification (NIST round-3 reference encoding). + * + *

Input: {@code pk(897) || sm(rest)} where pk is the reference public key (header 0x09) and sm is + * the reference signed-message blob. Output: 32-byte word, {@code ...01} if valid else {@code ...00}. + */ +public class Falcon512PrecompiledContract extends AbstractPrecompiledContract { + + static final int PK_LEN = 897; + private static final int LOGN = 9; + private static final long GAS = 40_000L; + + /** + * Instantiates a new Falcon-512 precompiled contract. + * + * @param gasCalculator the gas calculator + */ + Falcon512PrecompiledContract(final GasCalculator gasCalculator) { + super("AereFalcon512", gasCalculator); + } + + @Override + public long gasRequirement(final Bytes input) { + return GAS; + } + + @NotNull + @Override + public PrecompileContractResult computePrecompile( + final Bytes input, @NotNull final MessageFrame messageFrame) { + boolean valid = false; + if (input.size() > PK_LEN) { + final byte[] pk = input.slice(0, PK_LEN).toArrayUnsafe(); + final byte[] sm = input.slice(PK_LEN).toArrayUnsafe(); + valid = AereFalconSupport.verify(FalconParameters.falcon_512, LOGN, pk, sm); + } + return PrecompileContractResult.success(AereFalconSupport.resultWord(valid)); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/MLDSA44PrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/MLDSA44PrecompiledContract.java new file mode 100644 index 000000000..f25be641f --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/MLDSA44PrecompiledContract.java @@ -0,0 +1,84 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import jakarta.validation.constraints.NotNull; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner; + +/** + * AERE PQC precompile: ML-DSA-44 (FIPS 204) signature verification via the INTERNAL interface + * (ML-DSA.Verify_internal, Algorithm 8 — no context/domain-separation prefix). + * + *

Input: {@code pk(1312) || sig(2420) || message(rest)}. Output: 32-byte word, {@code ...01} + * valid else {@code ...00}. The internal (rather than pure) verifier is reached by subclassing + * Bouncy Castle's {@link MLDSASigner} and calling its {@code protected internalVerifySignature}. + */ +public class MLDSA44PrecompiledContract extends AbstractPrecompiledContract { + + static final int PK_LEN = 1312; + static final int SIG_LEN = 2420; + private static final long GAS = 55_000L; + + /** Subclass exposing Bouncy Castle's protected internal (Verify_internal) verifier. */ + private static final class InternalVerifier extends MLDSASigner { + boolean verifyInternal(final byte[] message, final byte[] signature) { + return internalVerifySignature(message, signature); + } + } + + /** + * Instantiates a new ML-DSA-44 precompiled contract. + * + * @param gasCalculator the gas calculator + */ + MLDSA44PrecompiledContract(final GasCalculator gasCalculator) { + super("AereMLDSA44", gasCalculator); + } + + @Override + public long gasRequirement(final Bytes input) { + return GAS; + } + + @NotNull + @Override + public PrecompileContractResult computePrecompile( + final Bytes input, @NotNull final MessageFrame messageFrame) { + boolean valid = false; + if (input.size() >= PK_LEN + SIG_LEN) { + try { + final byte[] pk = input.slice(0, PK_LEN).toArrayUnsafe(); + final byte[] sig = input.slice(PK_LEN, SIG_LEN).toArrayUnsafe(); + final byte[] message = input.slice(PK_LEN + SIG_LEN).toArrayUnsafe(); + final MLDSAPublicKeyParameters pub = + new MLDSAPublicKeyParameters(MLDSAParameters.ml_dsa_44, pk); + final InternalVerifier verifier = new InternalVerifier(); + verifier.init(false, pub); + valid = verifier.verifyInternal(message, sig); + } catch (final Throwable t) { + valid = false; + } + } + return PrecompileContractResult.success( + valid ? Bytes32.leftPad(Bytes.of((byte) 1)) : Bytes32.ZERO); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/MainnetPrecompiledContracts.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/MainnetPrecompiledContracts.java index 28d84abf1..43d9fb73a 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/MainnetPrecompiledContracts.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/MainnetPrecompiledContracts.java @@ -226,6 +226,15 @@ public interface MainnetPrecompiledContracts { */ static void populateForFutureEIPs( final PrecompileContractRegistry registry, final GasCalculator gasCalculator) { - populateForCancun(registry, gasCalculator); + // AERE "AerePQC" fork: full Osaka precompile set plus native post-quantum verifiers. + // Activated on a running chain via genesis config "futureEipsTime"; no re-genesis needed. + populateForOsaka(registry, gasCalculator); + + // Native post-quantum precompiles (audited Bouncy Castle BCPQC verifiers). + registry.put(Address.AERE_FALCON512, new Falcon512PrecompiledContract(gasCalculator)); + registry.put(Address.AERE_FALCON1024, new Falcon1024PrecompiledContract(gasCalculator)); + registry.put(Address.AERE_MLDSA44, new MLDSA44PrecompiledContract(gasCalculator)); + registry.put(Address.AERE_SLHDSA128S, new SLHDSA128sPrecompiledContract(gasCalculator)); + registry.put(Address.AERE_SHAKE256, new SHAKE256PrecompiledContract(gasCalculator)); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/SHAKE256PrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/SHAKE256PrecompiledContract.java new file mode 100644 index 000000000..0c20e6a66 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/SHAKE256PrecompiledContract.java @@ -0,0 +1,93 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import jakarta.validation.constraints.NotNull; +import org.apache.tuweni.bytes.Bytes; +import org.bouncycastle.crypto.digests.SHAKEDigest; + +/** + * AERE PQC precompile: SHAKE256 extendable-output function (FIPS 202). + * + *

Input layout: outLen (32 bytes, big-endian, capped at MAX_OUTPUT) || data (arbitrary length). + * Output: exactly {@code outLen} bytes of SHAKE256(data). + * + *

SHAKE256 is the hashing bottleneck inside Falcon, ML-DSA and SLH-DSA; exposing it natively lets + * on-chain PQC flows offload the hot path to audited Bouncy Castle rather than hand-rolled Solidity. + */ +public class SHAKE256PrecompiledContract extends AbstractPrecompiledContract { + + /** Upper bound on requested output length to keep gas/allocation bounded. */ + static final int MAX_OUTPUT = 1 << 16; // 65536 bytes + + private static final int BASE_GAS = 60; + private static final int GAS_PER_WORD = 12; + + /** + * Instantiates a new SHAKE256 precompiled contract. + * + * @param gasCalculator the gas calculator + */ + SHAKE256PrecompiledContract(final GasCalculator gasCalculator) { + super("AereSHAKE256", gasCalculator); + } + + private static int outputLength(final Bytes input) { + if (input.size() < 32) { + return 0; + } + // Big-endian 32-byte length; only the low 4 bytes are honoured, then capped. + long v = input.slice(28, 4).toLong() & 0xFFFFFFFFL; + // If any of the high 28 bytes are non-zero the value is enormous; cap regardless. + if (!input.slice(0, 28).isZero()) { + return MAX_OUTPUT; + } + if (v > MAX_OUTPUT) { + return MAX_OUTPUT; + } + return (int) v; + } + + @Override + public long gasRequirement(final Bytes input) { + int outLen = outputLength(input); + int dataLen = input.size() < 32 ? 0 : input.size() - 32; + long words = ((long) dataLen + 31) / 32 + ((long) outLen + 31) / 32; + return BASE_GAS + GAS_PER_WORD * words; + } + + @NotNull + @Override + public PrecompileContractResult computePrecompile( + final Bytes input, @NotNull final MessageFrame messageFrame) { + if (input.size() < 32) { + return PrecompileContractResult.success(Bytes.EMPTY); + } + final int outLen = outputLength(input); + final byte[] data = input.slice(32).toArrayUnsafe(); + final SHAKEDigest digest = new SHAKEDigest(256); + if (data.length > 0) { + digest.update(data, 0, data.length); + } + final byte[] out = new byte[outLen]; + if (outLen > 0) { + digest.doFinal(out, 0, outLen); + } + return PrecompileContractResult.success(Bytes.wrap(out)); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/SLHDSA128sPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/SLHDSA128sPrecompiledContract.java new file mode 100644 index 000000000..2666602f4 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/SLHDSA128sPrecompiledContract.java @@ -0,0 +1,84 @@ +/* + * Copyright contributors to the AERE Network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evm.precompile; + +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import jakarta.validation.constraints.NotNull; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner; + +/** + * AERE PQC precompile: SLH-DSA-SHA2-128s (SPHINCS+, FIPS 205) signature verification via the + * INTERNAL interface (slh_verify_internal, Algorithm 20 — message hashed directly, no prefix). + * + *

Input: {@code pk(32) || sig(7856) || message(rest)}. Output: 32-byte word, {@code ...01} valid + * else {@code ...00}. The internal verifier is reached by subclassing Bouncy Castle's + * {@link SLHDSASigner} and calling its {@code protected internalVerifySignature}. + */ +public class SLHDSA128sPrecompiledContract extends AbstractPrecompiledContract { + + static final int PK_LEN = 32; + static final int SIG_LEN = 7856; + private static final long GAS = 350_000L; + + /** Subclass exposing Bouncy Castle's protected internal (slh_verify_internal) verifier. */ + private static final class InternalVerifier extends SLHDSASigner { + boolean verifyInternal(final byte[] message, final byte[] signature) { + return internalVerifySignature(message, signature); + } + } + + /** + * Instantiates a new SLH-DSA-128s precompiled contract. + * + * @param gasCalculator the gas calculator + */ + SLHDSA128sPrecompiledContract(final GasCalculator gasCalculator) { + super("AereSLHDSA128s", gasCalculator); + } + + @Override + public long gasRequirement(final Bytes input) { + return GAS; + } + + @NotNull + @Override + public PrecompileContractResult computePrecompile( + final Bytes input, @NotNull final MessageFrame messageFrame) { + boolean valid = false; + if (input.size() >= PK_LEN + SIG_LEN) { + try { + final byte[] pk = input.slice(0, PK_LEN).toArrayUnsafe(); + final byte[] sig = input.slice(PK_LEN, SIG_LEN).toArrayUnsafe(); + final byte[] message = input.slice(PK_LEN + SIG_LEN).toArrayUnsafe(); + final SLHDSAPublicKeyParameters pub = + new SLHDSAPublicKeyParameters(SLHDSAParameters.sha2_128s, pk); + final InternalVerifier verifier = new InternalVerifier(); + verifier.init(false, pub); + valid = verifier.verifyInternal(message, sig); + } catch (final Throwable t) { + valid = false; + } + } + return PrecompileContractResult.success( + valid ? Bytes32.leftPad(Bytes.of((byte) 1)) : Bytes32.ZERO); + } +}