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