aere-node/precompiles/SLHDSA128sPrecompiledContract.java
Liviu e8deaa60b6 Licence hygiene, authoritative patches, and one spelling of the brand
- Apache 2.0 section 4(b): the patches modify files that are the work of
  Hyperledger Besu and now say so, with the notice inside the modified files,
  which is what the licence asks for and what applying the patch produces.
- patches/ and precompiles/ now carry the staged versions rather than an older
  export. The two had drifted in both directions; the only thing the published
  copy had that the staged one lacked was the word "audited" in front of Bouncy
  Castle, which we cannot evidence and which the staged version had dropped.
- the brand was spelled two ways in the same repository, 62 times one way and 23
  the other. It is Aere Network; AERE is the ticker. The 96 AERE_* code
  identifiers are untouched.
2026-08-11 23:47:17 +03:00

85 lines
3.2 KiB
Java

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