Skip to content

Commit

Permalink
Add Falcon signature verification precompiled contract
Browse files Browse the repository at this point in the history
  • Loading branch information
diega committed Jan 28, 2021
1 parent 9497fe7 commit 11bfb91
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 1 deletion.
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ allprojects {
maven { url "https://consensys.bintray.com/pegasys-repo" }
maven { url "https://splunk.jfrog.io/splunk/ext-releases-local" }
maven { url "https://dl.bintray.com/open-telemetry/maven" }
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/lacchain/liboqs-java/")
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
}
}
}

dependencies { errorprone "com.google.errorprone:error_prone_core" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ public interface GenesisConfigOptions {
*/
OptionalLong getThanosBlockNumber();

OptionalLong getLacchainPostQuantumBlockNumber();

Optional<BigInteger> getChainId();

OptionalInt getContractSizeLimit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ public OptionalLong getThanosBlockNumber() {
return getOptionalLong("thanosblock");
}

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

@Override
public Optional<BigInteger> getChainId() {
return getOptionalBigInteger("chainid");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
private final OptionalLong aghartaBlockNumber = OptionalLong.empty();
private final OptionalLong phoenixBlockNumber = OptionalLong.empty();
private final OptionalLong thanosBlockNumber = OptionalLong.empty();
private final OptionalLong lacchainPostQuantumBlockNumber = OptionalLong.empty();
private Optional<BigInteger> chainId = Optional.empty();
private OptionalInt contractSizeLimit = OptionalInt.empty();
private OptionalInt stackSizeLimit = OptionalInt.empty();
Expand Down Expand Up @@ -200,6 +201,11 @@ public OptionalLong getThanosBlockNumber() {
return thanosBlockNumber;
}

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

@Override
public OptionalInt getContractSizeLimit() {
return contractSizeLimit;
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 @@ -9,6 +9,7 @@
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"lacchainpqblock": 0,
"contractSizeLimit": 2147483647,
"ethash": {
"fixeddifficulty": 100
Expand Down
19 changes: 18 additions & 1 deletion docker/openjdk-11/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@

FROM openjdk:11.0.7-jre-slim-buster
FROM openjdk:11.0.7-jre-slim-buster as base

RUN apt-get update && apt-get install --no-install-recommends -yV \
dpkg-dev \
wget \
ca-certificates

RUN mkdir /debs/
RUN wget --directory-prefix=/debs/ https://github.com/lacchain/liboqs-debian/releases/download/0.4.0/liboqs_0.4.0_amd64.deb
RUN wget --directory-prefix=/debs/ https://github.com/lacchain/liboqs-debian/releases/download/0.4.0/SHA256SUMS
RUN cd /debs/ && sha256sum --check --ignore-missing --status SHA256SUMS && dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
RUN echo "deb [trusted=yes] file:/debs ./" >> /etc/apt/sources.list

FROM base as runner

RUN apt-get update && apt-get install --no-install-recommends -yV \
liboqs \
&& rm -rf /var/lib/apt/lists/*

RUN adduser --disabled-password --gecos "" --home /opt/besu besu && \
chown besu:besu /opt/besu
Expand Down
1 change: 1 addition & 0 deletions ethereum/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation 'org.apache.tuweni:units'
implementation 'org.hyperledger.besu:bls12-381'
implementation 'org.immutables:value-annotations'
implementation 'org.openquantumsafe:liboqs-java'

implementation 'org.xerial.snappy:snappy-java'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class Address extends DelegatingBytes implements org.hyperledger.besu.plu
public static final Address BLS12_PAIRING = Address.precompiled(0x10);
public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x11);
public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x12);
public static final Address LACCHAIN_FALCON = Address.precompiled(0x13);

// Last address that can be generated for a pre-compiled contract
public static final Integer PRIVACY = Byte.MAX_VALUE - 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.mainnet.precompiles.FalconPrecompiledContract;

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,
final boolean quorumCompatibilityMode) {
return MainnetProtocolSpecs.istanbulDefinition(
chainId,
contractSizeLimit,
configStackSizeLimit,
enableRevertReason,
quorumCompatibilityMode)
.precompileContractRegistryBuilder(
precompiledContractConfiguration -> {
PrecompileContractRegistry lacchainContractsRegistry =
MainnetPrecompiledContractRegistries.istanbul(precompiledContractConfiguration);
lacchainContractsRegistry.put(
Address.LACCHAIN_FALCON,
Account.DEFAULT_VERSION,
new FalconPrecompiledContract(
precompiledContractConfiguration.getGasCalculator()));
return lacchainContractsRegistry;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,15 @@ public ProtocolSchedule createProtocolSchedule() {
isRevertReasonEnabled,
config.getEcip1017EraRounds(),
quorumCompatibilityMode));
addProtocolSpec(
protocolSchedule,
config.getLacchainPostQuantumBlockNumber(),
LacchainProtocolSpecs.postQuantumDefinition(
chainId,
config.getContractSizeLimit(),
config.getEvmStackSize(),
isRevertReasonEnabled,
quorumCompatibilityMode));

LOG.info("Protocol schedule created with milestones: {}", protocolSchedule.listMilestones());
return protocolSchedule;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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.precompiles;

import static java.nio.charset.StandardCharsets.UTF_8;

import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.mainnet.AbstractPrecompiledContract;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.openquantumsafe.Signature;

/**
* note: Liboqs - random number generation defaults to /dev/urandom a better form is to use the
* OQS_RAND_agl_openssl "OpenSSL" random number algorithm, then set the environment default engine
* to IBRand for quantum entropy
*/
public class FalconPrecompiledContract extends AbstractPrecompiledContract {

private static final Logger LOG = LogManager.getLogger();

private static final Bytes METHOD_ABI =
Hash.keccak256(Bytes.of("verify(bytes,bytes,bytes)".getBytes(UTF_8))).slice(0, 4);
// taken from liboqs C sig.h header, OQS_SIG_alg_falcon_512
private static final String SIGNATURE_ALGORITHM = "Falcon-512";

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

@Override
public Gas gasRequirement(final Bytes input) {
return gasCalculator().sha256PrecompiledContractGasCost(input);
}

@Override
public Bytes compute(final Bytes methodInput, 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 dataOffset = input.slice(64, 32).trimLeadingZeros().toInt();

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

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

if (LOG.isTraceEnabled()) {
LOG.trace(
"{} verify: signature={}, pubKey={}, data={}",
SIGNATURE_ALGORITHM,
signatureSlice.toHexString(),
pubKeySlice.toHexString(),
dataSlice.toHexString());
}
Signature verifier = new Signature(SIGNATURE_ALGORITHM);
final boolean verifies =
verifier.verify(dataSlice.toArray(), signatureSlice.toArray(), pubKeySlice.toArray());

if (verifies) {
LOG.debug("Signature is VALID");
return Bytes32.leftPad(Bytes.of(0));
} else {
LOG.debug("Signature is INVALID");
return Bytes32.leftPad(Bytes.of(1));
}
}
}
2 changes: 2 additions & 0 deletions gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ dependencyManagement {

dependency 'org.springframework.security:spring-security-crypto:5.2.3.RELEASE'

dependency 'org.openquantumsafe:liboqs-java:1.1-SNAPSHOT'

dependency 'org.web3j:abi:4.5.15'
dependency 'org.web3j:besu:4.5.15'
dependency 'org.web3j:core:4.5.15'
Expand Down

0 comments on commit 11bfb91

Please sign in to comment.