Skip to content

Commit

Permalink
falcon signature verification with public key digest result
Browse files Browse the repository at this point in the history
  • Loading branch information
eum602 committed Jul 3, 2023
1 parent d81abd6 commit b670a98
Show file tree
Hide file tree
Showing 21 changed files with 286 additions and 12 deletions.
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,11 +26,18 @@
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 {
private Hash() {}

/** The constant KECCAK256_ALG. */
public static final String KECCAK256_ALG = "KECCAK-256";

private static final String SHA256_ALG = "SHA-256";
private static final String RIPEMD160_ALG = "RIPEMD160";
private static final String BLAKE2BF_ALG = "BLAKE2BF";
private static final Supplier<MessageDigest> KECCAK256_SUPPLIER =
Suppliers.memoize(() -> messageDigest(KECCAK256_ALG));
private static final Supplier<MessageDigest> SHA256_SUPPLIER =
Expand Down Expand Up @@ -105,4 +112,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

0 comments on commit b670a98

Please sign in to comment.