com.swirlds.common.crypto.engine.Ed25519VerificationProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
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.
/*
* Copyright (C) 2019-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 static com.swirlds.common.utility.CommonUtils.hex;
import static com.swirlds.logging.legacy.LogMarker.TESTING_EXCEPTIONS;
import com.goterl.lazysodium.LazySodiumJava;
import com.goterl.lazysodium.SodiumJava;
import com.goterl.lazysodium.interfaces.Sign;
import com.swirlds.common.crypto.SignatureType;
import com.swirlds.common.crypto.TransactionSignature;
import java.nio.ByteBuffer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Implementation of an Ed25519 signature verification provider. This implementation only supports
* Ed25519 signatures and depends on LazySodium (libSodium) for all operations.
*/
public class Ed25519VerificationProvider
extends OperationProvider {
private static final Logger logger = LogManager.getLogger(Ed25519VerificationProvider.class);
/**
* The JNI interface to the underlying native libSodium dynamic library. This variable is initialized when this
* class is loaded and initialized by the {@link ClassLoader}.
*/
private static final Sign.Native algorithm;
static {
final SodiumJava sodiumJava = new SodiumJava();
algorithm = new LazySodiumJava(sodiumJava);
}
/**
* Default Constructor.
*/
public Ed25519VerificationProvider() {
super();
}
/**
* Computes the result of the cryptographic transformation using the provided item and algorithm. This
* implementation defaults to an Ed25519 signature and is provided for convenience.
*
* @param message
* the original message that was signed
* @param signature
* the signature to be verified
* @param publicKey
* the public key used to verify the signature
* @return true if the provided signature is valid; false otherwise
*/
protected boolean compute(final byte[] message, final byte[] signature, final byte[] publicKey) {
return compute(message, signature, publicKey, SignatureType.ED25519);
}
/**
* Computes the result of the cryptographic transformation using the provided item and algorithm.
*
* @param algorithmType
* the type of algorithm to be used when performing the transformation
* @param message
* the original message that was signed
* @param signature
* the signature to be verified
* @param publicKey
* the public key used to verify the signature
* @return true if the provided signature is valid; false otherwise
*/
protected boolean compute(
final byte[] message, final byte[] signature, final byte[] publicKey, final SignatureType algorithmType) {
final Sign.Native loadedAlgorithm = loadAlgorithm(algorithmType);
return compute(loadedAlgorithm, algorithmType, message, signature, publicKey);
}
/**
* {@inheritDoc}
*/
@Override
protected Sign.Native loadAlgorithm(final SignatureType algorithmType) {
return algorithm;
}
/**
* {@inheritDoc}
*/
@Override
protected Boolean handleItem(
final Sign.Native algorithm,
final SignatureType algorithmType,
final TransactionSignature item,
final Void optionalData) {
return compute(algorithm, algorithmType, item);
}
/**
* Computes the result of the cryptographic transformation using the provided item and algorithm.
*
* @param algorithm
* the concrete instance of the required algorithm
* @param algorithmType
* the type of algorithm to be used when performing the transformation
* @param message
* the original message that was signed
* @param signature
* the signature to be verified
* @param publicKey
* the public key used to verify the signature
* @return true if the provided signature is valid; false otherwise
*/
private boolean compute(
final Sign.Native algorithm,
final SignatureType algorithmType,
final byte[] message,
final byte[] signature,
final byte[] publicKey) {
final boolean isValid = algorithm.cryptoSignVerifyDetached(signature, message, message.length, publicKey);
if (!isValid && logger.isDebugEnabled()) {
logger.debug(
TESTING_EXCEPTIONS.getMarker(),
"Adv Crypto Subsystem: Signature Verification Failure for signature type {} [ publicKey = {}, "
+ "signature = {} ]",
algorithmType,
hex(publicKey),
hex(signature));
}
return isValid;
}
/**
* Computes the result of the cryptographic transformation using the provided sig and algorithm.
*
* @param algorithm
* the concrete instance of the required algorithm
* @param algorithmType
* the type of algorithm to be used when performing the transformation
* @param sig
* the input signature to be transformed
* @return true if the provided signature is valid; false otherwise
*/
private boolean compute(
final Sign.Native algorithm, final SignatureType algorithmType, final TransactionSignature sig) {
final byte[] payload = sig.getContentsDirect();
final byte[] expandedPublicKey = sig.getExpandedPublicKey();
final ByteBuffer buffer = ByteBuffer.wrap(payload);
final ByteBuffer pkBuffer = (expandedPublicKey != null && expandedPublicKey.length > 0)
? ByteBuffer.wrap(expandedPublicKey)
: buffer;
final byte[] signature = new byte[sig.getSignatureLength()];
final byte[] publicKey = new byte[sig.getPublicKeyLength()];
final byte[] message = new byte[sig.getMessageLength()];
buffer.position(sig.getMessageOffset())
.get(message)
.position(sig.getSignatureOffset())
.get(signature);
pkBuffer.position(sig.getPublicKeyOffset()).get(publicKey);
return compute(algorithm, algorithmType, message, signature, publicKey);
}
}