Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
95 lines
3.8 KiB
Java
95 lines
3.8 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 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.
|
|
*
|
|
* <p>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.
|
|
*
|
|
* <p>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;
|
|
}
|
|
}
|
|
}
|