/* * 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); } }