All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swirlds.common.crypto.engine.CryptoEngine Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.56.6
Show newest version
/*
 * Copyright (C) 2018-2024 Hedera Hashgraph, LLC
 *
 * 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.
 */

package com.swirlds.common.crypto.engine;

import com.swirlds.common.crypto.Cryptography;
import com.swirlds.common.crypto.CryptographyException;
import com.swirlds.common.crypto.DigestType;
import com.swirlds.common.crypto.Hash;
import com.swirlds.common.crypto.HashBuilder;
import com.swirlds.common.crypto.Message;
import com.swirlds.common.crypto.SerializableHashable;
import com.swirlds.common.crypto.SignatureType;
import com.swirlds.common.crypto.TransactionSignature;
import com.swirlds.common.crypto.VerificationStatus;
import com.swirlds.common.io.SelfSerializable;
import com.swirlds.common.threading.futures.StandardFuture;
import com.swirlds.logging.legacy.LogMarker;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class CryptoEngine implements Cryptography {

    /**
     * The constant value used as the component name for all threads created by this module.
     */
    public static final String THREAD_COMPONENT_NAME = "adv crypto";

    static {
        // Register the BouncyCastle Provider instance with the JVM
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * The digest provider instance that is used to generate hashes of SelfSerializable objects.
     */
    private final SerializationDigestProvider serializationDigestProvider;

    /**
     * The digest provider instance that is used to generate running hashes.
     */
    private final RunningHashProvider runningHashProvider;

    /**
     * The digest provider instance that is used to compute hashes of {@link Message} instances and byte arrays.
     */
    private final DigestProvider digestProvider;

    /**
     * The verification provider used to perform signature verification of {@link TransactionSignature} instances.
     */
    private final Ed25519VerificationProvider ed25519VerificationProvider;

    /**
     * The verification provider used to perform signature verification of {@link TransactionSignature} instances.
     */
    private final EcdsaSecp256k1VerificationProvider ecdsaSecp256k1VerificationProvider;

    /**
     * a pre-computed {@link Map} of each algorithm's {@code null} hash value.
     */
    private Map nullHashes;

    /**
     * Constructor.
     */
    public CryptoEngine() {
        this.digestProvider = new DigestProvider();

        this.ed25519VerificationProvider = new Ed25519VerificationProvider();
        this.ecdsaSecp256k1VerificationProvider = new EcdsaSecp256k1VerificationProvider();

        this.serializationDigestProvider = new SerializationDigestProvider();
        this.runningHashProvider = new RunningHashProvider();

        buildNullHashes();
    }

    /**
     * Common private utility method for performing synchronous signature verification.
     *
     * @param signature the signature to be verified
     * @param provider  the underlying provider to be used
     * @param future    the {@link Future} to be associated with the {@link TransactionSignature}
     * @return true if the signature is valid; otherwise false
     */
    private static boolean verifySyncInternal(
            final TransactionSignature signature,
            final OperationProvider provider,
            final StandardFuture future) {
        final boolean isValid;

        try {
            isValid = provider.compute(signature, signature.getSignatureType());
            signature.setSignatureStatus(isValid ? VerificationStatus.VALID : VerificationStatus.INVALID);
            signature.setFuture(future);
        } catch (final NoSuchAlgorithmException ex) {
            signature.setFuture(future);
            throw new CryptographyException(ex, LogMarker.EXCEPTION);
        }

        return isValid;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Hash digestSync(final byte[] message, final DigestType digestType) {
        return new Hash(digestSyncInternal(message, digestType, digestProvider), digestType);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public byte[] digestBytesSync(final SelfSerializable serializable, final DigestType digestType) {
        try {
            return serializationDigestProvider.compute(serializable, digestType);
        } catch (final NoSuchAlgorithmException ex) {
            throw new CryptographyException(ex, LogMarker.EXCEPTION);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Hash digestSync(
            final SerializableHashable serializableHashable, final DigestType digestType, final boolean setHash) {
        try {
            final byte[] bytes = serializationDigestProvider.compute(serializableHashable, digestType);
            final Hash hash = new Hash(bytes, digestType);
            if (setHash) {
                serializableHashable.setHash(hash);
            }
            return hash;
        } catch (final NoSuchAlgorithmException ex) {
            throw new CryptographyException(ex, LogMarker.EXCEPTION);
        }
    }

    @NonNull
    @Override
    public byte[] digestBytesSync(@NonNull final byte[] message, @NonNull final DigestType digestType) {
        return digestSyncInternal(message, digestType, digestProvider);
    }

    /**
     * Compute and store hash for null using different digest types.
     */
    private void buildNullHashes() {
        nullHashes = new HashMap<>();
        for (final DigestType digestType : DigestType.values()) {
            final HashBuilder hb = new HashBuilder(digestType);
            nullHashes.put(digestType, hb.build());
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Hash getNullHash(final DigestType digestType) {
        return nullHashes.get(digestType);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean verifySync(final TransactionSignature signature) {
        final StandardFuture future = new StandardFuture<>();
        future.complete(null);
        if (signature.getSignatureType() == SignatureType.ECDSA_SECP256K1) {
            return verifySyncInternal(signature, ecdsaSecp256k1VerificationProvider, future);
        } else {
            return verifySyncInternal(signature, ed25519VerificationProvider, future);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean verifySync(final List signatures) {
        final StandardFuture future = new StandardFuture<>();
        future.complete(null);

        boolean finalOutcome = true;

        OperationProvider provider;
        for (final TransactionSignature signature : signatures) {
            if (signature.getSignatureType() == SignatureType.ECDSA_SECP256K1) {
                provider = ecdsaSecp256k1VerificationProvider;
            } else {
                provider = ed25519VerificationProvider;
            }

            if (!verifySyncInternal(signature, provider, future)) {
                finalOutcome = false;
            }
        }

        return finalOutcome;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean verifySync(
            final byte[] data, final byte[] signature, final byte[] publicKey, final SignatureType signatureType) {
        if (signatureType == SignatureType.ECDSA_SECP256K1) {
            return ecdsaSecp256k1VerificationProvider.compute(data, signature, publicKey, signatureType);
        } else {
            return ed25519VerificationProvider.compute(data, signature, publicKey, signatureType);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Hash calcRunningHash(final Hash runningHash, final Hash newHashToAdd, final DigestType digestType) {
        try {
            return runningHashProvider.compute(runningHash, newHashToAdd, digestType);
        } catch (final NoSuchAlgorithmException e) {
            throw new CryptographyException(e, LogMarker.EXCEPTION);
        }
    }
    /**
     * Common private utility method for performing synchronous digest computations.
     *
     * @param message    the message contents to be hashed
     * @param digestType the type of digest used to compute the hash
     * @param provider   the underlying provider to be used
     * @return the cryptographic hash for the given message contents
     */
    private @NonNull byte[] digestSyncInternal(
            @NonNull final byte[] message,
            @NonNull final DigestType digestType,
            @NonNull final DigestProvider provider) {
        try {
            return provider.compute(message, digestType);
        } catch (final NoSuchAlgorithmException ex) {
            throw new CryptographyException(ex, LogMarker.EXCEPTION);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy