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

org.cardanofoundation.cip30.Cip30VerificationResult Maven / Gradle / Ivy

package org.cardanofoundation.cip30;

import com.bloxbean.cardano.client.address.util.AddressUtil;
import com.bloxbean.cardano.client.exception.AddressExcepion;
import com.bloxbean.cardano.client.util.HexUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.Objects;
import java.util.Optional;

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

/**
 * The Cip30VerificationResult contains validation information after parsing / verifying.
 */
@ParametersAreNonnullByDefault
public class Cip30VerificationResult {

    /**
     * Static instance of {@code Logger} used for logging.
     */
    private static final Logger logger = LoggerFactory.getLogger(CIP30Verifier.class);

    /**
     * Provides information in case that the validation of the message fails.
     */
    private Optional validationError = Optional.of(ValidationError.UNKNOWN);

    /**
     * Optional Cardano address as byte array
     */
    private Optional address = Optional.empty();

    private byte[] ed25519PublicKey;

    private byte[] ed25519Signature;

    /**
     * The actual message encoded in signature field of DataSignature.
     */
    private byte[] message;

    /**
     * This is cose wrapped message (Signature1) that has been directly signed by ED 25519 algorithm.
     */
    private byte[] cosePayload;

    /**
     * whether body of the message is hashed rather than full body
     */
    private boolean isHashed;

    public static class Builder {


        private Optional validationError = Optional.of(ValidationError.UNKNOWN);

        private Optional address = Optional.empty();

        private byte[] ed25519PublicKey;

        private byte[] ed25519Signature;

        private byte[] message;

        private byte[] cosePayload;

        private boolean isHashed;

        /**
         * Creates an object {@code Builder} in charge of building the class
         * {@code Cip30VerificationResult}.
         */
        static Builder newBuilder() {
            return new Builder();
        }

        public Builder valid() {
            this.validationError = Optional.empty();
            return Builder.this;
        }

        public Builder validationError(ValidationError error) {
            Objects.requireNonNull(error, "validation error is required");

            this.validationError = Optional.of(error);
            return Builder.this;
        }

        public Builder address(byte[] address) {
            Objects.requireNonNull(address, "address is required");
            this.address = Optional.of(address);
            return Builder.this;
        }

        public Builder ed25519PublicKey(byte[] ed25519PublicKey) {
            Objects.requireNonNull(ed25519PublicKey, "public key is required");
            this.ed25519PublicKey = ed25519PublicKey;
            return Builder.this;
        }

        public Builder ed25519Signature(byte[] signature) {
            Objects.requireNonNull(signature, "signature is required");
            this.ed25519Signature = signature;
            return Builder.this;
        }

        public Builder message(byte[] message) {
            this.message = message;
            return Builder.this;
        }

        public Builder cosePayload(byte[] cosePayload) {
            Objects.requireNonNull(cosePayload, "cosePayload is required");
            this.cosePayload = cosePayload;
            return Builder.this;
        }

        public Builder isHashed(boolean isHashed) {
            this.isHashed = isHashed;
            return Builder.this;
        }

        /**
         * Creates an instance of the class {@code Cip30VerificationResult} using the information
         * stored.
         */
        public Cip30VerificationResult build() {
            return new Cip30VerificationResult(this);
        }
    }

    /**
     * Builder's private constructor
     *
     * @param builder
     */
    private Cip30VerificationResult(Builder builder) {
        this.validationError = builder.validationError;
        this.address = builder.address;
        this.ed25519PublicKey = builder.ed25519PublicKey;
        this.ed25519Signature = builder.ed25519Signature;
        this.message = builder.message;
        this.cosePayload = builder.cosePayload;
        this.isHashed = builder.isHashed;
    }

    /**
     * Checks if CIP-30 DataSignature is valid.
     *
     * @return true if valid, false otherwise
     */
    public boolean isValid() {
        return validationError.isEmpty();
    }

    /**
     * Returns an optional of the enum {@code ValidationError}.
     *
     * @return if CIP-30 DataSignature is valid returns Optional.empty,
     * if DataSignature is invalid it will return Optional with an actual {@code ValidationError}.
     */
    public Optional getValidationError() {
        return validationError;
    }

    /**
     * @return optionally present Cardano address
     */
    public Optional getAddress() {
        return address;
    }

    public Optional getAddress(AddressFormat format) {
        return switch (format) {
            case HEX -> address.map(HexUtil::encodeHexString);
            case TEXT -> address.flatMap(addr -> {
                try {
                    return Optional.of(AddressUtil.bytesToAddress(addr));
                } catch (AddressExcepion e) {
                    logger.error("Error converting address to text", e);
                    return Optional.empty();
                }
            });
        };
    }

    /**
     * @return ED 25519 public key embedded in signature part of DataSignature (CIP-30).
     * Returns null in case CIP-30 DataSignature is invalid.
     */
    public @Nullable byte[] getEd25519PublicKey() {
        return ed25519PublicKey;
    }

    /**
     * @return ED 25519 signature embedded in signature part of DataSignature (CIP-30).
     * Returns null in case CIP-30 DataSignature is invalid.
     */
    public @Nullable byte[] getEd25519Signature() {
        return ed25519Signature;
    }

    /**
     * @return actual signed message, which is embedded in signature part of DataSignature (CIP-30).
     * Returns null in case CIP-30 DataSignature is invalid.
     */
    public @Nullable byte[] getMessage() {
        return message;
    }

    /**
     * @return Signature1 map serialised as bytes, which is embedded in signature part of DataSignature (CIP-30).
     * It will return null in case CIP-30 DataSignature is invalid.
     */
    public @Nullable byte[] getCosePayload() {
        return cosePayload;
    }

    /**
     * return whether body is hashed or not (e.g. hardware wallet scenario)
     * @return
     */
    public boolean isHashed() {
        return isHashed;
    }

    /**
     * Returns the Ed25519 public key in a specific encoding format and charset.
     * 

* The possible encoding formats are defined by the enum {@code Format} and * the possible charset by the enum {@code StandardCharsets}. * * @param f the encoding format wanted for the returned public key. * @param c the wanted charset * @return the formatted public key or null if CIP-30 DataSignature parsing / validation failed. */ public String getEd25519PublicKey(MessageFormat f, Charset c) { return formatter(ed25519PublicKey, f, c); } /** * Returns the Ed25519 public key in a specific encoding format and {@code UTF_8} charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the charset is assumed to be {@code UTF_8}. * * @param f The encoding format wanted for the returned Ed25519 public key. * @return the Ed25519 public key or null if CIP-30 DataSignature parsing / validation failed. */ public @Nullable String getEd25519PublicKey(MessageFormat f) { return getEd25519PublicKey(f, UTF_8); } /** * Returns the Ed25519 signature of the message in a specific encoding format and charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the possible charset by the enum {@code StandardCharsets}. * * @param f the encoding format wanted for the returned Ed25519 signature. * @param c the wanted charset * @return the formatted Ed25519 signature or null if CIP-30 DataSignature parsing / validation failed. */ public @Nullable String getEd25519Signature(MessageFormat f, Charset c) { return formatter(ed25519Signature, f, c); } /** * Returns the Ed25519 signature of the message in a specific encoding format and * {@code UTF_8} charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the charset is assumed to be {@code UTF_8}. * * @param f the encoding format wanted for the returned signature. * @return the formatted Ed25519 signature or null if CIP-30 DataSignature parsing / validation failed. */ public @Nullable String getEd25519Signature(MessageFormat f) { return getEd25519Signature(f, UTF_8); } /** * Returns the message in a specific encoding format and charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the possible charset by the enum {@code StandardCharsets}. * * @param f The encoding format wanted for the returned message. * @param c The charset wanted for the returned message. * @return the formatted message or null if CIP-30 DataSignature parsing / validation failed. */ public @Nullable String getMessage(MessageFormat f, Charset c) { return formatter(message, f, c); } /** * Returns the message in a specific encoding format and {@code UTF_8} charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the charset is {@code UTF_8}. * * @param f The encoding format wanted for the returned message. * @return the formatted message or null if CIP-30 DataSignature parsing / validation failed. */ public @Nullable String getMessage(MessageFormat f) { return getMessage(f, UTF_8); } /** * Returns the cose payload in a specific encoding format and {@code UTF_8} charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the charset is {@code UTF_8}. * * @param f The encoding format wanted for the returned cose payload. * @return the COSE payload in the provided encoding format. */ public @Nullable String getCosePayload(MessageFormat f) { return getCosePayload(f, UTF_8); } /** * Returns the cose payload in a specific encoding format and charset. *

* The possible encoding formats are defined by the enum {@code Format} and * the possible charset by the enum {@code StandardCharsets}. * * @param f The encoding format wanted for the returned cose payload. * @param c The charset wanted for the returned cose payload. * @return the COSE payload in the provided encoding format and charset. */ public @Nullable String getCosePayload(MessageFormat f, Charset c) { return formatter(cosePayload, f, c); } /** * Creates a new {@code Cip30VerificationResult} containing information of * the validation error in case that the information is not valid with the * CIP 30 specification. * * @param error the value of the enum {@code ValidationError} corresponding with * the reason why the information is not valid. * @return a new {@code Cip30VerificationResult} containing information of * the validation error. */ public static Cip30VerificationResult createInvalid(ValidationError error) { return Builder.newBuilder() .validationError(error) .build(); } /** * Changes the format of the information provided. *

* The possible encoding formats are defined by the enum {@code Format} and * the possible charset by the enum {@code StandardCharsets}. * * @param bytes array of bytes with the information to be formatted. * @param f The encoding format wanted for the returned information. * @param c The charset wanted for the returned information. * @return array of bytes provided transformed to the encoding and format and * charset specified. */ private String formatter(byte[] bytes, MessageFormat f, Charset c) { if (bytes == null) { return null; } if (f == null) { throw new IllegalArgumentException("format must be defined"); } if (c == null) { throw new IllegalArgumentException("charset must be defined"); } return switch (f) { case HEX -> HexUtil.encodeHexString(bytes); case TEXT -> new String(bytes, c); case BASE64 -> Base64.getEncoder().encodeToString(bytes); }; } /** * Returns a string representation of this {@code Cip30VerificationResult}. This method is * intended to be used only for debugging purposes. * * @return a string representation of this {@code Cip30VerificationResult}. */ @Override public String toString() { return "Cip30VerificationResult{" + "valid=" + validationError.isEmpty() + ", validationError=" + validationError + ", address=" + address + ", ed25519PublicKey=" + ed25519PublicKey + ", ed25519Signature=" + ed25519Signature + ", message=" + message + ", cosePayload=" + cosePayload + ", isHashed=" + isHashed + '}'; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy