package org.bouncycastle.pqc.crypto.falcon;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.pqc.crypto.MessageSigner;

public class FalconSigner
    implements MessageSigner
{
    private byte[] encodedkey;
    private FalconNIST nist;

    public void init(boolean forSigning, CipherParameters param)
    {
        if (forSigning)
        {
            if (param instanceof ParametersWithRandom)
            {
                FalconPrivateKeyParameters skparam = ((FalconPrivateKeyParameters)((ParametersWithRandom)param).getParameters());
                encodedkey = skparam.getEncoded();
                nist = new FalconNIST(skparam.getParameters().getLogN(),
                    skparam.getParameters().getNonceLength(),
                    ((ParametersWithRandom)param).getRandom());
            }
            else
            {
                FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)param;
                encodedkey = ((FalconPrivateKeyParameters)param).getEncoded();
                nist = new FalconNIST(skparam.getParameters().getLogN(),
                    skparam.getParameters().getNonceLength(),
                    CryptoServicesRegistrar.getSecureRandom());
            }
        }
        else
        {
            FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)param;
            encodedkey = pkparam.getH();
            nist = new FalconNIST(pkparam.getParameters().getLogN(),
                pkparam.getParameters().getNonceLength(),
                CryptoServicesRegistrar.getSecureRandom());
        }
    }

    public byte[] generateSignature(byte[] message)
    {
        byte[] sm = new byte[nist.CRYPTO_BYTES];

        return nist.crypto_sign(sm, message, message.length, encodedkey);
    }

    public boolean verifySignature(byte[] message, byte[] signature)
    {
        // Reject a malformed/truncated signature before indexing it: a signature
        // shorter than the header byte + nonce would otherwise throw
        // ArrayIndexOutOfBoundsException / NegativeArraySizeException here.
        if (signature.length < nist.NONCELEN + 1)
        {
            return false;
        }
        if (signature[0] != (byte)(0x30 + nist.LOGN))
        {
            return false;
        }
        byte[] nonce = new byte[nist.NONCELEN];
        byte[] sig = new byte[signature.length - nist.NONCELEN - 1];
        System.arraycopy(signature, 1, nonce, 0, nist.NONCELEN);
        System.arraycopy(signature, nist.NONCELEN + 1, sig, 0, signature.length - nist.NONCELEN - 1);
        return nist.crypto_sign_open(sig,nonce,message,encodedkey) == 0;
    }
}
