Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

falcon signature verification with public key digest result #1

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ default boolean isConsensusMigration() {
*/
OptionalLong getThanosBlockNumber();

OptionalLong getLacchainPostQuantumBlockNumber();

/**
* Block number to activate Magneto on Classic networks.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@ public OptionalLong getThanosBlockNumber() {
return getOptionalLong("thanosblock");
}

@Override
public OptionalLong getLacchainPostQuantumBlockNumber() {
return getOptionalLong("lacchainpqblock");
}

@Override
public OptionalLong getMagnetoBlockNumber() {
return getOptionalLong("magnetoblock");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable
private OptionalLong aghartaBlockNumber = OptionalLong.empty();
private OptionalLong phoenixBlockNumber = OptionalLong.empty();
private OptionalLong thanosBlockNumber = OptionalLong.empty();
private final OptionalLong lacchainPostQuantumBlockNumber = OptionalLong.empty();
private OptionalLong magnetoBlockNumber = OptionalLong.empty();
private OptionalLong mystiqueBlockNumber = OptionalLong.empty();
private Optional<BigInteger> chainId = Optional.empty();
Expand Down Expand Up @@ -301,6 +302,11 @@ public OptionalLong getThanosBlockNumber() {
return thanosBlockNumber;
}

@Override
public OptionalLong getLacchainPostQuantumBlockNumber() {
return lacchainPostQuantumBlockNumber;
}

@Override
public OptionalLong getMagnetoBlockNumber() {
return magnetoBlockNumber;
Expand Down
1 change: 1 addition & 0 deletions config/src/main/resources/dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"config": {
"chainId": 1337,
"londonBlock": 0,
"lacchainpqblock": 0,
"contractSizeLimit": 2147483647,
"ethash": {
"fixeddifficulty": 100
Expand Down
2 changes: 1 addition & 1 deletion crypto/algorithms/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jar {
}

dependencies {
api 'org.bouncycastle:bcprov-jdk15on'
api 'org.bouncycastle:bcprov-jdk18on'
api 'org.slf4j:slf4j-api'

implementation 'net.java.dev.jna:jna'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.bouncycastle.crypto.digests.SHAKEDigest;

/** Various utilities for providing hashes (digests) of arbitrary data. */
public abstract class Hash {
Expand Down Expand Up @@ -105,4 +106,19 @@ public static Bytes ripemd160(final Bytes input) {
public static Bytes blake2bf(final Bytes input) {
return Bytes.wrap(digestUsingAlgorithm(input, BLAKE2BF_SUPPLIER));
}

/**
* Digest using Shake256
*
* @param input The input bytes to produce the digest for
* @param outputLength the number of bytes to produce for the output length
* @return A digest
*/
public static Bytes shake256(final Bytes input, final int outputLength) {
SHAKEDigest digest = new SHAKEDigest(256);
digest.update(input.toArray(), 0, input.size());
byte[] output = new byte[32];
digest.doFinal(output, 0, outputLength);
return Bytes.wrap(output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public class Address extends DelegatingBytes {
public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x11);
/** The constant BLS12_MAP_FP2_TO_G2. */
public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x12);
/** Constant for Precompiled Falcon verification signature. */
public static final Address LACCHAIN_FALCON = Address.precompiled(0x13);
/** The constant KZG_POINT_EVAL. */
public static final Address KZG_POINT_EVAL = Address.precompiled(0x14);
/** The constant ZERO. */
Expand Down
4 changes: 2 additions & 2 deletions enclave/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies {
implementation 'io.vertx:vertx-web'
implementation 'org.apache.tuweni:tuweni-net'

runtimeOnly('org.bouncycastle:bcpkix-jdk15on')
runtimeOnly('org.bouncycastle:bcpkix-jdk18on')

// test dependencies.
testImplementation project(':testutil')
Expand All @@ -20,7 +20,7 @@ dependencies {
// integration test dependencies.
integrationTestImplementation project(':testutil')
integrationTestImplementation 'org.assertj:assertj-core'
integrationTestImplementation 'org.bouncycastle:bcpkix-jdk15on'
integrationTestImplementation 'org.bouncycastle:bcpkix-jdk18on'
integrationTestImplementation 'org.awaitility:awaitility'
integrationTestImplementation 'org.junit.jupiter:junit-jupiter-api'
integrationTestImplementation 'org.mockito:mockito-core'
Expand Down
6 changes: 3 additions & 3 deletions ethereum/api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ dependencies {
implementation 'org.apache.tuweni:tuweni-toml'
implementation 'org.apache.tuweni:tuweni-units'
implementation 'org.antlr:antlr4-runtime'
implementation 'org.bouncycastle:bcprov-jdk15on'
implementation 'org.bouncycastle:bcprov-jdk18on'
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.xerial.snappy:snappy-java'

annotationProcessor "org.immutables:value"
implementation "org.immutables:value-annotations"

runtimeOnly 'org.bouncycastle:bcpkix-jdk15on'
runtimeOnly 'org.bouncycastle:bcpkix-jdk18on'
runtimeOnly 'io.netty:netty-transport-native-epoll'
runtimeOnly 'io.netty:netty-transport-native-kqueue'

Expand Down Expand Up @@ -106,7 +106,7 @@ dependencies {

testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'

testSupportImplementation 'org.bouncycastle:bcpkix-jdk15on'
testSupportImplementation 'org.bouncycastle:bcpkix-jdk18on'

integrationTestImplementation project(':config')
integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright IADB.
*
* 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.ethereum.mainnet;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.precompile.FalconPrecompiledContract;
import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry;

import java.math.BigInteger;
import java.util.Optional;
import java.util.OptionalInt;

public class LacchainProtocolSpecs {
public static ProtocolSpecBuilder postQuantumDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason) {
return MainnetProtocolSpecs.istanbulDefinition(
chainId,
contractSizeLimit,
configStackSizeLimit,
enableRevertReason,
EvmConfiguration.DEFAULT)
.precompileContractRegistryBuilder(
precompiledContractConfiguration -> {
PrecompileContractRegistry lacchainContractsRegistry =
MainnetPrecompiledContractRegistries.istanbul(precompiledContractConfiguration);
lacchainContractsRegistry.put(
Address.LACCHAIN_FALCON,
new FalconPrecompiledContract(
precompiledContractConfiguration.getGasCalculator()));
return lacchainContractsRegistry;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ public ProtocolSpecBuilder experimentalEipsDefinition(
evmConfiguration);
}

public ProtocolSpecBuilder lacchainDefinition() {
return LacchainProtocolSpecs.postQuantumDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled);
}

////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Classic Protocol Specs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ private Stream<Optional<BuilderMapEntry>> createMilestones(
config.getGrayGlacierBlockNumber(), specFactory.grayGlacierDefinition(config)),
blockNumberMilestone(
config.getMergeNetSplitBlockNumber(), specFactory.parisDefinition(config)),
blockNumberMilestone(
config.getLacchainPostQuantumBlockNumber(), specFactory.lacchainDefinition()),
// Timestamp Forks
timestampMilestone(config.getShanghaiTime(), specFactory.shanghaiDefinition(config)),
timestampMilestone(config.getCancunTime(), specFactory.cancunDefinition(config)),
Expand Down
2 changes: 1 addition & 1 deletion ethereum/trie/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
implementation 'com.google.guava:guava'
implementation 'io.opentelemetry:opentelemetry-api'
implementation 'org.apache.tuweni:tuweni-bytes'
implementation 'org.bouncycastle:bcprov-jdk15on'
implementation 'org.bouncycastle:bcprov-jdk18on'

annotationProcessor 'org.immutables:value'

Expand Down
2 changes: 1 addition & 1 deletion ethereum/verkletrie/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
implementation 'io.opentelemetry:opentelemetry-api'
implementation 'org.apache.tuweni:tuweni-bytes'
implementation 'org.apache.tuweni:tuweni-units'
implementation 'org.bouncycastle:bcprov-jdk15on'
implementation 'org.bouncycastle:bcprov-jdk18on'
implementation 'org.hyperledger.besu:ipa-multipoint'

annotationProcessor "org.immutables:value"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public class FrontierGasCalculator implements GasCalculator {

private static final long SELF_DESTRUCT_REFUND_AMOUNT = 24_000L;

private static final long FREC_PRECOMPILED_GAS_COST = 2100L;

@Override
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreate) {
int zeros = 0;
Expand Down Expand Up @@ -158,6 +160,11 @@ public long getEcrecPrecompiledContractGasCost() {
return ECREC_PRECOMPILED_GAS_COST;
}

@Override
public long getFrecPrecompiledContractGasCost() {
return FREC_PRECOMPILED_GAS_COST;
}

@Override
public long sha256PrecompiledContractGasCost(final Bytes input) {
return SHA256_PRECOMPILED_WORD_GAS_COST * Words.numWords(input)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.hyperledger.besu.evm.operation.SLoadOperation;
import org.hyperledger.besu.evm.operation.SelfDestructOperation;
import org.hyperledger.besu.evm.precompile.ECRECPrecompiledContract;
import org.hyperledger.besu.evm.precompile.FalconPrecompiledContract;
import org.hyperledger.besu.evm.precompile.IDPrecompiledContract;
import org.hyperledger.besu.evm.precompile.RIPEMD160PrecompiledContract;
import org.hyperledger.besu.evm.precompile.SHA256PrecompiledContract;
Expand Down Expand Up @@ -75,6 +76,13 @@ public interface GasCalculator {
*/
long getEcrecPrecompiledContractGasCost();

/**
* Returns the gas cost to execute the {@link FalconPrecompiledContract}.
*
* @return the gas cost to execute the Falcon Signature verification precompiled contract
*/
long getFrecPrecompiledContractGasCost();

/**
* Returns the gas cost to execute the {@link SHA256PrecompiledContract}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright IADB.
*
* 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 static java.nio.charset.StandardCharsets.UTF_8;

import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

import javax.annotation.Nonnull;

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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FalconPrecompiledContract extends AbstractPrecompiledContract {

private static final Logger LOG = LoggerFactory.getLogger(AbstractBLS12PrecompiledContract.class);

private static final Bytes METHOD_ABI =
Hash.keccak256(Bytes.of("verify(bytes,bytes,bytes32)".getBytes(UTF_8))).slice(0, 4);
private static final String SIGNATURE_ALGORITHM = "Falcon-512";

private final FalconSigner falconSigner = new FalconSigner();

public FalconPrecompiledContract(final GasCalculator gasCalculator) {
super("Falcon", gasCalculator);
}

@Override
public long gasRequirement(final Bytes input) {
long value = gasCalculator().getFrecPrecompiledContractGasCost();
LOG.debug("Gas requirement calculation for Falcon has been called {}", value);
return value;
}

@Nonnull
@Override
public PrecompileContractResult computePrecompile(
final Bytes methodInput, @Nonnull final MessageFrame messageFrame) {
Bytes methodAbi = methodInput.slice(0, METHOD_ABI.size());
if (!methodAbi.xor(METHOD_ABI).isZero()) {
throw new IllegalArgumentException("Unexpected method ABI: " + methodAbi.toHexString());
}
Bytes input = methodInput.slice(METHOD_ABI.size());
int signatureOffset = input.slice(0, 32).trimLeadingZeros().toInt();
int pubKeyOffset = input.slice(32, 32).trimLeadingZeros().toInt();

int signatureLength = input.slice(signatureOffset, 32).trimLeadingZeros().toInt();
int pubKeyLength = input.slice(pubKeyOffset, 32).trimLeadingZeros().toInt();
int dataLength = 32;

Bytes signatureSlice = input.slice(signatureOffset + 32, signatureLength);
Bytes pubKeySlice = input.slice(pubKeyOffset + 32 + 1, pubKeyLength - 1);
Bytes dataSlice = input.slice(64, dataLength);

if (LOG.isTraceEnabled()) {
LOG.trace(
"{} verify: signature={}, pubKey={}, data={}",
SIGNATURE_ALGORITHM,
signatureSlice.toHexString(),
pubKeySlice.toHexString(),
dataSlice.toHexString());
}
FalconPublicKeyParameters falconPublicKeyParameters =
new FalconPublicKeyParameters(FalconParameters.falcon_512, pubKeySlice.toArray());
falconSigner.init(false, falconPublicKeyParameters);
final boolean verifies =
falconSigner.verifySignature(dataSlice.toArray(), signatureSlice.toArray());
if (verifies) {
Bytes digest = Hash.shake256(input.slice(pubKeyOffset + 32, pubKeyLength), 32);
return PrecompileContractResult.success(Bytes32.leftPad(digest));
} else {
return PrecompileContractResult.success(Bytes32.leftPad(Bytes.of(0)));
}
}
}
Loading
Loading